Skip to content

API Reference

This reference documents the public API exported by azure_functions_logging.

Use this page together with:

setup_logging

Configure logging for the current environment. Behavior depends on the detected environment:

  • Azure / Core Tools: Installs ContextFilter on the root logger's handlers only. Does NOT add handlers or modify the root logger level (respects host.json configuration). If functions_formatter is provided, it is applied to every root handler before the filter is added.
  • Standalone local development: Adds a StreamHandler with ColorFormatter or JsonFormatter to the specified logger (or root logger if logger_name is None). Sets the level.

This function is idempotent — calling it multiple times has no additional effect.

Parameters:

Name Type Description Default
level int

Logging level for local development. Ignored in Azure/Core Tools.

INFO
format str

Log output format for local development. Supported values are "color" (default) and "json". Ignored when functions_formatter is provided.

'color'
logger_name str | None

Optional logger name to configure. When None, configures the root logger (local dev) or installs filter on root handlers (Azure).

None
functions_formatter Formatter | None

Optional custom formatter applied to all root handlers when running inside Azure/Core Tools. Useful for injecting a custom JSON formatter or third-party formatter without losing ContextFilter integration.

None
Source code in src/azure_functions_logging/_setup.py
def setup_logging(
    *,
    level: int = logging.INFO,
    format: str = "color",
    logger_name: str | None = None,
    functions_formatter: logging.Formatter | None = None,
) -> None:
    """Configure logging for the current environment.
    Behavior depends on the detected environment:

    - **Azure / Core Tools**: Installs ``ContextFilter`` on the root logger's
      handlers only. Does NOT add handlers or modify the root logger level
      (respects ``host.json`` configuration). If ``functions_formatter`` is
      provided, it is applied to every root handler before the filter is added.
    - **Standalone local development**: Adds a ``StreamHandler`` with
      ``ColorFormatter`` or ``JsonFormatter`` to the specified logger
      (or root logger if ``logger_name`` is None). Sets the level.

    This function is idempotent — calling it multiple times has no additional
    effect.

    Args:
        level: Logging level for local development. Ignored in Azure/Core Tools.
        format: Log output format for local development. Supported values are
            ``"color"`` (default) and ``"json"``. Ignored when
            ``functions_formatter`` is provided.
        logger_name: Optional logger name to configure. When None, configures
            the root logger (local dev) or installs filter on root handlers (Azure).
        functions_formatter: Optional custom formatter applied to all root
            handlers when running inside Azure/Core Tools. Useful for
            injecting a custom JSON formatter or third-party formatter
            without losing ContextFilter integration.
    """
    global _setup_done
    if format not in {"color", "json"}:
        msg = "format must be 'color' or 'json'"
        raise ValueError(msg)

    if _setup_done:
        return
    _setup_done = True

    context_filter = ContextFilter()
    is_functions_env = _is_functions_environment()

    if is_functions_env:
        # Azure or Core Tools: install filter only, don't touch handlers/level
        root = logging.getLogger()
        for handler in root.handlers:
            if functions_formatter is not None:
                handler.setFormatter(functions_formatter)
            handler.addFilter(context_filter)
        # Also install on any future handlers via the logger itself
        root.addFilter(context_filter)
    else:
        # Standalone local development
        target = logging.getLogger(logger_name)
        target.setLevel(level)

        # Add colored handler only if no handlers exist
        if not target.handlers:
            handler = logging.StreamHandler()
            handler.setFormatter(ColorFormatter() if format == "color" else JsonFormatter())
            handler.addFilter(context_filter)
            target.addHandler(handler)
        else:
            # Add filter to existing handlers
            for handler in target.handlers:
                handler.addFilter(context_filter)

    if is_functions_env:
        warn_host_json_level_conflict(level)

Usage Notes

  • Call once during startup.
  • Default format is "color".
  • In Azure/Core Tools runtime, filter-only behavior avoids duplicate handlers.

Example

import logging
from azure_functions_logging import setup_logging

setup_logging(level=logging.INFO, format="json")

Example: Named Target Logger

from azure_functions_logging import setup_logging

setup_logging(logger_name="my_service")

Example: Invalid Format Handling

from azure_functions_logging import setup_logging

try:
    setup_logging(format="pretty")
except ValueError:
    pass

get_logger

Create a FunctionLogger wrapping a standard logging.Logger.

Parameters:

Name Type Description Default
name str | None

Logger name. Typically __name__.

None

Returns:

Type Description
FunctionLogger

A FunctionLogger instance.

Source code in src/azure_functions_logging/__init__.py
def get_logger(name: str | None = None) -> FunctionLogger:
    """Create a ``FunctionLogger`` wrapping a standard ``logging.Logger``.

    Args:
        name: Logger name. Typically ``__name__``.

    Returns:
        A ``FunctionLogger`` instance.
    """
    import logging

    return FunctionLogger(logging.getLogger(name))

Usage Notes

  • Returns a FunctionLogger wrapper over a standard logger.
  • Pass __name__ for module-level identity.
  • Use the wrapper methods like standard logging methods.

