-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix logger implementation errors and standardize on new loguru system…
… and expectations
- Loading branch information
Showing
3 changed files
with
232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
""" | ||
Guidellm is a package that provides an easy and intuitive interface for | ||
evaluating and benchmarking large language models (LLMs). | ||
""" | ||
|
||
from .logger import LoggerConfig, configure_logger, logger | ||
|
||
__all__ = ["logger", "configure_logger", "LoggerConfig"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
""" | ||
Logger configuration for GuideLLM. | ||
This module provides a flexible logging configuration using the loguru library. | ||
It supports console and file logging with options to configure via environment | ||
variables or direct function calls. | ||
Environment Variables: | ||
- GUIDELLM_LOG_DISABLED: Disable logging (default: false). | ||
- GUIDELLM_CLEAR_LOGGERS: Clear existing loggers from loguru (default: true). | ||
- GUIDELLM_LOG_LEVEL: Log level for console logging | ||
(default: none, options: DEBUG, INFO, WARNING, ERROR, CRITICAL). | ||
- GUIDELLM_LOG_FILE: Path to the log file for file logging | ||
(default: guidellm.log if log file level set else none) | ||
- GUIDELLM_LOG_FILE_LEVEL: Log level for file logging | ||
(default: INFO if log file set else none). | ||
Usage: | ||
from guidellm import logger, configure_logger, LoggerConfig | ||
# Configure metrics with default settings | ||
configure_logger( | ||
config=LoggerConfig( | ||
disabled=False, | ||
clear_loggers=True, | ||
console_log_level="DEBUG", | ||
log_file=None, | ||
log_file_level=None, | ||
) | ||
) | ||
logger.debug("This is a debug message") | ||
logger.info("This is an info message") | ||
""" | ||
|
||
import os | ||
import sys | ||
from dataclasses import dataclass | ||
from typing import Optional | ||
|
||
from loguru import logger | ||
|
||
__all__ = ["LoggerConfig", "configure_logger", "logger"] | ||
|
||
|
||
@dataclass | ||
class LoggerConfig: | ||
disabled: bool = False | ||
clear_loggers: bool = True | ||
console_log_level: Optional[str] = "INFO" | ||
log_file: Optional[str] = None | ||
log_file_level: Optional[str] = None | ||
|
||
|
||
def configure_logger(config: Optional[LoggerConfig] = None): | ||
""" | ||
Configure the metrics for LLM Compressor. | ||
This function sets up the console and file logging | ||
as per the specified or default parameters. | ||
Note: Environment variables take precedence over the function parameters. | ||
:param config: The configuration for the logger to use. | ||
:type config: LoggerConfig | ||
""" | ||
|
||
_ENV_CONFIG = LoggerConfig( | ||
disabled=os.getenv("GUIDELLM_LOG_DISABLED") == "true", | ||
clear_loggers=os.getenv("GUIDELLM_CLEAR_LOGGERS") == "true", | ||
console_log_level=os.getenv("GUIDELLM_LOG_LEVEL"), | ||
log_file=os.getenv("GUIDELLM_LOG_FILE"), | ||
log_file_level=os.getenv("GUIDELLM_LOG_FILE_LEVEL"), | ||
) | ||
|
||
if not config: | ||
config = LoggerConfig() | ||
# override from environment variables, if set | ||
logger_config = LoggerConfig( | ||
disabled=_ENV_CONFIG.disabled or config.disabled, | ||
console_log_level=_ENV_CONFIG.console_log_level or config.console_log_level, | ||
log_file=_ENV_CONFIG.log_file or config.log_file, | ||
log_file_level=_ENV_CONFIG.log_file_level or config.log_file_level, | ||
) | ||
|
||
if logger_config.disabled: | ||
logger.disable("guidellm") | ||
return | ||
|
||
logger.enable("guidellm") | ||
|
||
if logger_config.clear_loggers: | ||
logger.remove() | ||
|
||
if logger_config.console_log_level: | ||
# log as a human readable string with the time, function, level, and message | ||
logger.add( | ||
sys.stdout, | ||
level=logger_config.console_log_level.upper(), | ||
format="{time} | {function} | {level} - {message}", | ||
) | ||
|
||
if logger_config.log_file or logger_config.log_file_level: | ||
log_file = logger_config.log_file or "guidellm.log" | ||
log_file_level = logger_config.log_file_level or "INFO" | ||
# log as json to the file for easier parsing | ||
logger.add(log_file, level=log_file_level.upper(), serialize=True) | ||
|
||
|
||
# invoke logger setup on import with default values enabling console logging with INFO | ||
# and disabling file logging | ||
configure_logger( | ||
config=LoggerConfig( | ||
disabled=False, | ||
clear_loggers=True, | ||
console_log_level="INFO", | ||
log_file=None, | ||
log_file_level=None, | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import pytest | ||
|
||
from guidellm import LoggerConfig, configure_logger, logger | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def reset_logger(): | ||
# Ensure logger is reset before each test | ||
logger.remove() | ||
yield | ||
logger.remove() | ||
|
||
|
||
def test_default_logger_settings(capsys): | ||
configure_logger() | ||
|
||
# Default settings should log to console with INFO level and no file logging | ||
logger.info("Info message") | ||
logger.debug("Debug message") | ||
|
||
captured = capsys.readouterr() | ||
assert captured.out.count("Info message") == 1 | ||
assert "Debug message" not in captured.out | ||
|
||
|
||
def test_configure_logger_console_settings(capsys): | ||
# Test configuring the logger to change console log level | ||
config = LoggerConfig(console_log_level="DEBUG") | ||
configure_logger(config=config) | ||
logger.info("Info message") | ||
logger.debug("Debug message") | ||
|
||
captured = capsys.readouterr() | ||
assert captured.out.count("Info message") == 1 | ||
assert captured.out.count("Debug message") == 1 | ||
|
||
|
||
def test_configure_logger_file_settings(tmp_path): | ||
# Test configuring the logger to log to a file | ||
log_file = tmp_path / "test.log" | ||
config = LoggerConfig(log_file=str(log_file), log_file_level="DEBUG") | ||
configure_logger(config=config) | ||
logger.info("Info message") | ||
logger.debug("Debug message") | ||
|
||
with open(log_file, "r") as f: | ||
log_contents = f.read() | ||
assert log_contents.count('"message": "Info message"') == 1 | ||
assert log_contents.count('"message": "Debug message"') == 1 | ||
|
||
|
||
def test_configure_logger_console_and_file(capsys, tmp_path): | ||
# Test configuring the logger to change both console and file settings | ||
log_file = tmp_path / "test.log" | ||
config = LoggerConfig( | ||
console_log_level="ERROR", log_file=str(log_file), log_file_level="INFO" | ||
) | ||
configure_logger(config=config) | ||
logger.info("Info message") | ||
logger.error("Error message") | ||
|
||
captured = capsys.readouterr() | ||
assert "Info message" not in captured.out | ||
assert captured.out.count("Error message") == 1 | ||
|
||
with open(log_file, "r") as f: | ||
log_contents = f.read() | ||
assert log_contents.count('"message": "Info message"') == 1 | ||
assert log_contents.count('"message": "Error message"') == 1 | ||
|
||
|
||
def test_environment_variable_override(monkeypatch, capsys, tmp_path): | ||
# Test environment variables override settings | ||
monkeypatch.setenv("GUIDELLM_LOG_LEVEL", "ERROR") | ||
monkeypatch.setenv("GUIDELLM_LOG_FILE", str(tmp_path / "env_test.log")) | ||
monkeypatch.setenv("GUIDELLM_LOG_FILE_LEVEL", "DEBUG") | ||
|
||
configure_logger(config=LoggerConfig()) | ||
logger.info("Info message") | ||
logger.error("Error message") | ||
logger.debug("Debug message") | ||
|
||
captured = capsys.readouterr() | ||
assert "Info message" not in captured.out | ||
assert captured.out.count("Error message") == 1 | ||
assert "Debug message" not in captured.out | ||
|
||
with open(tmp_path / "env_test.log", "r") as f: | ||
log_contents = f.read() | ||
assert log_contents.count('"message": "Error message"') == 1 | ||
assert log_contents.count('"message": "Info message"') == 1 | ||
assert log_contents.count('"message": "Debug message"') == 1 | ||
|
||
|
||
def test_environment_variable_disable_logging(monkeypatch, capsys): | ||
# Test environment variable to disable logging | ||
monkeypatch.setenv("GUIDELLM_LOG_DISABLED", "true") | ||
|
||
configure_logger(config=LoggerConfig()) | ||
logger.info("Info message") | ||
logger.error("Error message") | ||
|
||
captured = capsys.readouterr() | ||
assert captured.out == "" | ||
assert captured.err == "" |