mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-11-12 16:44:18 -08:00
textfile: Allow specifiying multiple directory globs. (#3135)
Some checks are pending
golangci-lint / lint (push) Waiting to run
Some checks are pending
golangci-lint / lint (push) Waiting to run
We already support reading from multiple directories though only using globs. Now we can specify them outright. Example use case is exporting both static info on a RO FS generated during image building and traditional uses of textfiles (e.g. for R/W service metrics files) without scripting a file copy. * keep flag name for compatibility * clarify flag help text * add test case (replicating the glob one) Signed-off-by: eduarrrd <eduarrrd@users.noreply.github.com>
This commit is contained in:
parent
b5ce6bcc4d
commit
11f93d3da1
|
@ -32,8 +32,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
textFileDirectory = kingpin.Flag("collector.textfile.directory", "Directory to read text files with metrics from.").Default("").String()
|
||||
mtimeDesc = prometheus.NewDesc(
|
||||
textFileDirectories = kingpin.Flag("collector.textfile.directory", "Directory to read text files with metrics from, supports glob matching. (repeatable)").Default("").Strings()
|
||||
mtimeDesc = prometheus.NewDesc(
|
||||
"node_textfile_mtime_seconds",
|
||||
"Unixtime mtime of textfiles successfully read.",
|
||||
[]string{"file"},
|
||||
|
@ -42,7 +42,7 @@ var (
|
|||
)
|
||||
|
||||
type textFileCollector struct {
|
||||
path string
|
||||
paths []string
|
||||
// Only set for testing to get predictable output.
|
||||
mtime *float64
|
||||
logger *slog.Logger
|
||||
|
@ -56,7 +56,7 @@ func init() {
|
|||
// in the given textfile directory.
|
||||
func NewTextFileCollector(logger *slog.Logger) (Collector, error) {
|
||||
c := &textFileCollector{
|
||||
path: *textFileDirectory,
|
||||
paths: *textFileDirectories,
|
||||
logger: logger,
|
||||
}
|
||||
return c, nil
|
||||
|
@ -194,11 +194,15 @@ func (c *textFileCollector) Update(ch chan<- prometheus.Metric) error {
|
|||
metricsNamesToFiles := map[string][]string{}
|
||||
metricsNamesToHelpTexts := map[string][2]string{}
|
||||
|
||||
paths, err := filepath.Glob(c.path)
|
||||
if err != nil || len(paths) == 0 {
|
||||
// not glob or not accessible path either way assume single
|
||||
// directory and let os.ReadDir handle it
|
||||
paths = []string{c.path}
|
||||
paths := []string{}
|
||||
for _, glob := range c.paths {
|
||||
ps, err := filepath.Glob(glob)
|
||||
if err != nil || len(ps) == 0 {
|
||||
// not glob or not accessible path either way assume single
|
||||
// directory and let os.ReadDir handle it
|
||||
ps = []string{glob}
|
||||
}
|
||||
paths = append(paths, ps...)
|
||||
}
|
||||
|
||||
mtimes := make(map[string]time.Time)
|
||||
|
|
|
@ -52,75 +52,82 @@ func (a collectorAdapter) Collect(ch chan<- prometheus.Metric) {
|
|||
|
||||
func TestTextfileCollector(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
out string
|
||||
paths []string
|
||||
out string
|
||||
}{
|
||||
{
|
||||
path: "fixtures/textfile/no_metric_files",
|
||||
out: "fixtures/textfile/no_metric_files.out",
|
||||
paths: []string{"fixtures/textfile/no_metric_files"},
|
||||
out: "fixtures/textfile/no_metric_files.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/two_metric_files",
|
||||
out: "fixtures/textfile/two_metric_files.out",
|
||||
paths: []string{"fixtures/textfile/two_metric_files"},
|
||||
out: "fixtures/textfile/two_metric_files.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/nonexistent_path",
|
||||
out: "fixtures/textfile/nonexistent_path.out",
|
||||
paths: []string{"fixtures/textfile/nonexistent_path"},
|
||||
out: "fixtures/textfile/nonexistent_path.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/client_side_timestamp",
|
||||
out: "fixtures/textfile/client_side_timestamp.out",
|
||||
paths: []string{"fixtures/textfile/client_side_timestamp"},
|
||||
out: "fixtures/textfile/client_side_timestamp.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/different_metric_types",
|
||||
out: "fixtures/textfile/different_metric_types.out",
|
||||
paths: []string{"fixtures/textfile/different_metric_types"},
|
||||
out: "fixtures/textfile/different_metric_types.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/inconsistent_metrics",
|
||||
out: "fixtures/textfile/inconsistent_metrics.out",
|
||||
paths: []string{"fixtures/textfile/inconsistent_metrics"},
|
||||
out: "fixtures/textfile/inconsistent_metrics.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/histogram",
|
||||
out: "fixtures/textfile/histogram.out",
|
||||
paths: []string{"fixtures/textfile/histogram"},
|
||||
out: "fixtures/textfile/histogram.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/histogram_extra_dimension",
|
||||
out: "fixtures/textfile/histogram_extra_dimension.out",
|
||||
paths: []string{"fixtures/textfile/histogram_extra_dimension"},
|
||||
out: "fixtures/textfile/histogram_extra_dimension.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/summary",
|
||||
out: "fixtures/textfile/summary.out",
|
||||
paths: []string{"fixtures/textfile/summary"},
|
||||
out: "fixtures/textfile/summary.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/summary_extra_dimension",
|
||||
out: "fixtures/textfile/summary_extra_dimension.out",
|
||||
paths: []string{"fixtures/textfile/summary_extra_dimension"},
|
||||
out: "fixtures/textfile/summary_extra_dimension.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/*_extra_dimension",
|
||||
out: "fixtures/textfile/glob_extra_dimension.out",
|
||||
paths: []string{
|
||||
"fixtures/textfile/histogram_extra_dimension",
|
||||
"fixtures/textfile/summary_extra_dimension",
|
||||
},
|
||||
out: "fixtures/textfile/glob_extra_dimension.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/metrics_merge_empty_help",
|
||||
out: "fixtures/textfile/metrics_merge_empty_help.out",
|
||||
paths: []string{"fixtures/textfile/*_extra_dimension"},
|
||||
out: "fixtures/textfile/glob_extra_dimension.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/metrics_merge_no_help",
|
||||
out: "fixtures/textfile/metrics_merge_no_help.out",
|
||||
paths: []string{"fixtures/textfile/metrics_merge_empty_help"},
|
||||
out: "fixtures/textfile/metrics_merge_empty_help.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/metrics_merge_same_help",
|
||||
out: "fixtures/textfile/metrics_merge_same_help.out",
|
||||
paths: []string{"fixtures/textfile/metrics_merge_no_help"},
|
||||
out: "fixtures/textfile/metrics_merge_no_help.out",
|
||||
},
|
||||
{
|
||||
path: "fixtures/textfile/metrics_merge_different_help",
|
||||
out: "fixtures/textfile/metrics_merge_different_help.out",
|
||||
paths: []string{"fixtures/textfile/metrics_merge_same_help"},
|
||||
out: "fixtures/textfile/metrics_merge_same_help.out",
|
||||
},
|
||||
{
|
||||
paths: []string{"fixtures/textfile/metrics_merge_different_help"},
|
||||
out: "fixtures/textfile/metrics_merge_different_help.out",
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
mtime := 1.0
|
||||
c := &textFileCollector{
|
||||
path: test.path,
|
||||
paths: test.paths,
|
||||
mtime: &mtime,
|
||||
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
}
|
||||
|
@ -146,7 +153,7 @@ func TestTextfileCollector(t *testing.T) {
|
|||
}
|
||||
|
||||
if string(want) != got {
|
||||
t.Fatalf("%d.%q want:\n\n%s\n\ngot:\n\n%s", i, test.path, string(want), got)
|
||||
t.Fatalf("%d.%q want:\n\n%s\n\ngot:\n\n%s", i, test.paths, string(want), got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue