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.1b0.tar.gz (16.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.1b0-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file muga-0.1.1b0.tar.gz.

File metadata

  • Download URL: muga-0.1.1b0.tar.gz
  • Upload date:
  • Size: 16.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.1b0.tar.gz
Algorithm Hash digest
SHA256 37cce5914ca780848d57d817a38bbae9d3901eb05bffd9b999a6df7dbbf6f906
MD5 bef8732505b3467e61bfb42cdb0a9ff8
BLAKE2b-256 b6f2a395c7f9affdfb23d6c7321587e7ce47caba965193ece09d7077e71a96d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for muga-0.1.1b0.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.1b0-py3-none-any.whl.

File metadata

  • Download URL: muga-0.1.1b0-py3-none-any.whl
  • Upload date:
  • Size: 11.6 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.1b0-py3-none-any.whl
Algorithm Hash digest
SHA256 715495667363ca65c45da7f1b2d2de2a3c16598b889b49fd85e4c9a92f7ef5a0
MD5 e2b2927abd08c491354ec6ecbd660b9a
BLAKE2b-256 8ef8aca139ec1d9bf475ffe32027835d478b5619e8e3ddee60cc8ae31cbe450c

See more details on using hashes here.

Provenance

The following attestation bundles were made for muga-0.1.1b0-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