beberlei/metrics
A lightweight PHP metrics library for instrumenting applications with counters, gauges, and timings. Pluggable collectors send measurements to backends like StatsD and Graphite, keeping monitoring code decoupled from your application logic.
CollectorInterface, per-call tags, four new collectors (Chain, OpenTelemetry, InfluxDB v2, CloudWatch), and a maintained dependency tree (the abandoned Prometheus and InfluxDB SDKs are gone). The hand-rolled StatsDClient wrapper argument is stronger than before, because the replacement now covers dimensional metrics and multiple backends without you writing adapters.MeterProviderInterface, so the same call sites can feed a Prometheus/OTLP pipeline later. This meaningfully weakens the old "instrumenting twice" objection: you can adopt this now as a phase 1 and converge on OTel metrics without touching call sites. It does not give you spans or trace correlation — that remains a separate, additive decision.array $tags, someone must own the policy: which tag keys are allowed, what their value domains are, and what the cardinality budget is per metric. The library gives no guardrails, sampling, or aggregation hints. Deciding "we slice by endpoint and plan tier, but never by user ID or request ID" is a product/ops decision, and it belongs in the same doc as the metric naming standard.examples/ app ships Docker stacks for Prometheus, Graphite/StatsD, InfluxDB 1.x/2.x, PostgreSQL, and LocalStack CloudWatch, each with a provisioned Grafana dashboard, and it runs in CI. Evaluating Datadog vs. CloudWatch vs. self-hosted Prometheus becomes a two-week spike rather than a quarter-long integration project — useful input to the buy-vs-self-host observability decision.kernel.reset, so long-running workers don't leak state), feature-adoption counters sliced by plan tier or region, AWS-native shops that want CloudWatch without an extra agent, and before/after measurement for pricing or performance experiments.#[Target], lazy optional services, empty config falls back to null). Laravel still gets nothing, so the plain-PHP interface remains your portability story.Adopt when most of these hold:
NullMetrics fallback for local/test. No auto-discovery, no middleware, no /metrics route — that is still yours.^3.0) and treat the adapter layer as yours to wrap or compose (note: collectors and Factory are now final, so fork-by-subclassing is out; decorate or implement CollectorInterface instead).Look elsewhere when:
Factory (now final), or on TaggableCollector::setTags() / the null_inlinetaggable factory type — all removed.To executives: We're adopting a free (MIT), thin instrumentation layer so reliability and usage measurement don't lock us into one observability vendor. This release materially changes the calculus in our favor: it now supports tags (so we can slice latency and adoption by endpoint, plan tier, or region), it can write to several backends at once, and it has an OpenTelemetry path — meaning our instrumentation survives a future vendor change instead of being rewritten. It also ships a demo stack with dashboards for Prometheus, CloudWatch, InfluxDB, and Graphite, so we can compare observability vendors on real data before signing. The cost is small: roughly a day of integration, plus a PHP 8.4 runtime upgrade we should schedule regardless. The expensive, reversible commercial decision — which backend and dashboards we pay for — stays separate and stays ours.
To engineering: One strictly typed interface, one service-provider binding, and vendor adapters behind it. Every metric call now takes array $tags, so application code emits a stable, testable API and swapping StatsD for CloudWatch or an OTLP pipeline is config plus one adapter — not a refactor of call sites. The Chain collector lets us dual-write during any migration; the OpenTelemetry collector lets us converge on OTel metrics without re-instrumenting; collectors swallow client exceptions so the telemetry path can't take down the app; and everything is kernel.reset-tagged for long-running workers. A null collector covers local and test. Trade-offs we accept explicitly: PHP 8.4+ only, no tracing/spans, no histograms-percentiles-sampling, a tag-cardinality policy we must write and enforce ourselves, and a single maintainer — so we pin ^3.0, treat metric names/units/tag keys as our contract, and wrap rather than extend (collectors and Factory are final). If we need traces within two quarters, we should start with the OpenTelemetry SDK instead and skip the intermediate step. Upgrading from 2.x is a breaking change with a documented guide; we should budget the interface and tag migration in the same sprint as the runtime bump.
How can I help you explore Laravel packages today?