File size: 2,576 Bytes
e7f1d57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Dependencies
import sys
import logging
from datetime import datetime
from config.settings import settings


class ColoredFormatter(logging.Formatter):
    """
    Colored log formatter for better readability
    """
    COLORS = {'DEBUG'    : '\033[36m',  # Cyan
              'INFO'     : '\033[32m',  # Green
              'WARNING'  : '\033[33m',  # Yellow
              'ERROR'    : '\033[31m',  # Red
              'CRITICAL' : '\033[35m',  # Magenta
              'RESET'    : '\033[0m',
             }
    

    def format(self, record):
        if sys.stdout.isatty():
            levelname = record.levelname

            if (levelname in self.COLORS):
                record.levelname = f"{self.COLORS[levelname]}{levelname}{self.COLORS['RESET']}"
        
        return super().format(record)


def setup_logger(name: str = None) -> logging.Logger:
    """
    Setup logger with console and file handlers
    
    Arguments:
    ----------
        name   { str }     : Logger name (defaults to root logger)
    
    Returns:
    --------
        { logging.Logger } : Configured logger instance
    """
    logger = logging.getLogger(name or settings.APP_NAME)
    
    # Avoid duplicate handlers
    if logger.handlers:
        return logger
    
    level             = getattr(logging, settings.LOG_LEVEL, logging.INFO)
    logger.setLevel(level)

    logger.propagate  = False
    
    # Console handler with colors
    console_handler   = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(logging.DEBUG if settings.DEBUG else logging.INFO)
    
    console_formatter = ColoredFormatter('%(asctime)s | %(levelname)-8s | %(name)s | %(message)s',
                                         datefmt = '%Y-%m-%d %H:%M:%S'
                                        )
    console_handler.setFormatter(console_formatter)

    logger.addHandler(console_handler)
    
    # File handler
    log_file          = settings.LOGS_DIR / f"app_{datetime.now().strftime('%Y%m%d')}.log"
    file_handler      = logging.FileHandler(log_file)
    file_handler.setLevel(logging.DEBUG)

    file_formatter    = logging.Formatter('%(asctime)s | %(levelname)-8s | %(name)s | %(funcName)s:%(lineno)d | %(message)s',
                                          datefmt = '%Y-%m-%d %H:%M:%S'
                                         )

    file_handler.setFormatter(file_formatter)
    
    logger.addHandler(file_handler)
    
    return logger


def get_logger(name: str = None) -> logging.Logger:
    """
    Get or create logger instance
    """
    return setup_logger(name)