Skip to content

Conversation

cam-stitt
Copy link
Contributor

Ref #489.

I'm reasonably happy with the current implementation, but I am having some trouble working out the best way to test the writing of metrics. Going to spend some time investigating ways to run integration tests for this.

CloudWatch charges per API request so we batch the requests for all metrics at once.

@peterbourgon
Copy link
Member

peterbourgon commented Mar 9, 2017

I imagine the best way to test it would be to make a mock cloudwatchiface.CloudWatchAPI in the test, have it accept the writes, and compare output.

edit: (ಠ_ಠ)

@xla
Copy link
Member

xla commented Mar 9, 2017

An approach could be to have a slimmed down interface locally which also makes it explicit what part of the Cloudwatch API the code depends on. Currently only PutMetricData is used, which would reduce the surface to mock significantly.

@cam-stitt
Copy link
Contributor Author

@peterbourgon I did in fact use the interface earlier today. It's all there.

@cam-stitt
Copy link
Contributor Author

I'm happy with where this PR is at. Would love a review.

Copy link
Member

@peterbourgon peterbourgon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The basic structure is good! A few small things to fix up and then LGTM.

"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/generic"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import grouping here.

import (
    // stdlib

    // third-party

    // go-kit/kit/...
)

// New returns a CloudWatch object that may be used to create metrics. Namespace is
// applied to all created metrics and maps to the CloudWatch namespace.
// Callers must ensure that regular calls to Send are performed, either manually or with one of the helper methods.
func New(namespace string, logger log.Logger, svc cloudwatchiface.CloudWatchAPI) *CloudWatch {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logger is typically the last parameter in the constructor.

}

// NewCounter returns a new usable counter metric.
func NewCounter(name string) *Counter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the only "correct" way to construct a new {Counter, Gauge, Histogram} is via the corresponding method on the CloudWatch struct. Am I reading this correctly? If so, should these free functions be eliminated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I followed the pattern from one of the other metric packages. I'll clean this up.

"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/metrics/teststat"
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import grouping, as above.

}
}

// Send will fire an api request to CloudWatch with the latest stats for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API

}

// Send will fire an api request to CloudWatch with the latest stats for
// all metrics.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a note that most users will want to call WriteLoop, instead? Or — better yet — maybe you can unexport this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it might be worth keeping this around as someone might have their own way they want to fire the api call.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, totally fair, just some guidance in the comment would be good.

// WriteLoop is a helper method that invokes Send every
// time the passed channel fires. This method blocks until the channel is
// closed, so clients probably want to run it in its own goroutine. For typical
// usage, create a time.Ticker and pass its C channel to this method.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment wrapping.

cw.counters[name] = c
cw.mtx.Unlock()
return c
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cw.mtx.Lock()
defer cw.mtx.Unlock()
c := &counter{...} // assuming you remove the free constructor
cw.counters[name] = c
return c

defer cw.mtx.RUnlock()
now := time.Now()

datums := []*cloudwatch.MetricDatum{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I slightly prefer

var datums []*cloudwatch.MetricDatum

but this is a tiny nit.

@peterbourgon
Copy link
Member

Oh! And can you also please add CloudWatch to the appropriate table/s in the documentation in the parent directory?

@cam-stitt
Copy link
Contributor Author

The only thing I haven't done is add it to the table in documentation. I don't quite understand the table and haven't yet had enough time to read into it.

@peterbourgon
Copy link
Member

Mentioned this in Slack but just for the record:

DIM = does the system support arbitrary dimensionality (i.e. does it support With)? if yes, n; if not, 1
COUNTERS = batch push-aggregate
GAUGES = batch push-aggregate
HISTOGRAMS = synthetic (because they're modeled as per-quantile gauges), batch, push-aggregate

@cam-stitt
Copy link
Contributor Author

Sorted. Thanks for clearing that up.

@peterbourgon
Copy link
Member

Amazing, thank you so much!

@peterbourgon peterbourgon merged commit 04dd4f7 into go-kit:master Mar 20, 2017
jamesgist pushed a commit to jamesgist/kit that referenced this pull request Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants