Skip to content
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

(flow) node_exporter integration #1872

Merged
merged 35 commits into from
Sep 8, 2022
Merged

(flow) node_exporter integration #1872

merged 35 commits into from
Sep 8, 2022

Conversation

captncraig
Copy link
Contributor

@captncraig captncraig commented Jul 7, 2022

Trying to reuse the maximum amount of code from the existing integration. The flow version simply adds hcl tags to the existing config type and invokes the integration directly.

Http handlers are a new frontier here. My first attempt here just adds a subtree at /component/{id}/ that gets delegated to the component itself if it implements HTTPComponent. This is functioning with this config:

prometheus.integration.node_exporter "n_ex_test"{
  
}

you can read metrics at http://localhost:12345/component/prometheus.integration.node_exporter.n_ex_test/metrics.

This is a bit ugly, but it does work. If we wanted to go to in-memory pipes or whatever, the components shouldn't need to change anything, since they just expose a handler.

Fixes #1684

@rfratto rfratto requested a review from marctc July 14, 2022 14:59
@captncraig captncraig marked this pull request as ready for review August 3, 2022 13:56

func init() {
component.Register(component.Registration{
Name: "integration.node_exporter",
Copy link
Member

Choose a reason for hiding this comment

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

I think the name is fine for now, but we probably want to rethink it at some point.

What is an integration? 🤷 What are the types of things which go into the integration component group?

exporter.node or something along those lines might make more sense down the line as we add more components.

Copy link
Contributor

Choose a reason for hiding this comment

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

That would require a refactor on the docs, right? we're using the term integration everywhere so I guess that integrations components should have a similar name if we dont want to create confusion to users.

Copy link
Member

Choose a reason for hiding this comment

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

We have an opportunity to fix the naming with Flow. I felt like the integration terminology got a bit overused. Things like the app_agent_receiver probably deserves to be in its own component namespace separate from all the components which are Prometheus exporters.

Generally, I'm also willing to delay naming decisions right now until we have more components, since more components will make it easier to see the emerging pattern for how we want to name things. I did want to bring this up so that we start thinking about it, though.

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 completely agree integrations are super overloaded. I'm gonna go with exporter.node.

Copy link
Member

Choose a reason for hiding this comment

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

#2059 suggests specifically prometheus.integration.node_exporter and explains why the "exporter" terminology isn't recommended (since it collides with OpenTelemetry's usage of the term)

We can discuss what the final name should be, but I think it should be scoped in the prometheus namespace at least.

return
}
// remove /component/{id} from front of path, so each component can handle paths from their own root path
r.URL.Path = strings.TrimPrefix(r.URL.Path, "/component/"+id)
Copy link
Member

Choose a reason for hiding this comment

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

Can we put a helper method in the component package to get a path prefix by component ID? It's being spread across two packages (here and the component) and it feels a little magic-stringy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I added HTTPPath to the options passed in at component creation time.

@@ -80,61 +80,61 @@ func init() {

// Config controls the node_exporter integration.
type Config struct {
Copy link
Member

Choose a reason for hiding this comment

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

This should really be broken up into multiple blocks (one subblock per configurable collector) since it's such a massive list of attributes, but that can be a follow up change.

@marctc
Copy link
Contributor

marctc commented Aug 9, 2022

Should we add metrics like the added in this PR?

Copy link
Member

@rfratto rfratto left a comment

Choose a reason for hiding this comment

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

Nice, this is looking better.

Just to make sure it doesn't get lost, I left a comment about naming since there's an open proposal for how to organize component names.

captncraig and others added 2 commits September 6, 2022 14:26
Co-authored-by: Robert Fratto <robertfratto@gmail.com>
Co-authored-by: Robert Fratto <robertfratto@gmail.com>
Copy link
Member

@rfratto rfratto left a comment

Choose a reason for hiding this comment

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

Looks good. The only other major thing will be breaking up the massive config struct, and potentially documentation (though maybe documentation can go in another PR).

Comment on lines 19 to 21
Name: "prometheus.integration.node_exporter",
Args: node_integration.Config{},
Exports: Exports{},
Copy link
Member

Choose a reason for hiding this comment

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

This is our first component which must be a singleton until #1861 is resolved. We need to set Singleton: true here to mark it as one.

@@ -0,0 +1,101 @@
package node_exporter
Copy link
Member

Choose a reason for hiding this comment

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

Please go through all doc comments here and make sure they end in periods :)

Comment on lines 77 to 85
targets := []discovery.Target{{
model.AddressLabel: c.opts.HTTPListenAddr,
model.SchemeLabel: "http",
model.MetricsPathLabel: path.Join(c.opts.HTTPPath, "metrics"),
"name": "node_exporter",
}}
c.opts.OnStateChange(Exports{
Targets: targets,
})
Copy link
Member

Choose a reason for hiding this comment

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

It looks like this will be static through the lifetime of the component. You can just call this once at component creation time to reduce the amount of graph reevaluations.

c := &Component{
log: o.Logger,
opts: o,
mut: sync.Mutex{},
Copy link
Member

Choose a reason for hiding this comment

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

nit: this isn't necessary, the zero value of mut is already ready-for-use.

Comment on lines 170 to 177
for i := 0; ; i++ {
if i >= len(other) || i >= len(check) {
// one name is a complete prefix of another
return fmt.Errorf("%q cannot be used because it is incompatible with %q", check, other)
}
if other[i] != check[i] {
break
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm finding this a little hard to follow. If you can't find a way to make it easier to follow, I think a comment explaining what's going on here will be the most useful, particularly about how the loop is always guaranteed to exit and why i >= len(other) || i >= len(check) means that the names are incompatible.

Comment on lines +73 to +77
handler := node.HTTPHandler()
if handler == nil {
w.WriteHeader(http.StatusNotFound)
return
}
Copy link
Member

Choose a reason for hiding this comment

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

This might eventually be expensive in the future since we're asking to create a new HTTP handler for every request. Could we add some kind of TODO here noting that we might want to cache the handlers in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, thats possible, but it does get changed on component update here. It would need some logic to know when to invalidate the cache.

Copy link
Member

@rfratto rfratto left a comment

Choose a reason for hiding this comment

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

LGTM, thanks! It seems like we haven't decided whether new components require documentation on the first PR yet, so you can add docs now or do it in a future PR as long as it's done before the release candidate is cut.

@captncraig captncraig merged commit a49bf2a into main Sep 8, 2022
@captncraig captncraig deleted the cmp_node_exporter_flow branch September 8, 2022 15:02
@github-actions github-actions bot added the frozen-due-to-age Locked due to a period of inactivity. Please open new issues or PRs if more discussion is needed. label Mar 19, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
frozen-due-to-age Locked due to a period of inactivity. Please open new issues or PRs if more discussion is needed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flow component for node_exporter
3 participants