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