PHPackages                             sugarcraft/candy-metrics - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. sugarcraft/candy-metrics

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

sugarcraft/candy-metrics
========================

Telemetry primitives for SugarCraft / CandyWish — counters, gauges, histograms with pluggable backends (in-memory, StatsD UDP, Prometheus textfile, JSON stream). Drop-in middleware for SSH session metrics.

10PHP

Since Jun 29Pushed 1mo agoCompare

[ Source](https://github.com/sugarcraft/candy-metrics)[ Packagist](https://packagist.org/packages/sugarcraft/candy-metrics)[ RSS](/packages/sugarcraft-candy-metrics/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependenciesVersions (1)Used By (0)

[![candy-metrics](.assets/icon.png)](.assets/icon.png)

CandyMetrics
============

[](#candymetrics)

[![CI](https://github.com/detain/sugarcraft/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/detain/sugarcraft/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/865cf236017c9ec2171ba40da00c51e55db03e0553cd7137007d50bea4ee4d60/68747470733a2f2f636f6465636f762e696f2f67682f64657461696e2f737567617263726166742f6272616e63682f6d61737465722f67726170682f62616467652e7376673f666c61673d63616e64792d6d657472696373)](https://app.codecov.io/gh/detain/sugarcraft?flags%5B0%5D=candy-metrics)[![Packagist Version](https://camo.githubusercontent.com/f97ea27888c373ec05e29f70fb6d9453701bd511863939ffb65b6a0fe94f5b5e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f737567617263726166742f63616e64792d6d6574726963733f6c6162656c3d7061636b6167697374)](https://packagist.org/packages/sugarcraft/candy-metrics)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/e78ffc83837c0d12647811a7fd1910c3cbeae04988de94bb4fd5b67e0874696a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135382e312d3838393262662e737667)](https://www.php.net/)

Lightweight telemetry primitives for SugarCraft / CandyWish servers. Counters, gauges, histograms with pluggable backends — drop-in middleware for SSH session metrics.

```
composer require sugarcraft/candy-metrics
```

Concepts
--------

[](#concepts)

PrimitiveBehaviourCounterMonotonic value that accumulates (connect counts, errors).GaugeInstantaneous value that replaces on set (queue depth, RSS).HistogramDistribution of samples (latency, payload size); Prometheus backend emits 14 classic `le` buckets +Inf.UpDownCounterSynchronous counter that supports positive *and* negative increments — used for values that go up and down (active connections).AsyncCounterAsynchronous counter whose value is observed at collection time via a callback. External values (DB pool size, GC counts).AsyncGaugeAsynchronous gauge whose value is observed at collection time via a callback. External instantaneous readings (memory, queue depth).A `Registry` is the application-facing facade; it forwards every emit to the configured `Backend`. Backends decide how to persist or forward.

Instrument factory helpers
--------------------------

[](#instrument-factory-helpers)

The registry exposes dedicated factory methods that return instrument objects — useful when an instrument is held for repeated `add()` / `observe()` calls:

```
$connCounter = $reg->upDownCounter('server.active_connections', ['host' => $host]);
$connCounter->add(1);    // connection opened
// ... later ...
$connCounter->add(-1);    // connection closed
```

Async instruments accept a callback that is invoked at collection time:

```
$gcCount = $reg->asyncCounter('jvm.gc.count', 'JVM garbage collection count', fn() => $jvm->gcCount());
$gcCount->observe();   // called during collection sweep
```

Cardinality management
----------------------

[](#cardinality-management)

Every unique label-value combination is a distinct time series. High-cardinality labels (e.g. `user_id`, `request_id`) can exhaust memory if left unchecked.

The registry tracks per-metric cardinality and evicts the oldest combination when the limit (default: 10 000) is reached:

```
// Default limit of 10 000 label combinations per metric
$reg = new Registry($backend);

// Custom limit
$reg = new Registry($backend, [], 500);

// Inspect current cardinality
$reg->cardinality('http.requests');   // → int

// Manually evict a label combination (e.g. after a session ends)
$reg->deleteLabelValues('http.requests', ['route' => '/logout']);

// Eviction is also called automatically — FIFO; the oldest entry
// is removed when the limit is exceeded.
```

Descriptor registration
-----------------------

[](#descriptor-registration)

The `Descriptor` DTO carries a metric's name, help text, type, and label keys. Register it with the registry so backends can pre-emit `TYPE` and `HELP` lines before any samples are recorded — required by the Prometheus textfile collector for uninitialized metrics:

```
use SugarCraft\Metrics\Registry;
use SugarCraft\Metrics\Descriptor;
use SugarCraft\Metrics\Backend\PrometheusFileBackend;

$reg = new Registry(new PrometheusFileBackend('/var/lib/app/metrics.prom'));

$reg->register(new Descriptor(
    name: 'http.request.duration',
    help: 'HTTP request duration in seconds',
    type: 'histogram',
    labelKeys: ['route', 'status'],
));

$stop = $reg->time('http.request.duration', ['route' => '/api/foo']);
handleRequest();
$stop();
```

`register()` is idempotent — registering the same metric name twice is a no-op.

Usage
-----

[](#usage)

```
use SugarCraft\Metrics\Registry;
use SugarCraft\Metrics\Backend\StatsdBackend;

$reg = new Registry(new StatsdBackend('127.0.0.1', 8125));

$reg->counter('http.requests', 1, ['route' => '/api/foo', 'status' => '200']);
$reg->gauge  ('queue.depth',   42);

$stop = $reg->time('http.duration', ['route' => '/api/foo']);
handleRequest();
$stop();
```

`withTags()` returns a registry that pre-tags every emit:

```
$req = $reg->withTags(['request_id' => $rid, 'user' => $userId]);
$req->counter('events');   // tagged with request_id + user automatically
```

Backends
--------

[](#backends)

### `InMemoryBackend`

[](#inmemorybackend)

Useful for tests and for fanning out to multiple backends. Counters add up, gauges hold the last value, histograms keep every sample.

### `JsonStreamBackend`

[](#jsonstreambackend)

Newline-delimited JSON, one event per line. The simplest, most diagnostic-friendly target. Default writes to `stderr`.

```
{"ts":"2026-05-02T16:30:00+00:00","kind":"counter","name":"hits","value":1,"tags":{"route":"/x"}}
```

### `StatsdBackend`

[](#statsdbackend)

UDP datagrams in the etsy / DogStatsD wire format. Tags emitted as `|#k:v,...` (drop with `dogstatsd: false` for legacy servers).

```
hits:1|c|#route:/x,env:prod

```

### `PrometheusFileBackend`

[](#prometheusfilebackend)

Atomically rewrites a `.prom` textfile-collector file with the current state of every metric. Pairs with `node_exporter --collector.textfile.directory=…`. Counter values accumulate across `flush()`s; histograms emit all 14 classic cumulative bucket boundaries (`le="0.005"` … `le="100"`) plus `le="+Inf"`, alongside `_count` and `_sum`.

### `MultiBackend`

[](#multibackend)

Fan out to multiple backends — e.g. live StatsD plus a JSON audit trail.

```
$reg = new Registry(new MultiBackend(
    new StatsdBackend(),
    new JsonStreamBackend('/var/log/metrics.jsonl'),
));
```

CandyWish session middleware
----------------------------

[](#candywish-session-middleware)

Wires session telemetry into a CandyWish stack:

```
use SugarCraft\Wish\Server;
use SugarCraft\Metrics\Registry;
use SugarCraft\Metrics\Backend\PrometheusFileBackend;
use SugarCraft\Metrics\Middleware\SessionMetrics;

$reg = new Registry(new PrometheusFileBackend('/var/lib/wish/metrics.prom'));

Server::new()
    ->use(new SessionMetrics($reg))
    ->use(/* ... your stack ... */)
    ->serve();
```

Per session this emits:

MetricTypeTags`wish.session.connect`counter`user`, `term``wish.session.duration`histogram`user`, `term``wish.session.error`counter`user`, `term`, `exception`Pass `extraTags` (a callable receiving the `Session`) to add things like client subnet, geo, build version.

Status
------

[](#status)

Phase 9 — UpDownCounter, AsyncCounter, AsyncGauge instrument kinds + Registry cardinality tracking with FIFO DeleteLabelValues eviction. 41 tests across Registry, four backends, SessionMetrics middleware, and instrument coverage.

###  Health Score

20

—

LowBetter than 12% of packages

Maintenance59

Moderate activity, may be stable

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/b1036e0717211b8030b83cbe729e8ba6ba442fdbd5285fb97a39d7dcfe339342?d=identicon)[detain](/maintainers/detain)

---

Top Contributors

[![detain](https://avatars.githubusercontent.com/u/1364504?v=4)](https://github.com/detain "detain (73 commits)")

---

Tags

alertingcandycorecandywishcounterdatadoggaugehistograminfrastructuremetricsmonitoringobservabilityprometheusprometheus-clientpromwishpromwish-portsressh-metricsstatsdstatsd-clienttelemetry

### Embed Badge

![Health badge](/badges/sugarcraft-candy-metrics/health.svg)

```
[![Health](https://phpackages.com/badges/sugarcraft-candy-metrics/health.svg)](https://phpackages.com/packages/sugarcraft-candy-metrics)
```

###  Alternatives

[psr/log

Common interface for logging libraries

10.4k1.2B11.9k](/packages/psr-log)[open-telemetry/api

API for OpenTelemetry PHP.

2041.5M289](/packages/open-telemetry-api)[open-telemetry/sdk

SDK for OpenTelemetry PHP.

2428.5M356](/packages/open-telemetry-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
