github.com/mweagle/Sparta@v1.15.0/aws/cloudwatch/metrics_awsbinary.go (about)

     1  // +build lambdabinary
     2  
     3  package cloudwatch
     4  
     5  import (
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	awsCloudWatch "github.com/aws/aws-sdk-go/service/cloudwatch"
    11  	sparta "github.com/mweagle/Sparta"
    12  	spartaAWS "github.com/mweagle/Sparta/aws"
    13  	gopsutilCPU "github.com/shirou/gopsutil/cpu"
    14  	gopsutilDisk "github.com/shirou/gopsutil/disk"
    15  	gopsutilHost "github.com/shirou/gopsutil/host"
    16  	gopsutilLoad "github.com/shirou/gopsutil/load"
    17  	gopsutilNet "github.com/shirou/gopsutil/net"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  // publishMetrics is the actual metric publishing logic. T
    22  func publishMetrics(customDimensionMap map[string]string) {
    23  	currentTime := time.Now()
    24  
    25  	// https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
    26  	functionName := os.Getenv("AWS_LAMBDA_FUNCTION_NAME")
    27  	cpuMetrics, cpuMetricsErr := gopsutilCPU.Percent(0, false)
    28  	// https://docs.aws.amazon.com/lambda/latest/dg/limits.html
    29  	diskMetrics, diskMetricsErr := gopsutilDisk.Usage("/tmp")
    30  	uptime, uptimeErr := gopsutilHost.Uptime()
    31  	loadMetrics, loadMetricsErr := gopsutilLoad.Avg()
    32  	netMetrics, netMetricsErr := gopsutilNet.IOCounters(false)
    33  
    34  	// For now, just log everything...
    35  	logger, _ := sparta.NewLogger("info")
    36  	logger.WithFields(logrus.Fields{
    37  		"functionName":   functionName,
    38  		"cpuMetrics":     cpuMetrics,
    39  		"cpuMetricsErr":  cpuMetricsErr,
    40  		"diskMetrics":    diskMetrics,
    41  		"diskMetricsErr": diskMetricsErr,
    42  		"uptime":         uptime,
    43  		"uptimeErr":      uptimeErr,
    44  		"loadMetrics":    loadMetrics,
    45  		"loadMetricsErr": loadMetricsErr,
    46  		"netMetrics":     netMetrics,
    47  		"netMetricsErr":  netMetricsErr,
    48  	}).Info("Metric info")
    49  
    50  	// Return the array of metricDatum for the item
    51  	metricDatum := func(name string, value float64, unit MetricUnit) []*awsCloudWatch.MetricDatum {
    52  		defaultDatum := []*awsCloudWatch.MetricDatum{{
    53  			MetricName: aws.String(name),
    54  			Dimensions: []*awsCloudWatch.Dimension{{
    55  				Name:  aws.String("Name"),
    56  				Value: aws.String(sparta.StampedServiceName),
    57  			}},
    58  			Value:     aws.Float64(value),
    59  			Timestamp: &currentTime,
    60  			Unit:      aws.String(string(unit)),
    61  		},
    62  		}
    63  		if len(customDimensionMap) != 0 {
    64  			metricDimension := []*awsCloudWatch.Dimension{{
    65  				Name:  aws.String("Name"),
    66  				Value: aws.String(sparta.StampedServiceName),
    67  			}}
    68  			for eachKey, eachValue := range customDimensionMap {
    69  				metricDimension = append(metricDimension, &awsCloudWatch.Dimension{
    70  					Name:  aws.String(eachKey),
    71  					Value: aws.String(eachValue),
    72  				})
    73  			}
    74  			defaultDatum = append(defaultDatum, &awsCloudWatch.MetricDatum{
    75  				MetricName: aws.String(name),
    76  				Dimensions: metricDimension,
    77  				Value:      aws.Float64(value),
    78  				Timestamp:  &currentTime,
    79  				Unit:       aws.String(string(unit)),
    80  			})
    81  		}
    82  		return defaultDatum
    83  	}
    84  	// Publish all the metrics...
    85  	// https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html
    86  	metricData := []*awsCloudWatch.MetricDatum{}
    87  	// CPU?
    88  	if len(cpuMetrics) == 1 {
    89  		metricData = append(metricData, metricDatum("CPUPercent", cpuMetrics[0], UnitPercent)...)
    90  	}
    91  	if diskMetricsErr == nil {
    92  		metricData = append(metricData, metricDatum("DiskUsedPercent", diskMetrics.UsedPercent, UnitPercent)...)
    93  	}
    94  	if uptimeErr == nil {
    95  		metricData = append(metricData, metricDatum("Uptime", float64(uptime), UnitMilliseconds)...)
    96  	}
    97  	if loadMetricsErr == nil {
    98  		metricData = append(metricData, metricDatum("Load1", loadMetrics.Load1, UnitNone)...)
    99  		metricData = append(metricData, metricDatum("Load5", loadMetrics.Load5, UnitNone)...)
   100  		metricData = append(metricData, metricDatum("Load15", loadMetrics.Load15, UnitNone)...)
   101  	}
   102  	if netMetricsErr == nil && len(netMetrics) == 1 {
   103  		metricData = append(metricData, metricDatum("NetBytesSent", float64(netMetrics[0].BytesSent), UnitBytes)...)
   104  		metricData = append(metricData, metricDatum("NetBytesRecv", float64(netMetrics[0].BytesRecv), UnitBytes)...)
   105  		metricData = append(metricData, metricDatum("NetErrin", float64(netMetrics[0].Errin), UnitCount)...)
   106  		metricData = append(metricData, metricDatum("NetErrout", float64(netMetrics[0].Errout), UnitCount)...)
   107  	}
   108  	putMetricInput := &awsCloudWatch.PutMetricDataInput{
   109  		MetricData: metricData,
   110  		Namespace:  aws.String(sparta.ProperName),
   111  	}
   112  	session := spartaAWS.NewSession(logger)
   113  	awsCloudWatchSvc := awsCloudWatch.New(session)
   114  	putMetricResponse, putMetricResponseErr := awsCloudWatchSvc.PutMetricData(putMetricInput)
   115  	if putMetricResponseErr != nil {
   116  		logger.WithField("Error", putMetricResponseErr).Error("Failed to submit CloudWatch Metric data")
   117  	} else {
   118  		logger.WithField("Response", putMetricResponse).Info("CloudWatch Metric response")
   119  	}
   120  }
   121  
   122  // RegisterLambdaUtilizationMetricPublisher installs a periodic task
   123  // to publish the current system metrics to CloudWatch Metrics. See
   124  // https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html
   125  // for more information.
   126  func RegisterLambdaUtilizationMetricPublisher(customDimensionMap map[string]string) {
   127  
   128  	// Publish when we start
   129  	publishMetrics(customDimensionMap)
   130  
   131  	ticker := time.NewTicker(1 * time.Minute)
   132  	quit := make(chan struct{})
   133  	go func() {
   134  		for {
   135  			select {
   136  			case <-ticker.C:
   137  				publishMetrics(customDimensionMap)
   138  			case <-quit:
   139  				ticker.Stop()
   140  				return
   141  			}
   142  		}
   143  	}()
   144  }