Skip to main content

Shared OpenTelemetry bootstrap for AgentOps (control plane + SDK workers).

Project description

agentops-otel

Shared logging + OpenTelemetry bootstrap for AgentOps.

Logging (configure_logging, get_logger)

One entry point sets up the process's logging; every module then grabs a logger and lets records propagate to the single root handler:

from agentops_otel import configure_logging, get_logger

configure_logging()          # once, at process start (idempotent)
log = get_logger(__name__)   # in every module
log.info("worker started", extra={"worker_id": wid})

configure_logging() installs one stdout handler on the root logger and picks its shape from the environment:

  • Local (AGENTOPS_ENV / AGENTOPS_DD_ENV / ENV unset or local) — a readable, coloured console line: time LEVEL name file:line message key=val.
  • Anything else (staging, production, …) — one-line JSON per event with explicit level/status and Datadog unified-service dd.* tags, so a Datadog agent tailing container stdout reads the real severity and correlates to traces.

Our staging/prod control plane sets AGENTOPS_DD_ENV, and worker pods set OTEL_EXPORTER_OTLP_ENDPOINT — either signal flips a deployed process to JSON automatically, with no extra config. Overrides: json_logs=True|False forces a format; level comes from the arg, then AGENTOPS_LOG_LEVEL, then AGENTOPS_DEBUG, then INFO.

Trace correlation is generic OpenTelemetry. We read the current span through the OTel API only. When no tracer/exporter is configured (the default — configure_telemetry is opt-in), there is no active span and nothing is added, so logging needs no running collector. When a span is active, each JSON record gains otelTraceID/otelSpanID plus the dd.trace_id/dd.span_id (lower-64-bit) form Datadog uses.

Forwarding worker logs to the control plane (CPForwardingHandler)

agentops_otel.CPForwardingHandler bridges the standard logging module to a sink callback — the SDK worker runtime (komodor_agentops.worker.logging_bridge.install_cp_log_forwarding) uses it to also ship every worker log record to the control plane as a log.created event, since Komodor has no pod/log access to customer-hosted workers. Two env vars control it:

  • AGENTOPS_CP_LOG_LEVEL (default INFO) — minimum level forwarded to CP.
  • AGENTOPS_CP_LOG_CAPTURE_ALL (default off) — forward only the SDK's own loggers (komodor_agentops, agentops) when unset; set to attach to the root logger instead and capture the whole process.

Telemetry (configure_telemetry)

configure_telemetry(service_name, *, app=None, engine=None) builds OTLP tracer/meter/logger providers (HTTP/protobuf or gRPC), attaches the OTel logging handler, and runs the FastAPI / httpx / logging auto-instrumentors. SQLAlchemy instrumentation is the optional agentops-otel[sqlalchemy] extra.

Off by default: nothing is installed unless OTEL_EXPORTER_OTLP_ENDPOINT or AGENTOPS_OTEL_ENABLED is set. Used by the control plane and by the SDK worker runtime; neither duplicates the setup.

Metric naming (metric_name, METRIC_PREFIX)

Every AgentOps metric lives under a single agentops. namespace root so the whole product's metrics are isolated and trivially sliceable in Datadog. When you create an instrument, name it through metric_name() rather than passing a raw string:

from agentops_otel import metric_name
from opentelemetry import metrics

meter = metrics.get_meter("agentops.controlplane.authz")
hist = meter.create_histogram(metric_name("authz.pdp.duration_ms"), unit="ms")
# → exported as "agentops.authz.pdp.duration_ms"

metric_name() is idempotent — a name that already starts with METRIC_PREFIX ("agentops.") is returned unchanged, so passing either the bare suffix or the full name is safe.

Why a helper and not a global rewrite? OpenTelemetry Python has no View/exporter-level facility for dynamic per-instrument renaming (a wildcard View's name is a single static string), so the exported metric name is fixed at instrument creation. This helper is therefore the one canonical entry point. Note that the meter/instrumentation-scope name is separate from the metric name and does not affect it — the agentops. prefix must be on the instrument name.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentops_otel-0.1.1.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentops_otel-0.1.1-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file agentops_otel-0.1.1.tar.gz.

File metadata

  • Download URL: agentops_otel-0.1.1.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for agentops_otel-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6901652b01f4f466180bf1387727f3ce72a066f5bf7969913540fc83d73c81f1
MD5 aa9c868165e0a263aa5411de235b02a4
BLAKE2b-256 c3f567c410a072cd02776288e9b0441e26601b8c687d5aa0b085335b988aea1c

See more details on using hashes here.

File details

Details for the file agentops_otel-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: agentops_otel-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for agentops_otel-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4ed529361ec7544f7588846d1c5712f97bde180c794a9cdbc30b6386e63a79a9
MD5 b1c08c700628d40f2bdcdc0b9b9efff9
BLAKE2b-256 2fe714bfc92f44c37d5601c254933718ebbd46bec5fcc45d76b06467be10021a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page