11
11
from app .utils .singleton import SingletonMetaNoArgs
12
12
13
13
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 ):
17
18
self .handler = handler
18
- self .encoding = encoding
19
19
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 )
26
49
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
29
65
30
- def close (self ):
31
- self .handler . close ( )
66
+ def __call__ (self , * args , ** kwargs ):
67
+ return RotatingBytesLogger ( self .handler )
32
68
33
69
34
- @define ( slots = True )
70
+ @define
35
71
class AppStructLogger (metaclass = SingletonMetaNoArgs ):
36
72
_logger : structlog .BoundLogger = field (init = False )
37
73
@@ -40,8 +76,7 @@ def __attrs_post_init__(self):
40
76
_log_path = Path (f"{ _log_date } _{ os .getpid ()} .log" )
41
77
_handler = RotatingFileHandler (
42
78
filename = _log_path ,
43
- mode = "a" ,
44
- maxBytes = 10 * 1024 * 1024 ,
79
+ maxBytes = 10 * 1024 * 1024 , # 10MB
45
80
backupCount = 5 ,
46
81
encoding = "utf-8"
47
82
)
@@ -55,9 +90,7 @@ def __attrs_post_init__(self):
55
90
structlog .processors .TimeStamper (fmt = "iso" , utc = True ),
56
91
structlog .processors .JSONRenderer (serializer = orjson .dumps ),
57
92
],
58
- logger_factory = structlog .BytesLoggerFactory (
59
- file = BytesToTextIOWrapper (_handler )
60
- )
93
+ logger_factory = RotatingBytesLoggerFactory (_handler )
61
94
)
62
95
self ._logger = structlog .get_logger ()
63
96
0 commit comments