Architecture¶
This document explains how azure-functions-logging is structured internally and why key design choices support Azure Functions production behavior.
Design Objectives¶
The package is intentionally focused:
- Keep logging setup small for application developers.
- Preserve compatibility with Python standard
logging. - Add invocation-aware metadata without invasive patterns.
- Avoid duplicate handlers in runtime-managed environments.
- Stay dependency-light and operationally predictable.
High-Level Components¶
Core modules and responsibilities:
__init__.py: public exports andget_logger()factory._setup.py: setup orchestration, environment detection, idempotency._logger.py:FunctionLoggerwrapper and immutablebind()behavior._context.py: context variables,inject_context(), andContextFilter._formatter.py: local color formatter._json_formatter.py: structured JSON formatter._host_config.py: host policy mismatch warning logic._decorator.py:with_contextdecorator for automatic context injection and cleanup._filters.py:SamplingFilter(rate-limiting) andRedactionFilter(PII masking).
Public API Boundary¶
Public symbols intentionally kept small:
setup_loggingget_loggerFunctionLoggerJsonFormatterinject_contextwith_contextRedactionFilterSamplingFilter__version__Everything else remains internal to keep migration and evolution manageable. (__version__is exported for programmatic version checks.)
Setup Pipeline¶
setup_logging() is the entrypoint for configuration.
Behavior summary:
- Validate input (
formatmust becolororjson). - Enforce idempotency (per
logger_name— repeated calls are no-ops). - Build
ContextFilter. - Detect runtime environment.
- Apply local or runtime-safe setup strategy.
- Check potential host-level log suppression mismatch.
Environment Detection Strategy¶
Detection checks the FUNCTIONS_WORKER_RUNTIME environment variable to branch between local and runtime-safe paths:
- Present → Azure Functions / Core Tools runtime (host-managed handlers).
- Absent → local standalone Python (needs handler setup).
Runtime-Safe Behavior in Azure/Core Tools¶
In Functions runtime contexts, setup avoids replacing host handler graph.
Instead, it:
- Installs
ContextFilteronto existing root handlers. - Installs filter on root logger for future handler coverage.
- Optionally sets
functions_formatteron existing handlers when provided. - Preserves host-managed output pipeline.
This prevents duplicate output and alignment issues with platform logging.
Local Standalone Behavior¶
In non-Functions environments:
- Target logger level is set.
StreamHandleris created only when the target logger has no existing handlers.- Formatter is selected by
formatparameter when a new handler is created. ContextFilteris attached for metadata fields.
This gives deterministic local behavior with minimal code.
Request Flow and Runtime Relationship¶
azure-functions-logging operates at two distinct lifecycle points within the Azure Functions runtime:
- Startup —
setup_logging()configures handlers, formatters, and filters once during module initialization. - Per-request —
inject_context()(or@with_context) captures invocation metadata intocontextvarsat the start of each function invocation.
The host manages log shipping to Application Insights. This library enriches log records with invocation context but does not replace or bypass the host's log pipeline.
Context Propagation Model¶
Invocation metadata is carried through contextvars:
invocation_id_varfunction_name_vartrace_id_varcold_start_var
Benefits of contextvars:
- Thread-safe isolation.
- Async task-safe isolation.
- No need to pass context objects through deep call stacks.
Context Enrichment Flow¶
Request-level flow:
- Handler calls
inject_context(context)(or uses the@with_contextdecorator). - Context values are extracted and stored in context variables.
ContextFiltercopies context variable values onto eachLogRecord.- Formatter reads enriched
LogRecordattributes and outputs the message.
This decouples business code from formatter implementation details.
Cold Start Detection Design¶
Cold start is process-scoped and simple by design:
- Internal flag starts
True. - First
inject_context()setscold_start=True, then flips flag. - Future calls in same process return
False.
This model maps well to Azure Functions worker reuse semantics.
FunctionLogger Wrapper Pattern¶
FunctionLogger wraps standard loggers rather than replacing logging internals.
Key properties:
- Full standard method familiarity (
info,warning,exception, etc.). - Immutable binding (
bind()returns a new wrapper). - Bound keys merged into per-record extra context.
Why wrapper over subclassing global logger:
- Less risky integration with existing libraries.
- Easier incremental adoption.
- Lower chance of side effects in framework code.
Formatter Responsibilities¶
Color Formatter¶
- Optimized for local human readability.
- Shows timestamp, level, logger, message.
- Includes context metadata when present.
- Appends traceback text for exceptions.
JSON Formatter¶
- Outputs one JSON object per line.
- Captures core fields and context metadata.
- Preserves custom record fields under
extra. - Supports downstream indexing and analytics workflows.
host.json Conflict Detection¶
Host-level settings can suppress app-level log events.
The warning helper:
- Reads
host.jsonwhen present. - Resolves host default level into logging equivalent.
- Warns if host policy is stricter than configured level.
This closes a common observability blind spot during setup.
Error Handling Philosophy¶
The library prioritizes application continuity:
- Context extraction failures are silent and non-fatal.
- Missing context fields degrade to
None. - Setup validates format strictly and fails fast for invalid options.
- Host config parsing failures fail safe without crashing the app.
Operational Implications¶
For production teams, this architecture means:
- You can adopt gradually without replacing logging foundations.
- Context correlation is easy with a single injection call.
- Local and runtime behavior differ intentionally to match platform constraints.
- Cold start analysis becomes available without custom plumbing.
Key Design Decisions¶
1. Environment-driven setup strategy¶
FUNCTIONS_WORKER_RUNTIME is the branch variable that determines whether setup runs the Azure/Core Tools path or the local standalone path. WEBSITE_INSTANCE_ID is available as a helper signal but is not used in the primary branching logic.
2. Idempotent configuration per logger name¶
setup_logging() tracks configured logger names in an internal _configured_loggers set. Repeated calls for the same logger_name are no-ops. Different logger names each get their own setup pass.
3. contextvars for invocation metadata¶
Invocation-scoped metadata (invocation_id, function_name, trace_id, cold_start) is stored in contextvars rather than thread-locals or logger attributes. This provides automatic async-task isolation and avoids polluting the global logger namespace.
4. Wrapper over logger subclass¶
FunctionLogger wraps a standard logging.Logger instance rather than subclassing logging.Logger or replacing the logger class globally. This avoids side effects in third-party libraries and allows incremental adoption.
5. Process-scoped cold start flag¶
Cold start detection uses a module-level boolean that starts True and flips to False after the first inject_context() call. This maps directly to the Azure Functions worker process lifecycle without requiring external state.
6. Filter-based context enrichment¶
ContextFilter copies context variable values onto each LogRecord during the filter phase, before the formatter runs. This keeps the enrichment mechanism orthogonal to formatter choice — the same filter works with both ColorFormatter and JsonFormatter.
Module Boundaries¶
Related Documents¶
Sources¶
- Azure Functions Python developer reference
- Monitor Azure Functions
- host.json logging configuration
- Supported languages in Azure Functions
See Also¶
- azure-functions-validation — Architecture — Request/response validation and serialization
- azure-functions-openapi — Architecture — API documentation and spec generation
- azure-functions-doctor — Architecture — Pre-deploy diagnostic CLI
- azure-functions-scaffold — Architecture — Project scaffolding CLI
- azure-functions-langgraph — Architecture — LangGraph runtime exposure for Azure Functions