Skip to content

Commit 888c097

Browse files
committed
Revert "Revert "Keep log messages from last full run and last run with error or warnings (#2118)""
This reverts commit 41dabdc.
1 parent 1b3335a commit 888c097

3 files changed

Lines changed: 124 additions & 2 deletions

File tree

packages/helpermodules/logger.py

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
import threading
77
import typing_extensions
88
import re
9+
import io
10+
import os
11+
import shutil
912

1013
FORMAT_STR_DETAILED = '%(asctime)s - {%(name)s:%(lineno)s} - {%(levelname)s:%(threadName)s} - %(message)s'
1114
FORMAT_STR_SHORT = '%(asctime)s - %(message)s'
1215
RAMDISK_PATH = str(Path(__file__).resolve().parents[2]) + '/ramdisk/'
1316
PERSISTENT_LOG_PATH = str(Path(__file__).resolve().parents[2]) + '/data/log/'
17+
NUMBER_OF_LOGFILES = 3
1418

1519
KNOWN_SENSITIVE_FIELDS = [
1620
'password', 'secret', 'token', 'apikey', 'access_token',
@@ -104,18 +108,117 @@ def filter_pos(name: str, record) -> bool:
104108
return False
105109

106110

111+
class InMemoryLogHandler(logging.Handler):
112+
def __init__(self, base_handler=None):
113+
super().__init__()
114+
self.base_handler = base_handler
115+
self.log_stream = io.StringIO()
116+
self.has_warning_or_error = False
117+
118+
def emit(self, record):
119+
if self.base_handler is None or self.base_handler.filter(record):
120+
msg = self.format(record)
121+
self.log_stream.write(msg + '\n')
122+
if record.levelno >= logging.WARNING:
123+
self.has_warning_or_error = True
124+
125+
def get_logs(self):
126+
return self.log_stream.getvalue()
127+
128+
def clear(self):
129+
self.log_stream = io.StringIO()
130+
self.has_warning_or_error = False
131+
132+
133+
def clear_in_memory_log_handler(logger_name: str = None) -> None:
134+
global in_memory_log_handlers
135+
if logger_name is None:
136+
# Clear all in-memory log handlers
137+
for handler in in_memory_log_handlers.values():
138+
handler.clear()
139+
else:
140+
# Clear specified in-memory log handler
141+
if logger_name in in_memory_log_handlers:
142+
in_memory_log_handlers[logger_name].clear()
143+
144+
145+
def write_logs_to_file(logger_name: str = None) -> None:
146+
global in_memory_log_handlers
147+
148+
def rotate_logs(base_path: str, name: str):
149+
# Rotate the log files
150+
for i in range(NUMBER_OF_LOGFILES-1, 0, -1):
151+
src = os.path.join(base_path, f'{name}.previous{i}.log')
152+
dst = os.path.join(base_path, f'{name}.previous{i+1}.log')
153+
if os.path.exists(src):
154+
shutil.move(src, dst)
155+
# Move the current log to previous1
156+
current_log = os.path.join(base_path, f'{name}.current.log')
157+
if os.path.exists(current_log):
158+
shutil.move(current_log, os.path.join(base_path, f'{name}.previous1.log'))
159+
160+
def combine_logs(base_path: str, name: str):
161+
latest_log_path = os.path.join(base_path, f'{name}.latest.log')
162+
with open(latest_log_path, 'w') as latest_log:
163+
for i in range(NUMBER_OF_LOGFILES-1, -1, -1):
164+
log_file = os.path.join(
165+
base_path, f'{name}.previous{i}.log') if i > 0 else os.path.join(base_path, f'{name}.current.log')
166+
if os.path.exists(log_file):
167+
with open(log_file, 'r') as f:
168+
latest_log.write(f.read())
169+
170+
if logger_name is None:
171+
# Write logs for all in-memory log handlers
172+
for name, handler in in_memory_log_handlers.items():
173+
logs = handler.get_logs()
174+
if logs:
175+
rotate_logs(RAMDISK_PATH, name)
176+
with open(os.path.join(RAMDISK_PATH, f'{name}.current.log'), 'w') as f:
177+
f.write(logs)
178+
combine_logs(RAMDISK_PATH, name)
179+
180+
# If any warning or error messages were logged, create a -warning copy
181+
if handler.has_warning_or_error:
182+
with open(os.path.join(RAMDISK_PATH, f'{name}.latest-warning.log'), 'w') as f:
183+
f.write(logs)
184+
185+
else:
186+
# Write logs for specified in-memory log handler
187+
if logger_name in in_memory_log_handlers:
188+
handler = in_memory_log_handlers[logger_name]
189+
logs = handler.get_logs()
190+
if logs:
191+
rotate_logs(RAMDISK_PATH, logger_name)
192+
with open(os.path.join(RAMDISK_PATH, f'{logger_name}.current.log'), 'w') as f:
193+
f.write(logs)
194+
combine_logs(RAMDISK_PATH, logger_name)
195+
196+
# If any warning or error messages were logged, create a -warning copy
197+
if handler.has_warning_or_error:
198+
with open(os.path.join(RAMDISK_PATH, f'{logger_name}.latest-warning.log'), 'w') as f:
199+
f.write(logs)
200+
201+
107202
def setup_logging() -> None:
108203
def mb_to_bytes(megabytes: int) -> int:
109204
return megabytes * 1000000
110-
# Mehrere kleine Dateien verwenden, damit nicht zu viel verworfen wird, wenn die Datei voll ist.
205+
206+
global in_memory_log_handlers
207+
in_memory_log_handlers = {name: InMemoryLogHandler() for name in ["main", "internal_chargepoint"]}
208+
# to do: add smarthome and soc to in_memory_log_handlers, needs updates in individual thread calls
209+
210+
# Main logger
111211
main_file_handler = RotatingFileHandler(RAMDISK_PATH + 'main.log', maxBytes=mb_to_bytes(5), backupCount=4)
112212
main_file_handler.setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
113213
main_file_handler.addFilter(RedactingFilter())
114-
logging.basicConfig(level=logging.DEBUG, handlers=[main_file_handler])
214+
in_memory_log_handlers["main"] = InMemoryLogHandler(main_file_handler)
215+
in_memory_log_handlers["main"].setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
216+
logging.basicConfig(level=logging.DEBUG, handlers=[main_file_handler, in_memory_log_handlers["main"]])
115217
logging.getLogger().handlers[0].addFilter(functools.partial(filter_neg, "soc"))
116218
logging.getLogger().handlers[0].addFilter(functools.partial(filter_neg, "Internal Chargepoint"))
117219
logging.getLogger().handlers[0].addFilter(functools.partial(filter_neg, "smarthome"))
118220

221+
# Chargelog logger
119222
chargelog_log = logging.getLogger("chargelog")
120223
chargelog_log.propagate = False
121224
chargelog_file_handler = RotatingFileHandler(
@@ -124,6 +227,7 @@ def mb_to_bytes(megabytes: int) -> int:
124227
chargelog_file_handler.addFilter(RedactingFilter())
125228
chargelog_log.addHandler(chargelog_file_handler)
126229

230+
# Data migration logger
127231
data_migration_log = logging.getLogger("data_migration")
128232
data_migration_log.propagate = False
129233
data_migration_file_handler = RotatingFileHandler(
@@ -132,6 +236,7 @@ def mb_to_bytes(megabytes: int) -> int:
132236
data_migration_file_handler.addFilter(RedactingFilter())
133237
data_migration_log.addHandler(data_migration_file_handler)
134238

239+
# MQTT logger
135240
mqtt_log = logging.getLogger("mqtt")
136241
mqtt_log.propagate = False
137242
mqtt_file_handler = RotatingFileHandler(RAMDISK_PATH + 'mqtt.log', maxBytes=mb_to_bytes(3), backupCount=1)
@@ -170,19 +275,27 @@ def mb_to_bytes(megabytes: int) -> int:
170275
smarthome_log_handler.addFilter(RedactingFilter())
171276
logging.getLogger().addHandler(smarthome_log_handler)
172277

278+
# SoC logger
173279
soc_log_handler = RotatingFileHandler(RAMDISK_PATH + 'soc.log', maxBytes=mb_to_bytes(2), backupCount=1)
174280
soc_log_handler.setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
175281
soc_log_handler.addFilter(functools.partial(filter_pos, "soc"))
176282
soc_log_handler.addFilter(RedactingFilter())
283+
in_memory_log_handlers["soc"] = InMemoryLogHandler(soc_log_handler)
284+
in_memory_log_handlers["soc"].setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
177285
logging.getLogger().addHandler(soc_log_handler)
286+
logging.getLogger().addHandler(in_memory_log_handlers["soc"])
178287

288+
# Internal chargepoint logger
179289
internal_chargepoint_log_handler = RotatingFileHandler(RAMDISK_PATH + 'internal_chargepoint.log',
180290
maxBytes=mb_to_bytes(1),
181291
backupCount=1)
182292
internal_chargepoint_log_handler.setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
183293
internal_chargepoint_log_handler.addFilter(functools.partial(filter_pos, "Internal Chargepoint"))
184294
internal_chargepoint_log_handler.addFilter(RedactingFilter())
295+
in_memory_log_handlers["internal_chargepoint"] = InMemoryLogHandler(internal_chargepoint_log_handler)
296+
in_memory_log_handlers["internal_chargepoint"].setFormatter(logging.Formatter(FORMAT_STR_DETAILED))
185297
logging.getLogger().addHandler(internal_chargepoint_log_handler)
298+
logging.getLogger().addHandler(in_memory_log_handlers["internal_chargepoint"])
186299

187300
# urllib3 logger
188301
urllib3_log = logging.getLogger("urllib3.connectionpool")

packages/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ def handler_with_control_interval():
172172
self.interval_counter = 1
173173
else:
174174
self.interval_counter = self.interval_counter + 1
175+
176+
# In-Memory Log-Handler zurücksetzen
177+
logger.clear_in_memory_log_handler("main")
178+
175179
log.info("# ***Start*** ")
176180
# log.debug(run_command.run_shell_command("top -b -n 1 | head -n 20"))
177181
# log.debug(f'Drosselung: {run_command.run_shell_command("if which vcgencmd >/dev/null; then vcgencmd get_throttled; else echo not found; fi")}')
@@ -180,6 +184,7 @@ def handler_with_control_interval():
180184
return
181185
try:
182186
handler_with_control_interval()
187+
logger.write_logs_to_file("main")
183188
write_gc_stats()
184189
#print_active_threads_and_referrers()
185190
#analyze_function_origins()

packages/modules/update_soc.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from helpermodules.utils import joined_thread_handler
1313
from modules.common.abstract_vehicle import VehicleUpdateData
1414
from modules.utils import wait_for_module_update_completed
15+
from helpermodules.logger import clear_in_memory_log_handler, write_logs_to_file
1516

1617
log = logging.getLogger(__name__)
1718

@@ -30,14 +31,17 @@ def update(self) -> None:
3031
self.event_update_soc.clear()
3132
topic = "openWB/set/vehicle/set/vehicle_update_completed"
3233
try:
34+
clear_in_memory_log_handler("soc")
3335
threads_update, threads_store = self._get_threads()
3436
joined_thread_handler(threads_update, 300)
3537
wait_for_module_update_completed(self.event_vehicle_update_completed, topic)
3638
# threads_store = self._filter_failed_store_threads(threads_store)
3739
joined_thread_handler(threads_store, data.data.general_data.data.control_interval/3)
3840
wait_for_module_update_completed(self.event_vehicle_update_completed, topic)
41+
write_logs_to_file("soc")
3942
except Exception:
4043
log.exception("Fehler im update_soc-Modul")
44+
write_logs_to_file("soc")
4145

4246
def _get_threads(self) -> Tuple[List[Thread], List[Thread]]:
4347
threads_update, threads_store = [], []

0 commit comments

Comments
 (0)