Skip to content

Prometheus metrics from logs ​

The metrics plugin watches your log entries and builds Prometheus metrics from their payload fields. You get request-duration histograms, error counters and gauges without a second instrumentation layer, and no extra dependency: the Prometheus text format is generated by logixia.

ts
import express from 'express';
import { createLogger, createMetricsPlugin } from 'logixia';

const metrics = createMetricsPlugin({
  http_request_duration: {
    type: 'histogram',
    field: 'duration',
    labels: ['method', 'statusCode'],
    help: 'HTTP request duration in milliseconds',
  },
  error_count: {
    type: 'counter',
    levelFilter: 'error',
    labels: ['context'],
    help: 'Total error log entries',
  },
  active_connections: { type: 'gauge', field: 'connections' },
});

const logger = createLogger({ appName: 'api' });
logger.use(metrics);

const app = express();
app.get('/metrics', metrics.expressHandler());

All metric names get the prefix logixia_, so error_count is exposed as logixia_error_count. Names and label names are sanitized to valid Prometheus identifiers.

Metric types ​

Counter ​

Increments once per matching entry.

OptionDescription
levelFilterCount only entries at this level. Omit to count every level.
field, valueCount only entries where payload[field] === value.
labelsPayload field names to use as label dimensions. 'level' is also valid.
helpThe # HELP text.

Histogram ​

Observes a numeric payload field.

OptionDescription
fieldThe payload field with the number to observe (required).
bucketsUpper bounds, sorted automatically. Default: 1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000.
labels, helpAs for counters.

Gauge ​

Keeps the most recent numeric value of field. Takes labels and help.

Exposing the metrics ​

MethodUse
expressHandler()An Express route handler: app.get('/metrics', metrics.expressHandler()).
httpHandler()A raw Node http handler that serves GET /metrics and answers 404 elsewhere.
render()The text exposition format as a string, for any other framework.
reset()Clear all collected values.
ts
import http from 'node:http';
import { createMetricsPlugin } from 'logixia';

const metrics = createMetricsPlugin({
  checkout_total: { type: 'counter', field: 'event', value: 'checkout' },
});

http.createServer(metrics.httpHandler()).listen(9464);

Label cardinality ​

Labels come from payload values, so a field like userId could create an unbounded number of series. Each metric tracks at most maxLabelSets distinct label combinations (default 1000). Further combinations are folded into one extra series whose label values are all __overflow__ (exported as OVERFLOW_LABEL_VALUE). Label values are cut at 256 characters.

ts
import { createMetricsPlugin } from 'logixia';

const metrics = createMetricsPlugin(
  { requests: { type: 'counter', labels: ['route'] } },
  { maxLabelSets: 200 }
);
console.log(metrics.name);

Prefer low-cardinality labels such as method, statusCode and context.

Sampling affects metrics

The plugin sees entries after sampling. A sampled logger undercounts. Keep metric-bearing entries out of sampling or count them elsewhere.

The plugin is an ordinary plugin; MetricsPlugin is also exported if you prefer new MetricsPlugin(map, options).

Released under the MIT License.