Python 로거가 로그 파일 외에 모든 메시지를 stdout으로 출력하게 만들기


450

logging모듈을 사용하여 Python 로깅 을 수행하면 로그 파일 외에도 stdout으로 자동으로 출력 하는 방법 이 있습니까? 예를 들어, 나는 모든 통화를하고 싶습니다 logger.warning, logger.critical, logger.error의도 한 장소로 이동하지만, 또한 항상에 복사 stdout. 이것은 다음과 같은 메시지 복제를 피하기위한 것입니다.

mylogger.critical("something failed")
print "something failed"

1
이 답변을 확인하십시오. stackoverflow.com/questions/9321741/…
SeF

답변:


635

모든 로깅 출력은 핸들러에 의해 처리됩니다. logging.StreamHandler()루트 로거에 추가하십시오 .

다음은 스트림 핸들러를 구성하고 ( stdoutdefault 대신 사용 stderr) 루트 로거에 추가 하는 예제입니다 .

import logging
import sys

root = logging.getLogger()
root.setLevel(logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)

4
괜찮지 만 이미 파일로 리디렉션 된 경우 어떻게 stdout추가 로 인쇄 할 수 있습니까?

54
@ user248237 : 그림과 같이 핸들러 를 추가합니다 . 기존 핸들러를 대체하지 않는 새로운 핸들러, 그들은 또한 로그 항목을 처리 할 수.
Martijn Pieters

@MartijnPieters 인쇄 된 모든 로그 문에 문자열을 추가하는 방법이 있습니까?
Prakhar Mohan Srivastava

7
@PrakharMohanSrivastava에 전달 된 문자열에 추가 할 수 있다고 생각합니다 logging.Formatter.
A.Wan

3
@ himanshu219 : 유스 케이스는 여러 핸들러를 추가하자마자 차별화하려는 것입니다. 콘솔에 경고, 경고 및 파일 등
Martijn Pieters

505

stdout에 로그인하는 가장 간단한 방법 :

import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

57
흠, 그러나 이것은 파일에 기록되지 않습니다. 문제는 파일 콘솔에 로깅하는 방법이었습니다 .
Weidenrinde


적어도 파이썬 3에서는 생략해도 stream=sys.stdout여전히 콘솔에 로깅하는 것으로 보입니다 .
Taylor Edmiston

3
@TaylorEdmiston 그래,하지만 그것은 stderr 스트림 AFAIK입니다. 셸에서 출력을 리디렉션하십시오.
Sorin

1
확인. 이것은 파일과 콘솔에 로깅하는 것이 아니라 3 줄 이하로 필요한 것을 찾는 것이 좋았습니다.
Steve3p0

67

여러 핸들러를 사용하는 것이 가능합니다.

import logging
import auxiliary_module

# create logger with 'spam_application'
log = logging.getLogger('spam_application')
log.setLevel(logging.DEBUG)

# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(fh)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
ch.setFormatter(formatter)
log.addHandler(ch)

log.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
log.info('created an instance of auxiliary_module.Auxiliary')

log.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
log.info('finished auxiliary_module.Auxiliary.do_something')

log.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
log.info('done with auxiliary_module.some_function()')

# remember to close the handlers
for handler in log.handlers:
    handler.close()
    log.removeFilter(handler)

https://docs.python.org/2/howto/logging-cookbook.html을 참조 하십시오


4
조금 지저분하지만 멋진 대답. 스트림과 파일에 다른 레벨과 형식을 사용하는 방법을 보여주는 방법을 좋아하십시오. +1, 정신 +2
The Unfun Cat

나를 위해 이것은 sys.stdout매개 변수 없이 작동하지 않았습니다ch = logging.StreamHandler()
veuncent

64

file 및 stdout에 대한 두 개의 핸들러를 작성한 후에 handlers인수를 사용하여 하나의 로거를 작성할 수 basicConfig있습니다. 두 핸들러에 대해 동일한 log_level 및 형식 출력이있는 경우 유용 할 수 있습니다.

import logging
import sys

file_handler = logging.FileHandler(filename='tmp.log')
stdout_handler = logging.StreamHandler(sys.stdout)
handlers = [file_handler, stdout_handler]

logging.basicConfig(
    level=logging.DEBUG, 
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
    handlers=handlers
)

logger = logging.getLogger('LOGGER_NAME')

32

파일과 stderr에 로그인하는 가장 간단한 방법 :

import logging

logging.basicConfig(filename="logfile.txt")
stderrLogger=logging.StreamHandler()
stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
logging.getLogger().addHandler(stderrLogger)

콘솔의 로깅 메시지 앞에 INFO, DEBUG 및 ERROR 레이블이 표시되지 않습니다. 파일에 해당 레이블이 표시됩니다. 콘솔에 레이블을 표시하는 아이디어가 있습니까?
JahMyst

1
감사합니다, @JahMyst, 나는 포매터를 추가했습니다. 불행히도 더 이상 짧지는 않지만 여전히 가장 간단한 방법입니다. :-)
Weidenrinde

12

강력하지만 문서화가 잘되지 않은 logging.config.dictConfig방법을 기반으로 한 솔루션이 있습니다 . 대신에 모든 로그 메시지를 보내는 stdout, 그것은 로그 수준과 메시지 전송 ERROR및 이상으로 stderr하고 다른 모든 것을 stdout. 시스템의 다른 부분이 stderr또는을 듣고있는 경우 유용 할 수 있습니다 stdout.

import logging
import logging.config
import sys

class _ExcludeErrorsFilter(logging.Filter):
    def filter(self, record):
        """Filters out log messages with log level ERROR (numeric value: 40) or higher."""
        return record.levelno < 40


config = {
    'version': 1,
    'filters': {
        'exclude_errors': {
            '()': _ExcludeErrorsFilter
        }
    },
    'formatters': {
        # Modify log message format here or replace with your custom formatter class
        'my_formatter': {
            'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'console_stderr': {
            # Sends log messages with log level ERROR or higher to stderr
            'class': 'logging.StreamHandler',
            'level': 'ERROR',
            'formatter': 'my_formatter',
            'stream': sys.stderr
        },
        'console_stdout': {
            # Sends log messages with log level lower than ERROR to stdout
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filters': ['exclude_errors'],
            'stream': sys.stdout
        },
        'file': {
            # Sends all log messages to a file
            'class': 'logging.FileHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filename': 'my.log',
            'encoding': 'utf8'
        }
    },
    'root': {
        # In general, this should be kept at 'NOTSET'.
        # Otherwise it would interfere with the log levels set for each handler.
        'level': 'NOTSET',
        'handlers': ['console_stderr', 'console_stdout', 'file']
    },
}

logging.config.dictConfig(config)

실제로 루트 로거를 얻으려면 로거의 이름을 빈 문자열로 바꿔야했습니다. 그렇지 않으면 매우 도움이됩니다. 감사합니다!
Newtopian September

8

깔끔한 2 개의 라이너를 공유 한 사람이 없기 때문에 본인의 것을 공유 할 것입니다.

logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())

2

다음은 매우 간단한 예입니다.

import logging
l = logging.getLogger("test")

# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)

# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)

# Send a test message to both -- critical will always log
l.critical("test msg")

출력은 stdout 및 파일에도 "test msg"를 표시합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.