File size: 5,875 Bytes
58de15f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9b43b2
58de15f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# app/core/logging_config.py

import logging
import logging.config
import sys
import os # Added to potentially create log directory

# Optional: Could make log level configurable via settings
# from app.core.config import settings

LOG_LEVEL = "INFO" # Default level (e.g., INFO, DEBUG, WARNING)
# You could override this with an environment variable if needed:
# LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()

# Define the logging configuration dictionary
LOGGING_CONFIG = {
    "version": 1,
    "disable_existing_loggers": False, # Let default loggers (like uvicorn) work
    "formatters": {
        "default": {
            # Example format: timestamp | level | logger_name | function:line | message
            "format": "%(asctime)s | %(levelname)-8s | %(name)-30s | %(funcName)s:%(lineno)d | %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S",
        },
        "simple": {
            "format": "%(levelname)-8s | %(name)-20s | %(message)s",
        },
    },
    "handlers": {
        # Handler for console output
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "default", # Use the detailed default formatter
            "stream": sys.stdout, # Log to standard output
        },
        # --- Example File Handler (Optional) ---
        # Uncomment and configure if you want to log to a file
        # "file": {
        #     "class": "logging.handlers.RotatingFileHandler",
        #     "formatter": "default", # Use the detailed formatter for file logs too
        #     "filename": "logs/chatbot_v2.log", # Path to log file
        #     "maxBytes": 10 * 1024 * 1024,  # 10 MB
        #     "backupCount": 5, # Keep 5 backup files
        #     "encoding": "utf-8",
        # },
        # --- End File Handler ---
    },
    "loggers": {
        # Root logger configuration
        "": {
            "handlers": ["console"], # Add "file" here if using file handler
            "level": LOG_LEVEL, # Default level for all loggers
            "propagate": False, # Prevent logs from propagating to higher-level handlers if any
        },
        # Specific configuration for YOUR application's logger(s)
        # This assumes your code uses loggers like logging.getLogger("app.api.v2_endpoints")
        "app": {
            "handlers": ["console"], # Add "file" here if using file handler
            # Set your app's code to DEBUG for more detailed logs during development
            "level": "INFO", # Or keep as LOG_LEVEL if preferred
            "propagate": False, # Don't pass messages up to the root logger
        },
        # Configuration for noisy third-party libraries
        "uvicorn": {
            "handlers": ["console"],
            "level": "INFO", # Keep uvicorn's own info messages
            "propagate": False,
        },
         "uvicorn.error": {
             "handlers": ["console"],
             "level": "INFO", # Keep uvicorn errors visible
             "propagate": False,
         },
         "uvicorn.access": {
             # Use simple formatter and higher level for access logs to reduce noise
             "handlers": ["console"],
             "level": "WARNING", # Change to INFO to see every request path
             "propagate": False,
             # "formatter": "simple", # Optional: Use simpler format
         },
        "sqlalchemy": { # Catch-all for sqlalchemy loggers
            "handlers": ["console"],
            "level": "WARNING", # Set to INFO/DEBUG to see SQL statements/pool info
            "propagate": False,
        },
        # Example: Quieten down specific noisy loggers if needed
        # "httpx": {
        #     "handlers": ["console"],
        #     "level": "WARNING",
        #     "propagate": False,
        # },
        # "openai": {
        #     "handlers": ["console"],
        #     "level": "WARNING",
        #     "propagate": False,
        # },
    },
}
def get_logger(name: str = __name__) -> logging.Logger:
    """
    Returns a logger configured with a StreamHandler and a basic formatter.
    """
    logger = logging.getLogger(name)
    if not logger.handlers:
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter(
            "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s"
        ))
        logger.addHandler(handler)
    logger.setLevel(logging.INFO)
    return logger
def setup_logging():
    """
    Applies the logging configuration using dictConfig.
    Creates log directory if file handler is used and directory doesn't exist.
    """
    # --- Optional: Create log directory if file handler is used ---
    # if "file" in LOGGING_CONFIG["handlers"]:
    #     log_dir = os.path.dirname(LOGGING_CONFIG["handlers"]["file"]["filename"])
    #     if log_dir and not os.path.exists(log_dir):
    #         try:
    #             os.makedirs(log_dir)
    #             print(f"Created log directory: {log_dir}")
    #         except OSError as e:
    #             print(f"Error creating log directory {log_dir}: {e}", file=sys.stderr)
    #             # Decide if this is critical and should prevent startup
    # --- End Optional Directory Creation ---

    try:
        logging.config.dictConfig(LOGGING_CONFIG)
        # Get a logger for this module *after* config is applied
        logger = logging.getLogger(__name__)
        logger.info(f"Logging configured successfully using dictConfig. Root level: {LOG_LEVEL}")
    except Exception as e:
        # Fallback to basic config if dictConfig fails for any reason
        print(f"Error configuring logging with dictConfig, falling back to basicConfig: {e}", file=sys.stderr)
        logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)-8s | %(name)-20s | %(message)s")
        logger = logging.getLogger(__name__)
        logger.exception("Logging setup failed, using basic config.")