# 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:

```python
from azure_functions_logging import get_logger, 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.
- `inject_context(context)` to add invocation metadata fields.
- Automatic `cold_start` flag detection on first invocation per process.
- `FunctionLogger.bind()` for immutable request-scoped context binding.
- Host-level `host.json` conflict warnings when Azure suppresses lower-level logs.
- 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`, `cold_start`.
- Structured per-event fields from keyword arguments.
- Bound context keys from `bind()`.

## Azure Handler Example

```python
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="health")
def health(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    inject_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 runtime context injection and request binding in a safe, explicit flow.

## Environment-Aware Behavior

Behavior changes intentionally by runtime:

- Local standalone process: installs handler and formatter (`color` or `json`).
- Azure/Core Tools runtime: installs context filter only and avoids handler duplication.

!!! 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 environments: `setup_logging(format="json")`
- Logger creation: `get_logger(__name__)`
- Function entrypoint: `inject_context(context)` as first operation

## Documentation Map

Start here, then branch by need:

- [Installation](installation.md) for package setup.
- [Quickstart](getting-started.md) for first runnable flow.
- [Configuration](configuration.md) for all `setup_logging()` options.
- [Usage Guide](usage.md) for complete patterns and advanced sections.
- [Examples](examples/basic_setup.md) for scenario-focused snippets.
- [API Reference](api.md) for signatures and typed docs.
- [Troubleshooting](troubleshooting.md) for production incident cases.
- [FAQ](faq.md) 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:

1. Add package and call `setup_logging()` once.
2. Update handlers to call `inject_context(context)`.
3. Add request-scoped keys with `bind()`.
4. Select `json` format for production tiers.
5. Verify `host.json` level settings to avoid silent suppression.

When these are complete, your logs become immediately easier to read, correlate, and operate.