Example

from azure_functions_logging import get_logger, setup_logging

setup_logging()
logger = get_logger(__name__)
logger.info("module logger ready")

Example: Root Logger Wrapper

from azure_functions_logging import get_logger, setup_logging

setup_logging()
root_logger = get_logger()
root_logger.warning("root logger event")

FunctionLogger

Wrapper around a standard logging.Logger with context binding.

FunctionLogger delegates all standard logging methods to the underlying logger. The bind() method returns a new wrapper with additional context fields that are merged into extra on each log call.

Context from bind() is supplementary to the ContextFilter-based context (invocation_id, function_name, etc.) which is set globally via inject_context().

Source code in src/azure_functions_logging/_logger.py
def __init__(self, logger: logging.Logger) -> None:
    self._logger = logger
    self._context: dict[str, Any] = {}

name property

Return the name of the underlying logger.

bind(**kwargs)

Return a new FunctionLogger with additional bound context.

The returned logger shares the same underlying logging.Logger but carries merged context fields. This is an immutable operation.

Parameters:

Name Type Description Default
**kwargs Any

Context key-value pairs to bind.

{}

Returns:

Type Description
FunctionLogger

A new FunctionLogger with merged context.

Source code in src/azure_functions_logging/_logger.py
def bind(self, **kwargs: Any) -> FunctionLogger:
    """Return a new ``FunctionLogger`` with additional bound context.

    The returned logger shares the same underlying ``logging.Logger``
    but carries merged context fields. This is an immutable operation.

    Args:
        **kwargs: Context key-value pairs to bind.

    Returns:
        A new ``FunctionLogger`` with merged context.
    """
    new = FunctionLogger(self._logger)
    new._context = {**self._context, **kwargs}
    return new

clear_context()

Clear all bound context fields.

Source code in src/azure_functions_logging/_logger.py
def clear_context(self) -> None:
    """Clear all bound context fields."""
    self._context = {}

critical(msg, *args, **kwargs)

Log a CRITICAL message.

