Skip to navigation

Logging

configure_logging(), LogSettings, the BAND_LOG_* variables, and OpenTelemetry correlation

Band logging is opt-in. Two entry points apply the same process-wide configuration: configure_logging() takes it as arguments, and LogSettings reads and validates it from the BAND_LOG_* variables. Without one of them, the Agent started line that confirms a connection never prints.

configure_logging()

For an embedded SDK, show Band logs and leave other loggers at WARNING:

from band import configure_logging
configure_logging()

For an agent, runner, or CLI that owns the process, also raise every other logger:

from band import configure_logging
configure_logging(root_level="INFO")

root_level applies to all non-Band loggers, so third-party dependencies such as httpx become as verbose as the level you pass. Use extra_loggers to pin individual dependencies back down, or chatty_logger_levels() for the Band HTTP and WebSocket dependencies (httpx, httpcore, phoenix_channels_python_client) as a group.

ParameterDefaultDescription
levelINFOLevel for the band logger, as a logging constant or a name such as "DEBUG"
root_levelWARNINGLevel for non-Band loggers
stylestandardConsole style: standard, rich, or json
streamstderrConsole stream: stderr or stdout
datefmt%Y-%m-%d %H:%M:%STimestamp format
fmtNoneCustom format string for the standard console and file formatters; ignored by rich and json
fmt_style%Format string style for fmt: %, {, or $
extra_loggersNoneLogger name to level mapping, such as {"httpx": "WARNING"}
json_fieldsNoneLogRecord field names to include in json output
static_fieldsNoneFixed fields added to every json record
log_fileNonePath for a second, file handler; None disables file logging
max_bytes0Maximum file size before rotation; 0 uses a plain FileHandler
backup_count1Rotated files to keep when max_bytes is positive. 0 there raises backup_count must be at least 1 when max_bytes is set; a rotating handler with no backups never rotates
file_styleNoneFile formatter style: standard or json; defaults to standard when log_file is set
file_levelNoneLevel for the file handler; defaults to level

The rich and json styles require the logging extra, uv add "band-sdk[logging]==6.0.1". Without it, configuration raises BandConfigError, for example Logging style <LoggingStyle.JSON: 'json'> requires optional dependency 'python-json-logger>=3.1.0'. Install it with: pip install 'band-sdk[logging]'.

Both entry points call logging.config.dictConfig, which replaces the root handlers, so configure Band logging first and attach your host application’s handlers after. build_logging_config() and LogSettings().build_config() return the dictConfig dictionary without applying it. Log files Band creates are owner-only (mode 0600, in a 0700 directory), because Band logs message content at DEBUG.

The public logging types are LogLevel (an int or a level name), LogStream (stderr, stdout), LoggingStyle (standard, rich, json), FileStyle (standard, json), FormatStyle (%, {, $), and LoggingConfig (the dictConfig mapping). All are importable from band.

LogSettings

LogSettings maps the same configuration onto environment variables. LogSettings().configure() suits an embedded SDK; LogSettings().for_application().configure() raises all non-Band loggers to BAND_LOG_LEVEL for a process that owns its logs, unless BAND_LOG_ROOT_LEVEL is set. configure_logging_from_env() is shorthand for LogSettings().configure().

from band import LogSettings
LogSettings().for_application().configure()
VariableDefaultDescription
BAND_LOG_LEVELINFOLevel for the band logger
BAND_LOG_ROOT_LEVELWARNINGLevel for non-Band loggers
BAND_LOG_FILEunsetOptional file sink path
BAND_LOG_FILE_LEVELfollows BAND_LOG_LEVELLevel for the file sink
BAND_LOG_MAX_BYTES0Maximum file size before rotation; 0 disables rotation
BAND_LOG_BACKUPS1Rotated files to keep; at least 1 when rotation is on
BAND_LOG_CONSOLE_STYLEstandardstandard, rich, or json
BAND_LOG_FILE_STYLEstandardstandard or json
BAND_LOG_STREAMstderrstderr or stdout
BAND_LOG_OVERRIDES{}JSON object mapping logger names to levels, such as {"httpx":"WARNING"}

Explicit LogSettings constructor values take precedence over environment variables, which take precedence over the defaults above, and an empty variable falls back to the default. LogSettings.create(...) drops None fields, so an optional CLI flag that was not passed leaves the environment value alone:

import argparse
from band import LogSettings
parser = argparse.ArgumentParser()
parser.add_argument("--log-level")
args = parser.parse_args([])
LogSettings.create(log_level=args.log_level).configure()

BAND_LOG_OVERRIDES is merged with the extra_loggers mapping passed to configure(), and the environment wins when both name the same logger.

OpenTelemetry Correlation

The host application owns OpenTelemetry providers, processors, exporters, and handlers, and Band exports no telemetry of its own. Band provides correlation: the json style writes otelTraceID, otelSpanID, otelTraceSampled, and otelServiceName in every record, plus trace_context, which holds the active W3C traceparent for the current turn or a generated ID when no span is active. Without instrumentation the four otel* fields serialize as null.

Select the json style with BAND_LOG_CONSOLE_STYLE=json or LogSettings(log_console_style=LoggingStyle.JSON), and configure Band logging before attaching an OpenTelemetry log handler, because dictConfig would drop it:

from band import LogSettings
LogSettings().for_application().configure()
# Attach the host application's OpenTelemetry LoggingHandler here.

If you replace the default JSON field list with json_fields=..., splice OTEL_CORRELATION_FIELDS from band.logging_config back in or the correlation keys are dropped.

PydanticAIAdapter forwards its instrument argument to Pydantic AI. Other frameworks are instrumented through their own OpenTelemetry integration, and out-of-process model backends emit their spans outside the SDK process. The OpenTelemetry example at band-sdk-v6.0.1 shows console exporters, trace-context injection, and provider shutdown.