Skip to content

Commit 47f6570

Browse files
feat(metrics)!: add "server" label to per-worker series
Workers declared in distinct php_server blocks can share a name now that the per-scope routing landed; without a second label dimension, their metric series collide on the existing "worker" label. This adds a sibling "server" label (resolved via ScopeLabel(w.backgroundScope) at every call site) so each (server, worker) pair stays on its own series. BREAKING CHANGE: every Metrics interface method that took (name string) now takes (server, name string). Embedders implementing frankenphp.Metrics need to widen their signatures; PrometheusMetrics and the null impl are updated in-tree. Mirrors the shape of php#1376 (which introduced the "worker" label the same way).
1 parent 0e7fa25 commit 47f6570

8 files changed

Lines changed: 113 additions & 103 deletions

File tree

caddy/caddy_test.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -828,19 +828,19 @@ func TestWorkerMetrics(t *testing.T) {
828828
829829
# HELP frankenphp_busy_workers Number of busy PHP workers for this worker
830830
# TYPE frankenphp_busy_workers gauge
831-
frankenphp_busy_workers{worker="` + workerName + `"} 0
831+
frankenphp_busy_workers{server="0",worker="` + workerName + `"} 0
832832
833833
# HELP frankenphp_total_workers Total number of PHP workers for this worker
834834
# TYPE frankenphp_total_workers gauge
835-
frankenphp_total_workers{worker="` + workerName + `"} 2
835+
frankenphp_total_workers{server="0",worker="` + workerName + `"} 2
836836
837837
# HELP frankenphp_worker_request_count
838838
# TYPE frankenphp_worker_request_count counter
839-
frankenphp_worker_request_count{worker="` + workerName + `"} 10
839+
frankenphp_worker_request_count{server="0",worker="` + workerName + `"} 10
840840
841841
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
842842
# TYPE frankenphp_ready_workers gauge
843-
frankenphp_ready_workers{worker="` + workerName + `"} 2
843+
frankenphp_ready_workers{server="0",worker="` + workerName + `"} 2
844844
`
845845

846846
ctx := caddy.ActiveContext()
@@ -922,19 +922,19 @@ func TestNamedWorkerMetrics(t *testing.T) {
922922
923923
# HELP frankenphp_busy_workers Number of busy PHP workers for this worker
924924
# TYPE frankenphp_busy_workers gauge
925-
frankenphp_busy_workers{worker="my_app"} 0
925+
frankenphp_busy_workers{server="0",worker="my_app"} 0
926926
927927
# HELP frankenphp_total_workers Total number of PHP workers for this worker
928928
# TYPE frankenphp_total_workers gauge
929-
frankenphp_total_workers{worker="my_app"} 2
929+
frankenphp_total_workers{server="0",worker="my_app"} 2
930930
931931
# HELP frankenphp_worker_request_count
932932
# TYPE frankenphp_worker_request_count counter
933-
frankenphp_worker_request_count{worker="my_app"} 10
933+
frankenphp_worker_request_count{server="0",worker="my_app"} 10
934934
935935
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
936936
# TYPE frankenphp_ready_workers gauge
937-
frankenphp_ready_workers{worker="my_app"} 2
937+
frankenphp_ready_workers{server="0",worker="my_app"} 2
938938
`
939939

940940
ctx := caddy.ActiveContext()
@@ -1018,19 +1018,19 @@ func TestAutoWorkerConfig(t *testing.T) {
10181018
10191019
# HELP frankenphp_busy_workers Number of busy PHP workers for this worker
10201020
# TYPE frankenphp_busy_workers gauge
1021-
frankenphp_busy_workers{worker="` + workerName + `"} 0
1021+
frankenphp_busy_workers{server="0",worker="` + workerName + `"} 0
10221022
10231023
# HELP frankenphp_total_workers Total number of PHP workers for this worker
10241024
# TYPE frankenphp_total_workers gauge
1025-
frankenphp_total_workers{worker="` + workerName + `"} ` + workers + `
1025+
frankenphp_total_workers{server="0",worker="` + workerName + `"} ` + workers + `
10261026
10271027
# HELP frankenphp_worker_request_count
10281028
# TYPE frankenphp_worker_request_count counter
1029-
frankenphp_worker_request_count{worker="` + workerName + `"} 10
1029+
frankenphp_worker_request_count{server="0",worker="` + workerName + `"} 10
10301030
10311031
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
10321032
# TYPE frankenphp_ready_workers gauge
1033-
frankenphp_ready_workers{worker="` + workerName + `"} ` + workers + `
1033+
frankenphp_ready_workers{server="0",worker="` + workerName + `"} ` + workers + `
10341034
`
10351035

10361036
ctx := caddy.ActiveContext()
@@ -1284,7 +1284,7 @@ func TestMaxWaitTimeWorker(t *testing.T) {
12841284

12851285
expectedMetrics := `
12861286
# TYPE frankenphp_worker_queue_depth gauge
1287-
frankenphp_worker_queue_depth{worker="service"} 0
1287+
frankenphp_worker_queue_depth{server="0",worker="service"} 0
12881288
`
12891289

12901290
ctx := caddy.ActiveContext()
@@ -1385,21 +1385,21 @@ func TestMultiWorkersMetrics(t *testing.T) {
13851385
13861386
# HELP frankenphp_busy_workers Number of busy PHP workers for this worker
13871387
# TYPE frankenphp_busy_workers gauge
1388-
frankenphp_busy_workers{worker="service1"} 0
1388+
frankenphp_busy_workers{server="0",worker="service1"} 0
13891389
13901390
# HELP frankenphp_total_workers Total number of PHP workers for this worker
13911391
# TYPE frankenphp_total_workers gauge
1392-
frankenphp_total_workers{worker="service1"} 2
1393-
frankenphp_total_workers{worker="service2"} 3
1392+
frankenphp_total_workers{server="0",worker="service1"} 2
1393+
frankenphp_total_workers{server="0",worker="service2"} 3
13941394
13951395
# HELP frankenphp_worker_request_count
13961396
# TYPE frankenphp_worker_request_count counter
1397-
frankenphp_worker_request_count{worker="service1"} 10
1397+
frankenphp_worker_request_count{server="0",worker="service1"} 10
13981398
13991399
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
14001400
# TYPE frankenphp_ready_workers gauge
1401-
frankenphp_ready_workers{worker="service1"} 2
1402-
frankenphp_ready_workers{worker="service2"} 3
1401+
frankenphp_ready_workers{server="0",worker="service1"} 2
1402+
frankenphp_ready_workers{server="0",worker="service2"} 3
14031403
`
14041404

14051405
ctx := caddy.ActiveContext()
@@ -1552,10 +1552,10 @@ func TestWorkerRestart(t *testing.T) {
15521552
expectedMetrics := `
15531553
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
15541554
# TYPE frankenphp_ready_workers gauge
1555-
frankenphp_ready_workers{worker="service"} 1
1555+
frankenphp_ready_workers{server="0",worker="service"} 1
15561556
# HELP frankenphp_total_workers Total number of PHP workers for this worker
15571557
# TYPE frankenphp_total_workers gauge
1558-
frankenphp_total_workers{worker="service"} 1
1558+
frankenphp_total_workers{server="0",worker="service"} 1
15591559
`
15601560

15611561
require.NoError(t,
@@ -1580,13 +1580,13 @@ func TestWorkerRestart(t *testing.T) {
15801580
expectedMetrics = `
15811581
# HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once
15821582
# TYPE frankenphp_ready_workers gauge
1583-
frankenphp_ready_workers{worker="service"} 1
1583+
frankenphp_ready_workers{server="0",worker="service"} 1
15841584
# HELP frankenphp_total_workers Total number of PHP workers for this worker
15851585
# TYPE frankenphp_total_workers gauge
1586-
frankenphp_total_workers{worker="service"} 1
1586+
frankenphp_total_workers{server="0",worker="service"} 1
15871587
# HELP frankenphp_worker_restarts Number of PHP worker restarts for this worker
15881588
# TYPE frankenphp_worker_restarts counter
1589-
frankenphp_worker_restarts{worker="service"} 3
1589+
frankenphp_worker_restarts{server="0",worker="service"} 3
15901590
`
15911591

15921592
require.NoError(t,

docs/metrics.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ When [Caddy metrics](https://caddyserver.com/docs/metrics) are enabled, FrankenP
1313
- `frankenphp_total_threads`: The total number of PHP threads.
1414
- `frankenphp_busy_threads`: The number of PHP threads currently processing a request (running workers always consume a thread).
1515
- `frankenphp_queue_depth`: The number of regular queued requests
16-
- `frankenphp_total_workers{worker="[worker_name]"}`: The total number of workers.
17-
- `frankenphp_busy_workers{worker="[worker_name]"}`: The number of workers currently processing a request.
18-
- `frankenphp_worker_request_time{worker="[worker_name]"}`: The time spent processing requests by all workers.
19-
- `frankenphp_worker_request_count{worker="[worker_name]"}`: The number of requests processed by all workers.
20-
- `frankenphp_ready_workers{worker="[worker_name]"}`: The number of workers that have called `frankenphp_handle_request` at least once.
21-
- `frankenphp_worker_crashes{worker="[worker_name]"}`: The number of times a worker has unexpectedly terminated.
22-
- `frankenphp_worker_restarts{worker="[worker_name]"}`: The number of times a worker has been deliberately restarted.
23-
- `frankenphp_worker_queue_depth{worker="[worker_name]"}`: The number of queued requests.
16+
- `frankenphp_total_workers{server="[server]",worker="[worker_name]"}`: The total number of workers.
17+
- `frankenphp_busy_workers{server="[server]",worker="[worker_name]"}`: The number of workers currently processing a request.
18+
- `frankenphp_worker_request_time{server="[server]",worker="[worker_name]"}`: The time spent processing requests by all workers.
19+
- `frankenphp_worker_request_count{server="[server]",worker="[worker_name]"}`: The number of requests processed by all workers.
20+
- `frankenphp_ready_workers{server="[server]",worker="[worker_name]"}`: The number of workers that have called `frankenphp_handle_request` at least once.
21+
- `frankenphp_worker_crashes{server="[server]",worker="[worker_name]"}`: The number of times a worker has unexpectedly terminated.
22+
- `frankenphp_worker_restarts{server="[server]",worker="[worker_name]"}`: The number of times a worker has been deliberately restarted.
23+
- `frankenphp_worker_queue_depth{server="[server]",worker="[worker_name]"}`: The number of queued requests.
2424

25-
For worker metrics, the `[worker_name]` placeholder is replaced by the worker name in the Caddyfile, otherwise the absolute path of the worker file will be used.
25+
For worker metrics, the `[worker_name]` placeholder is replaced by the worker name in the Caddyfile, otherwise the absolute path of the worker file will be used. The `[server]` label identifies the `php_server` block that declared the worker; the Caddy module resolves it to the first host of the route's host matcher (e.g. `api.example.com`), falling back to the user-set Caddy server name and finally to the first listener address. Same-named workers in distinct `php_server` blocks therefore stay on distinct series.

frankenphp.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,15 @@ func calculateMaxThreads(opt *opt) (numWorkers int, _ error) {
182182
// Register the expected worker count for metrics too: without
183183
// this, a bg-worker-only deployment never initialises
184184
// totalWorkers, and StartWorker calls become silent no-ops.
185-
metrics.TotalWorkers(w.name, extra)
185+
metrics.TotalWorkers(ScopeLabel(w.backgroundScope), w.name, extra)
186186
continue
187187
}
188188

189189
if w.num <= 0 {
190190
// https://github.com/php/frankenphp/issues/126
191191
opt.workers[i].num = maxProcs
192192
}
193-
metrics.TotalWorkers(w.name, w.num)
193+
metrics.TotalWorkers(ScopeLabel(w.backgroundScope), w.name, w.num)
194194

195195
numWorkers += opt.workers[i].num
196196

metrics.go

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,49 @@ const (
1616

1717
type StopReason int
1818

19+
// Metrics is the worker-level instrumentation surface. Every method that
20+
// identifies a specific worker takes a (server, name) pair: server is the
21+
// per-php_server label resolved via ScopeLabel, name is the worker name.
22+
// The pair is what disambiguates same-named workers declared in distinct
23+
// php_server blocks.
1924
type Metrics interface {
2025
// StartWorker collects started workers
21-
StartWorker(name string)
26+
StartWorker(server, name string)
2227
// ReadyWorker collects ready workers
23-
ReadyWorker(name string)
28+
ReadyWorker(server, name string)
2429
// StopWorker collects stopped workers
25-
StopWorker(name string, reason StopReason)
30+
StopWorker(server, name string, reason StopReason)
2631
// TotalWorkers collects expected workers
27-
TotalWorkers(name string, num int)
32+
TotalWorkers(server, name string, num int)
2833
// TotalThreads collects total threads
2934
TotalThreads(num int)
3035
// StartRequest collects started requests
3136
StartRequest()
3237
// StopRequest collects stopped requests
3338
StopRequest()
3439
// StopWorkerRequest collects stopped worker requests
35-
StopWorkerRequest(name string, duration time.Duration)
40+
StopWorkerRequest(server, name string, duration time.Duration)
3641
// StartWorkerRequest collects started worker requests
37-
StartWorkerRequest(name string)
42+
StartWorkerRequest(server, name string)
3843
Shutdown()
39-
QueuedWorkerRequest(name string)
40-
DequeuedWorkerRequest(name string)
44+
QueuedWorkerRequest(server, name string)
45+
DequeuedWorkerRequest(server, name string)
4146
QueuedRequest()
4247
DequeuedRequest()
4348
}
4449

4550
type nullMetrics struct{}
4651

47-
func (n nullMetrics) StartWorker(string) {
52+
func (n nullMetrics) StartWorker(string, string) {
4853
}
4954

50-
func (n nullMetrics) ReadyWorker(string) {
55+
func (n nullMetrics) ReadyWorker(string, string) {
5156
}
5257

53-
func (n nullMetrics) StopWorker(string, StopReason) {
58+
func (n nullMetrics) StopWorker(string, string, StopReason) {
5459
}
5560

56-
func (n nullMetrics) TotalWorkers(string, int) {
61+
func (n nullMetrics) TotalWorkers(string, string, int) {
5762
}
5863

5964
func (n nullMetrics) TotalThreads(int) {
@@ -65,18 +70,18 @@ func (n nullMetrics) StartRequest() {
6570
func (n nullMetrics) StopRequest() {
6671
}
6772

68-
func (n nullMetrics) StopWorkerRequest(string, time.Duration) {
73+
func (n nullMetrics) StopWorkerRequest(string, string, time.Duration) {
6974
}
7075

71-
func (n nullMetrics) StartWorkerRequest(string) {
76+
func (n nullMetrics) StartWorkerRequest(string, string) {
7277
}
7378

7479
func (n nullMetrics) Shutdown() {
7580
}
7681

77-
func (n nullMetrics) QueuedWorkerRequest(string) {}
82+
func (n nullMetrics) QueuedWorkerRequest(string, string) {}
7883

79-
func (n nullMetrics) DequeuedWorkerRequest(string) {}
84+
func (n nullMetrics) DequeuedWorkerRequest(string, string) {}
8085

8186
func (n nullMetrics) QueuedRequest() {}
8287
func (n nullMetrics) DequeuedRequest() {}
@@ -97,54 +102,54 @@ type PrometheusMetrics struct {
97102
mu sync.Mutex
98103
}
99104

100-
func (m *PrometheusMetrics) StartWorker(name string) {
105+
func (m *PrometheusMetrics) StartWorker(server, name string) {
101106
m.busyThreads.Inc()
102107

103108
// tests do not register workers before starting them
104109
if m.totalWorkers == nil {
105110
return
106111
}
107112

108-
m.totalWorkers.WithLabelValues(name).Inc()
113+
m.totalWorkers.WithLabelValues(server, name).Inc()
109114
}
110115

111-
func (m *PrometheusMetrics) ReadyWorker(name string) {
116+
func (m *PrometheusMetrics) ReadyWorker(server, name string) {
112117
if m.totalWorkers == nil {
113118
return
114119
}
115120

116-
m.readyWorkers.WithLabelValues(name).Inc()
121+
m.readyWorkers.WithLabelValues(server, name).Inc()
117122
}
118123

119-
func (m *PrometheusMetrics) StopWorker(name string, reason StopReason) {
124+
func (m *PrometheusMetrics) StopWorker(server, name string, reason StopReason) {
120125
m.busyThreads.Dec()
121126

122127
// tests do not register workers before starting them
123128
if m.totalWorkers == nil {
124129
return
125130
}
126131

127-
m.totalWorkers.WithLabelValues(name).Dec()
132+
m.totalWorkers.WithLabelValues(server, name).Dec()
128133

129134
// only decrement readyWorkers if the worker actually reached frankenphp_handle_request
130135
if reason != StopReasonBootFailure {
131-
m.readyWorkers.WithLabelValues(name).Dec()
136+
m.readyWorkers.WithLabelValues(server, name).Dec()
132137
}
133138

134139
switch reason {
135140
case StopReasonCrash, StopReasonBootFailure:
136-
m.workerCrashes.WithLabelValues(name).Inc()
141+
m.workerCrashes.WithLabelValues(server, name).Inc()
137142
case StopReasonRestart:
138-
m.workerRestarts.WithLabelValues(name).Inc()
143+
m.workerRestarts.WithLabelValues(server, name).Inc()
139144
}
140145
}
141146

142-
func (m *PrometheusMetrics) TotalWorkers(string, int) {
147+
func (m *PrometheusMetrics) TotalWorkers(string, string, int) {
143148
m.mu.Lock()
144149
defer m.mu.Unlock()
145150

146151
const ns, sub = "frankenphp", "worker"
147-
basicLabels := []string{"worker"}
152+
basicLabels := []string{"server", "worker"}
148153

149154
if m.totalWorkers == nil {
150155
m.totalWorkers = prometheus.NewGaugeVec(prometheus.GaugeOpts{
@@ -257,35 +262,35 @@ func (m *PrometheusMetrics) StopRequest() {
257262
m.busyThreads.Dec()
258263
}
259264

260-
func (m *PrometheusMetrics) StopWorkerRequest(name string, duration time.Duration) {
265+
func (m *PrometheusMetrics) StopWorkerRequest(server, name string, duration time.Duration) {
261266
if m.workerRequestTime == nil {
262267
return
263268
}
264269

265-
m.workerRequestCount.WithLabelValues(name).Inc()
266-
m.busyWorkers.WithLabelValues(name).Dec()
267-
m.workerRequestTime.WithLabelValues(name).Add(duration.Seconds())
270+
m.workerRequestCount.WithLabelValues(server, name).Inc()
271+
m.busyWorkers.WithLabelValues(server, name).Dec()
272+
m.workerRequestTime.WithLabelValues(server, name).Add(duration.Seconds())
268273
}
269274

270-
func (m *PrometheusMetrics) StartWorkerRequest(name string) {
275+
func (m *PrometheusMetrics) StartWorkerRequest(server, name string) {
271276
if m.busyWorkers == nil {
272277
return
273278
}
274-
m.busyWorkers.WithLabelValues(name).Inc()
279+
m.busyWorkers.WithLabelValues(server, name).Inc()
275280
}
276281

277-
func (m *PrometheusMetrics) QueuedWorkerRequest(name string) {
282+
func (m *PrometheusMetrics) QueuedWorkerRequest(server, name string) {
278283
if m.workerQueueDepth == nil {
279284
return
280285
}
281-
m.workerQueueDepth.WithLabelValues(name).Inc()
286+
m.workerQueueDepth.WithLabelValues(server, name).Inc()
282287
}
283288

284-
func (m *PrometheusMetrics) DequeuedWorkerRequest(name string) {
289+
func (m *PrometheusMetrics) DequeuedWorkerRequest(server, name string) {
285290
if m.workerQueueDepth == nil {
286291
return
287292
}
288-
m.workerQueueDepth.WithLabelValues(name).Dec()
293+
m.workerQueueDepth.WithLabelValues(server, name).Dec()
289294
}
290295

291296
func (m *PrometheusMetrics) QueuedRequest() {

0 commit comments

Comments
 (0)