로깅 모듈 소개
Python의 로깅 모듈은 타사 모듈이나 애플리케이션에서 사용할 수 있는 일반적인 로깅 시스템을 제공합니다. 이 모듈은 다양한 로그 수준을 제공하며 파일, HTTP GET/POST, SMTP, 소켓 등과 같은 다양한 방식으로 로그를 기록할 수 있습니다. 특정 로깅 방법을 직접 구현할 수도 있습니다.
로깅 모듈과 log4j의 메커니즘은 동일하지만 구체적인 구현 세부 사항은 다릅니다. 이 모듈은 로거, 처리기, 필터 및 포맷터를 제공합니다.
log4j와 유사하게 로거, 핸들러 및 로그 메시지에 대한 호출은 로그 메시지의 레벨이 로거 및 핸들러의 레벨보다 높은 경우에만 특정 로그 레벨(레벨)을 가질 수 있습니다.
로깅 사용량 분석
1. 로거 초기화 = login.getLogger("endlesscode"). 후속 로그 형식의 %(name)s는 다음과 같습니다. 모듈 이름은 여기에 있습니다
2. logger.setLevel(logging.DEBUG) 수준을 설정합니다. NOTSET < DEBUG < WARNING < ERROR < CRITICAL.
3. 흔히 사용되는 핸들러는 StreamHandler와 FileHandler가 있습니다. Windows에서는 하나는 콘솔과 파일 로그이고, 하나는 CMD 창에 출력되고, 다른 하나는 파일에 기록된다고 간단히 이해하시면 됩니다.
4. 최종 로그 정보의 순서, 구조 및 내용을 정의하는 포맷터. 나는 '[%(asctime)s] [%(levelname)s] %(message)s', '%Y- 형식을 사용하는 것을 좋아합니다. %m -%d %H:%M:%S',
%(name)s 로거 이름
텍스트 형식의 %(levelname)s 로그 수준
%(message)s 사용자가 출력한 메시지
%(asctime)s 현재 시간을 문자열로 나타냅니다. 기본 형식은 "2003-07-08 16:49:45,896"입니다. 쉼표 뒤에 오는 것은 밀리초입니다
%(levelno)s 숫자 형식의 로그 수준
%(pathname)s 로그 출력 함수를 호출하는 모듈의 전체 경로 이름에는
이 포함되지 않을 수 있습니다.
%(filename)s 로그 출력 함수를 호출하는 모듈의 파일 이름
%(module)s 로그 출력 함수를 호출하는 모듈 이름
%(funcName)s는 로그 출력 함수를 호출하는 함수 이름입니다
%(lineno)d 로그 출력 함수를 호출하는 문장이 위치한 코드라인
%(created)f 현재 시간, 시간을 나타내는 UNIX 표준 부동 소수점 숫자로 표시
%(relativeCreated)d 로그 정보 출력 시 Logger가 생성된 후 경과된 시간(밀리초)
%(thread)d 스레드 ID입니다. 아마도 아닐 것이다
%(threadName)s 스레드 이름입니다. 아마도 아닐 것이다
%(process)d 프로세스 ID입니다. 아마도 아닐 것이다
5. 기록 object.debug(message)를 사용하여 로그를 기록하세요
CMD 창에는 error 레벨 이상의 로그만 출력되고, debug 레벨 이상의 정보는 로그에 출력되는 예를 들어보겠습니다
import logging logger = logging.getLogger("simple_example") logger.setLevel(logging.DEBUG) # 建立一个filehandler来把日志记录在文件里,级别为debug以上 fh = logging.FileHandler("spam.log") fh.setLevel(logging.DEBUG) # 建立一个streamhandler来把日志打在CMD窗口上,级别为error以上 ch = logging.StreamHandler() ch.setLevel(logging.ERROR) # 设置日志格式 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") ch.setFormatter(formatter) fh.setFormatter(formatter) #将相应的handler添加在logger对象中 logger.addHandler(ch) logger.addHandler(fh) # 开始打日志 logger.debug("debug message") logger.info("info message") logger.warn("warn message") logger.error("error message") logger.critical("critical message")실행해 보면 CMD 창에는 2개의 로그만 기록되고 spam.log에는 5개의 로그가 기록되는 것을 볼 수 있습니다
프로젝트가 상대적으로 크고 Log가 다른 파일에서 사용되는 경우 이를 클래스로 캡슐화하여 사용하는 것을 고려할 수 있습니다
#! /usr/bin/env python #coding=gbk import logging,os class Logger: def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG): self.logger = logging.getLogger(path) self.logger.setLevel(logging.DEBUG) fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S') #设置CMD日志 sh = logging.StreamHandler() sh.setFormatter(fmt) sh.setLevel(clevel) #设置文件日志 fh = logging.FileHandler(path) fh.setFormatter(fmt) fh.setLevel(Flevel) self.logger.addHandler(sh) self.logger.addHandler(fh) def debug(self,message): self.logger.debug(message) def info(self,message): self.logger.info(message) def war(self,message): self.logger.warn(message) def error(self,message): self.logger.error(message) def cri(self,message): self.logger.critical(message) if __name__ =='__main__': logyyx = Logger('yyx.log',logging.ERROR,logging.DEBUG) logyyx.debug('一个debug信息') logyyx.info('一个info信息') logyyx.war('一个warning信息') logyyx.error('一个error信息') logyyx.cri('一个致命critical信息')이런 방식으로 객체를 사용할 때마다 객체를 인스턴스화하기만 하면 됩니다
logobj = Logger(‘filename',clevel,Flevel)CMD 창에서 오류 로그를 빨간색으로, 경고 로그를 노란색으로 표시하려면 ctypes 모듈을 사용하면 됩니다
#! /usr/bin/env python #coding=gbk import logging,os import ctypes FOREGROUND_WHITE = 0x0007 FOREGROUND_BLUE = 0x01 # text color contains blue. FOREGROUND_GREEN= 0x02 # text color contains green. FOREGROUND_RED = 0x04 # text color contains red. FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN STD_OUTPUT_HANDLE= -11 std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) def set_color(color, handle=std_out_handle): bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color) return bool class Logger: def __init__(self, path,clevel = logging.DEBUG,Flevel = logging.DEBUG): self.logger = logging.getLogger(path) self.logger.setLevel(logging.DEBUG) fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S') #设置CMD日志 sh = logging.StreamHandler() sh.setFormatter(fmt) sh.setLevel(clevel) #设置文件日志 fh = logging.FileHandler(path) fh.setFormatter(fmt) fh.setLevel(Flevel) self.logger.addHandler(sh) self.logger.addHandler(fh) def debug(self,message): self.logger.debug(message) def info(self,message): self.logger.info(message) def war(self,message,color=FOREGROUND_YELLOW): set_color(color) self.logger.warn(message) set_color(FOREGROUND_WHITE) def error(self,message,color=FOREGROUND_RED): set_color(color) self.logger.error(message) set_color(FOREGROUND_WHITE) def cri(self,message): self.logger.critical(message) if __name__ =='__main__': logyyx = Logger('yyx.log',logging.WARNING,logging.DEBUG) logyyx.debug('一个debug信息') logyyx.info('一个info信息') logyyx.war('一个warning信息') logyyx.error('一个error信息') logyyx.cri('一个致命critical信息')
여러 모듈에 로깅 사용
로깅 모듈은 동일한 Python 인터프리터 내에서 여러 모듈이 있는 경우에도 login.getLogger('log_name')에 대한 여러 호출이 동일한 로거 인스턴스를 반환하도록 보장합니다. 따라서 다중 모듈 시나리오에서 로깅을 사용하는 일반적인 방법은 기본 모듈에서 로깅을 구성하는 것입니다. 이 구성은 여러 하위 모듈에 영향을 미치고 다른 모듈의 getLogger를 통해 Logger 개체를 직접 가져옵니다.
구성 파일:
[loggers] keys=root,main [handlers] keys=consoleHandler,fileHandler [formatters] keys=fmt [logger_root] level=DEBUG handlers=consoleHandler [logger_main] level=DEBUG qualname=main handlers=fileHandler [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=fmt args=(sys.stdout,) [handler_fileHandler] class=logging.handlers.RotatingFileHandler level=DEBUG formatter=fmt args=('tst.log','a',20000,5,) [formatter_fmt] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt=메인 모듈 main.py:
import logging import logging.config logging.config.fileConfig('logging.conf') root_logger = logging.getLogger('root') root_logger.debug('test root logger...') logger = logging.getLogger('main') logger.info('test main logger') logger.info('start import module \'mod\'...') import mod logger.debug('let\'s test mod.testLogger()') mod.testLogger() root_logger.info('finish test...')하위 모듈 mod.py:
import logging import submod logger = logging.getLogger('main.mod') logger.info('logger of mod say something...') def testLogger(): logger.debug('this is mod.testLogger...') submod.tst()하위 하위 모듈 submod.py:
import logging logger = logging.getLogger('main.mod.submod') logger.info('logger of submod say something...') def tst(): logger.info('this is submod.tst()...')
然后运行python main.py,控制台输出:
2012-03-09 18:22:22,793 - root - DEBUG - test root logger... 2012-03-09 18:22:22,793 - main - INFO - test main logger 2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()... 2012-03-09 18:22:22,841 - root - INFO - finish test...
可以看出,和预想的一样,然后在看一下tst.log,logger配置中的输出的目的地:
2012-03-09 18:22:22,793 - main - INFO - test main logger 2012-03-09 18:22:22,809 - main - INFO - start import module 'mod'... 2012-03-09 18:22:22,809 - main.mod.submod - INFO - logger of submod say something... 2012-03-09 18:22:22,809 - main.mod - INFO - logger say something... 2012-03-09 18:22:22,809 - main - DEBUG - let's test mod.testLogger() 2012-03-09 18:22:22,825 - main.mod - DEBUG - this is mod.testLogger... 2012-03-09 18:22:22,825 - main.mod.submod - INFO - this is submod.tst()...
tst.log中没有root logger输出的信息,因为logging.conf中配置了只有main logger及其子logger使用RotatingFileHandler,而root logger是输出到标准输出。