Source code for client.logging
"""Logging configuration for jobmon client applications.
This module provides the standard logging configuration used by
workflow.run(configure_logging=True).
The module supports both legacy dict-based configs and new template-based
configurations. Requester logs are automatically captured by OTLP when
enabled (handled by the Requester class itself).
"""
from __future__ import annotations
import logging
import logging.config
import os
import sys
from typing import Dict
# Legacy default configuration - used as fallback only
[docs]
_DEFAULT_LOG_FORMAT = (
"%(asctime)s [%(name)-12s] %(module)s %(levelname)-8s: %(message)s"
)
[docs]
default_config: Dict = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {"format": _DEFAULT_LOG_FORMAT, "datefmt": "%Y-%m-%d %H:%M:%S"}
},
"handlers": {
"default": {
"level": "INFO",
"class": "logging.StreamHandler",
"formatter": "default",
"stream": sys.stdout,
}
},
}
# Legacy configuration - kept for backward compatibility if needed
# The primary interface is now configure_client_logging()
[docs]
def configure_client_logging() -> None:
"""Configure client logging with template and user override support.
This is the primary interface for configuring client logging. It supports:
1. Default template-based configuration
2. User file overrides via logging.client_logconfig_file
3. User section overrides via logging.client.*
4. Environment variable overrides
Configuration precedence:
1. Custom file (logging.client_logconfig_file)
2. Section overrides (logging.client.formatters/handlers/loggers)
3. Default template (logconfig_client.yaml)
4. Basic fallback configuration
Note: Requester OTLP is handled separately by the Requester class.
"""
try:
from jobmon.core.config.logconfig_utils import configure_logging_with_overrides
# Get default template path
current_dir = os.path.dirname(__file__)
default_template_path = os.path.join(
current_dir, "config/logconfig_client.yaml"
)
# Configure with override support
configure_logging_with_overrides(
default_template_path=default_template_path,
config_section="client",
fallback_config=default_config,
)
except Exception:
# Fall back to basic configuration for any error:
# - ImportError: core module not available
# - FileNotFoundError: template file missing
# - yaml.YAMLError: malformed YAML
# - ValueError: template resolution errors
# - PermissionError: file access issues
# - OSError: other I/O errors
# - logging configuration errors
try:
logging.config.dictConfig(default_config)
except Exception:
# If even the fallback config fails, set up minimal logging
logging.basicConfig(
level=logging.INFO,
format=_DEFAULT_LOG_FORMAT,
datefmt="%Y-%m-%d %H:%M:%S",
stream=sys.stdout,
)