Logging Management
Most customers manage loggers through the Console UI. The management API is for infrastructure-as-code, CI/CD pipelines, setup scripts, and automated testing. Management operations are stateless HTTP calls — no install() or WebSocket needed.
Loggers and log groups are independent namespaces:
client.manage.loggers.*— individual logger entries (one per logger category in your app).client.manage.log_groups.*(orlogGroups/LogGroups) — groups for bulk-setting levels across many loggers.
Create a Logger
A logger is identified by a string id matching the category name in your application's logging framework (com.acme.payments, sqlalchemy.engine, MyApp.Db, etc.). Set the level (and optional environment overrides), then save.
import asyncio
from smplkit import AsyncSmplManagementClient, LogLevel
async with AsyncSmplManagementClient() as manage:
payments = manage.loggers.new("acme.payments")
payments.set_level(LogLevel.INFO)
payments.set_level(LogLevel.WARN, environment="production")
payments.set_level(LogLevel.DEBUG, environment="staging")
await payments.save()Log Levels
Available log levels, from finest to most restrictive:
| Constant | Value | Description |
|---|---|---|
TRACE | "TRACE" | Finest-grained diagnostic output |
DEBUG | "DEBUG" | Detailed diagnostic information |
INFO | "INFO" | General operational information |
WARN | "WARN" | Potential issues that don't prevent operation |
ERROR | "ERROR" | Errors that affect operation |
FATAL | "FATAL" | Severe errors that may cause termination |
SILENT | "SILENT" | Suppresses all output |
Naming by SDK:
| Language | Reference |
|---|---|
| Python | LogLevel.WARN |
| TypeScript | LogLevel.WARN |
| Go | smplkit.LogLevelWarn |
| Java | LogLevel.WARN |
| C# | LogLevel.Warn |
Inheritance
A logger's effective level resolves through a chain (first non-null wins):
- Per-environment override on the logger
- Logger's own base level
- Group level (if the logger belongs to a group)
- Dot-notation ancestor (
acme.paymentsfalls through toacme) - System fallback:
INFO
Create a parent logger and let children inherit:
root = manage.loggers.new("acme")
root.set_level(LogLevel.INFO)
await root.save()
# child with no level — inherits "acme.INFO" by dot-notation
db = manage.loggers.new("acme.db")
await db.save() # level=None — inherits
# child with explicit level — overrides parent
payments = manage.loggers.new("acme.payments")
payments.set_level(LogLevel.WARN)
await payments.save()Clear Levels
Clear the base level (falls back to group / ancestor / system default), or clear a specific environment override.
root.clear_level(environment="staging") # remove staging override
root.clear_level() # remove base level
await root.save()Log Groups
Log groups bulk-set levels across many loggers. A group has its own base level and environment overrides; loggers assigned to a group inherit the group's level when they have no explicit level of their own.
Create a Group
group = manage.log_groups.new("databases", name="Databases")
group.set_level(LogLevel.WARN)
group.set_level(LogLevel.ERROR, environment="production")
await group.save()Assign a Logger to a Group
Set the logger's group to the group's id, then save.
db_logger = manage.loggers.new("acme.db")
db_logger.group = group.id
await db_logger.save()List, Get, Delete Groups
groups = await manage.log_groups.list()
group = await manage.log_groups.get("databases")
await manage.log_groups.delete("databases")Promote and Release
Toggle a logger's managed flag. A managed logger has its level applied to the native logger by the runtime; releasing (managed=false) removes it from active management without deleting it.
Auto-demote: If a managed logger has no base level, no environment overrides, and no group assignment, the server automatically sets
managed=falseon save. This prevents "zombie" managed loggers that have no configuration. To keep a logger managed with no explicit level, set at least one environment override or assign it to a group before saving.
payments.managed = False
await payments.save() # release
payments.managed = True
await payments.save() # re-promote (level / overrides reset)List, Get, Delete Loggers
loggers = await manage.loggers.list()
fetched = await manage.loggers.get("acme.payments")
await manage.loggers.delete("acme.payments")Bulk-Register Logger Sources
For seeding fresh accounts or migrating fixtures across services, bulk-register a list of logger sources (key + level + service + environment). The runtime auto-discovery uses the same buffer; calling register(...) directly is for setup scripts that don't have a live application to discover from.
from smplkit import LoggerSource, LogLevel
manage.loggers.register([
LoggerSource(name="acme.db", level=LogLevel.INFO),
LoggerSource(name="acme.payments", level=LogLevel.WARN),
])
manage.loggers.flush() # or pass flush=True to registerSync Client (Python)
For synchronous applications (Django, Flask, CLI tools), use SmplManagementClient instead of AsyncSmplManagementClient:
from smplkit import SmplManagementClient, LogLevel
with SmplManagementClient() as manage:
lg = manage.loggers.new("acme.payments")
lg.set_level(LogLevel.WARN)
lg.save()
lg.set_level(LogLevel.ERROR, environment="production")
lg.save()
grp = manage.log_groups.new("databases", name="Databases")
grp.set_level(LogLevel.WARN)
grp.save()
lg.group = grp.id
lg.save()From a runtime client
Inside a service that already holds a SmplClient, use client.manage.loggers.* and client.manage.log_groups.* to avoid juggling two clients:
from smplkit import SmplClient, LogLevel
with SmplClient(environment="production", service="my-service") as client:
lg = client.manage.loggers.get("acme.payments")
lg.set_level(LogLevel.ERROR, environment="production")
lg.save()The same pattern applies in every SDK: client.manage.loggers.* / client.manage.log_groups.* (Python/TS/C#), client.Manage().Loggers() / client.Manage().LogGroups() (Go), client.manage().loggers / client.manage().logGroups (Java).
Next Steps
- Logging Runtime — Wire smplkit into your logging framework
- Smpl Config — Manage application configuration across environments
- API Reference — Logging — Full REST API documentation

