1717
1818Example:: 
1919
20+     import logging 
2021    from uuid import uuid4 
21-     from etos_lib.logging.logger import setup_logging, get_logger  
22+     from etos_lib.logging.logger import setup_logging, FORMAT_CONFIG  
2223
24+     FORMAT_CONFIG.identifier = str(uuid4()) 
2325    setup_logging("myApp", "1.0.0", "production") 
24-     logger = get_logger (__name__, str(uuid4()) ) 
26+     logger = logging.getLogger (__name__) 
2527    logger.info("Hello!") 
2628    >>> [2020-12-16 10:35:00][cb7c8cd9-40a6-4ecc-8321-a1eae6beae35] INFO: Hello! 
2729
2830""" 
31+ import  sys 
2932from  pathlib  import  Path 
33+ import  threading 
3034import  logging 
3135import  logging .config 
36+ from  box  import  Box 
3237from  etos_lib .logging .filter  import  EtosFilter 
38+ from  etos_lib .logging .formatter  import  EtosLogFormatter 
3339from  etos_lib .lib .debug  import  Debug 
34- from  etos_lib .lib .config  import  Config 
3540
36- DEFAULT_CONFIG  =  Path (__file__ ).parent .joinpath ("default_config.conf " )
41+ DEFAULT_CONFIG  =  Path (__file__ ).parent .joinpath ("default_config.yaml " )
3742DEFAULT_LOG_PATH  =  Debug ().default_log_path 
38- DEFAULT_LOG_PATH .parent .mkdir (exist_ok = True , parents = True )
43+ 
44+ FORMAT_CONFIG  =  threading .local ()
45+ 
46+ 
47+ def  setup_file_logging (config , log_filter ):
48+     """Set up logging to file using the ETOS log formatter. 
49+ 
50+     Cofiguration file parameters ('file' must exist or no file handler is set up): 
51+ 
52+         logging: 
53+           file: 
54+             # Log level for file logging. Default=DEBUG. 
55+             loglevel: INFO 
56+             # Where to store logfile. Default=/home/you/etos/output.log.json 
57+             logfile: path/to/log/file 
58+             # Maximum number of files to rotate. Default=10 
59+             max_files: 5 
60+             # Maximum number of bytes in each logfile. Default=1048576/1MB 
61+             max_bytes: 100 
62+ 
63+     :param config: File logging configuration. 
64+     :type config: :obj:`Box` 
65+     :param log_filter: Logfilter to add to file handler. 
66+     :type log_filter: :obj:`EtosFilter` 
67+     """ 
68+     loglevel  =  getattr (logging , config .get ("loglevel" , "DEBUG" ))
69+     logfile  =  Path (config .get ("logfile" , DEFAULT_LOG_PATH ))
70+     logfile .parent .mkdir (parents = True , exist_ok = True )
71+ 
72+     max_files  =  config .get ("max_files" , 10 )
73+     max_bytes  =  config .get ("max_bytes" , 10485760 )  # Default is 10 MB 
74+     root_logger  =  logging .getLogger ()
75+ 
76+     file_handler  =  logging .handlers .RotatingFileHandler (
77+         logfile , maxBytes = max_bytes , backupCount = max_files 
78+     )
79+     file_handler .setFormatter (EtosLogFormatter ())
80+     file_handler .setLevel (loglevel )
81+     file_handler .addFilter (log_filter )
82+     root_logger .addHandler (file_handler )
83+ 
84+ 
85+ def  setup_stream_logging (config , log_filter ):
86+     """Set up logging to stdout stream. 
87+ 
88+     Cofiguration file parameters ('stream' must exist or no stream handler is set up): 
89+ 
90+         logging: 
91+           stream: 
92+             # Log level for stream logging. Default=INFO. 
93+             loglevel: ERROR 
94+             # Format to print logs with. 
95+             # Default: [%(asctime)s][%(identifier)s] %(levelname)s:%(name)s: %(message)s 
96+             logformat: %(message)s 
97+             # Dateformat for %(asctime) format. Default: %Y-%m-%d %H:%M:%S 
98+             dateformat: %Y-%d-%m %H:%M:%S 
99+ 
100+     :param config: Stream logging configuration. 
101+     :type config: :obj:`Box` 
102+     :param log_filter: Logfilter to add to stream handler. 
103+     :type log_filter: :obj:`EtosFilter` 
104+     """ 
105+     loglevel  =  getattr (logging , config .get ("loglevel" , "INFO" ))
106+ 
107+     logformat  =  config .get (
108+         "logformat" ,
109+         "[%(asctime)s][%(identifier)s] %(levelname)s:%(name)s: %(message)s" 
110+     )
111+     dateformat  =  config .get ("dateformat" , "%Y-%m-%d %H:%M:%S" )
112+     root_logger  =  logging .getLogger ()
113+     stream_handler  =  logging .StreamHandler (sys .stdout )
114+     stream_handler .setFormatter (logging .Formatter (logformat , datefmt = dateformat ))
115+     stream_handler .setLevel (loglevel )
116+     stream_handler .addFilter (log_filter )
117+     root_logger .addHandler (stream_handler )
39118
40119
41120def  setup_logging (
42-     application , version , environment , filename = DEFAULT_CONFIG ,  output = DEFAULT_LOG_PATH 
121+     application , version , environment , config_file = DEFAULT_CONFIG 
43122):
44123    """Set up basic logging. 
45124
@@ -49,27 +128,25 @@ def setup_logging(
49128    :type version: str 
50129    :param environment: Environment in which this application resides. 
51130    :type environment: str 
52-     :param filename: Filename of logging configuration. 
53-     :type filename: str 
54-     :param output: Output filename for logging to file. 
55-     :type output: str 
131+     :param config_file: Filename of logging configuration. 
132+     :type config_file: str 
56133    """ 
57-     Config ().set ("log_filter" , EtosFilter (application , version , environment ))
58-     logging .config .fileConfig (filename , defaults = {"logfilename" : output })
59-     root_logger  =  logging .getLogger ()
60-     root_logger .addFilter (Config ().get ("log_filter" ))
134+     with  open (config_file ) as  yaml_file :
135+         config  =  Box .from_yaml (yaml_file )
136+     logging_config  =  config .logging 
61137
138+     log_filter  =  EtosFilter (application , version , environment , FORMAT_CONFIG )
62139
63- def  get_logger (name , identifier ):
64-     """Get a logger adapter with attached identiifer. 
140+     # Create a default logger which will not propagate messages 
141+     # to the root logger. This logger will create records for all 
142+     # messages, but not print them to stdout. Stdout printing 
143+     # is setup in "setup_stream_logging" if the "stream" key exists 
144+     # in the configuration file. 
145+     root_logger  =  logging .getLogger ()
146+     root_logger .setLevel (logging .DEBUG )
147+     root_logger .propagate  =  0 
65148
66-     :param name: Name of logger to get. 
67-     :type name: str 
68-     :param identifier: Unique identifier to attach to logger. 
69-     :type identifier: str 
70-     :return: LoggerAdapter instance. 
71-     :rtype: :obj:`logging.LoggerAdapter` 
72-     """ 
73-     logger  =  logging .getLogger (name )
74-     logger .addFilter (Config ().get ("log_filter" ))
75-     return  logging .LoggerAdapter (logger , {"identifier" : identifier })
149+     if  logging_config .get ("stream" ):
150+         setup_stream_logging (logging_config .get ("stream" ), log_filter )
151+     if  logging_config .get ("file" ):
152+         setup_file_logging (logging_config .get ("file" ), log_filter )
0 commit comments