Observability for developers who live in the terminal.
Project description
muga (Python SDK)
Muga observability SDK for Python. Ships logs to Muga via OpenTelemetry OTLP, captures uncaught exceptions, instruments Flask/FastAPI, and pings cron monitors.
Install
pip install muga
Framework extras:
pip install 'muga[flask]'
pip install 'muga[fastapi]'
Set your project token:
export MUGA_TOKEN=muga_xxxxxxxxxxxx
Quickstart
from muga import init, MugaLogger
init(service_name="api")
log = MugaLogger("api")
log.info("server started", {"port": "3000"})
init() reads MUGA_TOKEN and MUGA_ENDPOINT from env (or accepts token= / endpoint=). When the token is missing, init() does not raise — it prints a single warning to stderr and returns. MugaLogger calls and the framework middlewares stay importable; their emits become no-ops via OpenTelemetry's default NoOpLoggerProvider. This keeps dev/CI runs unblocked when no token is configured.
On successful init the resolved endpoint and service name are printed to stderr so misconfigurations (wrong MUGA_ENDPOINT, fallback to default) are visible without enabling debug=True.
Auto-exception capture
init() installs sys.excepthook, threading.excepthook, and an asyncio loop exception handler by default. They emit a FATAL/ERROR log with exception.type, exception.message, and exception.stacktrace attributes, force-flush the batch processor so the record drains before the interpreter exits, then delegate to the runtime's default behaviour.
Behaviour matrix
| Source | Severity | Triggered by |
|---|---|---|
sys.excepthook |
FATAL | Uncaught exception on the main thread. |
threading.excepthook |
ERROR | Uncaught exception in a worker thread. |
asyncio loop handler |
ERROR | Unhandled exception on a task in a loop attached at init() time. |
Caveats:
- The
asynciohandler is only attached to the loop that exists wheninit()runs. If your code creates a new loop later (asyncio.run(...), a freshasyncio.new_event_loop()), callinstall_exception_handlers(loop=...)from inside that loop, or re-callinit()once the loop is current. - All three hooks are idempotent — calling
init()twice does not double-install.
Opt out:
init(capture_exceptions=False)
Flask
from flask import Flask
from muga import init
from muga.flask import muga_flask
init()
app = Flask(__name__)
muga_flask(app)
One log per request: INFO for <500, ERROR for >=500. Attributes: http.method, http.path, http.status_code, http.duration_ms, http.user_agent.
FastAPI
from fastapi import FastAPI
from muga import init
from muga.fastapi import MugaFastAPIMiddleware
init()
app = FastAPI()
app.add_middleware(MugaFastAPIMiddleware)
Same attribute set as the Flask middleware.
Cron heartbeat
Stand-alone helper. Does not require init().
from muga import heartbeat
heartbeat("daily-cleanup")
POSTs to <endpoint>/v1/crons/daily-cleanup/ping with Authorization: Bearer $MUGA_TOKEN. Raises on missing token or non-2xx response. The cron name is URL-encoded.
For async code, wrap in a thread:
import asyncio
from muga import heartbeat
await asyncio.to_thread(heartbeat, "daily-cleanup")
Shutdown
Flush pending logs on graceful shutdown:
import signal
from muga import shutdown
def _handle(*_):
shutdown()
raise SystemExit(0)
signal.signal(signal.SIGTERM, _handle)
Configuration reference
| Argument | Env var | Default |
|---|---|---|
token |
MUGA_TOKEN |
(missing → SDK no-ops with a stderr warning) |
endpoint |
MUGA_ENDPOINT |
https://api.muga.sh |
service_name |
MUGA_SERVICE |
default |
capture_exceptions |
— | True |
debug |
— | False |
init() also registers atexit.register(shutdown) on first successful call so any process exit drains queued records. Repeat calls do not double-register.
Reporting bugs
File a SDK bug report — the form prompts for SDK version, runtime, minimal repro, and expected vs actual. For anything potentially security-sensitive (token leaks, signature bypass, etc.), email security@muga.sh instead of opening a public issue.
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 muga-0.1.3b0.tar.gz.
File metadata
- Download URL: muga-0.1.3b0.tar.gz
- Upload date:
- Size: 19.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ed9e45e3994aba0304c7daaf420e5669e1d173cd21d2daed14243b3587ff5a0
|
|
| MD5 |
cfb3a802c24752c9ae1c66f86f777d1f
|
|
| BLAKE2b-256 |
8ea2a1a74dd91a35065710a007b559d50276e0323879251e331b488938ecec40
|
Provenance
The following attestation bundles were made for muga-0.1.3b0.tar.gz:
Publisher:
publish-python.yml on mugahq/muga-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muga-0.1.3b0.tar.gz -
Subject digest:
9ed9e45e3994aba0304c7daaf420e5669e1d173cd21d2daed14243b3587ff5a0 - Sigstore transparency entry: 1429707782
- Sigstore integration time:
-
Permalink:
mugahq/muga-server@d9fb487721bc190979f9c38a7d9238d4a0e2b489 -
Branch / Tag:
refs/tags/python-v0.1.3-beta.0 - Owner: https://github.com/mugahq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@d9fb487721bc190979f9c38a7d9238d4a0e2b489 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file muga-0.1.3b0-py3-none-any.whl.
File metadata
- Download URL: muga-0.1.3b0-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
307a79b00b88c9d9ef908457193cc47eee82b131b217ac13eb75fd518e5c9d1a
|
|
| MD5 |
b1bf9d1d72d6c6be5dae48364de7addd
|
|
| BLAKE2b-256 |
4de3391a4770362d8d658bb2e0b2a94ba0dde416d6db9f2a777521b268d58aa7
|
Provenance
The following attestation bundles were made for muga-0.1.3b0-py3-none-any.whl:
Publisher:
publish-python.yml on mugahq/muga-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muga-0.1.3b0-py3-none-any.whl -
Subject digest:
307a79b00b88c9d9ef908457193cc47eee82b131b217ac13eb75fd518e5c9d1a - Sigstore transparency entry: 1429707788
- Sigstore integration time:
-
Permalink:
mugahq/muga-server@d9fb487721bc190979f9c38a7d9238d4a0e2b489 -
Branch / Tag:
refs/tags/python-v0.1.3-beta.0 - Owner: https://github.com/mugahq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@d9fb487721bc190979f9c38a7d9238d4a0e2b489 -
Trigger Event:
workflow_dispatch
-
Statement type: