platform/lambda/metrics.go
package lambda
import (
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/golang/sync/errgroup"
"github.com/apex/up/internal/metrics"
"github.com/apex/up/platform/event"
)
// TODO: write a higher level pkg in tj/aws
// TODO: move the metrics pkg to tj/aws
type stat struct {
Namespace string
Name string
Metric string
Stat string
point *cloudwatch.Datapoint
}
// Value returns the metric value.
func (s *stat) Value() int {
if s.point == nil {
return 0
}
switch s.Stat {
case "Sum":
return int(*s.point.Sum)
case "Average":
return int(*s.point.Average)
case "Minimum":
return int(*s.point.Minimum)
case "Maximum":
return int(*s.point.Maximum)
default:
return 0
}
}
// stats to fetch.
var stats = []*stat{
{"AWS/ApiGateway", "Requests", "Count", "Sum", nil},
{"AWS/ApiGateway", "Duration min", "Latency", "Minimum", nil},
{"AWS/ApiGateway", "Duration avg", "Latency", "Average", nil},
{"AWS/ApiGateway", "Duration max", "Latency", "Maximum", nil},
{"AWS/Lambda", "Duration sum", "Duration", "Sum", nil},
{"AWS/ApiGateway", "Errors 4xx", "4XXError", "Sum", nil},
{"AWS/ApiGateway", "Errors 5xx", "5XXError", "Sum", nil},
{"AWS/Lambda", "Invocations", "Invocations", "Sum", nil},
{"AWS/Lambda", "Errors", "Errors", "Sum", nil},
{"AWS/Lambda", "Throttles", "Throttles", "Sum", nil},
}
// ShowMetrics implementation.
func (p *Platform) ShowMetrics(region, stage string, start time.Time) error {
s := session.New(aws.NewConfig().WithRegion(region))
c := cloudwatch.New(s)
var g errgroup.Group
name := p.config.Name
d := time.Now().UTC().Sub(start)
for _, s := range stats {
s := s
g.Go(func() error {
m := metrics.New().
Namespace(s.Namespace).
TimeRange(time.Now().Add(-d), time.Now()).
Period(int(d.Seconds() * 2)).
Stat(s.Stat).
Metric(s.Metric)
switch s.Namespace {
case "AWS/ApiGateway":
m = m.Dimension("ApiName", name).Dimension("Stage", stage)
case "AWS/Lambda":
m = m.Dimension("FunctionName", name).Dimension("Resource", name+":"+stage)
}
res, err := c.GetMetricStatistics(m.Params())
if err != nil {
return err
}
if len(res.Datapoints) > 0 {
s.point = res.Datapoints[0]
}
return nil
})
}
if err := g.Wait(); err != nil {
return err
}
for _, s := range stats {
p.events.Emit("metrics.value", event.Fields{
"name": s.Name,
"value": s.Value(),
"memory": p.config.Lambda.Memory,
})
}
return nil
}