Lock-free, allocation-free observability for high-performance C applications
fwProm is a lightweight Prometheus metrics library for C, built around the constraint that observability must not compromise the performance of the system being observed. Every design decision eliminates overhead on the hot path.
int64_t × 1000, enabling atomic load/store without floating-point races/metrics endpoint is scraped, never on the hot pathKpromMetric* fwPromCounterCreate(const char* name, const char* help);
Creates a counter metric. Counters are monotonically increasing — they only go up (or reset to zero on restart).
KpromMetric* fwPromGaugeCreate(const char* name, const char* help);
Creates a gauge metric. Gauges represent a current value that can rise and fall — queue depth, active connections, temperature.
KpromMetric* fwPromHistogramCreate(const char* name, const char* help,
double* buckets, int bucketCount);
Creates a histogram with the specified bucket boundaries. A +Inf bucket is appended automatically. All bucket counters, sum, and count are updated atomically on each observation.
void fwPromCounterInc(KpromMetric* counter); // Increment by 1
void fwPromCounterAdd(KpromMetric* counter, int64_t value); // Add value
void fwPromGaugeSet(KpromMetric* gauge, double value); // Set to value
void fwPromGaugeAdd(KpromMetric* gauge, double value); // Add to gauge
void fwPromGaugeSub(KpromMetric* gauge, double value); // Subtract from gauge
void fwPromHistogramObserve(KpromMetric* histogram, double value);
Records an observation. Atomically increments all bucket counters whose upper boundary is ≥ value, and updates the running sum and count.
KpromMetric* fwPromLookup(const char* name); // Find metric by name
int fwPromRenderSize(void); // Calculate buffer size needed
int fwPromRender(char* buf, int bufLen); // Render to Prometheus text format
FtNode* fwPromMetrics(FjParser* kjP); // Render as JSON tree
fwPromRenderSize returns the exact byte count needed so the caller can size its buffer before calling fwPromRender. fwPromMetrics produces a JSON representation of all metrics for use with fwJson-based response pipelines.
#include "fwProm/fwProm.h"
// Create metrics at startup (allocations happen here, not on the hot path)
KpromMetric* requestsTotal = fwPromCounterCreate("http_requests_total",
"Total HTTP requests");
KpromMetric* activeConns = fwPromGaugeCreate("active_connections",
"Active connections");
double buckets[] = { 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0 };
KpromMetric* duration = fwPromHistogramCreate("request_duration_seconds",
"Request duration", buckets, 7);
// Update metrics on hot path (lock-free, allocation-free)
fwPromCounterInc(requestsTotal);
fwPromGaugeSet(activeConns, 42);
fwPromHistogramObserve(duration, 0.023);
// Render for /metrics endpoint (on-demand, off hot path)
char buf[8192];
int len = fwPromRender(buf, sizeof(buf));
Rendered output:
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total 1
# HELP active_connections Active connections
# TYPE active_connections gauge
active_connections 42
# HELP request_duration_seconds Request duration
# TYPE request_duration_seconds histogram
request_duration_seconds_bucket{le="0.001"} 0
request_duration_seconds_bucket{le="0.005"} 0
request_duration_seconds_bucket{le="0.010"} 0
request_duration_seconds_bucket{le="0.050"} 1
request_duration_seconds_bucket{le="0.100"} 1
request_duration_seconds_bucket{le="0.500"} 1
request_duration_seconds_bucket{le="1.000"} 1
request_duration_seconds_bucket{le="+Inf"} 1
request_duration_seconds_sum 0.023
request_duration_seconds_count 1
fwProm uses trace levels 90–99 (reserved). See the full trace level table for all assignments across the fw-lib stack.