Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion livekit-agents/livekit/agents/cli/_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from .. import llm
from .._exceptions import CLIError
from ..job import JobExecutorType
from ..log import logger
from ..log import _add_global_log_fields, logger
from ..plugin import Plugin
from ..utils import aio, shortuuid
from ..voice import AgentSession, io
Expand Down Expand Up @@ -991,9 +991,11 @@ def _configure_logger(c: AgentsConsole | None, log_level: int | str) -> None:

root = logging.getLogger()
if c:
_add_global_log_fields(c._log_handler)
root.addHandler(c._log_handler)
else:
handler = logging.StreamHandler(sys.stdout)
_add_global_log_fields(handler)
root.addHandler(handler)
handler.setFormatter(JsonFormatter())

Expand Down
2 changes: 2 additions & 0 deletions livekit-agents/livekit/agents/cli/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from inspect import istraceback
from typing import Any

from ..log import _add_global_log_fields
from ..plugin import Plugin

# noisy loggers are set to warn by default
Expand Down Expand Up @@ -229,6 +230,7 @@ def setup_logging(log_level: str, devmode: bool, console: bool, compact: bool =
json_formatter = JsonFormatter()
handler.setFormatter(json_formatter)

_add_global_log_fields(handler)
root.addHandler(handler)
root.setLevel(log_level)

Expand Down
3 changes: 2 additions & 1 deletion livekit-agents/livekit/agents/ipc/job_proc_lazy_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from livekit import rtc

from ..job import JobContext, JobExecutorType, JobProcess, _JobContextVar
from ..log import logger
from ..log import _add_global_log_fields, logger
from ..telemetry import trace_types, tracer
from ..utils import aio, http_context, log_exceptions, shortuuid
from .channel import Message
Expand Down Expand Up @@ -77,6 +77,7 @@ def proc_main(args: ProcStartArgs) -> None:

log_cch = aio.duplex_unix._Duplex.open(args.log_cch)
log_handler = LogQueueHandler(log_cch)
_add_global_log_fields(log_handler)
root_logger.addHandler(log_handler)

job_proc = _JobProc(
Expand Down
42 changes: 42 additions & 0 deletions livekit-agents/livekit/agents/log.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from __future__ import annotations

import logging
import os
from typing import Any

DEV_LEVEL = 23
Expand All @@ -21,3 +24,42 @@ def dev(self, message: str, *args: Any, **kwargs: Any) -> None:
logging.setLoggerClass(Logger)
logger: Logger = logging.getLogger("livekit.agents") # type: ignore[assignment]
logging.setLoggerClass(_logger_class)


# LiveKit Cloud injects LIVEKIT_REGION_NAME into deployed agents (e.g. "ca-central").
# The variable is inherited by the job and inference processes, so every process reads
# it directly. It is unset outside of LiveKit Cloud, in which case no field is added.
_deployed_region = os.environ.get("LIVEKIT_REGION_NAME") or None


class _GlobalLogFieldsFilter(logging.Filter):
"""Adds the process-wide log fields to every record passing through a handler.

Attributes already on the record are never overwritten, so an explicit
``extra={"region": ...}`` still wins.
"""

def filter(self, record: logging.LogRecord) -> bool:
if _deployed_region is not None and not hasattr(record, "region"):
record.region = _deployed_region

return True


_global_log_fields_filter = _GlobalLogFieldsFilter()


def _add_global_log_fields(handler: logging.Handler) -> None:
"""Attach the global log fields (currently the deployed region) to ``handler``.

A filter is used instead of a log record factory because the factory runs before
``Logger.makeRecord`` applies ``extra``, which would make any user-provided
``extra={"region": ...}`` raise a KeyError.

No-op when there is nothing to add, and safe to call more than once.
"""
if _deployed_region is None:
return

if _global_log_fields_filter not in handler.filters:
handler.addFilter(_global_log_fields_filter)