Unfazed Logging¶
Unfazed configures logging through Python's standard logging.config.dictConfig. You provide a LOGGING dictionary in your settings, and Unfazed merges it with sensible defaults so that framework-internal loggers (unfazed, uvicorn, tortoise) work out of the box. If you don't provide any logging config, the defaults are used as-is.
Quick Start¶
Add a LOGGING key to your settings to configure application-level logging:
# settings.py
UNFAZED_SETTINGS = {
"PROJECT_NAME": "myproject",
"LOGGING": {
"version": 1,
"formatters": {
"verbose": {
"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "verbose",
"stream": "ext://sys.stdout",
},
},
"loggers": {
"myapp": {
"handlers": ["console"],
"level": "DEBUG",
"propagate": False,
},
},
},
}
Then use standard Python logging in your code:
import logging
logger = logging.getLogger("myapp")
async def my_endpoint(request):
logger.info("Request received")
...
Configuration¶
The LOGGING setting follows Python's dictConfig schema:
"LOGGING": {
"version": 1, # required, always 1
"disable_existing_loggers": False, # optional
"formatters": {
"<name>": {
"format": "...",
"datefmt": "...",
},
},
"filters": {
"<name>": {
"()": "dotted.path.to.FilterClass",
},
},
"handlers": {
"<name>": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "<formatter_name>",
"filters": ["<filter_name>"],
# ... handler-specific options
},
},
"loggers": {
"<name>": {
"level": "DEBUG",
"handlers": ["<handler_name>"],
"filters": ["<filter_name>"],
"propagate": True,
},
},
"root": {
"level": "WARNING",
"handlers": ["<handler_name>"],
},
}
How merging works¶
Your config is merged with Unfazed's defaults — it does not replace them. The merge rules are:
- formatters, handlers, filters, loggers — your entries are added alongside the defaults. If you define a key that already exists in the defaults, your value wins.
- Other top-level keys (e.g.
version,root,disable_existing_loggers) — the defaults are kept; your values for these keys are ignored. This ensures the framework's internal logging always works.
This means you never need to re-declare the unfazed or tortoise loggers unless you want to change their configuration.
Default Configuration¶
When no LOGGING setting is provided (or it is empty), Unfazed uses these defaults:
{
"version": 1,
"formatters": {
"_simple": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
},
"handlers": {
"_console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "_simple",
},
},
"loggers": {
"unfazed": {
"level": "DEBUG",
"handlers": ["_console"],
},
"uvicorn": {
"level": "INFO",
"handlers": ["_console"],
},
"tortoise": {
"level": "INFO",
"handlers": ["_console"],
},
},
"filters": {},
}
Default handler and formatter names are prefixed with _ to avoid collisions with your own config.
API Reference¶
LogCenter¶
Central logging configuration manager. Merges user config with defaults and applies it via logging.config.dictConfig.
Methods:
setup() -> None: Apply the merged logging configuration.merge_default(dictconfig: Dict) -> Dict: Merge user config with the default config and return the result.
Attributes:
config: Dict— The final merged configuration.raw_dictconfig: Dict— The original user-provided configuration.
LogConfig¶
class LogConfig(BaseModel):
version: int = 1
formatters: Dict[str, Formatter] | None = None
filters: Dict[str, Filter] | None = None
handlers: Dict[str, Handler] | None = None
loggers: Dict[str, Logger] | None = None
root: RootLogger | None = None
incremental: bool | None = None
disable_existing_loggers: bool | None = None
Pydantic model used to validate the LOGGING setting before it is passed to LogCenter.