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.0.tar.gz (13.2 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.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: muscles_otel-1.0.0.tar.gz
  • Upload date:
  • Size: 13.2 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.0.tar.gz
Algorithm Hash digest
SHA256 94c4e3c971bb9104da8169ee3ea04d83877b8ae684b7bc37f2bfe03c60148f50
MD5 9d8371ea5fb2591ab92949760f4f7082
BLAKE2b-256 0d2f9835a648a4f1580638b5c5abac29b921463d795f2b06eb3d771e578115ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_otel-1.0.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: muscles_otel-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1dbc84df740b3a3fbe32f387437078f39f096e274998f16ef7ab551f3e7ca9cb
MD5 410bfcabe1e17e7c7ec17e0e795b557b
BLAKE2b-256 5ea77241d70e22143dc66b9eec42d11a3b8c6a44ecde39a08f75729091d6a822

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_otel-1.0.0-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