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
OtelPackageonce during bootstrap; - other packages call
resolve_telemetry(app)frommuscles; - 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)installsOtelPackagethrough Muscles core lifecycle; - provider registration: enabled tracer is registered as the neutral
TelemetryProviderservice, so other packages only depend onmuscles; OtelStrategyMixinformuscles.strategy.execute;OtelContextMixinformuscles.context.execute;instrument_server_dispatch()formuscles.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:
OtelContextMixinformuscles.context.execute;OtelStrategyMixinformuscles.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:
- English: docs/otel-lifecycle.en.md
- Русский: docs/otel-lifecycle.ru.md
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94c4e3c971bb9104da8169ee3ea04d83877b8ae684b7bc37f2bfe03c60148f50
|
|
| MD5 |
9d8371ea5fb2591ab92949760f4f7082
|
|
| BLAKE2b-256 |
0d2f9835a648a4f1580638b5c5abac29b921463d795f2b06eb3d771e578115ef
|
Provenance
The following attestation bundles were made for muscles_otel-1.0.0.tar.gz:
Publisher:
release.yml on butkoden/muscles-otel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muscles_otel-1.0.0.tar.gz -
Subject digest:
94c4e3c971bb9104da8169ee3ea04d83877b8ae684b7bc37f2bfe03c60148f50 - Sigstore transparency entry: 2258897788
- Sigstore integration time:
-
Permalink:
butkoden/muscles-otel@6c25179e6c4d1fbb4038d278d0d33c505453c738 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/butkoden
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6c25179e6c4d1fbb4038d278d0d33c505453c738 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dbc84df740b3a3fbe32f387437078f39f096e274998f16ef7ab551f3e7ca9cb
|
|
| MD5 |
410bfcabe1e17e7c7ec17e0e795b557b
|
|
| BLAKE2b-256 |
5ea77241d70e22143dc66b9eec42d11a3b8c6a44ecde39a08f75729091d6a822
|
Provenance
The following attestation bundles were made for muscles_otel-1.0.0-py3-none-any.whl:
Publisher:
release.yml on butkoden/muscles-otel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muscles_otel-1.0.0-py3-none-any.whl -
Subject digest:
1dbc84df740b3a3fbe32f387437078f39f096e274998f16ef7ab551f3e7ca9cb - Sigstore transparency entry: 2258897863
- Sigstore integration time:
-
Permalink:
butkoden/muscles-otel@6c25179e6c4d1fbb4038d278d0d33c505453c738 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/butkoden
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6c25179e6c4d1fbb4038d278d0d33c505453c738 -
Trigger Event:
release
-
Statement type: