External adapters
MVX Metrics does not require a final monitoring platform from the beginning.
Production code can emit metric events now.
Metrics can aggregate those events now.
Recorders can expose snapshots now.
An external adapter can be added later, when the project decides where metric state should go.
What an external adapter is
An external adapter is code that connects MVX Metrics to another observability system.
For example:
MVX Metrics
|
v
adapter
|
v
Prometheus / OpenTelemetry / StatsD / custom backend
The adapter lives at the edge of the metrics system.
It should not live inside production methods.
Production code should not know whether metric state is later sent to Prometheus, OpenTelemetry, StatsD, a dashboard, a database, or a custom monitoring service.
Why adapters belong at the edge
The core pipeline is already enough to make code observable:
production code
|
v
metric events
|
v
metrics
|
v
snapshots
An adapter adds one more step:
production code
|
v
metric events
|
v
metrics
|
v
snapshots or hook
|
v
external adapter
|
v
external monitoring platform
The important part is that the production side does not change.
The same production component emits the same metric events.
The adapter is added around recorder, snapshot, or hook boundaries.
Two integration styles
There are two common ways to connect external systems.
snapshot-based adapter
hook-based adapter
They solve different problems.
Snapshot-based adapter
A snapshot-based adapter reads current metric state from recorders.
snapshots = recorder.get_metric_snapshots()
Then it transforms those snapshots into the format expected by the external system.
Conceptually:
recorder.get_metric_snapshots()
|
v
snapshot adapter
|
v
external platform format
This style is useful when the external system can consume current state periodically or on demand.
Typical uses:
diagnostics pages;
health endpoints;
pull-style exporters;
periodic reporting;
simple dashboards;
tests that check adapter output.
A snapshot-based adapter works with already aggregated state.
It does not need to receive every raw metric event.
It does not need to replay history.
Hook-based adapter
A hook-based adapter reacts when metric state changes.
This is usually done by extending recorder behavior through _on_metric_changed().
The hook runs after a metric accepts an event and updates its state.
metric.handle_event(event)
|
v
metric state changed
|
v
_on_metric_changed(metric=metric, event=event)
|
v
adapter logic
This style is useful when an integration should react to changes as they happen.
Typical uses:
notifying observers;
pushing updated metric state;
feeding a live diagnostic view;
triggering an export operation;
connecting a custom backend.
The custom recorder example uses this style.
It opens a publisher on recorder startup, publishes records after metric changes, and closes the publisher on recorder shutdown.
Choosing between snapshot and hook adapters
Use a snapshot-based adapter when the external side can read or receive current state.
current state is enough
|
v
use snapshots
Use a hook-based adapter when the integration must react after each accepted metric event.
react after metric changed
|
v
use _on_metric_changed()
Both styles keep production code unchanged.
The difference is where the adapter attaches.
snapshot adapter
|
v
attaches to the read surface
hook adapter
|
v
attaches to recorder processing
Adapter responsibilities
An adapter owns the external integration details.
Those details may include:
external metric naming;
unit conversion;
labels or tags;
batching;
retries;
authentication;
network delivery;
serialization;
endpoint exposure;
backend-specific error handling.
These concerns should not leak into production methods.
They also should not normally belong inside metric classes.
Metrics should aggregate state.
Adapters should translate or deliver state.
What MVX Metrics does not decide
MVX Metrics does not choose the final monitoring backend.
It does not define a Prometheus exposition format.
It does not define an OpenTelemetry exporter.
It does not define a StatsD sender.
It does not require a dashboard, collector, agent, or storage backend.
This is intentional.
The package provides the internal metrics foundation:
events
metrics
recorders
snapshots
hooks
runtime
External platform integration can be added later at the adapter layer.
Production code should stay unchanged
The key rule is:
do not put adapter logic into production code
Avoid this shape:
business method
|
+--> emit MVX metric event
|
+--> send Prometheus metric
|
+--> send OpenTelemetry metric
|
+--> update dashboard
Use this shape instead:
business method
|
v
emit MVX metric event
|
v
metrics infrastructure
|
v
adapter at the edge
This keeps business code stable.
It also makes it possible to change the monitoring backend later.
Why this pattern is useful
Many projects need observability early.
But the final monitoring stack may not be chosen at the start.
With MVX Metrics, the project can still add observability from the beginning:
add metric events now
aggregate metrics now
test snapshots now
inspect state now
choose external platform later
add adapter later
This is useful for reusable libraries and long-lived applications.
The code becomes observable and testable immediately, without being tied to a premature backend decision.
Adapter input options
An adapter can use several inputs depending on its design.
Recorder snapshots
snapshots = recorder.get_metric_snapshots()
Use this when the adapter wants current state.
Runtime recorder registry
If the application owns many recorders, adapter code can be wired around the runtime-level recorder collection.
This lets an integration collect state from several measured scopes.
The exact registry traversal belongs to application integration code.
Metric changed hook
async def _on_metric_changed(
self,
*,
metric: Metric,
event: MetricEvent,
) -> None:
...
Use this when the adapter should react after metric state changes.
Custom recorder
Use a custom recorder when adapter behavior belongs naturally to recorder lifecycle.
For example, a recorder may open an external publisher on startup and close it on shutdown.
Adapter output
Adapter output depends on the target system.
The adapter may produce:
flat records;
JSON payloads;
HTTP requests;
Prometheus samples;
OpenTelemetry measurements;
StatsD packets;
database rows;
in-memory dashboard updates.
This output is outside the core metrics package.
The core should not need to know which form is used.
Failure handling
External adapters introduce external failure modes.
For example:
network timeout;
backend unavailable;
authentication failure;
serialization error;
rate limit;
retry exhaustion.
Those failures should be handled at the adapter boundary.
They should not automatically become business operation failures.
This follows the same design principle as recorder integration: observability should not accidentally own business behavior.
A strict application may choose to surface adapter failures.
A tolerant application may log them and continue.
The adapter owns that policy.
Summary
External adapters connect MVX Metrics to monitoring platforms or custom observability systems.
They should attach at the edge: snapshots, hooks, custom recorders, or runtime-level integration.
They should not be embedded in production methods.
MVX Metrics lets code become observable before the final monitoring platform is chosen.
When the platform is chosen, an adapter can publish the same metric state without changing production code.