Metrics

class aerospike_sdk.metrics.MetricsPolicy[source]

Bases: object

Configuration for client metrics collection.

Enabling metrics records the always-on gauges only. The operational tier – latency and byte histograms, result codes, retry and error counters – is opt-in through operational_enabled, so the cost of measuring every command is never paid by accident.

That tier’s defaults are the cross-SDK metrics defaults: latency recorded in milliseconds across 7 logarithmic buckets whose boundaries double per column (<= 1, > 1, > 2, > 4, > 8, > 16, > 32 ms), with every command recorded. Choose MICROSECONDS with more columns when sub-millisecond resolution matters.

Re-enabling metrics with a changed latency unit or histogram shape discards the accumulated latency samples (counters are retained).

Example:

from aerospike_sdk.metrics import LatencyUnit, MetricsPolicy, Sampler

# Pool and membership gauges only -- no per-command measurement.
cluster.enable_metrics(MetricsPolicy())

# Classic milliseconds view, sampling 10% of calls.
policy = MetricsPolicy(
    operational_enabled=True,
    sampler=Sampler.probability(0.1),
)
cluster.enable_metrics(policy)

# Sub-millisecond resolution for a low-latency deployment.
fine = MetricsPolicy(
    operational_enabled=True,
    latency_unit=LatencyUnit.MICROSECONDS,
    latency_columns=18,
)
Parameters:
  • latency_unit (LatencyUnit) – Unit latency histograms are recorded in. Defaults to milliseconds.

  • latency_columns (int) – Number of histogram buckets. Defaults to 7.

  • latency_shift (int) – Bucket-boundary spacing exponent — each boundary after the first bucket multiplies by 2**latency_shift. Defaults to 1 (no skipped powers of two). Must be at least 1.

  • operational_enabled (bool) – Record the operational tier – latency and byte histograms, result codes, the command count, and the command retry/error and connection failure counters. Off by default, leaving the always-on gauges: pool occupancy, connections opened and closed, tend counts and node membership. The histogram settings above shape this tier and do nothing while it is off.

  • sampler (Optional[Sampler]) – Record-time gate for the per-command metrics; a fractional sampler decides once per call (not per retry) whether the whole call is measured. Defaults to recording every command.

  • usage_enabled (bool) – Record which SDK features the application uses (aerospike_sdk.metrics.usage). Off by default. Recorded by this SDK rather than the client core, and independent of latency collection – usage counters ignore the sampler.

  • labels (Optional[Dict[str, str]]) – Static labels attached to every snapshot, e.g. {"team": "billing"}.

Raises:

ValueError – If latency_shift is less than 1.

__init__(*, operational_enabled=False, latency_unit=LatencyUnit.MILLISECONDS, latency_columns=_DEFAULT_LATENCY_COLUMNS, latency_shift=_DEFAULT_LATENCY_SHIFT, sampler=None, labels=None, usage_enabled=False)[source]
operational_enabled
latency_unit
latency_columns
latency_shift
sampler
labels
usage_enabled
class aerospike_sdk.metrics.MetricsSnapshot[source]

Bases: object

A point-in-time view of accumulated client metrics.

Counter values are cumulative since metrics were enabled; connection gauges are point-in-time. The canonical detail is the per-node, per-command-type breakdown reachable through nodes and cluster_aggregated; latency() adds the classic five-way grouped view on top.

Example:

cluster.enable_metrics()
...
snapshot = cluster.metrics_snapshot()
reads = snapshot.latency(LatencyType.READ)
print(f"{reads.count} reads, avg {reads.average:.1f} {reads.latency_unit}")
for host, node in snapshot.nodes.items():
    print(host, node.connections_attempts)
__init__(pnc_metrics, *, policy=None, nodes=None, usage=None, command_count=None, app_id=None, process=None, metrics_enabled=False, usage_enabled=False)[source]

Wrap a raw PNC snapshot.

