Skip to content

Metrics

See the Instrumentation & metrics guide for usage.

asyncly.client.metrics.sinks.base.MetricsSink

Bases: Protocol

Protocol for metrics backends used by InstrumentableHttpClient.

Implement observe_request to record requests in any backend.

observe_request

observe_request(
    *,
    client: str,
    method: str,
    route: str,
    status: int | str,
    duration_seconds: float,
    error_type: str | None = None,
) -> None

Record a single completed request.

Parameters:

Name Type Description Default
client str

The client name (client_name).

required
method str

HTTP method.

required
route str

Normalized, low-cardinality route label.

required
status int | str

Response status code, or a string marker on error.

required
duration_seconds float

Total time including response handling.

required
error_type str | None

Exception class name if the request failed, else None.

None
Source code in asyncly/client/metrics/sinks/base.py
def observe_request(
    self,
    *,
    client: str,
    method: str,
    route: str,
    status: int | str,
    duration_seconds: float,
    error_type: str | None = None,
) -> None:
    """Record a single completed request.

    Args:
        client: The client name (`client_name`).
        method: HTTP method.
        route: Normalized, low-cardinality route label.
        status: Response status code, or a string marker on error.
        duration_seconds: Total time including response handling.
        error_type: Exception class name if the request failed, else None.
    """
    ...

asyncly.client.metrics.sinks.noop.NoopSink

The default sink: records nothing and adds no overhead.

asyncly.client.metrics.sinks.prometheus.PrometheusSink

PrometheusSink(
    namespace: str = "asyncly",
    subsystem: str = "client",
    buckets: Iterable[float] = (
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
    ),
    registry: CollectorRegistry = REGISTRY,
)

Metrics sink that records to Prometheus (needs the prometheus extra).

Exposes a request-duration histogram and a request counter, labeled by client, method, route, and status.

Parameters:

Name Type Description Default
namespace str

Prometheus metric namespace prefix.

'asyncly'
subsystem str

Prometheus metric subsystem prefix.

'client'
buckets Iterable[float]

Histogram bucket boundaries in seconds.

(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0)
registry CollectorRegistry

Collector registry to register the metrics on.

REGISTRY
Source code in asyncly/client/metrics/sinks/prometheus.py
def __init__(
    self,
    namespace: str = "asyncly",
    subsystem: str = "client",
    buckets: Iterable[float] = (
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
    ),
    registry: CollectorRegistry = REGISTRY,
) -> None:
    metric_prefix = f"{namespace}_{subsystem}"
    self._latency = Histogram(
        f"{metric_prefix}_request_seconds",
        "HTTP client request duration including handler",
        ("client", "method", "route", "status"),
        buckets=tuple(buckets),
        registry=registry,
    )
    self._total = Counter(
        f"{metric_prefix}_requests_total",
        "Total HTTP client requests",
        ("client", "method", "route", "status"),
        registry=registry,
    )
    self._errors = Counter(
        f"{metric_prefix}_errors_total",
        "Total HTTP client errors",
        ("client", "method", "route", "error_type"),
        registry=registry,
    )

asyncly.client.metrics.sinks.opentelemetry.OpenTelemetrySink

OpenTelemetrySink(meter: Meter)

Metrics sink backed by OpenTelemetry (needs the opentelemetry extra).

Records request counts, durations, and errors through the given Meter.

Parameters:

Name Type Description Default
meter Meter

An OpenTelemetry Meter to create instruments from.

required
Source code in asyncly/client/metrics/sinks/opentelemetry.py
def __init__(self, meter: Meter) -> None:
    # Counter: количество
    self._req_counter = meter.create_counter(
        name="http_client_requests_total",
        unit="1",
        description="Total HTTP client requests",
    )
    # Histogram: длительность
    self._req_hist = meter.create_histogram(
        name="http_client_request_seconds",
        unit="s",
        description="HTTP client request duration including handler",
    )
    # Counter: ошибки
    self._err_counter = meter.create_counter(
        name="http_client_errors_total",
        unit="1",
        description="Total HTTP client errors",
    )

asyncly.client.metrics.route_resolver.default_route_resolver

default_route_resolver(url: URL) -> str

Normalize a URL path into a low-cardinality route label.

Numeric and UUID-like path segments are replaced with :id so that, for example, /cats/42 and /cats/7 both map to /cats/:id. Used as the default route label for client metrics.

Source code in asyncly/client/metrics/route_resolver.py
def default_route_resolver(url: URL) -> str:
    """Normalize a URL path into a low-cardinality route label.

    Numeric and UUID-like path segments are replaced with ``:id`` so that, for
    example, ``/cats/42`` and ``/cats/7`` both map to ``/cats/:id``. Used as the
    default route label for client metrics.
    """
    parts: list[str] = []
    for p in url.path.split("/"):
        if not p:
            continue
        if p.isdigit() or (len(p) in (8, 16, 32, 36) and any(ch.isalpha() for ch in p)):
            parts.append(":id")
        else:
            parts.append(p)
    return "/" + "/".join(parts) if parts else "/"