diff --git a/sdv/logging/logger.py b/sdv/logging/logger.py index 52a178638..adc2c1b25 100644 --- a/sdv/logging/logger.py +++ b/sdv/logging/logger.py @@ -1,11 +1,35 @@ """SDV Logger.""" - +import csv import logging from functools import lru_cache +from io import StringIO from sdv.logging.utils import get_sdv_logger_config +class CSVHandler(logging.Formatter): + """Logging formatter to convert to CSV.""" + + def __init__(self): + super().__init__() + self.output = StringIO() + headers = [ + 'LEVEL', 'EVENT', 'TIMESTAMP', 'SYNTHESIZER CLASS NAME', 'SYNTHESIZER ID', + 'TOTAL NUMBER OF TABLES', 'TOTAL NUMBER OF ROWS', 'TOTAL NUMBER OF COLUMNS' + ] + self.writer = csv.DictWriter(self.output, headers) + + def format(self, record): # noqa: A003 + """Format the record and write to CSV.""" + row = record.msg + row['LEVEL'] = record.levelname + self.writer.writerow(row) + data = self.output.getvalue() + self.output.truncate(0) + self.output.seek(0) + return data.strip() + + @lru_cache() def get_sdv_logger(logger_name): """Get a logger instance with the specified name and configuration. @@ -35,7 +59,7 @@ def get_sdv_logger(logger_name): logger.removeHandler(handler) if logger_name in logger_conf.get('loggers'): - formatter = None + formatter = CSVHandler() config = logger_conf.get('loggers').get(logger_name) log_level = getattr(logging, config.get('level', 'INFO')) if config.get('format'): diff --git a/tests/unit/logging/test_logger.py b/tests/unit/logging/test_logger.py index 4770d39cd..82481e5af 100644 --- a/tests/unit/logging/test_logger.py +++ b/tests/unit/logging/test_logger.py @@ -2,7 +2,31 @@ import logging from unittest.mock import Mock, patch -from sdv.logging.logger import get_sdv_logger +from sdv.logging.logger import CSVHandler, get_sdv_logger + + +class TestCSVHandler: + + def test_format(self): + """Test CSV formatter correctly formats the log entry.""" + # Setup + instance = CSVHandler() + instance.writer = Mock() + instance.output = Mock() + record = Mock() + record.msg = { + 'EVENT': 'Instance', + 'TIMESTAMP': '2024-04-19 16:20:10.037183', + 'SYNTHESIZER CLASS NAME': 'GaussianCopulaSynthesizer', + 'SYNTHESIZER ID': 'GaussainCopulaSynthesizer_1.0.0_92aff11e9a5649d1a280990d1231a5f5', + } + record.levelname = 'INFO' + + # Run + instance.format(record) + + # Assert + assert instance.writer.writerow.called_once_with({'LEVEL': 'INFO', **record.msg}) @patch('sdv.logging.logger.logging.StreamHandler')