Parameters:
  • pnc_metrics (ClusterMetrics) – The snapshot from the underlying client.

  • policy (Optional[MetricsPolicy]) – Policy in effect, supplying the histogram shape that the snapshot itself does not carry.

  • nodes (Optional[List[Any]]) – Live cluster nodes, joined by host to name the nodes in to_canonical_dict().

  • usage (Optional[Dict[str, int]]) – Feature-usage counters recorded by this SDK.

  • command_count (Optional[int]) – User API calls counted by this SDK, or None when the caller has no count to report.

  • app_id (Optional[str]) – Application identity to report when the underlying client carries none, normally the authenticated user. None falls back to "not-set".

  • metrics_enabled (bool) – Whether collection was on when the snapshot was taken.

  • usage_enabled (bool) – Whether the usage counters were being recorded.

property nodes: Dict[str, NodeMetricsSnapshot]

Per-node snapshots keyed by host address.

property cluster_aggregated: NodeMetricsSnapshot

All node snapshots aggregated into one view.

property total_nodes: int

Number of nodes in the snapshot.

property metrics_enabled: bool

Whether collection was on when the snapshot was taken.

A snapshot can be pulled while collection is off; its counters are then frozen at the values they had when collection was last on.

property operational_metrics_enabled: bool

Whether the operational tier (latency, errors, bytes) was being recorded.

property usage_metrics_enabled: bool

Whether the feature-usage counters were being recorded.

property command_retries: int

Wire retries across the cluster, cumulative since metrics enable.

The per-node retry counters summed: every retry increments on the node it was sent to, and the aggregate retains departed hosts, so the total survives node churn. Retries happen inside the client core, so unlike command_count this covers all traffic on the client, however it was issued.

Example:

snapshot = cluster.metrics_snapshot()
retries_per_call = snapshot.command_retries / max(snapshot.command_count, 1)
latency(latency_type, node=None)[source]

The derived latency histogram for one legacy grouping.

Parameters:
  • latency_type (LatencyType) – Which grouped view to compute (see LatencyType for the category mapping).

  • node (Optional[str]) – Host address of a single node, or None for the cluster-aggregated view.

Return type:

DerivedHistogram

Returns:

A DerivedHistogram in the snapshot’s latency unit. CONN sums the connection-acquisition phase across all namespaces and command types.

Raises:

KeyError – If node names a host not present in the snapshot.

Example:

writes = snapshot.latency(LatencyType.WRITE)
slowest_bucket = writes.buckets[-1]
property usage: Dict[str, int]

Feature-usage counters, cumulative since the client started.

Empty unless MetricsPolicy.usage_enabled was set. Counts calls made through this SDK, so traffic issued through the underlying client directly is not represented.

Returns:

Counter name to count, e.g. {"feature.shape.point": 42}.

Example:

snapshot = cluster.metrics_snapshot()
print(snapshot.usage.get("feature.filter.ael", 0))
property command_count: int

User API calls counted while operational metrics were on, cumulative.

Counted by this SDK — one increment per data-path call (point, batch, query, UDF, background job) made through this API, whatever the sampler decides — so it is an exact total, and traffic issued through the underlying client directly is not represented. 0 when the operational tier was never enabled.

Example:

snapshot = cluster.metrics_snapshot()
errors_per_call = errors / max(snapshot.command_count, 1)
to_canonical_dict()[source]

The snapshot in the cross-SDK structured form exporters consume.

A stable, snake_case document that a JSON, OTEL or Prometheus exporter can serialize directly, independent of how the underlying client happens to name its fields.

The cluster section carries the pool occupancy split, recover-queue depth and invalid-node count the underlying client reports, this process’s CPU share and resident memory when the cluster sampled them, and each node its circuit-breaker error_rate and the pool_exhausted count among its connection counters. The cluster command_retries is the per-node retry counters summed; command_count is present when this SDK counted calls — see command_count for its scope.

Each namespace’s errors is the remainder: failures not already counted under timeouts, key_busy, record_too_big or device_overload, so summing the five never counts a failure twice. timeouts counts server-reported timeouts; a command that expired on the client side has no result code and is counted once, cluster-wide, under command_timeout_client, while command_timeout_server is the namespace timeouts summed.

app_id is always populated, so a consumer can group by application without a missing-field case: the identity the application set on the cluster definition, else the authenticated user, else "not-set".