Source code in src/azure_functions_logging/_logger.py
def critical(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log a CRITICAL message."""
    self._log(logging.CRITICAL, msg, args, **kwargs)

debug(msg, *args, **kwargs)

Log a DEBUG message.

Source code in src/azure_functions_logging/_logger.py
def debug(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log a DEBUG message."""
    self._log(logging.DEBUG, msg, args, **kwargs)

error(msg, *args, **kwargs)

Log an ERROR message.

Source code in src/azure_functions_logging/_logger.py
def error(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log an ERROR message."""
    self._log(logging.ERROR, msg, args, **kwargs)

exception(msg, *args, **kwargs)

Log an ERROR message with exception info.

Source code in src/azure_functions_logging/_logger.py
def exception(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log an ERROR message with exception info."""
    kwargs["exc_info"] = kwargs.get("exc_info", True)
    self._log(logging.ERROR, msg, args, **kwargs)

getEffectiveLevel()

Return the effective level of the underlying logger.

Source code in src/azure_functions_logging/_logger.py
def getEffectiveLevel(self) -> int:
    """Return the effective level of the underlying logger."""
    return self._logger.getEffectiveLevel()

info(msg, *args, **kwargs)

Log an INFO message.

Source code in src/azure_functions_logging/_logger.py
def info(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log an INFO message."""
    self._log(logging.INFO, msg, args, **kwargs)

isEnabledFor(level)

Check if the underlying logger is enabled for the given level.

Source code in src/azure_functions_logging/_logger.py
def isEnabledFor(self, level: int) -> bool:
    """Check if the underlying logger is enabled for the given level."""
    return self._logger.isEnabledFor(level)

setLevel(level)

Set the logging level of the underlying logger.

Source code in src/azure_functions_logging/_logger.py
def setLevel(self, level: int | str) -> None:
    """Set the logging level of the underlying logger."""
    self._logger.setLevel(level)

warning(msg, *args, **kwargs)

Log a WARNING message.

Source code in src/azure_functions_logging/_logger.py
def warning(self, msg: object, *args: Any, **kwargs: Any) -> None:
    """Log a WARNING message."""
    self._log(logging.WARNING, msg, args, **kwargs)

Usage Notes

  • bind() returns a new immutable logger wrapper with merged context.
  • clear_context() clears bound context on that wrapper instance.
  • Logging methods mirror standard logger API.

Example: Binding Context

from azure_functions_logging import get_logger, setup_logging

setup_logging(format="json")
logger = get_logger("checkout")

request_logger = logger.bind(request_id="r-100", user_id="u-55")
request_logger.info("checkout started")

Example: Chained Binding

base = get_logger("service")
l1 = base.bind(tenant_id="tenant-a")
l2 = l1.bind(operation="import")
l2.info("import queued")

Example: Clearing Bound Context

log = get_logger("demo").bind(session="s-1")
log.info("before clear")
log.clear_context()
log.info("after clear")

Example: Exception Logging

log = get_logger("errors")

try:
    raise RuntimeError("boom")
except RuntimeError:
    log.exception("operation failed", phase="load")

JsonFormatter

Bases: Formatter

Structured JSON log formatter.

Output is newline-delimited JSON (NDJSON), with one JSON object per log line. Context fields (invocation_id, function_name, etc.) are included when present on the LogRecord (set by ContextFilter).

Source code in src/azure_functions_logging/_json_formatter.py
def __init__(self) -> None:
    super().__init__()

format(record)

Format a log record as one NDJSON object.

Source code in src/azure_functions_logging/_json_formatter.py
def format(self, record: logging.LogRecord) -> str:
    """Format a log record as one NDJSON object."""
    message = record.getMessage()
    timestamp = datetime.fromtimestamp(record.created, tz=timezone.utc).isoformat()

    exception: str | None = None
    if record.exc_info:
        exception = self.formatException(record.exc_info)

    excluded_fields = _STANDARD_RECORD_FIELDS | _CONTEXT_FIELDS
    extra = {key: value for key, value in record.__dict__.items() if key not in excluded_fields}

    payload = {
        "timestamp": timestamp,
        "level": record.levelname,
        "logger": record.name,
        "message": message,
        "invocation_id": getattr(record, "invocation_id", None),
        "function_name": getattr(record, "function_name", None),
        "trace_id": getattr(record, "trace_id", None),
        "cold_start": getattr(record, "cold_start", None),
        "exception": exception,
        "extra": extra,
    }

    return json.dumps(payload, ensure_ascii=False)

Usage Notes

  • Use indirectly via setup_logging(format="json") for most cases.
  • Produces one JSON object per line (NDJSON style).
  • Includes context fields when available on log records.

Example: Automatic Selection

from azure_functions_logging import get_logger, setup_logging

setup_logging(format="json")
logger = get_logger("api")
logger.info("json formatter active", version="v1")

Example: Manual Formatter Wiring

import logging
from azure_functions_logging import JsonFormatter, get_logger

handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())

target = logging.getLogger("manual")
target.handlers = [handler]
target.setLevel(logging.INFO)

logger = get_logger("manual")
logger.info("manual formatter configured")

inject_context

Set invocation context from an Azure Functions context object.

Extracts invocation_id, function_name, trace_id, and cold_start from the provided context and stores them in contextvars.

This function is safe to call with any object. Missing or inaccessible attributes are silently ignored (Principle 3: context injection failures never cause application failures).

Parameters:

Name Type Description Default
context Any

An Azure Functions context object (func.Context).

required
Source code in src/azure_functions_logging/_context.py
def inject_context(context: Any) -> None:
    """Set invocation context from an Azure Functions context object.

    Extracts invocation_id, function_name, trace_id, and cold_start
    from the provided context and stores them in contextvars.

    This function is safe to call with any object. Missing or inaccessible
    attributes are silently ignored (Principle 3: context injection failures
    never cause application failures).

    Args:
        context: An Azure Functions context object (func.Context).
    """
    try:
        invocation_id_var.set(getattr(context, "invocation_id", None))
    except Exception:  # nosec B110 — Principle 3: context failures are silent
        invocation_id_var.set(None)

    try:
        function_name_var.set(getattr(context, "function_name", None))
    except Exception:  # nosec B110 — Principle 3: context failures are silent
        function_name_var.set(None)

    try:
        trace_context = getattr(context, "trace_context", None)
        trace_parent = getattr(trace_context, "trace_parent", None) if trace_context else None
        trace_id_var.set(_extract_trace_id(trace_parent))
    except Exception:  # nosec B110 — Principle 3: context failures are silent
        trace_id_var.set(None)

    try:
        cold_start_var.set(_check_cold_start())
    except Exception:  # nosec B110 — Principle 3: context failures are silent
        pass

Usage Notes

  • Call at the start of every function invocation.
  • Sets invocation metadata in context variables.
  • Enables automatic cold start field in output.

Example: Azure Function Entrypoint

import azure.functions as func
from azure_functions_logging import get_logger, inject_context, setup_logging

setup_logging(format="json")
logger = get_logger(__name__)

app = func.FunctionApp()


@app.route(route="status")
def status(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    inject_context(context)
    logger.info("status request")
    return func.HttpResponse("ok")

Example: Safe with Partial Context Object

from azure_functions_logging import get_logger, inject_context, setup_logging

class PartialContext:
    invocation_id = "local-123"


setup_logging(format="json")
logger = get_logger("partial")

inject_context(PartialContext())
logger.info("partial context accepted")

End-to-End API Example

import logging
import azure.functions as func
from azure_functions_logging import get_logger, inject_context, setup_logging

setup_logging(level=logging.INFO, format="json")
logger = get_logger(__name__)

app = func.FunctionApp()


@app.route(route="orders")
def orders(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    inject_context(context)
    req_logger = logger.bind(route="/orders", method=req.method)
    req_logger.info("orders request started")
    req_logger.info("orders request completed")
    return func.HttpResponse("ok")

Cross-Reference