-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlogger.py
167 lines (143 loc) · 5.42 KB
/
logger.py
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# logger.py
import json
import logging
import logging.config
import logging.handlers
import os
import pathlib
from typing import Any, Dict, Optional
from stream_pipeline.logger import PipelineLogger
def get_logger() -> logging.Logger:
return logging.getLogger("live_translation")
def setup_logging() -> logging.Logger:
logger = logging.getLogger("live_translation")
log_directory: str = "logs"
if not os.path.exists(log_directory):
os.makedirs(log_directory)
config_file: pathlib.Path = pathlib.Path("logging_config.json")
with open(config_file) as f_in:
logging_config: Dict[str, Any] = json.load(f_in)
logging.config.dictConfig(logging_config)
pipeline_logger: PipelineLogger = PipelineLogger()
pipeline_logger.set_debug(True)
pipeline_logger.set_info(logger.info)
pipeline_logger.set_warning(logger.warning)
pipeline_logger.set_error(logger.error)
pipeline_logger.set_critical(logger.critical)
pipeline_logger.set_log(logger.log)
pipeline_logger.set_exception(logger.exception)
pipeline_logger.set_excepthook(logger.error)
pipeline_logger.set_threading_excepthook(logger.error)
return logger
LOG_RECORD_BUILTIN_ATTRS: set[str] = {
"args",
"asctime",
"created",
"exc_info",
"exc_text",
"extra",
"filename",
"funcName",
"levelname",
"levelno",
"lineno",
"module",
"msecs",
"message",
"msg",
"name",
"pathname",
"process",
"processName",
"relativeCreated",
"stack_info",
"thread",
"threadName",
"taskName",
}
def truncate_dict(d: Any, max_length: int = 0) -> Any:
if isinstance(d, dict):
truncated: dict = {}
for key, value in d.items():
truncated[key] = truncate_dict(value, max_length)
return truncated
elif isinstance(d, (list, tuple, set)):
return type(d)(truncate_dict(item, max_length) for item in d)
elif hasattr(d, 'to_dict'):
return truncate_dict(d.to_dict(), max_length)
else:
return truncate_value(d, max_length)
def truncate_value(value: Any, max_length: int = 0) -> Any:
if isinstance(value, BaseException):
return str(value) # Simplified for exceptions
elif hasattr(value, 'to_dict'):
return value.to_dict()
elif isinstance(value, (dict, list, tuple, set)):
return truncate_dict(value, max_length)
else:
value_str: str = str(value)
if max_length > 0 and len(value_str) > max_length:
return value_str[:max_length] + '...'
return value_str
class MyJSONFormatter(logging.Formatter):
def __init__(
self,
datefmt: str = '%Y-%m-%dT%H:%M:%S%z',
max_length: int = 0,
fmt_keys: Optional[Dict[str, str]] = None,
*args: Any,
**kwargs: Any
) -> None:
super().__init__(*args, **kwargs)
self.datefmt: str = datefmt
self.max_length: int = max_length
self.fmt_keys: Dict[str, str] = fmt_keys or {}
def format(self, record: logging.LogRecord) -> str:
# Initialize an empty log record
log_record: Dict[str, Any] = {}
for key, value in self.fmt_keys.items(): # Use .items() to iterate over key-value pairs
if value not in LOG_RECORD_BUILTIN_ATTRS:
raise ValueError(f"Invalid value '{value}' in fmt_keys")
if key in log_record:
raise ValueError(f"Duplicate key '{key}' in fmt_keys")
if value == 'asctime':
log_record[key] = self.formatTime(record, self.datefmt)
continue
log_record[key] = getattr(record, value, None)
# Add extra attributes
# Add all attributes which are not in the LOG_RECORD_BUILTIN_ATTRS set
if 'extra' in self.fmt_keys.values():
for key, value in record.__dict__.items():
if key not in LOG_RECORD_BUILTIN_ATTRS:
extra_set: Dict[str, Any] = {}
extra_set[key] = value
log_record['extra'] = extra_set
# Truncate and serialize the final log record
truncated: Dict[str, Any] = truncate_dict(log_record, self.max_length)
return json.dumps(truncated)
class SimpleJSONFormatter(logging.Formatter):
def __init__(self, max_length: int = 64, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.max_length: int = max_length
def format(self, record: logging.LogRecord) -> str:
# Initialize the log record with the message
log_record: Dict[str, Any] = {"message": record.msg}
# Include extra fields that are not part of the default log attributes
extra: Dict[str, Any] = {
key: value for key, value in record.__dict__.items()
if key not in LOG_RECORD_BUILTIN_ATTRS and not key.startswith('_')
}
for key, value in extra.items():
if hasattr(value, 'to_dict'):
extra[key] = value.to_dict()
else:
# try to read json to dict
try:
extra[key] = json.loads(value)
except (TypeError, ValueError):
pass
if extra:
log_record["extra"] = extra
log_record = truncate_dict(log_record, self.max_length)
# Convert to JSON
return json.dumps(log_record, default=str, indent=4)