nodes lists the nodes still in the cluster. A node that left since the previous export appears once under nodes_departed – same shape, final counters – so an exporter can flush its series without a callback. Departure is tracked by the export timer; a snapshot pulled directly through metrics_snapshot() always carries an empty nodes_departed.

Returns:

timestamp, client_type, client_version, cluster_name, app_id, labels, the three tier flags, the histogram shape, cluster, nodes as a list, and nodes_departed.

Return type:

Dict[str, Any]

Example:

snapshot = cluster.metrics_snapshot()
payload = json.dumps(snapshot.to_canonical_dict())
class aerospike_sdk.metrics.LatencyType[source]

Bases: Enum

Legacy five-way latency grouping, derived from the command categories.

The canonical detail is the per-command-type breakdown (CommandType); these groups exist for compatibility with the classic latency views (conn/write/read/ batch/query) and are computed from the canonical histograms:

  • READ = get + get-header + exists

  • WRITE = put + delete + operate + udf

  • BATCH = batch-read + batch-write

  • QUERY = query + scan

  • CONN = connection acquisition (pool checkout; includes creation on a pool miss)

CONN = 'conn'
WRITE = 'write'
READ = 'read'
BATCH = 'batch'
QUERY = 'query'
class aerospike_sdk.metrics.DerivedHistogram[source]

Bases: object

A latency histogram summed across command categories.

Produced by MetricsSnapshot.latency(); bucket values are in the snapshot’s latency unit (see latency_unit).

buckets: tuple
count: int
min: int
max: int
sum: float
latency_unit: LatencyUnit
property average: float

Mean recorded value, or 0.0 when nothing was recorded.

__init__(buckets, count, min, max, sum, latency_unit)
class aerospike_sdk.metrics.MetricsExporter[source]

Bases: Protocol

Receives metrics snapshots from a synchronous cluster.

Implement this for SyncCluster. The call runs on the export thread, so a slow exporter delays the next export but never a request.

The snapshot argument is an owned copy: keeping a reference past the call is safe. Resources the exporter writes to are its own to manage – open them in the constructor or on first call, and close them from application code when done.

Example:

class JsonLinesExporter:
    def __init__(self, path):
        self._file = open(path, "a")

    def export(self, snapshot):
        self._file.write(json.dumps(snapshot.to_canonical_dict()) + "\n")
        self._file.flush()

    def close(self):
        self._file.close()

exporter = JsonLinesExporter("/var/log/aerospike/metrics.jsonl")
cluster.add_exporter(exporter)
...
exporter.close()   # the application closes it, never the client

See also

AsyncMetricsExporter: The same contract for the async client. add_exporter()

export(snapshot)[source]

A snapshot was taken, once per export interval.

Return type:

None

__init__(*args, **kwargs)
class aerospike_sdk.metrics.AsyncMetricsExporter[source]

Bases: Protocol

Receives metrics snapshots from an asynchronous cluster.

The same contract as MetricsExporter with an awaitable method, so an exporter can use an async HTTP client without blocking the event loop the cluster’s own operations run on.

Example:

class OtelExporter:
    def __init__(self, client):
        self._client = client

    async def export(self, snapshot):
        await self._client.post("/v1/metrics", json=snapshot.to_canonical_dict())

cluster.add_exporter(OtelExporter(httpx.AsyncClient()))

See also

MetricsExporter: The same contract for the sync client. add_exporter()

async export(snapshot)[source]

A snapshot was taken, once per export interval.

Return type:

None

__init__(*args, **kwargs)
class aerospike_sdk.metrics.MetricsExporterType[source]

Bases: str, Enum

Where the periodic push goes: the metrics.exporter setting.

The values are the configuration-file spellings; construction is case-insensitive, so MetricsExporterType("FILE") is FILE.

FILE

The built-in log writer under report_dir, and nothing else. The default.

CUSTOM

The exporters registered with add_exporter, in registration order, and nothing else.

NONE

No periodic push; snapshots remain available by polling.

Example:

