Configuration¶
This guide documents every setup_logging() option and how configuration behaves across local development, Azure Functions Core Tools, and Azure-hosted runtimes.
Function Signature¶
def setup_logging(
*,
level: int = logging.INFO,
format: str = "color",
logger_name: str | None = None,
functions_formatter: logging.Formatter | None = None,
host_json_path: Path | str | None = None,
use_record_factory: bool = False,
) -> None
setup_logging() is designed to be called once during startup.
Configuration Principles¶
- Idempotent initialization: repeated calls are no-ops.
- Environment-aware behavior: local and Azure runtime paths differ.
- Standard logging compatibility: no custom logging framework required.
Note
In Azure or Core Tools environments, the library intentionally avoids adding handlers to prevent duplicate output.
Parameter: level¶
level controls message filtering in local standalone execution.
Accepted values are standard logging levels:
logging.DEBUGlogging.INFO(default)logging.WARNINGlogging.ERRORlogging.CRITICAL
Example:
Behavior details:
- Local standalone: applied to target logger.
- Azure/Core Tools: host pipeline governs output; app-level level may be effectively constrained by host config.
Parameter: format¶
format selects output formatter in local standalone mode.
Supported values:
"color"(default)"json"
Example:
If an unsupported value is provided, setup_logging() raises ValueError.
Warning
Use format="json" for machine parsing and centralized ingestion. Color output is optimized for human readability in terminals.
Parameter: logger_name¶
logger_name lets you target a specific logger in local standalone mode.
When logger_name is None:
- Local standalone: root logger is configured.
- Azure/Core Tools: root handlers receive
ContextFilter.
When logger_name is set:
- Local standalone: named logger is configured.
- Azure/Core Tools: filter installation still follows runtime-safe behavior.
Practical recommendation:
- Prefer root configuration unless you have a clear logger isolation strategy.
Parameter: use_record_factory¶
use_record_factory is an opt-in flag that also installs a global
logging.LogRecordFactory so context fields (invocation_id, function_name,
trace_id, cold_start) are injected at LogRecord creation time. It guarantees
context propagation even when handler filters are misconfigured or bypassed by
third-party logging setups.
from azure_functions_logging import setup_logging
setup_logging(format="json", use_record_factory=True)
Behavior details:
- Default is
Falseto preserve the existing handler-filter-only behavior. - When
True,install_context_factory()is called once; repeated calls are no-ops. - When
True,ContextFilteris not attached to handlers. The globalLogRecordFactoryis the sole source of context fields, so values captured at record-creation time survive thread hops, queued handlers, and delayed flushes (no filter runs at handler dispatch time to overwrite the snapshot). - Modifies the global
LogRecordFactoryand affects all loggers in the process. - The four context field names (
invocation_id,function_name,trace_id,cold_start) become reserved on every LogRecord; preferFunctionLogger(which sanitizesextrakeys) when this option is enabled. - Input validation (e.g.
format) runs before the factory is installed, so invalid arguments raiseValueErrorwithout any global side effects.
Idempotency and Reconfiguration¶
setup_logging() uses internal setup state to guarantee idempotency.
Implications:
- First call wins.
- Later calls do not replace handler/formatter choices.
- Conflicting setup calls in different modules can lead to surprising expectations.
Best practice:
from azure_functions_logging import setup_logging
# Run once at module import or startup hook
setup_logging(format="json")
Environment Detection¶
The setup path depends on environment signals:
- Functions environment check:
FUNCTIONS_WORKER_RUNTIME - Azure-hosted check:
WEBSITE_INSTANCE_ID
Execution behavior by environment:
Local standalone Python process¶
- Sets logger level.
- Adds
StreamHandlerif no handlers exist. - Installs
ContextFilteron handlers (skipped whenuse_record_factory=True). - Uses selected formatter (
ColorFormatterorJsonFormatter).
Azure Functions / Core Tools¶
- Does not add new handlers.
- Does not override host-managed handler strategy.
- Installs
ContextFilterto enrich records with invocation fields (skipped whenuse_record_factory=True). - Emits host-level conflict warning checks.
Tip
This split behavior prevents duplicate logs in Azure while still giving rich local developer output.
host.json Level Conflict Warning¶
In Azure/Core Tools paths, the library checks host.json and warns if host defaults are stricter than your configured level.
Example warning intent:
Why this matters:
- You may set
level=logging.INFOin code. - Host config can still suppress
INFOlines. - App settings such as
AzureFunctionsJobHost__logging__logLevel__defaultcan override the deployedhost.jsonfile. - Without a warning, this looks like missing logs.
Recommended host.json baseline:
The warning checks both file-based host.json and Azure Functions app setting
overrides using the AzureFunctionsJobHost__logging__logLevel__... naming
convention. Function-specific overrides such as
AzureFunctionsJobHost__logging__logLevel__Function__MyFunction=Warning are
reported as category Function.MyFunction.
Color vs JSON Format Selection¶
Use format="color" when:
- You are iterating locally.
- Humans are primary log consumers.
- You want fast visual scanning of level severity.
Use format="json" when:
- Logs feed aggregation systems.
- You need structured indexing and queries.
- You rely on downstream analytics and alerting.
Using get_logger() with Configuration¶
Typical startup and logger creation:
from azure_functions_logging import get_logger, setup_logging
setup_logging(format="json")
logger = get_logger(__name__)
logger.info("application initialized")
get_logger(name) returns a FunctionLogger wrapper that preserves standard logging ergonomics and supports context binding.
Advanced Pattern: Custom Formatter Pipeline¶
For advanced local scenarios you can still combine standard logging with this package:
import logging
from azure_functions_logging import setup_logging
setup_logging(format="json")
custom_handler = logging.StreamHandler()
custom_handler.setFormatter(logging.Formatter("%(levelname)s %(name)s %(message)s"))
target = logging.getLogger("custom")
target.addHandler(custom_handler)
target.setLevel(logging.INFO)
Guidelines for advanced customization:
- Avoid duplicating handlers on root unless intentional.
- Keep
inject_context(context)in handlers so context fields remain available. - Prefer one canonical output format per deployment tier.
Validation Checklist¶
Before finalizing configuration:
- Verify setup is called exactly once.
- Verify chosen
formatmatches consumer expectations. - Verify
host.jsondoes not suppress required levels. - Verify named logger usage is consistent across modules.
- Verify JSON output can be parsed by your log ingestion tool.