-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prometheus exporter #334
Prometheus exporter #334
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good start! Thanks @paivagustavo. FYI @shreyassrivatsan we've taken this over, thanks for the initial draft and we'll keep you in the loop.
return tagKeys | ||
} | ||
|
||
func getCanonicalID(desc *export.Descriptor, labels export.Labels) (string, []string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way this is written, we need to use the defaultkeys Batcher, which ensures that the labels on each export Record are the same. I think this is another reason to integrate the exporter with the controller (and let it construct a Batcher).
The defaultkeys Batcher will let us simplify this code, since we can be fairly sure that the calls to With()
will match the tags declared for the vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not needed anymore so I have just deleted.
Do you mean this because of the labels.Encoded()
call? because I've just moved it to another place.
I guess I should make the Prometheus exporter implements the LabelEncoder
with a defaultkeys batcher for the moment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that no two -Vec types can exist with the same name and different key sets. The defaultkeys batcher will ensure that the tag sets are always equal--that's why it makes sense as a default. I still envision other batchers being created to support greater configuration, but for now yes, I would use defaultkeys.
Also, yes, it makes sense to use the LabelEncoder interface to compute anything needed to map the -Vec type into the handle-like interface. If the map[string]string
input to prometheus can be changed to a slice of values (as you said it could), then maybe the Encode()
function will compute a slice of values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
encoded: record.Labels().Encoded(), | ||
} | ||
|
||
// TODO(paivagustavo): how to choose between Histogram and Summary? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for now this can be in the exporter config. The user decides between histogram and summary at construction time.
In the future it would be nice to give a way to configure this on a per metric basis, but I am not very certain how that would looke..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm interested in more flexible and configurable exporters. I believe there's a question as to whether such a configuration can be in any way shared by more than one exporter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added an option to change how measures are exported, defaulting to histograms.
} | ||
|
||
func (e *Exporter) getCounterVec(desc *export.Descriptor, labels export.Labels) (*prometheus.CounterVec, error) { | ||
if c, ok := e.counterVecs[desc]; ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a separate loc for the *Vec
methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I actually didn't understand your suggestion here, could you discuss a little further?
counterVecs map[*export.Descriptor]*prometheus.CounterVec | ||
} | ||
|
||
func newCounters(registerer prometheus.Registerer) counters { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like this refactor..
this should probably return a pointer, no? the methods on the object rightly have a pointer receiver, so might as well return a pointer and reduce a copy here..
same applies to histograms and gauges too..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are placed in structs, so the pointer methods work. I'm happy with fewer pointers, fwiw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could reduce a copy using pointer or save an alloc not using a pointer. In the end both should have little to no difference since exporters are created once.
Are you okay leaving this that way or do you have a strong objections against this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave this. In the Go base libraries, this sort of class is often accompanied by a "Must not be copied after first use" sort of comment--would that help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually don't know if that solves it. Copies could be done, it would just be a shallow copy, It is not like Mutex that a copy could have inconsistent and incorrect state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a problem, anyway.
Thanks @shreyassrivatsan and @jmacd, for helping and reviewing this during the development. I've responded to all the open discussions. I think we can now open this for others to review. |
) | ||
|
||
func initMeter() *push.Controller { | ||
selector := simple.NewWithExactMeasure() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to create a simple wrapper for this block of code, as mentioned in #345. It's OK if you think we should wait for a future PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should take that on a next PR, I would happily take it when this gets merged.
counterVecs map[*export.Descriptor]*prometheus.CounterVec | ||
} | ||
|
||
func newCounters(registerer prometheus.Registerer) counters { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave this. In the Go base libraries, this sort of class is often accompanied by a "Must not be copied after first use" sort of comment--would that help?
// Export exports the provide metric record to prometheus. | ||
func (e *Exporter) Export(_ context.Context, checkpointSet export.CheckpointSet) error { | ||
var forEachError error | ||
checkpointSet.ForEach(func(record export.Record) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't a guard required if forEachError
is nil or not ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've being following the thought that if a single record fails to be exported that should not prevent the rest of the records to be processed.
There is still some questions we need to figure out about how to handle errors better on this ForEach
method. One of the suggestions is to change its argument from func(export.Record)
to func (export.Record) error
to have a more uniform and simpler error handling on all exporters. But that is an open question that I think should be taken on a separate PR since it would touch not only this exporter but others too.
@paivagustavo, I merged it to master but it failed due to #356 . Can you please fix the build? Thx. |
@rghetia just fixed it :) |
This adds prometheus metrics exporter.
This was started by @shreyassrivatsan and I've updated it with the last updates of the metrics sdk and support for measures (histogram and summary).