settings = SystemSettings(metrics=MetricsSettings(exporter=MetricsExporterType.CUSTOM))
cluster = await ClusterDefinition(host).with_system_settings(settings).connect()
cluster.add_exporter(my_exporter)
FILE = 'file'
CUSTOM = 'custom'
NONE = 'none'
__new__(value)
class aerospike_sdk.metrics.MetricsWriter[source]

Bases: object

Writes the line-oriented metrics log under a report directory.

Every line starts with a local timestamp. The first line of each file is a header declaring the schema; each export appends one positional cluster[...] line carrying the cluster totals, its labels, and every node with its namespaces. A node that left the cluster since the previous export is written once more in that list, with its final counters.

The four usage columns (blocking_count, deferred_count, background_count, tran_count) carry the canonical snapshot’s feature.api.* and feature.transaction counters, and read 0 unless usage counters are enabled. command_count and command_retries read 0 unless operational metrics are enabled. A namespace’s errors excludes the failures counted under timeouts and key_busy, and timeouts counts server-reported timeouts.

The header names the latency unit, column count and shift. A file only ever describes one histogram shape: an export whose shape differs from the header’s starts a new file.

An ordinary exporter, not a client lifecycle: the first export() creates the directory and opens metrics-<timestamp>.log. The application calls close() when done – the client never closes an exporter it did not install. IO errors propagate to the export timer, which logs them and suspends the exporter after repeated failures.

Parameters:
  • report_dir (str) – Directory for log files; created if absent. An empty directory makes the exporter a no-op, matching the config default.

  • report_size_limit (int) – Rotate once the file reaches this many bytes. 0 never rotates.

Raises:

ValueError – If report_size_limit is neither 0 nor at least 1,000,000.

Example:

exporter = MetricsWriter("/var/log/aerospike", 10_000_000)
cluster.add_exporter(exporter)
...
exporter.close()

See also

MetricsExporter: The protocol this implements.

__init__(report_dir, report_size_limit=0)[source]
export(snapshot)[source]

Append one cluster line, opening a file first when needed.

Return type:

None

close()[source]

Close the log file. Exporting again afterwards opens a new one.

Return type:

None

class aerospike_sdk.policy.system_settings.MetricsSettings[source]

Bases: object

Client metrics configuration from the system.<cluster>.metrics block.

Every field is None when the file did not set it, so an absent block changes nothing and a partial block only overrides what it names.

The two extended tiers each have their own enabled flag, under the cross-SDK key names: metrics.extended.operational.enabled gates the latency histograms and per-command counters, and carries the histogram shape keys that only mean anything while it is on; metrics.extended.usage.enabled gates the feature-usage counters, which this SDK records itself rather than reading from the client core.

metrics.enabled sits above both: it turns collection on at all, and on its own yields the always-on gauges.

exporter selects where the periodic push goes, as a MetricsExporterType: file (the default; the built-in log writer under report_dir), custom (the exporters registered with add_exporter) or none. A string in any case is accepted and stored as the enum member.

Example:

# system:
#   DEFAULT:
#     metrics:
#       enabled: true
#       exporter: file
#       report_dir: /var/log/aerospike/metrics
#       labels:
#         owner: platform-team
#       extended:
#         operational:
#           enabled: true
#           latency_unit: microseconds
#           latency_columns: 18
Raises:

ValueError – If exporter is not file, custom or none, or report_size_limit is neither 0 nor at least 1,000,000.

See also

MetricsPolicy: The runtime policy these

settings build.

enabled: bool | None = None
latency_unit: str | None = None
latency_columns: int | None = None
latency_shift: int | None = None
export_interval: timedelta | None = None
exporter: MetricsExporterType | None = None
report_dir: str | None = None
report_size_limit: int | None = None
sampler_range: int | None = None
sampler_threshold: int | None = None
labels: Dict[str, str] | None = None
operational_enabled: bool | None = None
usage_enabled: bool | None = None
__init__(*, enabled=None, latency_unit=None, latency_columns=None, latency_shift=None, export_interval=None, exporter=None, report_dir=None, report_size_limit=None, sampler_range=None, sampler_threshold=None, labels=None, operational_enabled=None, usage_enabled=None)