From 95156ff5d3e09c73606c7f8233d18056d687b650 Mon Sep 17 00:00:00 2001 From: Mika Date: Sun, 15 Mar 2026 03:07:36 +0000 Subject: [PATCH] Add log_handler/src/log_handler/core.py --- log_handler/src/log_handler/core.py | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 log_handler/src/log_handler/core.py diff --git a/log_handler/src/log_handler/core.py b/log_handler/src/log_handler/core.py new file mode 100644 index 0000000..8e0c311 --- /dev/null +++ b/log_handler/src/log_handler/core.py @@ -0,0 +1,85 @@ +import re +import json +import logging +from dataclasses import dataclass +from datetime import datetime +from pathlib import Path +from typing import List + + +logger = logging.getLogger(__name__) + + +@dataclass +class TemperatureLog: + timestamp: str + temperature: float + sensor_temp: float + + +class LogParseError(Exception): + """Custom exception raised when a log line cannot be parsed.""" + + +_TIMESTAMP_PATTERN = re.compile(r"(?P\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})") +_TEMPERATURE_PATTERN = re.compile( + r"temperature:\s*(?P-?\d+(?:\.\d+)?)C.*sensor_temp:\s*(?P-?\d+(?:\.\d+)?)C" +) + + +def _validate_log_file_path(log_file_path: str) -> Path: + path = Path(log_file_path) + if not path.exists() or not path.is_file(): + raise FileNotFoundError(f"Logfile '{log_file_path}' not found or not a file.") + return path + + +def _parse_line(line: str) -> TemperatureLog | None: + timestamp_match = _TIMESTAMP_PATTERN.search(line) + temp_match = _TEMPERATURE_PATTERN.search(line) + + if timestamp_match and temp_match: + timestamp = timestamp_match.group("timestamp") + try: + # Validate timestamp format + datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S") + except ValueError: + logger.warning("Invalid timestamp format in line: %s", line.strip()) + return None + + try: + temperature = float(temp_match.group("temperature")) + sensor_temp = float(temp_match.group("sensor_temp")) + except (ValueError, TypeError): + logger.warning("Invalid temperature values in line: %s", line.strip()) + return None + + return TemperatureLog(timestamp=timestamp, temperature=temperature, sensor_temp=sensor_temp) + return None + + +def parse_log_file(log_file_path: str) -> List[TemperatureLog]: + """ + Parse a raw camera log file and extract structured temperature and sensor information. + + Args: + log_file_path (str): Path to the logfile. + + Returns: + List[TemperatureLog]: List of structured temperature logs. + """ + logger.debug("Starting to parse log file: %s", log_file_path) + path = _validate_log_file_path(log_file_path) + results: List[TemperatureLog] = [] + + with path.open("r", encoding="utf-8") as f: + for line_no, line in enumerate(f, start=1): + parsed = _parse_line(line) + if parsed: + results.append(parsed) + else: + logger.debug("Line %d skipped: no valid data.", line_no) + + assert all(isinstance(t, TemperatureLog) for t in results), "Parsed data validation failed." + logger.info("Parsed %d valid temperature entries from %s", len(results), log_file_path) + return results \ No newline at end of file