-
Notifications
You must be signed in to change notification settings - Fork 104
/
logging_handler.py
142 lines (110 loc) · 4.57 KB
/
logging_handler.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
"""
Copyright (C) 2023-2024 Fern Lane
This file is part of the GPT-Telegramus distribution
(see <https://github.com/F33RNI/GPT-Telegramus>)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import datetime
import logging
import logging.handlers
import multiprocessing
import os
# Logging level
LOGGING_LEVEL = logging.INFO
# Where to save log files
LOGS_DIR = "logs"
# Logs entry to ignore if they started with any string from list below
LOGS_IGNORE_PREFIXES = ["HTTP Request: POST https://api.telegram.org/bot"]
# Logging formatter
FORMATTER_FMT = "[%(asctime)s] [%(process)-7d] [%(levelname)-7s] %(message)s"
FORMATTER_DATEFMT = "%Y-%m-%d %H:%M:%S"
def worker_configurer(queue: multiprocessing.Queue, log_test_message: bool = True):
"""Call this method in your process
Args:
queue (multiprocessing.Queue): logging queue
log_test_message (bool, optional): set to False to disable test log message with process PID. Defaults to True
"""
# Remove all current handlers
root_logger = logging.getLogger()
if root_logger.handlers:
for handler in root_logger.handlers:
root_logger.removeHandler(handler)
# Setup queue handler
queue_handler = logging.handlers.QueueHandler(queue)
root_logger.addHandler(queue_handler)
root_logger.setLevel(LOGGING_LEVEL)
# Log test message
if log_test_message:
logging.info(f"Logging setup is complete for process with PID: {multiprocessing.current_process().pid}")
class LoggingHandler:
def __init__(self):
# Logging queue
self.queue = multiprocessing.Queue(-1)
def configure_and_start_listener(self):
"""
Initializes logging and starts listening. Send None to queue to stop it
:return:
"""
# Create logs directory is not exists
if not os.path.exists(LOGS_DIR):
os.makedirs(LOGS_DIR)
# Create logs formatter
log_formatter = logging.Formatter(FORMATTER_FMT, datefmt=FORMATTER_DATEFMT)
# Setup logging into file
file_handler = logging.FileHandler(
os.path.join(LOGS_DIR, datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") + ".log"), encoding="utf-8"
)
file_handler.setFormatter(log_formatter)
# This import must be here
# pylint: disable=import-outside-toplevel
import sys
# pylint: enable=import-outside-toplevel
# Setup logging into console
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(log_formatter)
# Add all handlers and setup level
root_logger = logging.getLogger()
root_logger.addHandler(file_handler)
root_logger.addHandler(console_handler)
root_logger.setLevel(LOGGING_LEVEL)
# Start queue listener
while True:
try:
# Get logging record
record = self.queue.get()
# Send None to exit
if record is None:
break
# Skip empty messages
if record.message is None:
continue
# Ignore some record messages
ignore = False
for ignore_str in LOGS_IGNORE_PREFIXES:
if str(record.message).startswith(ignore_str):
ignore = True
break
if ignore:
continue
# Handle current logging record
logger = logging.getLogger(record.name)
logger.handle(record)
# Ignore Ctrl+C (call queue.put(None) to stop this listener)
except (SystemExit, KeyboardInterrupt):
pass
# Error! WHY???
except Exception:
# pylint: disable=import-outside-toplevel
import traceback
# pylint: enable=import-outside-toplevel
print("Logging error: ", file=sys.stderr)
traceback.print_exc(file=sys.stderr)