파일에 기록하고 stdout에 인쇄하는 로거 구성
Python의 로깅 모듈을 사용하여 디버깅 문자열을 파일에 기록하고 있습니다.또한 이 모듈을 사용하여 스트링을 stdout으로 출력합니다.이거 어떻게 해?파일에 문자열을 기록하려면 다음 코드를 사용합니다.
import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
로거 함수를 호출합니다.
logger.debug("I am written to the file")
도와주셔서 감사합니다!
logger에 root logger를 합니다.StreamHandler
. 。StreamHandler
stderr에 . stderr이하고 stdout over stderr도 할 때 합니다.FileHandler
는 모두 두 될 거야)그러면 모든 로그가 두 곳(원하는 것처럼 들립니다)으로 보내집니다.
import logging
logging.getLogger().addHandler(logging.StreamHandler())
" " 에 stdout
stderr
'아까운데'로 됩니다StreamHandler
컨스트럭터
import sys
# ...
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
또 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,Formatter
모든 로그 행에 공통 머리글을 사용할 수 있습니다.
즉,
import logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
rootLogger = logging.getLogger()
fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)
다음의 형식으로 인쇄합니다.
2012-12-05 16:58:26,618 [MainThread ] [INFO ] my message
logging.basicConfig()
키워드 인수를 사용할 수 있습니다.handlers
Python 3.3 이후, 특히 동일한 포맷터로 여러 핸들러를 설정할 때 로깅 설정을 매우 단순화합니다.
handlers
– 지정한 경우 루트 로거에 추가할 이미 작성된 핸들러를 반복할 수 있어야 합니다.포메터 세트가 아직 없는 핸들러에는 이 함수로 작성된 기본 포메터가 할당됩니다.
따라서 다음과 같은 단일 콜로 전체 설정을 수행할 수 있습니다.
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("debug.log"),
logging.StreamHandler()
]
)
(또)와 함께)import sys
+StreamHandler(sys.stdout)
StreamHandler의 디폴트는 stderr에 쓰는 것입니다.로그 형식을 커스터마이즈하여 파일 이름/행, 스레드 정보 등을 추가할 경우 LogRecord 속성을 참조하십시오.)
위의 셋업은 스크립트의 시작 부근에서1회만 실행할 필요가 있습니다.나중에 코드베이스의 다른 모든 장소에서 다음과 같이 로깅을 사용할 수 있습니다.
logging.info('Useful message')
logging.error('Something bad happened')
...
주의: 정상적으로 동작하지 않는 경우는, 다른 유저가 로그 시스템을 다른 방법으로 초기화하고 있을 가능성이 있습니다.에 '아까'라고 써있네요logging.root.handlers = []
의 콜 basicConfig()
.
인수 없이 Stream Handler를 추가하면 stdout이 아닌 stderr로 이동합니다.다른 프로세스가 stdout 덤프(NRPE 플러그인 쓰기 등)에 의존하고 있는 경우 stdout을 명시적으로 지정해야 합니다.그렇지 않으면 예기치 않은 문제가 발생할 수 있습니다.
다음은 질문에서 가정된 값과 LOGFILE을 재사용하는 간단한 예입니다.
import logging
from logging.handlers import RotatingFileHandler
from logging import handlers
import sys
log = logging.getLogger('')
log.setLevel(logging.DEBUG)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)
fh = handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
fh.setFormatter(format)
log.addHandler(fh)
Waterboy의 답변과 다양한 소스를 바탕으로 한 완전하고 깔끔하게 포장된 솔루션을 소개합니다.콘솔 파일과 로그 파일 모두에 대한 로깅을 지원하며 다양한 로그 수준 설정을 허용하고 컬러 출력을 제공하며 쉽게 구성할 수 있습니다(Gist라고도 함).
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------------
# -
# Python dual-logging setup (console and log file), -
# supporting different log levels and colorized output -
# -
# Created by Fonic <https://github.com/fonic> -
# Date: 04/05/20 -
# -
# Based on: -
# https://stackoverflow.com/a/13733863/1976617 -
# https://uran198.github.io/en/python/2016/07/12/colorful-python-logging.html -
# https://en.wikipedia.org/wiki/ANSI_escape_code#Colors -
# -
# -------------------------------------------------------------------------------
# Imports
import os
import sys
import logging
# Logging formatter supporting colorized output
class LogFormatter(logging.Formatter):
COLOR_CODES = {
logging.CRITICAL: "\033[1;35m", # bright/bold magenta
logging.ERROR: "\033[1;31m", # bright/bold red
logging.WARNING: "\033[1;33m", # bright/bold yellow
logging.INFO: "\033[0;37m", # white / light gray
logging.DEBUG: "\033[1;30m" # bright/bold black / dark gray
}
RESET_CODE = "\033[0m"
def __init__(self, color, *args, **kwargs):
super(LogFormatter, self).__init__(*args, **kwargs)
self.color = color
def format(self, record, *args, **kwargs):
if (self.color == True and record.levelno in self.COLOR_CODES):
record.color_on = self.COLOR_CODES[record.levelno]
record.color_off = self.RESET_CODE
else:
record.color_on = ""
record.color_off = ""
return super(LogFormatter, self).format(record, *args, **kwargs)
# Setup logging
def setup_logging(console_log_output, console_log_level, console_log_color, logfile_file, logfile_log_level, logfile_log_color, log_line_template):
# Create logger
# For simplicity, we use the root logger, i.e. call 'logging.getLogger()'
# without name argument. This way we can simply use module methods for
# for logging throughout the script. An alternative would be exporting
# the logger, i.e. 'global logger; logger = logging.getLogger("<name>")'
logger = logging.getLogger()
# Set global log level to 'debug' (required for handler levels to work)
logger.setLevel(logging.DEBUG)
# Create console handler
console_log_output = console_log_output.lower()
if (console_log_output == "stdout"):
console_log_output = sys.stdout
elif (console_log_output == "stderr"):
console_log_output = sys.stderr
else:
print("Failed to set console output: invalid output: '%s'" % console_log_output)
return False
console_handler = logging.StreamHandler(console_log_output)
# Set console log level
try:
console_handler.setLevel(console_log_level.upper()) # only accepts uppercase level names
except:
print("Failed to set console log level: invalid level: '%s'" % console_log_level)
return False
# Create and set formatter, add console handler to logger
console_formatter = LogFormatter(fmt=log_line_template, color=console_log_color)
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
# Create log file handler
try:
logfile_handler = logging.FileHandler(logfile_file)
except Exception as exception:
print("Failed to set up log file: %s" % str(exception))
return False
# Set log file log level
try:
logfile_handler.setLevel(logfile_log_level.upper()) # only accepts uppercase level names
except:
print("Failed to set log file log level: invalid level: '%s'" % logfile_log_level)
return False
# Create and set formatter, add log file handler to logger
logfile_formatter = LogFormatter(fmt=log_line_template, color=logfile_log_color)
logfile_handler.setFormatter(logfile_formatter)
logger.addHandler(logfile_handler)
# Success
return True
# Main function
def main():
# Setup logging
script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if (not setup_logging(console_log_output="stdout", console_log_level="warning", console_log_color=True,
logfile_file=script_name + ".log", logfile_log_level="debug", logfile_log_color=False,
log_line_template="%(color_on)s[%(created)d] [%(threadName)s] [%(levelname)-8s] %(message)s%(color_off)s")):
print("Failed to setup logging, aborting.")
return 1
# Log some messages
logging.debug("Debug message")
logging.info("Info message")
logging.warning("Warning message")
logging.error("Error message")
logging.critical("Critical message")
# Call main function
if (__name__ == "__main__"):
sys.exit(main())
Microsoft Windows 에 관한 주의:
Microsoft Windows 의 클래식한 커맨드 프롬프트로 색칠된 출력이 동작하려면 , 몇개의 추가 코드가 필요합니다.이는 색칠된 즉시 출력을 지원하는 새로운 터미널 앱에는 적용되지 않습니다.
두 가지 옵션이 있습니다.
1) Python 패키지 colorama 를 사용합니다(stdout 및 stderr 에 송신된 출력을 필터링 해, 이스케이프 시퀀스를 네이티브 Windows API 콜로 변환해, Windows XP 이후에 동작합니다).
import colorama
colorama.init()
2) 다음 기능을 사용하여 ANSI 단말기 모드를 활성화합니다(단말기가 플래그를 설정하여 이스케이프 시퀀스를 해석할 수 있습니다).ENABLE_VIRTUAL_TERMINAL_PROCESSING
자세한 내용은 이쪽, 이쪽, 이쪽, 이쪽, 이쪽, 이쪽, Windows 10 이후에서 동작합니다.
# Imports
import sys
import ctypes
# Enable ANSI terminal mode for Command Prompt on Microsoft Windows
def windows_enable_ansi_terminal_mode():
if (sys.platform != "win32"):
return None
try:
kernel32 = ctypes.windll.kernel32
result = kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
if (result == 0): raise Exception
return True
except:
return False
어느쪽이든 실행basicConfig
와 함께stream=sys.stdout
다른 핸들러를 설정하거나 메시지를 기록하기 전에 인수로 지정하거나 수동으로 추가합니다.StreamHandler
메시지를 루트 로거(또는 기타 필요한 로거)에 stdout으로 푸시합니다.
로그인처stdout
그리고.rotating file
수준과 형식이 다릅니다.
import logging
import logging.handlers
import sys
if __name__ == "__main__":
# Change root logger level from WARNING (default) to NOTSET in order for all messages to be delegated.
logging.getLogger().setLevel(logging.NOTSET)
# Add stdout handler, with level INFO
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.INFO)
formater = logging.Formatter('%(name)-13s: %(levelname)-8s %(message)s')
console.setFormatter(formater)
logging.getLogger().addHandler(console)
# Add file rotating handler, with level DEBUG
rotatingHandler = logging.handlers.RotatingFileHandler(filename='rotating.log', maxBytes=1000, backupCount=5)
rotatingHandler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rotatingHandler.setFormatter(formatter)
logging.getLogger().addHandler(rotatingHandler)
log = logging.getLogger("app." + __name__)
log.debug('Debug message, should only appear in the file.')
log.info('Info message, should appear in file and stdout.')
log.warning('Warning message, should appear in file and stdout.')
log.error('Error message, should appear in file and stdout.')
여러 Python 패키지에서 Waterboy의 코드를 여러 번 사용한 후, 나는 마침내 작은 독립형 Python 패키지에 그것을 넣었습니다.여기서 찾을 수 있습니다.
https://github.com/acschaefer/duallog
코드가 잘 문서화되어 있어 사용하기 쉽습니다.다운로드만 하면.py
파일에 저장하여 프로젝트에 포함시키거나 전체 패키지를 설치하세요.pip install duallog
.
다음 모듈을 통해 로그와 인쇄를 디스크, stdout 및 stderr의 파일로 동시에 리다이렉트하는 작업을 수행했습니다(Gist도 여기에 있습니다).
import logging
import pathlib
import sys
from ml.common.const import LOG_DIR_PATH, ML_DIR
def create_log_file_path(file_path, root_dir=ML_DIR, log_dir=LOG_DIR_PATH):
path_parts = list(pathlib.Path(file_path).parts)
relative_path_parts = path_parts[path_parts.index(root_dir) + 1:]
log_file_path = pathlib.Path(log_dir, *relative_path_parts)
log_file_path = log_file_path.with_suffix('.log')
# Create the directories and the file itself
log_file_path.parent.mkdir(parents=True, exist_ok=True)
log_file_path.touch(exist_ok=True)
return log_file_path
def set_up_logs(file_path, mode='a', level=logging.INFO):
log_file_path = create_log_file_path(file_path)
logging_handlers = [logging.FileHandler(log_file_path, mode=mode),
logging.StreamHandler(sys.stdout)]
logging.basicConfig(
handlers=logging_handlers,
format='%(asctime)s %(name)s %(levelname)s %(message)s',
level=level
)
class OpenedFileHandler(logging.FileHandler):
def __init__(self, file_handle, filename, mode):
self.file_handle = file_handle
super(OpenedFileHandler, self).__init__(filename, mode)
def _open(self):
return self.file_handle
class StandardError:
def __init__(self, buffer_stderr, buffer_file):
self.buffer_stderr = buffer_stderr
self.buffer_file = buffer_file
def write(self, message):
self.buffer_stderr.write(message)
self.buffer_file.write(message)
class StandardOutput:
def __init__(self, buffer_stdout, buffer_file):
self.buffer_stdout = buffer_stdout
self.buffer_file = buffer_file
def write(self, message):
self.buffer_stdout.write(message)
self.buffer_file.write(message)
class Logger:
def __init__(self, file_path, mode='a', level=logging.INFO):
self.stdout_ = sys.stdout
self.stderr_ = sys.stderr
log_file_path = create_log_file_path(file_path)
self.file_ = open(log_file_path, mode=mode)
logging_handlers = [OpenedFileHandler(self.file_, log_file_path,
mode=mode),
logging.StreamHandler(sys.stdout)]
logging.basicConfig(
handlers=logging_handlers,
format='%(asctime)s %(name)s %(levelname)s %(message)s',
level=level
)
# Overrides write() method of stdout and stderr buffers
def write(self, message):
self.stdout_.write(message)
self.stderr_.write(message)
self.file_.write(message)
def flush(self):
pass
def __enter__(self):
sys.stdout = StandardOutput(self.stdout_, self.file_)
sys.stderr = StandardError(self.stderr_, self.file_)
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self.stdout_
sys.stderr = self.stderr_
self.file_.close()
콘텍스트 매니저로 작성하면 python 스크립트에 다음 행을 추가하는 것만으로 기능을 추가할 수 있습니다.
from logger import Logger
...
if __name__ == '__main__':
with Logger(__file__):
main()
이 질문에서는 구체적으로 로거 설정을 요구하는 경우가 있습니다만, 다른 접근법으로는 로거 설정을 변경할 필요가 없습니다.logging
리다이렉트도 필요 없습니다.stdout
.
다소 단순하지만 효과가 있습니다.
def log_and_print(message: str, level: int, logger: logging.Logger):
logger.log(level=level, msg=message) # log as normal
print(message) # prints to stdout by default
를들 、 대신 、 。logger.debug('something')
는 리리지지 we we we라고 부른다log_and_print(message='something', level=logging.DEBUG, logger=logger)
.
또, 이것을 조금 더 확대해, 다음에 인쇄합니다.stdout
다음 중 하나:
def log_print(message: str, level: int, logger: logging.Logger):
# log the message normally
logger.log(level=level, msg=message)
# only print to stdout if the message is not logged to stdout
msg_logged_to_stdout = False
current_logger = logger
while current_logger and not msg_logged_to_stdout:
is_enabled = current_logger.isEnabledFor(level)
logs_to_stdout = any(
getattr(handler, 'stream', None) == sys.stdout
for handler in current_logger.handlers
)
msg_logged_to_stdout = is_enabled and logs_to_stdout
if not current_logger.propagate:
current_logger = None
else:
current_logger = current_logger.parent
if not msg_logged_to_stdout:
print(message)
와 그 가 로거, 로거, 로거, 로거, 로거 부모로 합니다.stdout
및 로거가 지정된 수준에서 활성화 되어 있는지 여부를 확인합니다.
이 기능은 퍼포먼스에 최적화되어 있지 않습니다.
2.7 의 경우는, 다음을 시험해 주세요.
fh = logging.handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
언급URL : https://stackoverflow.com/questions/13733552/logger-configuration-to-log-to-file-and-print-to-stdout
'programing' 카테고리의 다른 글
랜덤 (Java 7)의 181783497276652981 및 8682522807148012는 무엇입니까? (0) | 2022.10.26 |
---|---|
이미 데이터가 포함된 MariaDB 테이블에 키를 추가하려면 어떻게 해야 합니까? (0) | 2022.10.26 |
entity-manager가 있는 경우 session 개체를 가져오려면 어떻게 해야 합니까? (0) | 2022.10.26 |
.so 파일에 기호를 나열하려면 어떻게 해야 합니까? (0) | 2022.10.26 |
MariaDB 10의 FULLTEXT 색인 (0) | 2022.10.26 |