1313"""
1414
1515import sys
16+ import logging
1617import os
1718from datetime import timedelta , datetime
1819
1920from itzi .itzi_error import ItziFatal
2021from itzi .const import VerbosityLevel
2122
22- OUTPUT = sys .stderr
23- FATAL = "ERROR: "
24- WARNING = "WARNING: "
25- PAD = " " * 20 # Necessary to print a clean line
26-
2723raise_on_error = True
2824
2925
@@ -35,14 +31,90 @@ def verbosity():
3531 return VerbosityLevel .QUIET
3632
3733
34+ class ItziLogger :
35+ """Custom logger wrapper maintaining backward compatibility"""
36+
37+ VERBOSE_LEVEL = 15
38+ logging .addLevelName (VERBOSE_LEVEL , "VERBOSE" )
39+
40+ def __init__ (self ):
41+ self .logger = logging .getLogger ("itzi" )
42+ self .raise_on_error = True
43+ self ._setup_handlers ()
44+
45+ def _setup_handlers (self ):
46+ """Configure console and optional file handlers"""
47+ # Console handler (stderr)
48+ console_handler = logging .StreamHandler (sys .stderr )
49+ console_handler .setFormatter (logging .Formatter ("%(message)s" ))
50+ self .logger .addHandler (console_handler )
51+ self .logger .setLevel (logging .DEBUG )
52+
53+ def add_file_handler (self , filepath , level = logging .DEBUG ):
54+ """Add file logging capability"""
55+ file_handler = logging .FileHandler (filepath )
56+ file_handler .setLevel (level )
57+ file_handler .setFormatter (logging .Formatter ("%(asctime)s - %(levelname)s - %(message)s" ))
58+ self .logger .addHandler (file_handler )
59+
60+ def set_verbosity (self , verbosity_level ):
61+ """Map verbosity to logging level"""
62+ mapping = {
63+ VerbosityLevel .SUPER_QUIET : logging .ERROR ,
64+ VerbosityLevel .QUIET : logging .WARNING ,
65+ VerbosityLevel .MESSAGE : logging .INFO ,
66+ VerbosityLevel .VERBOSE : self .VERBOSE_LEVEL ,
67+ VerbosityLevel .DEBUG : logging .DEBUG ,
68+ }
69+ level = mapping .get (verbosity_level , logging .INFO )
70+ self .logger .setLevel (level )
71+ for handler in self .logger .handlers :
72+ if isinstance (handler , logging .StreamHandler ) and not isinstance (
73+ handler , logging .FileHandler
74+ ):
75+ handler .setLevel (level )
76+
77+ def fatal (self , msg ):
78+ """Log fatal error and raise or exit"""
79+ self .logger .error (f"ERROR: { msg } " )
80+ if raise_on_error :
81+ raise ItziFatal (msg )
82+ else :
83+ sys .exit (f"ERROR: { msg } " )
84+
85+ def warning (self , msg ):
86+ self .logger .warning (f"WARNING: { msg } " )
87+
88+ def message (self , msg ):
89+ self .logger .info (msg )
90+
91+ def verbose (self , msg ):
92+ self .logger .log (self .VERBOSE_LEVEL , msg )
93+
94+ def debug (self , msg ):
95+ self .logger .debug (msg )
96+
97+
98+ # Global instance
99+ _itzi_logger = ItziLogger ()
100+
101+ # Backward-compatible module-level interface
102+ raise_on_error = _itzi_logger .raise_on_error
103+ fatal = _itzi_logger .fatal
104+ warning = _itzi_logger .warning
105+ message = _itzi_logger .message
106+ verbose = _itzi_logger .verbose
107+ debug = _itzi_logger .debug
108+
109+
38110def percent (start_time , end_time , sim_time , sim_start_time ):
39111 """Display progress of the simulation"""
40112 sim_time_s = (sim_time - start_time ).total_seconds ()
41113 duration_s = (end_time - start_time ).total_seconds ()
42114 advance_perc = sim_time_s / duration_s
43115
44116 if verbosity () == VerbosityLevel .QUIET :
45- print ("{ :.1%}". format ( advance_perc ) , file = OUTPUT , end = "\r " )
117+ print (f" { advance_perc :.1%} " , file = sys . stderr , end = "\r " )
46118
47119 elif verbosity () >= VerbosityLevel .MESSAGE :
48120 elapsed_s = (datetime .now () - sim_start_time ).total_seconds ()
@@ -59,36 +131,4 @@ def percent(start_time, end_time, sim_time, sim_start_time):
59131 eta = eta ,
60132 pad = " " * 10 ,
61133 )
62- print (disp , file = OUTPUT , end = "\r " )
63-
64-
65- def message (msg ):
66- """Display a normal message"""
67- if verbosity () >= VerbosityLevel .MESSAGE :
68- print (msg + PAD , file = OUTPUT )
69-
70-
71- def verbose (msg ):
72- """Display a verbose message"""
73- if verbosity () >= VerbosityLevel .VERBOSE :
74- print (msg + PAD , file = OUTPUT )
75-
76-
77- def debug (msg ):
78- """Display a debug message"""
79- if verbosity () >= VerbosityLevel .DEBUG :
80- print (msg + PAD , file = OUTPUT )
81-
82-
83- def warning (msg ):
84- """Display a warning message"""
85- if verbosity () >= VerbosityLevel .SUPER_QUIET :
86- print (WARNING + msg + PAD , file = OUTPUT )
87-
88-
89- def fatal (msg ):
90- """Display a fatal error and (exit or raise)"""
91- if raise_on_error :
92- raise ItziFatal (msg )
93- else :
94- sys .exit (FATAL + msg + PAD )
134+ print (disp , file = sys .stderr , end = "\r " )
0 commit comments