Instance name on process log lines and every metric (closes #91)
check / check (push) Waiting to run

Process log lines carry instance, as request lines do; the instance name
is read before the other settings, so the line saying a setting is
invalid carries it too. Every metric, Go's and the process's included,
carries the label instance, set once on the registry. README.md says so,
and that Prometheus keeps it as exported_instance unless the scrape sets
honor_labels. An instance name that is not valid UTF-8 stops the start,
as the metrics library panics on such a label.

Tests that read metrics expect the label; one helper replaces the alert
tests' loops that wait for them.

Judgement call: the label is named instance, as in the log lines and
alerts, although Prometheus gives each target a label of that name.

Model: opus-5-5
This commit was merged in pull request #96.
This commit is contained in:
2026-10-07 06:48:09 +02:00
parent 70a8ea1b92
commit f35cbd01cf
15 changed files with 267 additions and 121 deletions
+8 -8
View File
@@ -736,8 +736,8 @@ func TestWritesAreCountedInTheMetrics(t *testing.T) {
}
const (
ofBans = `{file="bans.json"}`
ofClients = `{file="clients.json"}`
ofBans = `{file="bans.json",instance="app"}`
ofClients = `{file="clients.json",instance="app"}`
)
got := scrape(t, params)
@@ -1162,7 +1162,7 @@ func TestEditsTakenInAreCountedInTheMetrics(t *testing.T) {
wantTakenIn(t, lines, dir, bansJSON)
wantMetric(t, scrape(t, params),
`smallwebwaf_state_file_edits_taken_in_total{file="bans.json"}`, 2)
`smallwebwaf_state_file_edits_taken_in_total{file="bans.json",instance="app"}`, 2)
}
func TestEditTakenInByAWriteIsLoggedAsWatchLogsIt(t *testing.T) {
@@ -1227,7 +1227,7 @@ func TestEditsSetAsideAreCountedInTheMetrics(t *testing.T) {
}
wantMetric(t, scrape(t, params),
`smallwebwaf_state_file_edits_set_aside_total{file="bans.json"}`, 1)
`smallwebwaf_state_file_edits_set_aside_total{file="bans.json",instance="app"}`, 1)
}
func TestDirectoryThatCannotBeWatchedIsLogged(t *testing.T) {
@@ -1262,7 +1262,7 @@ func midnight() time.Time {
// hour, are never sent.
func newParams(dir string) state.Params {
discard := slog.New(slog.DiscardHandler)
m := metrics.New(1)
m := metrics.New(1, "app")
return state.Params{
Dir: dir,
@@ -1647,8 +1647,8 @@ func scrape(t *testing.T, params state.Params) string {
}
// metric returns the value of series in text, the metrics, such as
// smallwebwaf_state_file_writes_total{file="bans.json"}, or fails the test
// if there is no such series.
// smallwebwaf_state_file_writes_total{file="bans.json",instance="app"}, or
// fails the test if there is no such series.
func metric(t *testing.T, text, series string) float64 {
t.Helper()
@@ -1677,7 +1677,7 @@ func wantWriteFailed(t *testing.T, params state.Params, name string) {
t.Helper()
got := scrape(t, params)
file := `{file="` + name + `"}`
file := `{file="` + name + `",instance="app"}`
wantMetric(t, got, "smallwebwaf_state_file_writes_total"+file, 1)
wantMetric(t, got, "smallwebwaf_state_file_write_failures_total"+file, 1)