Azure Functions Logging¶
Production-oriented, developer-friendly logging for the Azure Functions Python v2 programming model.
azure-functions-logging keeps setup small while giving you structured context, cold start visibility, and practical local ergonomics.
Five-Second Start¶
Copy this into your function module:
from azure_functions_logging import get_logger, logging_context, setup_logging
setup_logging()
logger = get_logger(__name__)
logger.info("logging initialized")
That setup is enough to begin.
Why Teams Use It¶
Azure Functions projects often outgrow default logging quickly:
- Raw logs are hard to scan locally.
- Invocation metadata is missing unless manually carried around.
- Startup behavior is unclear during cold-start debugging.
- Local and production log consumers need different output formats.
This library addresses those gaps with a small API surface.
Core Features¶
setup_logging()one-liner startup configuration.- Local colorized output (
format="color") for fast visual scanning. - Structured NDJSON output (
format="json") for production ingestion. logging_context(context)context manager that always restores prior context on exit (recommended).inject_context(context)returnsContextTokensfor pairedrestore_context(tokens)use in middleware.install_context_factory()opt-in global LogRecordFactory so context flows to everyLogRecord.JsonFormatterfor host-managed handlers viasetup_logging(functions_formatter=JsonFormatter()).- Automatic
cold_startflag detection on first invocation per process. FunctionLogger.bind()for immutable request-scoped context binding.FunctionLogger.log()andFunctionLogger.hasHandlers()for stdlib parity.- Host-level
host.jsonconflict warnings, withhost_json_path=override and bounded parent-walk discovery. - Idempotent setup to avoid duplicate reconfiguration.
What Gets Logged¶
Depending on formatter and context, events include:
- Timestamp, level, logger name, message.
- Invocation metadata:
invocation_id,function_name,trace_id(from W3Ctraceparentheaders, strict validation),cold_start. - Structured per-event fields from keyword arguments.
- Bound context keys from
bind().
Azure Handler Example¶
import azure.functions as func
from azure_functions_logging import JsonFormatter, get_logger, logging_context, setup_logging
setup_logging(functions_formatter=JsonFormatter())
logger = get_logger(__name__)
app = func.FunctionApp()
@app.route(route="health")
def health(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
with logging_context(context):
request_logger = logger.bind(route="/health", method=req.method)
request_logger.info("health endpoint called")
return func.HttpResponse("ok", status_code=200)
This combines context-managed invocation context and request binding in a safe, explicit flow that always restores prior context on exit (even on exceptions).
Environment-Aware Behavior¶
Behavior changes intentionally by runtime:
- Local standalone process: sets the target/root logger level; adds a
StreamHandler(colororjson) only if no handlers exist, otherwise just attaches filters to existing handlers. - Azure/Core Tools runtime: installs
ContextFilteron existing root handlers and on the root logger itself (so direct calls on the root logger carry context); does not add handlers or change root level. To guarantee context on records that propagate from named child loggers to handlers attached later, passuse_record_factory=Truetosetup_logging()(preferred) or callinstall_context_factory()directly.
Warning
In Azure-hosted execution, host-level host.json settings can still suppress logs even when application-level setup appears correct.
Recommended Defaults¶
Use these defaults unless you have a specific reason to diverge:
- Local development:
setup_logging(format="color") - Production (standalone):
setup_logging(format="json") - Production (Azure Functions / Core Tools):
setup_logging(functions_formatter=JsonFormatter())—format="json"alone is ignored on host-managed handlers - Logger creation:
get_logger(__name__) - Function entrypoint:
with logging_context(context):wrapping the body, ortokens = inject_context(context); try: ...; finally: restore_context(tokens)
Documentation Map¶
Start here, then branch by need:
- Installation for package setup.
- Quickstart for first runnable flow.
- Configuration for all
setup_logging()options. - Usage Guide for complete patterns and advanced sections.
- Examples for scenario-focused snippets.
- API Reference for signatures and typed docs.
- Troubleshooting for production incident cases.
- FAQ for direct operational questions.
Design Goals¶
The library stays intentionally narrow:
- Improve application logging ergonomics.
- Preserve Python standard logging compatibility.
- Keep runtime dependencies minimal.
- Avoid replacing tracing/APM platforms.
It is a focused logging utility, not a full observability stack.
Next Actions¶
If you are integrating today:
- Add the package and call
setup_logging()once at startup. - Wrap each handler body in
with logging_context(context):(or apply@with_context). - Add request-scoped keys with
logger.bind(). - Use
setup_logging(functions_formatter=JsonFormatter())to emit NDJSON on host-managed handlers in Azure. - Verify
host.jsonlevel settings (or passhost_json_path=) to avoid silent suppression. When these are complete, your logs become immediately easier to read, correlate, and operate.