Skip to content

Example: JSON Output

Use structured JSON logs when logs are parsed by machines, indexed by platforms, or queried for metrics and alerting.

Goal

Configure JSON output with setup_logging(format="json"), emit structured fields, and parse each line safely.

Baseline Setup

import logging
from azure_functions_logging import get_logger, setup_logging

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

logger.info("service started", service="orders", environment="prod")

Sample JSON Line

A single log event is emitted as one JSON object per line:

{"timestamp":"2026-03-14T10:20:30.123456+00:00","level":"INFO","logger":"orders","message":"service started","invocation_id":null,"function_name":null,"trace_id":null,"cold_start":null,"exception":null,"extra":{"service":"orders","environment":"prod"}}

Field Breakdown

Top-level fields generated by formatter:

  • timestamp
  • level
  • logger
  • message
  • invocation_id
  • function_name
  • trace_id
  • cold_start
  • exception
  • extra

Use extra for application-specific dimensions such as tenant, order ID, and operation type.

Logging Structured Data

logger.info(
    "order accepted",
    order_id="ord-1001",
    tenant_id="tenant-a",
    amount=149.5,
    currency="USD",
)

logger.warning(
    "payment retry",
    order_id="ord-1001",
    attempt=2,
    gateway="stripe",
)

Parsing JSON Logs in Python

import json

line = '{"timestamp":"...","level":"INFO","logger":"orders","message":"order accepted","invocation_id":null,"function_name":null,"trace_id":null,"cold_start":null,"exception":null,"extra":{"order_id":"ord-1001"}}'

record = json.loads(line)

print(record["level"])
print(record["message"])
print(record["extra"].get("order_id"))

Azure Function Usage Pattern

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="orders")
def create_order(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    inject_context(context)
    logger.info("request received", method=req.method, route="/orders")
    return func.HttpResponse("ok", status_code=200)

With context injection, invocation fields are populated for every event in this request context.

Production Query Patterns

Typical query dimensions from JSON output:

  • level for error rates.
  • function_name for function-specific dashboards.
  • cold_start for startup impact monitoring.
  • extra.tenant_id for multi-tenant analysis.
  • extra.order_id for incident correlation.

Reliability Guidelines

  • Keep one JSON object per line.
  • Keep message concise; push dimensions to structured keys.
  • Use stable field names over time.
  • Avoid deeply nested extra payloads unless required.

Error Logging in JSON

try:
    1 / 0
except ZeroDivisionError:
    logger.exception("math failure", operation="division", request_id="r-1")

This produces exception text and preserves extra context.

Migration Strategy from Color to JSON

  1. Start locally with format="color".
  2. Add structured keys to log calls.
  3. Switch non-local tiers to format="json".
  4. Validate parser compatibility in staging.
  5. Roll out dashboards and alerts using structured fields.

Quick Validation Script

import json
import logging
from azure_functions_logging import get_logger, setup_logging

setup_logging(level=logging.INFO, format="json")
logger = get_logger("validation")
logger.info("json check", run_id="run-20260314")

# Validate line shape in your sink by loading one event as JSON.