Skip to main content

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 asyncio handler is only attached to the loop that exists when init() runs. If your code creates a new loop later (asyncio.run(...), a fresh asyncio.new_event_loop()), call install_exception_handlers(loop=...) from inside that loop, or re-call init() 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


Download files

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

Source Distribution

muga-0.1.3b0.tar.gz (19.1 kB view details)

Uploaded Source

Built Distribution

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

muga-0.1.3b0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

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

Hashes for muga-0.1.3b0.tar.gz
Algorithm Hash digest
SHA256 9ed9e45e3994aba0304c7daaf420e5669e1d173cd21d2daed14243b3587ff5a0
MD5 cfb3a802c24752c9ae1c66f86f777d1f
BLAKE2b-256 8ea2a1a74dd91a35065710a007b559d50276e0323879251e331b488938ecec40

See more details on using hashes here.

Provenance

The following attestation bundles were made for muga-0.1.3b0.tar.gz:

Publisher: publish-python.yml on mugahq/muga-server

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

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

Hashes for muga-0.1.3b0-py3-none-any.whl
Algorithm Hash digest
SHA256 307a79b00b88c9d9ef908457193cc47eee82b131b217ac13eb75fd518e5c9d1a
MD5 b1bf9d1d72d6c6be5dae48364de7addd
BLAKE2b-256 4de3391a4770362d8d658bb2e0b2a94ba0dde416d6db9f2a777521b268d58aa7

See more details on using hashes here.

Provenance

The following attestation bundles were made for muga-0.1.3b0-py3-none-any.whl:

Publisher: publish-python.yml on mugahq/muga-server

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