如何实现Python Logger仅记录ERROR级别以下日志?现有实现是否合理?
Great question! Let's start by evaluating your current implementation, then look at a more idiomatic approach using Python's built-in logging tools.
Your Current Implementation: Is It Reasonable?
First off, your code works perfectly for your requirement—it correctly filters out ERROR and higher-level logs, only keeping INFO and WARNING messages. The core logic of overriding StreamHandler.emit() to skip records with level >= logging.ERROR is sound.
That said, there's a minor redundancy worth noting: you've set handl.setLevel(logging.INFO) alongside your custom max_level check. Since your logger is already configured with logger.setLevel(logging.INFO), the handler's level setting ensures it only receives logs at INFO and above. Your emit() method then adds an extra layer to filter out ERROR+ logs. This isn't a bug, but it's a bit unnecessary—you could technically set the handler's level to logging.WARNING (since you want to keep WARNING and below), but again, your current code doesn't break anything.
A More Idiomatic Approach: Using logging.Filter
Python's logging module provides a dedicated Filter class for exactly this kind of log filtering, which aligns better with the module's design principles (separating logging logic into distinct components: loggers, handlers, filters, and formatters). This approach is more flexible, reusable, and readable.
Here's how you can rewrite your code using a custom Filter:
import logging from logging import StreamHandler, Filter def get_log_formatter(): datefmt = '%b %d %y %H:%M:%S' formatter = logging.Formatter('%(asctime)s [%(module)s:%(levelname)s] %(message)s', datefmt=datefmt) return formatter # Custom filter to keep logs below a specified max level class MaxLevelFilter(Filter): def __init__(self, max_level): self.max_level = max_level def filter(self, record): # Return True to keep the log, False to discard it return record.levelno < self.max_level # Initialize handler and formatter handl = StreamHandler() handl.setLevel(logging.INFO) handl.setFormatter(get_log_formatter()) # Add the filter to the handler handl.addFilter(MaxLevelFilter(logging.ERROR)) logger = logging.getLogger("testing_logger") logger.addHandler(handl) logger.setLevel(logging.INFO)
Why This Is Better:
- Separation of concerns: Handlers handle log output, filters handle log filtering. This makes your code more modular—you can reuse the same
MaxLevelFilterwith any other handler (e.g., a file handler) without rewriting logic. - Flexibility: If you ever need to add more filtering rules, you can simply add additional filters to the handler, rather than modifying a custom handler's
emit()method. - Readability: Other developers familiar with Python's logging module will immediately recognize the filtering logic, instead of having to dig into a custom handler's implementation.
For even simpler cases, you can use a lambda-based filter (no need for a class):
# Lambda filter equivalent to the class above max_level_filter = Filter(lambda record: record.levelno < logging.ERROR) handl.addFilter(max_level_filter)
Final Verdict
Your original implementation is valid and achieves your goal. However, using logging.Filter is the more idiomatic, flexible, and maintainable approach for log filtering in Python.
内容的提问来源于stack exchange,提问作者TheDude

