Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/integrations/node_exporter/node_exporter.go
5296 views
1
//go:build !windows
2
3
package node_exporter //nolint:golint
4
5
import (
6
"context"
7
"fmt"
8
"net/http"
9
"sort"
10
"strings"
11
12
"github.com/go-kit/log"
13
"github.com/go-kit/log/level"
14
"github.com/grafana/agent/pkg/build"
15
"github.com/grafana/agent/pkg/integrations/config"
16
"github.com/prometheus/client_golang/prometheus"
17
"github.com/prometheus/client_golang/prometheus/promhttp"
18
"github.com/prometheus/node_exporter/collector"
19
"gopkg.in/alecthomas/kingpin.v2"
20
)
21
22
// Integration is the node_exporter integration. The integration scrapes metrics
23
// from the host Linux-based system.
24
type Integration struct {
25
c *Config
26
logger log.Logger
27
nc *collector.NodeCollector
28
29
exporterMetricsRegistry *prometheus.Registry
30
}
31
32
// New creates a new node_exporter integration.
33
func New(log log.Logger, c *Config) (*Integration, error) {
34
// NOTE(rfratto): this works as long as node_exporter is the only thing using
35
// kingpin across the codebase. node_exporter may need a PR eventually to pass
36
// in a custom kingpin application or expose methods to explicitly enable/disable
37
// collectors that we can use instead of this command line hack.
38
flags, _ := MapConfigToNodeExporterFlags(c)
39
level.Debug(log).Log("msg", "initializing node_exporter with flags converted from agent config", "flags", strings.Join(flags, " "))
40
41
for _, warn := range c.UnmarshalWarnings {
42
level.Warn(log).Log("msg", warn)
43
}
44
45
_, err := kingpin.CommandLine.Parse(flags)
46
if err != nil {
47
return nil, fmt.Errorf("failed to parse flags for generating node_exporter configuration: %w", err)
48
}
49
50
nc, err := collector.NewNodeCollector(log)
51
if err != nil {
52
return nil, fmt.Errorf("failed to create node_exporter: %w", err)
53
}
54
55
level.Info(log).Log("msg", "Enabled node_exporter collectors")
56
collectors := []string{}
57
for n := range nc.Collectors {
58
collectors = append(collectors, n)
59
}
60
sort.Strings(collectors)
61
for _, c := range collectors {
62
level.Info(log).Log("collector", c)
63
}
64
65
return &Integration{
66
c: c,
67
logger: log,
68
nc: nc,
69
70
exporterMetricsRegistry: prometheus.NewRegistry(),
71
}, nil
72
}
73
74
// MetricsHandler implements Integration.
75
func (i *Integration) MetricsHandler() (http.Handler, error) {
76
r := prometheus.NewRegistry()
77
if err := r.Register(i.nc); err != nil {
78
return nil, fmt.Errorf("couldn't register node_exporter node collector: %w", err)
79
}
80
handler := promhttp.HandlerFor(
81
prometheus.Gatherers{i.exporterMetricsRegistry, r},
82
promhttp.HandlerOpts{
83
ErrorHandling: promhttp.ContinueOnError,
84
MaxRequestsInFlight: 0,
85
Registry: i.exporterMetricsRegistry,
86
},
87
)
88
89
// Register node_exporter_build_info metrics, generally useful for
90
// dashboards that depend on them for discovering targets.
91
if err := r.Register(build.NewCollector(i.c.Name())); err != nil {
92
return nil, fmt.Errorf("couldn't register %s: %w", i.c.Name(), err)
93
}
94
95
if i.c.IncludeExporterMetrics {
96
// Note that we have to use reg here to use the same promhttp metrics for
97
// all expositions.
98
handler = promhttp.InstrumentMetricHandler(i.exporterMetricsRegistry, handler)
99
}
100
101
return handler, nil
102
}
103
104
// ScrapeConfigs satisfies Integration.ScrapeConfigs.
105
func (i *Integration) ScrapeConfigs() []config.ScrapeConfig {
106
return []config.ScrapeConfig{{
107
JobName: i.c.Name(),
108
MetricsPath: "/metrics",
109
}}
110
}
111
112
// Run satisfies Integration.Run.
113
func (i *Integration) Run(ctx context.Context) error {
114
// We don't need to do anything here, so we can just wait for the context to
115
// finish.
116
<-ctx.Done()
117
return ctx.Err()
118
}
119
120