Add log_handler/src/log_handler/core.py
This commit is contained in:
parent
7941c11255
commit
95156ff5d3
1 changed files with 85 additions and 0 deletions
85
log_handler/src/log_handler/core.py
Normal file
85
log_handler/src/log_handler/core.py
Normal file
|
|
@ -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<timestamp>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})")
|
||||
_TEMPERATURE_PATTERN = re.compile(
|
||||
r"temperature:\s*(?P<temperature>-?\d+(?:\.\d+)?)C.*sensor_temp:\s*(?P<sensor_temp>-?\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
|
||||
Loading…
Reference in a new issue