@@ -29,7 +29,11 @@ func (h *StateHolder) Load() model.State {
2929
3030const prometheusContentType = "text/plain; version=0.0.4; charset=utf-8"
3131
32- func Handler (holder * StateHolder ) http.HandlerFunc {
32+ func Handler (holder * StateHolder , prefix ... string ) http.HandlerFunc {
33+ p := ""
34+ if len (prefix ) > 0 {
35+ p = prefix [0 ]
36+ }
3337 return func (w http.ResponseWriter , r * http.Request ) {
3438 s := holder .Load ()
3539 if s .Current == nil {
@@ -39,30 +43,38 @@ func Handler(holder *StateHolder) http.HandlerFunc {
3943
4044 w .Header ().Set ("Content-Type" , prometheusContentType )
4145
42- writeThreadMetrics (w , & s )
43- writeThreadMemory (w , & s )
44- writeWorkerMetrics (w , & s )
45- writeHostMetrics (w , & s )
46- writePercentiles (w , & s )
47- writeProcessMetrics (w , & s )
46+ writeThreadMetrics (w , & s , p )
47+ writeThreadMemory (w , & s , p )
48+ writeWorkerMetrics (w , & s , p )
49+ writeHostMetrics (w , & s , p )
50+ writePercentiles (w , & s , p )
51+ writeProcessMetrics (w , & s , p )
52+ }
53+ }
54+
55+ func prefixed (prefix , name string ) string {
56+ if prefix == "" {
57+ return name
4858 }
59+ return prefix + "_" + name
4960}
5061
51- func writeThreadMetrics (w http.ResponseWriter , s * model.State ) {
62+ func writeThreadMetrics (w http.ResponseWriter , s * model.State , prefix string ) {
5263 total := len (s .Current .Threads .ThreadDebugStates )
5364 other := total - s .Derived .TotalBusy - s .Derived .TotalIdle
5465 if other < 0 {
5566 other = 0
5667 }
5768
58- fmt .Fprintln (w , "# HELP frankenphp_threads_total Number of FrankenPHP threads by state" )
59- fmt .Fprintln (w , "# TYPE frankenphp_threads_total gauge" )
60- fmt .Fprintf (w , "frankenphp_threads_total{state=\" busy\" } %d\n " , s .Derived .TotalBusy )
61- fmt .Fprintf (w , "frankenphp_threads_total{state=\" idle\" } %d\n " , s .Derived .TotalIdle )
62- fmt .Fprintf (w , "frankenphp_threads_total{state=\" other\" } %d\n " , other )
69+ name := prefixed (prefix , "frankenphp_threads_total" )
70+ fmt .Fprintf (w , "# HELP %s Number of FrankenPHP threads by state\n " , name )
71+ fmt .Fprintf (w , "# TYPE %s gauge\n " , name )
72+ fmt .Fprintf (w , "%s{state=\" busy\" } %d\n " , name , s .Derived .TotalBusy )
73+ fmt .Fprintf (w , "%s{state=\" idle\" } %d\n " , name , s .Derived .TotalIdle )
74+ fmt .Fprintf (w , "%s{state=\" other\" } %d\n " , name , other )
6375}
6476
65- func writeThreadMemory (w http.ResponseWriter , s * model.State ) {
77+ func writeThreadMemory (w http.ResponseWriter , s * model.State , prefix string ) {
6678 hasMemory := false
6779 for _ , t := range s .Current .Threads .ThreadDebugStates {
6880 if t .MemoryUsage > 0 {
@@ -74,68 +86,75 @@ func writeThreadMemory(w http.ResponseWriter, s *model.State) {
7486 return
7587 }
7688
77- fmt .Fprintln (w , "# HELP frankenphp_thread_memory_bytes Memory usage per FrankenPHP thread" )
78- fmt .Fprintln (w , "# TYPE frankenphp_thread_memory_bytes gauge" )
89+ name := prefixed (prefix , "frankenphp_thread_memory_bytes" )
90+ fmt .Fprintf (w , "# HELP %s Memory usage per FrankenPHP thread\n " , name )
91+ fmt .Fprintf (w , "# TYPE %s gauge\n " , name )
7992 for _ , t := range s .Current .Threads .ThreadDebugStates {
8093 if t .MemoryUsage > 0 {
81- fmt .Fprintf (w , "frankenphp_thread_memory_bytes {index=\" %d\" } %d\n " , t .Index , t .MemoryUsage )
94+ fmt .Fprintf (w , "%s {index=\" %d\" } %d\n " , name , t .Index , t .MemoryUsage )
8295 }
8396 }
8497}
8598
86- func writeWorkerMetrics (out http.ResponseWriter , s * model.State ) {
99+ func writeWorkerMetrics (out http.ResponseWriter , s * model.State , prefix string ) {
87100 if len (s .Current .Metrics .Workers ) == 0 {
88101 return
89102 }
90103
91104 names := sortedWorkerNames (s .Current .Metrics .Workers )
92105
93- fmt .Fprintln (out , "# HELP frankenphp_worker_crashes_total Total worker crashes" )
94- fmt .Fprintln (out , "# TYPE frankenphp_worker_crashes_total counter" )
106+ crashes := prefixed (prefix , "frankenphp_worker_crashes_total" )
107+ fmt .Fprintf (out , "# HELP %s Total worker crashes\n " , crashes )
108+ fmt .Fprintf (out , "# TYPE %s counter\n " , crashes )
95109 for _ , name := range names {
96110 wm := s .Current .Metrics .Workers [name ]
97- fmt .Fprintf (out , "frankenphp_worker_crashes_total {worker=\" %s\" } %g\n " , escapeLabelValue (name ), wm .Crashes )
111+ fmt .Fprintf (out , "%s {worker=\" %s\" } %g\n " , crashes , escapeLabelValue (name ), wm .Crashes )
98112 }
99113
100- fmt .Fprintln (out , "# HELP frankenphp_worker_restarts_total Total worker restarts" )
101- fmt .Fprintln (out , "# TYPE frankenphp_worker_restarts_total counter" )
114+ restarts := prefixed (prefix , "frankenphp_worker_restarts_total" )
115+ fmt .Fprintf (out , "# HELP %s Total worker restarts\n " , restarts )
116+ fmt .Fprintf (out , "# TYPE %s counter\n " , restarts )
102117 for _ , name := range names {
103118 wm := s .Current .Metrics .Workers [name ]
104- fmt .Fprintf (out , "frankenphp_worker_restarts_total {worker=\" %s\" } %g\n " , escapeLabelValue (name ), wm .Restarts )
119+ fmt .Fprintf (out , "%s {worker=\" %s\" } %g\n " , restarts , escapeLabelValue (name ), wm .Restarts )
105120 }
106121
107- fmt .Fprintln (out , "# HELP frankenphp_worker_queue_depth Requests in queue per worker" )
108- fmt .Fprintln (out , "# TYPE frankenphp_worker_queue_depth gauge" )
122+ queue := prefixed (prefix , "frankenphp_worker_queue_depth" )
123+ fmt .Fprintf (out , "# HELP %s Requests in queue per worker\n " , queue )
124+ fmt .Fprintf (out , "# TYPE %s gauge\n " , queue )
109125 for _ , name := range names {
110126 wm := s .Current .Metrics .Workers [name ]
111- fmt .Fprintf (out , "frankenphp_worker_queue_depth {worker=\" %s\" } %g\n " , escapeLabelValue (name ), wm .QueueDepth )
127+ fmt .Fprintf (out , "%s {worker=\" %s\" } %g\n " , queue , escapeLabelValue (name ), wm .QueueDepth )
112128 }
113129
114- fmt .Fprintln (out , "# HELP frankenphp_worker_requests_total Total requests processed per worker" )
115- fmt .Fprintln (out , "# TYPE frankenphp_worker_requests_total counter" )
130+ reqs := prefixed (prefix , "frankenphp_worker_requests_total" )
131+ fmt .Fprintf (out , "# HELP %s Total requests processed per worker\n " , reqs )
132+ fmt .Fprintf (out , "# TYPE %s counter\n " , reqs )
116133 for _ , name := range names {
117134 wm := s .Current .Metrics .Workers [name ]
118- fmt .Fprintf (out , "frankenphp_worker_requests_total {worker=\" %s\" } %g\n " , escapeLabelValue (name ), wm .RequestCount )
135+ fmt .Fprintf (out , "%s {worker=\" %s\" } %g\n " , reqs , escapeLabelValue (name ), wm .RequestCount )
119136 }
120137}
121138
122- func writeHostMetrics (w http.ResponseWriter , s * model.State ) {
139+ func writeHostMetrics (w http.ResponseWriter , s * model.State , prefix string ) {
123140 if len (s .HostDerived ) == 0 {
124141 return
125142 }
126143
127144 hosts := sortedHostNames (s .HostDerived )
128145
129- fmt .Fprintln (w , "# HELP ember_host_rps Requests per second by host" )
130- fmt .Fprintln (w , "# TYPE ember_host_rps gauge" )
146+ rps := prefixed (prefix , "ember_host_rps" )
147+ fmt .Fprintf (w , "# HELP %s Requests per second by host\n " , rps )
148+ fmt .Fprintf (w , "# TYPE %s gauge\n " , rps )
131149 for _ , hd := range hosts {
132- fmt .Fprintf (w , "ember_host_rps {host=\" %s\" } %.2f\n " , escapeLabelValue (hd .Host ), hd .RPS )
150+ fmt .Fprintf (w , "%s {host=\" %s\" } %.2f\n " , rps , escapeLabelValue (hd .Host ), hd .RPS )
133151 }
134152
135- fmt .Fprintln (w , "# HELP ember_host_latency_avg_milliseconds Average response time by host" )
136- fmt .Fprintln (w , "# TYPE ember_host_latency_avg_milliseconds gauge" )
153+ avg := prefixed (prefix , "ember_host_latency_avg_milliseconds" )
154+ fmt .Fprintf (w , "# HELP %s Average response time by host\n " , avg )
155+ fmt .Fprintf (w , "# TYPE %s gauge\n " , avg )
137156 for _ , hd := range hosts {
138- fmt .Fprintf (w , "ember_host_latency_avg_milliseconds {host=\" %s\" } %.2f\n " , escapeLabelValue (hd .Host ), hd .AvgTime )
157+ fmt .Fprintf (w , "%s {host=\" %s\" } %.2f\n " , avg , escapeLabelValue (hd .Host ), hd .AvgTime )
139158 }
140159
141160 hasPercentiles := false
@@ -146,24 +165,26 @@ func writeHostMetrics(w http.ResponseWriter, s *model.State) {
146165 }
147166 }
148167 if hasPercentiles {
149- fmt .Fprintln (w , "# HELP ember_host_latency_milliseconds Response time percentiles by host" )
150- fmt .Fprintln (w , "# TYPE ember_host_latency_milliseconds gauge" )
168+ lat := prefixed (prefix , "ember_host_latency_milliseconds" )
169+ fmt .Fprintf (w , "# HELP %s Response time percentiles by host\n " , lat )
170+ fmt .Fprintf (w , "# TYPE %s gauge\n " , lat )
151171 for _ , hd := range hosts {
152172 if ! hd .HasPercentiles {
153173 continue
154174 }
155175 h := escapeLabelValue (hd .Host )
156- fmt .Fprintf (w , "ember_host_latency_milliseconds {host=\" %s\" ,quantile=\" 0.5\" } %.2f\n " , h , hd .P50 )
157- fmt .Fprintf (w , "ember_host_latency_milliseconds {host=\" %s\" ,quantile=\" 0.9\" } %.2f\n " , h , hd .P90 )
158- fmt .Fprintf (w , "ember_host_latency_milliseconds {host=\" %s\" ,quantile=\" 0.95\" } %.2f\n " , h , hd .P95 )
159- fmt .Fprintf (w , "ember_host_latency_milliseconds {host=\" %s\" ,quantile=\" 0.99\" } %.2f\n " , h , hd .P99 )
176+ fmt .Fprintf (w , "%s {host=\" %s\" ,quantile=\" 0.5\" } %.2f\n " , lat , h , hd .P50 )
177+ fmt .Fprintf (w , "%s {host=\" %s\" ,quantile=\" 0.9\" } %.2f\n " , lat , h , hd .P90 )
178+ fmt .Fprintf (w , "%s {host=\" %s\" ,quantile=\" 0.95\" } %.2f\n " , lat , h , hd .P95 )
179+ fmt .Fprintf (w , "%s {host=\" %s\" ,quantile=\" 0.99\" } %.2f\n " , lat , h , hd .P99 )
160180 }
161181 }
162182
163- fmt .Fprintln (w , "# HELP ember_host_inflight In-flight requests by host" )
164- fmt .Fprintln (w , "# TYPE ember_host_inflight gauge" )
183+ infl := prefixed (prefix , "ember_host_inflight" )
184+ fmt .Fprintf (w , "# HELP %s In-flight requests by host\n " , infl )
185+ fmt .Fprintf (w , "# TYPE %s gauge\n " , infl )
165186 for _ , hd := range hosts {
166- fmt .Fprintf (w , "ember_host_inflight {host=\" %s\" } %.0f\n " , escapeLabelValue (hd .Host ), hd .InFlight )
187+ fmt .Fprintf (w , "%s {host=\" %s\" } %.0f\n " , infl , escapeLabelValue (hd .Host ), hd .InFlight )
167188 }
168189
169190 hasStatus := false
@@ -174,14 +195,15 @@ func writeHostMetrics(w http.ResponseWriter, s *model.State) {
174195 }
175196 }
176197 if hasStatus {
177- fmt .Fprintln (w , "# HELP ember_host_status_rate Request rate by host and status class" )
178- fmt .Fprintln (w , "# TYPE ember_host_status_rate gauge" )
198+ sr := prefixed (prefix , "ember_host_status_rate" )
199+ fmt .Fprintf (w , "# HELP %s Request rate by host and status class\n " , sr )
200+ fmt .Fprintf (w , "# TYPE %s gauge\n " , sr )
179201 for _ , hd := range hosts {
180202 classes := statusClassRates (hd .StatusCodes )
181203 h := escapeLabelValue (hd .Host )
182204 for _ , c := range []string {"2xx" , "3xx" , "4xx" , "5xx" } {
183205 if rate , ok := classes [c ]; ok {
184- fmt .Fprintf (w , "ember_host_status_rate {host=\" %s\" ,class=\" %s\" } %.2f\n " , h , c , rate )
206+ fmt .Fprintf (w , "%s {host=\" %s\" ,class=\" %s\" } %.2f\n " , sr , h , c , rate )
185207 }
186208 }
187209 }
@@ -217,26 +239,29 @@ func sortedHostNames(hosts []model.HostDerived) []model.HostDerived {
217239 return sorted
218240}
219241
220- func writePercentiles (w http.ResponseWriter , s * model.State ) {
242+ func writePercentiles (w http.ResponseWriter , s * model.State , prefix string ) {
221243 if ! s .Derived .HasPercentiles {
222244 return
223245 }
224246
225- fmt .Fprintln (w , "# HELP frankenphp_request_duration_milliseconds Request duration percentiles" )
226- fmt .Fprintln (w , "# TYPE frankenphp_request_duration_milliseconds gauge" )
227- fmt .Fprintf (w , "frankenphp_request_duration_milliseconds{quantile=\" 0.5\" } %.2f\n " , s .Derived .P50 )
228- fmt .Fprintf (w , "frankenphp_request_duration_milliseconds{quantile=\" 0.95\" } %.2f\n " , s .Derived .P95 )
229- fmt .Fprintf (w , "frankenphp_request_duration_milliseconds{quantile=\" 0.99\" } %.2f\n " , s .Derived .P99 )
247+ name := prefixed (prefix , "frankenphp_request_duration_milliseconds" )
248+ fmt .Fprintf (w , "# HELP %s Request duration percentiles\n " , name )
249+ fmt .Fprintf (w , "# TYPE %s gauge\n " , name )
250+ fmt .Fprintf (w , "%s{quantile=\" 0.5\" } %.2f\n " , name , s .Derived .P50 )
251+ fmt .Fprintf (w , "%s{quantile=\" 0.95\" } %.2f\n " , name , s .Derived .P95 )
252+ fmt .Fprintf (w , "%s{quantile=\" 0.99\" } %.2f\n " , name , s .Derived .P99 )
230253}
231254
232- func writeProcessMetrics (w http.ResponseWriter , s * model.State ) {
233- fmt .Fprintln (w , "# HELP process_cpu_percent CPU usage of the monitored process" )
234- fmt .Fprintln (w , "# TYPE process_cpu_percent gauge" )
235- fmt .Fprintf (w , "process_cpu_percent %.2f\n " , s .Current .Process .CPUPercent )
255+ func writeProcessMetrics (w http.ResponseWriter , s * model.State , prefix string ) {
256+ cpu := prefixed (prefix , "process_cpu_percent" )
257+ fmt .Fprintf (w , "# HELP %s CPU usage of the monitored process\n " , cpu )
258+ fmt .Fprintf (w , "# TYPE %s gauge\n " , cpu )
259+ fmt .Fprintf (w , "%s %.2f\n " , cpu , s .Current .Process .CPUPercent )
236260
237- fmt .Fprintln (w , "# HELP process_rss_bytes Resident set size of the monitored process" )
238- fmt .Fprintln (w , "# TYPE process_rss_bytes gauge" )
239- fmt .Fprintf (w , "process_rss_bytes %d\n " , s .Current .Process .RSS )
261+ rss := prefixed (prefix , "process_rss_bytes" )
262+ fmt .Fprintf (w , "# HELP %s Resident set size of the monitored process\n " , rss )
263+ fmt .Fprintf (w , "# TYPE %s gauge\n " , rss )
264+ fmt .Fprintf (w , "%s %d\n " , rss , s .Current .Process .RSS )
240265}
241266
242267func escapeLabelValue (s string ) string {
0 commit comments