반응형
로깅, StreamHandler 및 표준 스트림
정보 수준 메시지는 stdout에 기록하는 방법을 알 수 없지만 모든 메시지는 stderr에 기록됩니다. 나는 이미 http://docs.python.org/library/logging.html을 읽었습니다 . 어떠한 제안?
다음 펼쳐보기 log1.py
:
import logging, sys
class SingleLevelFilter(logging.Filter):
def __init__(self, passlevel, reject):
self.passlevel = passlevel
self.reject = reject
def filter(self, record):
if self.reject:
return (record.levelno != self.passlevel)
else:
return (record.levelno == self.passlevel)
h1 = logging.StreamHandler(sys.stdout)
f1 = SingleLevelFilter(logging.INFO, False)
h1.addFilter(f1)
rootLogger = logging.getLogger()
rootLogger.addHandler(h1)
h2 = logging.StreamHandler(sys.stderr)
f2 = SingleLevelFilter(logging.INFO, True)
h2.addFilter(f2)
rootLogger.addHandler(h2)
logger = logging.getLogger("my.logger")
logger.setLevel(logging.DEBUG)
logger.debug("A DEBUG message")
logger.info("An INFO message")
logger.warning("A WARNING message")
logger.error("An ERROR message")
logger.critical("A CRITICAL message")
실행하면 다음과 같은 결과가 생성됩니다.
C : \ temp> log1.py 디버그 메시지 정보 메시지 경고 메시지 오류 메시지 중요한 메시지
예상대로 터미널에서 sys.stdout
와 sys.stderr
동일합니다. 이제 stdout을 파일로 리디렉션 해 보겠습니다 tmp
.
C : \ temp> log1.py> tmp 디버그 메시지 경고 메시지 오류 메시지 중요한 메시지
따라서 정보는 터미널에 메시지 인쇄되지 않았지만 지시 된 메시지 sys.stderr
는 인쇄되었습니다. 내용을 살펴 보겠습니다 tmp
.
C : \ temp> tmp 유형 정보 메시지
그래서 당신이 원하는 것을 원하는 것으로 보입니다.
일반적으로 나는 그것을 말이 생각 리디렉션 메시지보다 낮은 WARNING
에 표준 출력 대신만의, INFO
메시지 .
Vinay Sajip 의 존재를 바탕으로 다음과 같이 생각했습니다.
class MaxLevelFilter(Filter):
'''Filters (lets through) all messages with level < LEVEL'''
def __init__(self, level):
self.level = level
def filter(self, record):
return record.levelno < self.level # "<" instead of "<=": since logger.setLevel is inclusive, this should be exclusive
MIN_LEVEL= DEBUG
#...
stdout_hdlr = StreamHandler(sys.stdout)
stderr_hdlr = StreamHandler(sys.stderr)
lower_than_warning= MaxLevelFilter(WARNING)
stdout_hdlr.addFilter( lower_than_warning ) #messages lower than WARNING go to stdout
stdout_hdlr.setLevel( MIN_LEVEL )
stderr_hdlr.setLevel( max(MIN_LEVEL, WARNING) ) #messages >= WARNING ( and >= STDOUT_LOG_LEVEL ) go to stderr
#...
내 편집이 거부되었습니다. @goncalopp의 대답은 좋지만 혼자서 상자에서 작동하지 않습니다. 개선 된 버전은 다음과 가변됩니다.
import sys, logging
class LogFilter(logging.Filter):
"""Filters (lets through) all messages with level < LEVEL"""
# http://stackoverflow.com/a/24956305/408556
def __init__(self, level):
self.level = level
def filter(self, record):
# "<" instead of "<=": since logger.setLevel is inclusive, this should
# be exclusive
return record.levelno < self.level
MIN_LEVEL = logging.DEBUG
stdout_hdlr = logging.StreamHandler(sys.stdout)
stderr_hdlr = logging.StreamHandler(sys.stderr)
log_filter = LogFilter(logging.WARNING)
stdout_hdlr.addFilter(log_filter)
stdout_hdlr.setLevel(MIN_LEVEL)
stderr_hdlr.setLevel(max(MIN_LEVEL, logging.WARNING))
# messages lower than WARNING go to stdout
# messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr
rootLogger = logging.getLogger()
rootLogger.addHandler(stdout_hdlr)
rootLogger.addHandler(stderr_hdlr)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Example Usage
>>> logger.debug("A DEBUG message")
>>> logger.info("An INFO message")
>>> logger.warning("A WARNING message")
>>> logger.error("An ERROR message")
>>> logger.critical("A CRITICAL message")
이 원숭이 패치를 사용 ~~
import sys
import logging
import threading
def _logging_handle(self, record):
self.STREAM_LOCKER = getattr(self, "STREAM_LOCKER", threading.RLock())
if self.stream in (sys.stdout, sys.stderr) and record.levelname in self.FIX_LEVELS:
try:
self.STREAM_LOCKER.acquire()
self.stream = sys.stdout
self.old_handle(record)
self.stream = sys.stderr
finally:
self.STREAM_LOCKER.release()
else:
self.old_handle(record)
def patch_logging_stream(*levels):
"""
writing some logging level message to sys.stdout
example:
patch_logging_stream(logging.INFO, logging.DEBUG)
logging.getLogger('root').setLevel(logging.DEBUG)
logging.getLogger('root').debug('test stdout')
logging.getLogger('root').error('test stderr')
"""
stream_handler = logging.StreamHandler
levels = levels or [logging.DEBUG, logging.INFO]
stream_handler.FIX_LEVELS = [logging.getLevelName(i) for i in levels]
if hasattr(stream_handler, "old_handle"):
stream_handler.handle = stream_handler.old_handle
stream_handler.old_handle = stream_handler.handle
stream_handler.handle = _logging_handle
테스트
#
patch_logging_stream(logging.INFO, logging.DEBUG)
logging.getLogger('root').setLevel(logging.DEBUG)
logging.getLogger('root').debug('test root stdout')
logging.getLogger('root').error('test root stderr')
테스트 출력
$ python3 test_patch_logging.py 2>/dev/null
DEBUG:root:test root stdout
$ python3 test_patch_logging.py 1>/dev/null
ERROR:root:test root stderr
컬러 출력을 stderr로 가장 간단한 방법 :
class ColorStderr(logging.StreamHandler):
def __init__(self):
class AddColor(logging.Formatter):
def format(self, record: logging.LogRecord):
msg = super().format(record)
# Green/Cyan/Yellow/Red/Redder based on log level:
color = '\033[1;' + ('32m', '36m', '33m', '31m', '41m')[
min(4,int(4 * record.levelno / logging.FATAL))]
return color + record.levelname + '\033[1;0m: ' + msg
super().__init__(sys.stderr)
self.setFormatter(AddColor())
함께 사용 :
logging.basicConfig(level=logging.INFO, handlers=[ColorStderr()])
또는 다음 없이도 포맷터를 현재 로그에 직접 적용 할 수도 있습니다 ColorStderr
.
logging.getLogger().handlers[0].setFormatter(AddColor())
참고 URL : https://stackoverflow.com/questions/1383254/logging-streamhandler-and-standard-streams
반응형
'ProgramingTip' 카테고리의 다른 글
정수 접미사 J는 무엇을 의미합니까? (0) | 2020.11.28 |
---|---|
Convert.ChangeType 및 열거 형으로 변환? (0) | 2020.11.28 |
addTarget : action : forControlEvents : method에 해당하는 UIButton 블록 (0) | 2020.11.27 |
ORA-00904 : 잘못된 식별자 (0) | 2020.11.27 |
명령의 배열에 할당 할당입니까? (0) | 2020.11.27 |