Created
October 24, 2023 13:10
-
-
Save markscottwright/3ad5fa769d56d34d9dbef54068af9b35 to your computer and use it in GitHub Desktop.
Apache module that exports metrics in Prometheus format
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Need to install APR and HTTPD source | |
* https://github.com/apache/apr | |
* https://github.com/apache/httpd | |
* Build with `apxs -c -a mod_metrics.c` | |
* Install with: | |
* `sudo /PATH/TO/libtool --mode=install install mod_metrics.la /PATH/TO/modules/` | |
*/ | |
#include "httpd.h" | |
#include "http_core.h" | |
#include "http_protocol.h" | |
#include "http_request.h" | |
#include "ap_mpm.h" | |
static void register_hooks(apr_pool_t *pool); | |
static int metrics_handler(request_rec *r); | |
module AP_MODULE_DECLARE_DATA metrics_module = | |
{ | |
STANDARD20_MODULE_STUFF, | |
NULL, // Per-directory configuration handler | |
NULL, // Merge handler for per-directory configurations | |
NULL, // Per-server configuration handler | |
NULL, // Merge handler for per-server configurations | |
NULL, // Any directives we may have for httpd | |
register_hooks // Our hook registering function | |
}; | |
/* register_hooks: Adds a hook to the httpd process */ | |
static void register_hooks(apr_pool_t *pool) | |
{ | |
ap_hook_handler(metrics_handler, NULL, NULL, APR_HOOK_LAST); | |
} | |
/* return metrics in Prometheus-friendly format */ | |
static int metrics_handler(request_rec *r) | |
{ | |
apr_off_t total_request_count, total_bytes_served; | |
apr_uint32_t up_time_seconds; | |
apr_time_t total_duration; | |
int server_limit, thread_limit; | |
int server_index, thread_index; | |
int idle_worker_count, busy_worker_count, process_count; | |
worker_score *scoreboard_worker_info; | |
ap_loadavg_t load_averages; | |
/* request isn't for us, break out */ | |
if (!r->handler || strcmp(r->handler, "metrics-handler") != 0) { | |
return DECLINED; | |
} | |
/* iterate through workers and count totals */ | |
total_duration = total_request_count = total_bytes_served = 0; | |
busy_worker_count = idle_worker_count = 0; | |
ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); | |
ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); | |
scoreboard_worker_info = apr_palloc(r->pool, sizeof *scoreboard_worker_info); | |
for (server_index = 0; server_index < server_limit; ++server_index) { | |
for (thread_index = 0; thread_index < thread_limit; ++thread_index) { | |
ap_copy_scoreboard_worker(scoreboard_worker_info, server_index, thread_index); | |
total_bytes_served += scoreboard_worker_info->bytes_served; | |
total_request_count += scoreboard_worker_info->access_count; | |
total_duration += scoreboard_worker_info->duration; | |
switch (scoreboard_worker_info->status) { | |
case SERVER_READY: | |
case SERVER_IDLE_KILL: | |
idle_worker_count++; | |
break; | |
case SERVER_BUSY_READ: | |
case SERVER_BUSY_WRITE: | |
case SERVER_BUSY_KEEPALIVE: | |
case SERVER_BUSY_LOG: | |
case SERVER_BUSY_DNS: | |
case SERVER_CLOSING: | |
case SERVER_GRACEFUL: | |
busy_worker_count++; | |
break; | |
} | |
} | |
} | |
ap_get_loadavg(&load_averages); | |
up_time_seconds = (apr_uint32_t) apr_time_sec(apr_time_now() - ap_scoreboard_image->global->restart_time); | |
ap_rprintf(r, "# HELP apache_uptime_seconds Uptime\n"); | |
ap_rprintf(r, "# TYPE apache_uptime_seconds guage\n"); | |
ap_rprintf(r, "apache_uptime_seconds %u\n", up_time_seconds); | |
ap_rprintf(r, "# HELP apache_total_duration_milliseconds Total time spend servicing requests\n"); | |
ap_rprintf(r, "# TYPE apache_total_duration_milliseconds guage\n"); | |
ap_rprintf(r, "apache_total_duration_milliseconds %" APR_TIME_T_FMT "\n", apr_time_as_msec(total_duration)); | |
ap_rprintf(r, "# HELP apache_total_bytes_served Total bytes sent\n"); | |
ap_rprintf(r, "# TYPE apache_total_bytes_served guage\n"); | |
ap_rprintf(r, "apache_total_bytes_served %" APR_OFF_T_FMT "\n", total_bytes_served); | |
ap_rprintf(r, "# HELP apache_total_request_count Total number of requests handled\n"); | |
ap_rprintf(r, "# TYPE apache_total_request_count guage\n"); | |
ap_rprintf(r, "apache_total_request_count %" APR_OFF_T_FMT "\n", total_request_count); | |
ap_rprintf(r, "# HELP apache_load_average Server load average currently and over last 5 and 15 minutes\n"); | |
ap_rprintf(r, "# TYPE apache_load_average guage\n"); | |
ap_rprintf(r, "apache_load_average{period=\"now\"} %f\n", load_averages.loadavg); | |
ap_rprintf(r, "apache_load_average{period=\"5 min\"} %f\n", load_averages.loadavg5); | |
ap_rprintf(r, "apache_load_average{period=\"15 min\"} %f\n", load_averages.loadavg15); | |
ap_rprintf(r, "# HELP apache_worker_count Number of worker threads busy and idle\n"); | |
ap_rprintf(r, "# TYPE apache_worker_count guage\n"); | |
ap_rprintf(r, "apache_worker_count{status=\"busy\"} %d\n", busy_worker_count); | |
ap_rprintf(r, "apache_worker_count{status=\"idle\"} %d\n", idle_worker_count); | |
return OK; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output is something like: