Skip to content

Commit

Permalink
add support for s3 bucket metrics (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
fishnix authored May 5, 2020
1 parent 6e7d427 commit 8d1ee42
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ GET /v1/cost/{account}/instances/{id}/metrics/graph?metric={metric1}[&metric={me
GET /v1/metrics/{account}/instances/{id}/graph?metric={metric1}[&metric={metric2}&start=-P1D&end=PT0H&period=300]
GET /v1/metrics/{account}/clusters/{cluster}/services/{service}/graph?metric={metric1}[&metric={metric2}&start=-P1D&end=PT0H&period=300]
GET /v1/metrics/{account}/buckets/{bucket}/graph?metric={BucketSizeBytes|NumberOfObjects}
```

## Usage
Expand Down
83 changes: 83 additions & 0 deletions api/handlers_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,86 @@ func parseQuery(r *http.Request, request cloudwatch.MetricsRequest) error {

return nil
}

// GetS3MetricsURLHandler gets metrics from cloudwatch and returns a link to the image
func (s *server) GetS3MetricsURLHandler(w http.ResponseWriter, r *http.Request) {
w = LogWriter{w}
vars := mux.Vars(r)
account := vars["account"]
bucketName := vars["bucket"]
metric := vars["metric"]

cwService, ok := s.cloudwatchServices[account]
if !ok {
msg := fmt.Sprintf("cloudwatch service not found for account: %s", account)
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
return
}
log.Debugf("found cloudwatch service %+v", cwService)

resultCache, ok := s.resultCache[account]
if !ok {
msg := fmt.Sprintf("result cache not found for account: %s", account)
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
return
}
log.Debugf("found cost explorer result cache %+v", *resultCache)

// only support NumberOfObjects and BucketSizeBytes
var storageType string
switch metric {
case "BucketSizeBytes":
storageType = "StandardStorage"
case "NumberOfObjects":
storageType = "AllStorageTypes"
default:
msg := fmt.Sprintf("invalid metric requested: %s", metric)
handleError(w, apierror.New(apierror.ErrBadRequest, msg, nil))
return
}

req := cloudwatch.MetricsRequest{
"period": int64(86400),
"stat": "Maximum",
"start": "-P30D",
"end": "PT0H",
"metrics": []cloudwatch.Metric{
{"AWS/S3", metric, "StorageType", storageType, "BucketName", bucketName},
},
}

key := fmt.Sprintf("%s/%s/%s/%v/%v/%v", Org, bucketName, metric, req["start"], req["end"], req["period"])
hashedCacheKey := s.imageCache.HashedKey(key)
if res, expire, ok := resultCache.GetWithExpiration(hashedCacheKey); ok {
log.Debugf("found cached object: %s", res)

if body, ok := res.([]byte); ok {
w.Header().Set("X-Cache-Hit", "true")
w.Header().Set("X-Cache-Expire", fmt.Sprintf("%0.fs", time.Until(expire).Seconds()))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(body)
return
}
}

log.Debugf("getting metrics with request %+v", req)
image, err := cwService.GetMetricWidget(r.Context(), req)
if err != nil {
log.Errorf("failed getting metrics widget image: %s", err)
handleError(w, err)
return
}

meta, err := s.imageCache.Save(r.Context(), hashedCacheKey, image)
if err != nil {
log.Errorf("failed saving metrics widget image to cache: %s", err)
handleError(w, err)
return
}
resultCache.Set(hashedCacheKey, meta, 300*time.Second)

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(meta)
}
2 changes: 2 additions & 0 deletions api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ func (s *server) routes() {
metricsApi.HandleFunc("/{account}/instances/{id}/graph", s.GetEC2MetricsURLHandler).Methods(http.MethodGet)
// metrics endpoints for ECS services
metricsApi.HandleFunc("/{account}/clusters/{cluster}/services/{service}/graph", s.GetECSMetricsURLHandler).Methods(http.MethodGet)
// metrics endpoints for S3 buckets
metricsApi.HandleFunc("/{account}/buckets/{bucket}/graph", s.GetS3MetricsURLHandler).Queries("metric", "{metric:(?:BucketSizeBytes|NumberOfObjects)}").Methods(http.MethodGet)
}

0 comments on commit 8d1ee42

Please sign in to comment.