33import atexit
44import io
55import logging
6- import os
76import re
87import threading
98import time
109from dataclasses import dataclass
1110from datetime import datetime
1211from functools import reduce
12+ from pathlib import Path
1313from typing import Optional, List, Tuple
1414
1515import parse # type: ignore[import-untyped]
2222
2323from .arrow import FeatherWriter
2424
25+ logger = logging.getLogger(__name__)
2526
2627def root_dir() -> str:
2728 """Return the root directory for slog files."""
2829
2930 app_name = "meshtastic"
3031 app_author = "meshtastic"
3132 app_dir = platformdirs.user_data_dir(app_name, app_author)
32- dir_name = f"{ app_dir}/ slogs"
33- os.makedirs(dir_name, exist_ok=True)
34- return dir_name
33+ dir_name = Path( app_dir, " slogs")
34+ dir_name.mkdir( exist_ok=True)
35+ return str( dir_name)
3536
3637
3738@dataclass(init=False)
@@ -197,7 +198,7 @@ def _onLogMessage(self, line: str) -> None:
197198 if m:
198199 src = m.group(1)
199200 args = m.group(2)
200- logging .debug(f"SLog {src}, args: {args}")
201+ logger .debug(f"SLog {src}, args: {args}")
201202
202203 d = log_defs.get(src)
203204 if d:
@@ -219,9 +220,9 @@ def _onLogMessage(self, line: str) -> None:
219220 # If the last field is an empty string, remove it
220221 del di[last_field[0]]
221222 else:
222- logging .warning(f"Failed to parse slog {line} with {d.format}")
223+ logger .warning(f"Failed to parse slog {line} with {d.format}")
223224 else:
224- logging .warning(f"Unknown Structured Log: {line}")
225+ logger .warning(f"Unknown Structured Log: {line}")
225226
226227 # Store our structured log record
227228 if di or self.include_raw:
@@ -256,18 +257,22 @@ def __init__(
256257
257258 if not dir_name:
258259 app_dir = root_dir()
259- dir_name = f"{ app_dir}/{ datetime.now().strftime('%Y%m%d-%H%M%S')}"
260- os.makedirs(dir_name, exist_ok=True)
260+ dir_name = Path( app_dir, datetime.now().strftime('%Y%m%d-%H%M%S'))
261+ dir_name.mkdir( exist_ok=True)
261262
262263 # Also make a 'latest' directory that always points to the most recent logs
264+ latest_dir = Path(app_dir, "latest")
265+ latest_dir.unlink(missing_ok=True)
266+
263267 # symlink might fail on some platforms, if it does fail silently
264- if os.path.exists(f"{app_dir}/latest"):
265- os.unlink(f"{app_dir}/latest")
266- os.symlink(dir_name, f"{app_dir}/latest", target_is_directory=True)
268+ try:
269+ latest_dir.symlink_to(dir_name, target_is_directory=True)
270+ except OSError as e:
271+ pass
267272
268273 self.dir_name = dir_name
269274
270- logging .info(f"Writing slogs to {dir_name}")
275+ logger .info(f"Writing slogs to {dir_name}")
271276
272277 self.power_logger: Optional[PowerLogger] = (
273278 None
@@ -286,7 +291,7 @@ def close(self) -> None:
286291 """Close the log set."""
287292
288293 if self.slog_logger:
289- logging .info(f"Closing slogs in {self.dir_name}")
294+ logger .info(f"Closing slogs in {self.dir_name}")
290295 atexit.unregister(
291296 self.atexit_handler
292297 ) # docs say it will silently ignore if not found
0 commit comments