2021년 10월 8일 금요일

python 멀티 로그 레벨을 가지는 로거(how to set multi setlevel in python logger)

python logger를 사용하면서 우리는 가끔 파일로 출력되는 레벨과 화면으로 출력되는 레벨을 다르게 하고 싶은 경우가 있습니다.

여기에서는 핸들러별 level을 설정하는 방법에 대해서 알아보겠습니다.

기본적으로 handler 별로 설정하는건 간단합나다만, 동작중에 값을 변경시키고 기존 library에 값을 변경하는 예제를 만들어보았습니다.


예제 아래는 기존에 사용하던 color 출력기능을 가진 예제입니다. 여기에 레벨을 변경하는 기능을 가지도록 수정하였습니다.

import datetime
import sys
import os
import time
import logging
import colorlog
from logging import FileHandler
from logging import handlers

class CustomLog:
	def __init__(self):
		self.rotatingHandler = None
		self.fileHandler = None
		self.streamHandler = None
		pass
		
	def create(self,logfolder='', app_name=__name__, logprefix='log_', NEED_BACKUP_FILE = True, NEED_SCREEN_AND_FILE = True, level=logging.DEBUG, format='[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', maxBytes=10*1024*1024, backupCount = 10, encoding='utf-8', color=True):
		LOG_PREFIX = logprefix
		LOG_FOLDER_NAME = logfolder
		# 로그 파일 핸들러
		now = datetime.datetime.now().isoformat()[:10]
		logf = LOG_PREFIX + now + ".log"
		if LOG_FOLDER_NAME!='' and not os.path.exists(LOG_FOLDER_NAME):
			os.makedirs(LOG_FOLDER_NAME)
		logf = os.path.join(LOG_FOLDER_NAME, logf)
		logger = self.getLogger(logf, app_name, NEED_BACKUP_FILE, NEED_SCREEN_AND_FILE, level, format, maxBytes, backupCount, encoding, color)
		logger.logfilename_ = logf
		return logger

	def getLogger(self, filename, app_name, NEED_BACKUP_FILE, NEED_SCREEN_AND_FILE, level, format, maxBytes, backupCount, encoding, color):
		if color :
			self.logger = colorlog.getLogger(app_name)
		else:
			self.logger = logging.getLogger(app_name)
		
		self.logger.handlers.clear()
		self.logger.propagate = False
		# log level은 아래 순서에 따른다. setLevel 과 같거나 큰 출력만 나오게 된다.
		# logger.setLevel(logging.CRITICAL) 인 경우 logger.critical() 만 나온다
		#
		# logger.debug("debug")
		# logger.info("info")
		# logger.warning("warning")
		# logger.error("error")
		# logger.critical("critical")
		self.logger.setLevel(level)

		# 포맷을 결정한다. 좀더 자세한 정보는 다음 링크를 참조한다
		# https://docs.python.org/3/library/logging.html#logrecord-attributes
		if color :
			logFormatter = colorlog.ColoredFormatter('%(log_color)s'+format)
		else :
			logFormatter = logging.Formatter(format)
		
		if NEED_BACKUP_FILE == True:
			self.rotatingHandler = handlers.RotatingFileHandler(filename=filename, maxBytes=maxBytes, backupCount = backupCount, encoding=encoding)
			self.rotatingHandler.setFormatter(logFormatter)
			self.logger.addHandler(self.rotatingHandler)
		else:
			self.fileHandler = logging.FileHandler(filename)
			self.fileHandler.setFormatter(logFormatter)
			self.logger.addHandler(self.fileHandler)

		# StreamHandler 는 self.logger.critical("critical") 이런 형태의 로그가 화면으로도 나오고 file로도 저장이 되도록 한다
		if NEED_SCREEN_AND_FILE == True:
			self.streamHandler = logging.StreamHandler()
			self.streamHandler.setFormatter(logFormatter)
			self.logger.addHandler(self.streamHandler)
		return self.logger
	def setLevel(self,filelevel,streamlevel):
		if self.rotatingHandler :
			self.rotatingHandler.setLevel(filelevel)
		if self.fileHandler :
			self.fileHandler.setLevel(filelevel)
		if self.streamHandler :
			self.streamHandler.setLevel(streamlevel)
		
	
	
if __name__ == "__main__":
	LOG = CustomLog()
	logger = LOG.create('log')
	print("test")
	logger.debug("debug test")
	logger.info("info test")
	logger.warning("warning test")
	logger.error("error test")
	logger.critical("critical test")
	LOG.setLevel(filelevel=logging.INFO,streamlevel=logging.ERROR)
	logger.debug("debug test")
	logger.info("info test")
	logger.warning("warning test")
	logger.error("error test")
	logger.critical("critical test")

main 쪽을 보면 아래와 같은 부분이 있습니다.

파일은 INFO 이상 stream(화면 출력은) ERROR 이상이 나오도록 설정하는 코드 입니다.

LOG.setLevel(filelevel=logging.INFO,streamlevel=logging.ERROR)

코드를 따라가보면 저장된 핸들러들에 각각 setLevel 하는 부분이 보입니다.

위와 같이 하면 콘솔에서는 아래와 같이 출력됩니다.

[2021-10-07 20:38:50,724] DEBUG [_23_logger_multi_level.py.<module>:84] debug test
[2021-10-07 20:38:50,725] INFO [_23_logger_multi_level.py.<module>:85] info test
[2021-10-07 20:38:50,726] WARNING [_23_logger_multi_level.py.<module>:86] warning test
[2021-10-07 20:38:50,728] ERROR [_23_logger_multi_level.py.<module>:87] error test
[2021-10-07 20:38:50,729] CRITICAL [_23_logger_multi_level.py.<module>:88] critical test
[2021-10-07 20:38:50,730] ERROR [_23_logger_multi_level.py.<module>:93] error test
[2021-10-07 20:38:50,731] CRITICAL [_23_logger_multi_level.py.<module>:94] critical test

자세히 보시면 똑같이 두벌 출력이 되어야하는데 두번째 debug test, info test, warning test 가 출력이 되지 않았습니다. streamlevel은 ERROR로 설정했기 때문입니다.

이때 저장된 파일을 보면 아래와 같습니다.

[2021-10-07 20:38:50,724] DEBUG [_23_logger_multi_level.py.<module>:84] debug test
[2021-10-07 20:38:50,725] INFO [_23_logger_multi_level.py.<module>:85] info test
[2021-10-07 20:38:50,726] WARNING [_23_logger_multi_level.py.<module>:86] warning test
[2021-10-07 20:38:50,728] ERROR [_23_logger_multi_level.py.<module>:87] error test
[2021-10-07 20:38:50,729] CRITICAL [_23_logger_multi_level.py.<module>:88] critical test
[2021-10-07 20:38:50,730] INFO [_23_logger_multi_level.py.<module>:91] info test
[2021-10-07 20:38:50,730] WARNING [_23_logger_multi_level.py.<module>:92] warning test
[2021-10-07 20:38:50,730] ERROR [_23_logger_multi_level.py.<module>:93] error test
[2021-10-07 20:38:50,731] CRITICAL [_23_logger_multi_level.py.<module>:94] critical test

filelevel=logging.INFO 영향으로 debug test 만 한번 출력되었습니다. 


참고할만한 링크

python logger,colored log (컬러 로거 logger)

https://swlock.blogspot.com/2021/10/python-loggercolored-log-logger.html

댓글 없음:

댓글 쓰기