Skip to main content

OpenTelemetry integration for Muscles lifecycle

Project description

Muscles OpenTelemetry

Observability hooks and a neutral telemetry provider for Muscles lifecycle instrumentation.

This package traces real framework lifecycle points: strategy execution, server dispatch, action dispatch, validation, rules/security and handler execution. The current implementation ships an in-memory MusclesTracer that implements the core TelemetryProvider interface. It does not configure an OpenTelemetry SDK, OTLP exporter, collector or vendor backend by itself.

What This Package Is For

Use muscles-otel when a Muscles application or framework package needs a single tracing surface without importing an observability vendor directly:

  • applications install OtelPackage once during bootstrap;
  • other packages call resolve_telemetry(app) from muscles;
  • spans are recorded only when tracing is enabled;
  • sensitive attributes are redacted before they reach span records.

This keeps instrumentation optional. If muscles-otel is not installed, core falls back to NoopTelemetry, so package code can keep the same tracing calls.

What It Is Not Yet

muscles-otel is not yet a full OpenTelemetry distribution. It currently does not export traces to Jaeger, Tempo, Honeycomb, Datadog or an OTLP collector. A production exporter can be added behind the same TelemetryProvider surface without changing packages that already use resolve_telemetry(app).

Related Repositories

  • muscles - core lifecycle, context, actions and dispatcher hooks.
  • muscles-asgi - ASGI runtime spans and server dispatch surfaces.
  • muscles-wsgi - WSGI runtime spans and server dispatch surfaces.
  • muscles-sql - SQL flows that can be traced by application instrumentation.
  • muscles-benchmarks - observability overhead regression checks.

Concept Guardrails

  • Observability must follow the Muscles application model and inspect contract, not individual transport implementation details only.
  • A trace should show the same use case across ASGI, WSGI, CLI, SQL, MCP, JSON-RPC, and future adapters.
  • Instrumentation must be optional and low overhead when disabled.
  • Do not couple the framework to one vendor.
  • Sensitive data must be redacted by default.
  • Instrumentation must not own business dispatch or call handlers twice.

Initial Goal

Provide opt-in tracing helpers and strategy/server/action hooks for core Muscles lifecycle events with tests proving that disabled instrumentation is cheap and enabled instrumentation explains real action flow.

Current Stage (Issue #1)

Implemented opt-in lifecycle instrumentation:

  • disabled mode: no span allocation and zero records;
  • enabled mode: span duration and attributes are captured.
  • package lifecycle entry point: init_package(app, config) installs OtelPackage through Muscles core lifecycle;
  • provider registration: enabled tracer is registered as the neutral TelemetryProvider service, so other packages only depend on muscles;
  • OtelStrategyMixin for muscles.strategy.execute;
  • OtelContextMixin for muscles.context.execute;
  • instrument_server_dispatch() for muscles.server.dispatch;
  • instrument_action_dispatch() for:
    • muscles.action.execute;
    • muscles.action.validate;
    • muscles.action.rules;
    • muscles.action.handler;
  • error status/events for validation, permission, and execution failures;
  • sensitive attribute redaction by default.

Implementation note: action lifecycle spans currently mirror the core dispatcher phases through the available dispatcher methods. A future core hook API can replace this with official callbacks without changing the public instrumentation surface.

Package Lifecycle Provider

Applications should install muscles-otel as an optional framework package:

from muscles import (
    TelemetryProvider,
    doctor_application,
    inspect_application,
    install_package,
)
from muscles_otel import OtelPackage, init_package

app = App()
tracer = install_package(
    app,
    {
        "enabled": True,
        "service_name": "booking-api",
        "attributes": {"deployment.environment": "production"},
    },
    OtelPackage(),
)

telemetry = app.container.resolve(TelemetryProvider)
assert telemetry is tracer

contract = inspect_application(app)
doctor = doctor_application(app)

init_package(app, config) remains available for legacy auto-package loaders and delegates to the same core lifecycle installer.

Framework packages such as muscles-ai and muscles-documents must not import muscles_otel directly. They resolve telemetry through Muscles core:

from muscles import resolve_telemetry

telemetry = resolve_telemetry(app)
with telemetry.span("muscles.package.operation"):
    ...

When this package is not installed, core returns NoopTelemetry.

service_name and service.name both set the default service.name span attribute. Values under attributes are added to every span after sensitive keys such as tokens, API keys, prompts and payloads are removed. These are MusclesTracer defaults today; they are not yet OpenTelemetry SDK Resource configuration or exporter settings.

Adapters may enrich an active span with runtime facts that are only known after execution:

with telemetry.span("muscles.server.dispatch", **{"http.route": "/ready"}) as span:
    response = dispatch()
    if isinstance(span, dict):
        span["http.status_code"] = response.status_code

Inspection reports the installed otel package and a safe capability payload:

from muscles import inspect_application, doctor_application

inspect_application(app)["capabilities"]["otel"]
# {
#   "provider": "MusclesTracer",
#   "enabled": True,
#   "records.count": 0,
#   "attributes.keys": ["deployment.environment", "service.name"],
# }

doctor_application(app)["packages"]["otel"]
# {"status": "ok", "checks": [{"name": "otel.telemetry_provider", ...}]}

Direct Instrumentation Helpers

The package also exposes mixins and helper functions for integration points that already own a concrete dispatch call:

  • OtelContextMixin for muscles.context.execute;
  • OtelStrategyMixin for muscles.strategy.execute;
  • instrument_server_dispatch(...) for server/request boundaries;
  • instrument_action_dispatch(...) for action validation, rules and handler spans.

Use these helpers at runtime boundaries. Business packages should usually use only resolve_telemetry(app) and neutral span names.

Run tests

python -m pytest -q

When testing against local core changes:

PYTHONPATH=../muscles/src:src python -m pytest -q

User docs:

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

muscles_otel-1.0.1.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

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

muscles_otel-1.0.1-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file muscles_otel-1.0.1.tar.gz.

File metadata

  • Download URL: muscles_otel-1.0.1.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for muscles_otel-1.0.1.tar.gz
Algorithm Hash digest
SHA256 6d5437a783aaf40d7c512f9d5d8b16ed09dc0d488651960dcc5298fce2dd9c16
MD5 2edb2fac85a9f19c0595165a0363de66
BLAKE2b-256 fe0e6ed61d048e1a430f5e94536c74066f2de9b6a707032efd4b94e34cb77548

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_otel-1.0.1.tar.gz:

Publisher: release.yml on butkoden/muscles-otel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file muscles_otel-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: muscles_otel-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for muscles_otel-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 83f1c73c02bd3f2e75112d90350aa26c615ca18ee98a776e5af8f0a9647c4d8c
MD5 ff6f216eccc915af2ca9ab83519c21c5
BLAKE2b-256 9ab82944a2dd0c916831bb8d94881cc107eb92508228666ad577b26be22c41cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_otel-1.0.1-py3-none-any.whl:

Publisher: release.yml on butkoden/muscles-otel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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