diff --git a/src/harmonization_framework/replay_log/replay_logger.py b/src/harmonization_framework/replay_log/replay_logger.py index 4361398..fd93845 100644 --- a/src/harmonization_framework/replay_log/replay_logger.py +++ b/src/harmonization_framework/replay_log/replay_logger.py @@ -9,6 +9,14 @@ class Event: dataset: str def to_log(self): + """ + Serialize an event to a JSON-compatible dict. + + Returns: + dict with keys: + - action: serialized harmonization rule + - dataset: dataset identifier + """ log = { "action": self.action.serialize(), "dataset": self.dataset, @@ -16,6 +24,19 @@ def to_log(self): return log def _get_log_level(level: int): + """ + Map a numeric log level to a logging module constant. + + Args: + level: integer in the range 1-4. + 1 -> CRITICAL + 2 -> ERROR + 3 -> INFO + 4 -> DEBUG + + Returns: + A logging level constant. + """ match level: case 1: return logging.CRITICAL @@ -29,9 +50,22 @@ def _get_log_level(level: int): return ValueError(f"Invalid log level: {level}") def configure_logger(level: int, log_file: str): + """ + Configure a replay logger that writes JSON lines to a file. + + Args: + level: integer log level (1-4). + log_file: path to the output log file. + + Returns: + A configured logger instance. + """ # create logger logger = logging.getLogger("ReplayLogger") + # clear any existing handlers to avoid duplicate log entries + logger.handlers.clear() + # set logging level log_level = _get_log_level(level) logger.setLevel(log_level) @@ -48,5 +82,8 @@ def configure_logger(level: int, log_file: str): return logger def log_operation(logger, action, dataset): + """ + Log a single replay event for a given harmonization action and dataset. + """ event = Event(action, dataset) logger.info(json.dumps(event.to_log())) diff --git a/tests/test_replay_logger.py b/tests/test_replay_logger.py new file mode 100644 index 0000000..b7859ce --- /dev/null +++ b/tests/test_replay_logger.py @@ -0,0 +1,20 @@ +import logging + +from harmonization_framework.replay_log import replay_logger as rlog + + +def test_configure_logger_clears_handlers(tmp_path): + log1 = tmp_path / "log1.jsonl" + log2 = tmp_path / "log2.jsonl" + + logger1 = rlog.configure_logger(3, str(log1)) + assert len(logger1.handlers) == 1 + + logger2 = rlog.configure_logger(3, str(log2)) + assert logger2 is logger1 + assert len(logger2.handlers) == 1 + + # Ensure the active handler points to the most recent log file + handler = logger2.handlers[0] + assert isinstance(handler, logging.FileHandler) + assert handler.baseFilename == str(log2)