def internal_setup(config: TelemetryConfig | None = None, is_explicit_call: bool = False) -> None:
"""The single, internal setup function that both explicit and lazy setup call.
It is protected by the _PROVIDE_SETUP_LOCK in its callers.
"""
# This function assumes the lock is already held.
structlog.reset_defaults()
# Reset OTLP provider to ensure new LoggerProvider with updated config
# This is critical when service_name changes, as OpenTelemetry's Resource is immutable
try:
from provide.foundation.logger.processors.otlp import reset_otlp_provider
reset_otlp_provider()
except ImportError:
# OTLP not available (missing opentelemetry packages), skip reset
pass
# Use __dict__ access to avoid triggering proxy initialization
foundation_logger.__dict__["_is_configured_by_setup"] = False
foundation_logger.__dict__["_active_config"] = None
_LAZY_SETUP_STATE.update({"done": False, "error": None, "in_progress": False})
current_config = config if config is not None else TelemetryConfig.from_env()
core_setup_logger = create_foundation_internal_logger(globally_disabled=current_config.globally_disabled)
if not current_config.globally_disabled:
core_setup_logger.debug(
"🔧 Logger configuration initialized",
service_name=current_config.service_name,
log_level=current_config.logging.default_level,
formatter=current_config.logging.console_formatter,
)
# Log OpenTelemetry/OTLP configuration
if current_config.otlp_endpoint:
try:
from provide.foundation.integrations.openobserve.config import OpenObserveConfig
oo_config = OpenObserveConfig.from_env()
if oo_config.is_configured():
# OpenObserve auto-configured OTLP
core_setup_logger.debug(
"📡 OpenObserve integration enabled - OTLP log export active",
otlp_endpoint=current_config.otlp_endpoint,
openobserve_org=oo_config.org,
openobserve_stream=oo_config.stream,
)
else:
# Manually configured OTLP
core_setup_logger.debug(
"📡 OpenTelemetry OTLP log export active",
otlp_endpoint=current_config.otlp_endpoint,
otlp_traces_endpoint=current_config.otlp_traces_endpoint,
)
except ImportError:
# OpenObserve not available, just log basic OTLP config
core_setup_logger.debug(
"📡 OpenTelemetry OTLP log export active",
otlp_endpoint=current_config.otlp_endpoint,
otlp_traces_endpoint=current_config.otlp_traces_endpoint,
)
if current_config.globally_disabled:
core_setup_logger.trace("Setting up globally disabled telemetry")
handle_globally_disabled_setup()
else:
# Configure log file if specified
if current_config.logging.log_file is not None:
from provide.foundation.streams.file import configure_file_logging
configure_file_logging(log_file_path=str(current_config.logging.log_file))
core_setup_logger.trace("Configuring structlog output processors")
configure_structlog_output(current_config, get_log_stream())
# Use __dict__ access to avoid triggering proxy initialization
foundation_logger.__dict__["_is_configured_by_setup"] = is_explicit_call
foundation_logger.__dict__["_active_config"] = current_config
_LAZY_SETUP_STATE["done"] = True
# Configure Python stdlib logging for module-level suppression
if not current_config.globally_disabled and current_config.logging.module_levels:
_configure_stdlib_module_logging(current_config.logging.module_levels)
if not current_config.globally_disabled:
core_setup_logger.debug(
"✅ Logger setup complete",
processors_configured=True,
log_file_enabled=current_config.logging.log_file is not None,
)