1111from app .utils .singleton import SingletonMetaNoArgs
1212
1313
14- # TODO: merge this wrapper with the one in structlog under one hood of AppLogger
15- class BytesToTextIOWrapper :
16- def __init__ (self , handler , encoding = "utf-8" ):
14+ class RotatingBytesLogger :
15+ """Logger that respects RotatingFileHandler's rotation capabilities."""
16+
17+ def __init__ (self , handler ):
1718 self .handler = handler
18- self .encoding = encoding
1919
20- def write (self , b ):
21- if isinstance (b , bytes ):
22- self .handler .stream .write (b .decode (self .encoding ))
23- else :
24- self .handler .stream .write (b )
25- self .handler .flush ()
20+ def msg (self , message ):
21+ """Process a message and pass it through the handler's emit method."""
22+ if isinstance (message , bytes ):
23+ message = message .decode ("utf-8" )
24+
25+ # Create a log record that will trigger rotation checks
26+ record = logging .LogRecord (
27+ name = "structlog" ,
28+ level = logging .INFO ,
29+ pathname = "" ,
30+ lineno = 0 ,
31+ msg = message .rstrip ("\n " ),
32+ args = (),
33+ exc_info = None
34+ )
35+
36+ # Check if rotation is needed before emitting
37+ if self .handler .shouldRollover (record ):
38+ self .handler .doRollover ()
39+
40+ # Emit the record through the handler
41+ self .handler .emit (record )
42+
43+ # Required methods to make it compatible with structlog
44+ def debug (self , message ):
45+ self .msg (message )
46+
47+ def info (self , message ):
48+ self .msg (message )
2649
27- def flush (self ):
28- self .handler .flush ()
50+ def warning (self , message ):
51+ self .msg (message )
52+
53+ def error (self , message ):
54+ self .msg (message )
55+
56+ def critical (self , message ):
57+ self .msg (message )
58+
59+
60+ class RotatingBytesLoggerFactory :
61+ """Factory that creates loggers that respect file rotation."""
62+
63+ def __init__ (self , handler ):
64+ self .handler = handler
2965
30- def close (self ):
31- self .handler . close ( )
66+ def __call__ (self , * args , ** kwargs ):
67+ return RotatingBytesLogger ( self .handler )
3268
3369
34- @define ( slots = True )
70+ @define
3571class AppStructLogger (metaclass = SingletonMetaNoArgs ):
3672 _logger : structlog .BoundLogger = field (init = False )
3773
@@ -40,8 +76,7 @@ def __attrs_post_init__(self):
4076 _log_path = Path (f"{ _log_date } _{ os .getpid ()} .log" )
4177 _handler = RotatingFileHandler (
4278 filename = _log_path ,
43- mode = "a" ,
44- maxBytes = 10 * 1024 * 1024 ,
79+ maxBytes = 10 * 1024 * 1024 , # 10MB
4580 backupCount = 5 ,
4681 encoding = "utf-8"
4782 )
@@ -55,9 +90,7 @@ def __attrs_post_init__(self):
5590 structlog .processors .TimeStamper (fmt = "iso" , utc = True ),
5691 structlog .processors .JSONRenderer (serializer = orjson .dumps ),
5792 ],
58- logger_factory = structlog .BytesLoggerFactory (
59- file = BytesToTextIOWrapper (_handler )
60- )
93+ logger_factory = RotatingBytesLoggerFactory (_handler )
6194 )
6295 self ._logger = structlog .get_logger ()
6396
0 commit comments