logging
logging은 디버깅 및 오류 해결, 코드 유지 보수, 시스템 모니터링을 돕기 위해 중요한 역할을 한다.
로깅을 도입해야하는 주요 이유들은 다음과 같다.
1. 문제 해결 및 디버깅
logging
은 프로그램 실행 중 발생하는 이벤트와 상태를 기록하여 문제 발생 시 빠른 원인 파악이 가능하다.
예를 들어, 코드의 특정 부분에 오류가 발생하거나 예외 처리가 발동될 때 그에 대한 상세한 로그가 남아 있으면 문제 해결이 용이해진다.
2. 운영 환경에서의 모니터링
print()
와 같은 방법으로는 로그를 효과적으로 관리하기가 매우 어렵다.
반면 logging
모듈은 로그 메시지를 다양한 수준(예: DEBUG
, INFO
, WARNING
, ERROR
, CRITICAL
)으로 분류하고,
파일, 콘솔, 원격 서버 등 다양한 대상에 로그를 출력할 수 있게 해준다.
이를 통해 운영 환경에서 시스템을 모니터링하고 경고 또는 오류 발생 시 신속한 대처가 가능해진다.
3. 가독성 및 관리 용이
logging
모듈은 로그 메시지의 형식을 사용자가 지정할 수도 있고, 시간, 모듈 이름, 라인 번호 등과 같은 추가 정보를 포함할 수 있어
로그의 가독성이 향상된다.
이는 유지보수에 매우 유리하다.
Getting Started
1. 기본적인 로깅 사용 방법
logging
모듈은 애플리케이션에서 이벤트를 기록하기 위한 기본적인 방법을 제공한다.
로그 메시지를 기록하려면 간단하게 logging
의 함수를 호출하면 끝이다.
logging
모듈은 다섯 가지의 로그 수준을 제공한다:
DEBUG
INFO
WARNING
ERROR
CRITICAL
각 수준은 메시지의 중요도를 나타낸다.
코드 예제
import logging
# 기본 로깅 설정
logging.basicConfig(level=logging.INFO)
logging.debug("This is a debug message")
logging.info("This is an info message")
logging.warning("This is a warning message")
logging.error("This is an error message")
logging.critical("This is a critical message")
출력 결과
INFO:root:This is an info message
WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical message
여기서 DEBUG
메시지는 출력되지 않는다! 이유는 기본 설정의 로그 레벨(level=logging.INFO
)이 INFO
이기 때문이다.
2. 로그 형식과 레벨 설정하는 방법
로그 형식(format
)과 레벨(level
)은 사용자의 요구 사항에 따라 커스텀이 가능하다.
basicConfig
를 활용하여 다양한 형식 지정이 가능하다.
코드 예제
import logging
# 로그 형식 설정
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
logging.debug("Debugging the application")
logging.info("Information level log")
logging.warning("This is a warning")
logging.error("An error has occurred")
logging.critical("Critical error!")
출력 결과
2025-01-10 12:34:56 - root - DEBUG - Debugging the application
2025-01-10 12:34:56 - root - INFO - Information level log
2025-01-10 12:34:56 - root - WARNING - This is a warning
2025-01-10 12:34:56 - root - ERROR - An error has occurred
2025-01-10 12:34:56 - root - CRITICAL - Critical error!
주요 포맷 지정자
%(asctime)s
: 로그 발생 시간%(name)s
: 로거의 이름%(levelname)s
: 로그 레벨%(message)s
: 로그 메시지
3. 로그를 파일로 저장하는 방법
로그를 파일로 저장하려면 basicConfig
의 filename
파라미터를 사용하면 된다.
코드 예제
import logging
# 로그를 파일로 저장
logging.basicConfig(
level=logging.INFO,
filename="application.log",
filemode="w",
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("This log will be written to a file")
logging.warning("Another log entry in the file")
출력 결과
application.log
파일에 다음과 같은 로그가 기록된다.
2025-01-10 12:35:56 - INFO - This log will be written to a file
2025-01-10 12:35:56 - WARNING - Another log entry in the file
4. logging의 핸들러(Handler) 사용 방법과 종류
핸들러(Handler)는 로그 메시지를 다양한 출력 대상으로 보낼 수 있도록 도와준다.
예를 들어, 콘솔, 파일, 네트워크 등이 있다.
주요 핸들러 종류
StreamHandler
: 콘솔에 로그를 출력함.FileHandler
: 파일에 로그를 저장하도록 함.NullHandler
: 로그를 무시하도록 함.SocketHandler
,HTTPHandler
: 네트워크로 로그 전송
코드 예제
import logging
# 로거 생성
logger = logging.getLogger("MyLogger")
logger.setLevel(logging.DEBUG)
# 콘솔 핸들러
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 파일 핸들러
file_handler = logging.FileHandler("detailed.log")
file_handler.setLevel(logging.DEBUG)
# 핸들러에 포맷 설정
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 핸들러를 로거에 추가
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.debug("This will be written to the file")
logger.info("This will appear in console and file")
logger.warning("Warning logged")
출력 결과
1. 콘솔:
2025-01-10 12:36:56 - INFO - This will appear in console and file
2025-01-10 12:36:56 - WARNING - Warning logged
2. detailed.log
파일:
2025-01-10 12:36:56 - DEBUG - This will be written to the file
2025-01-10 12:36:56 - INFO - This will appear in console and file
2025-01-10 12:36:56 - WARNING - Warning logged
여러 핸들러를 지정해줄 수도 있다.
basicConfig
에 handlers
파라미터에 여러 핸들러를 지정해줄 수도 있다.
import logging
logging.basicConfig(
handlers=[
logging.FileHandler(filename="app.log", encoding="utf-8"),
logging.StreamHandler(),
]
)
이 예제에서는 FileHandler
와 StreamHandler
를 지정하였다.
5. 로테이팅 파일 핸들러(RotatingFileHandler) 사용 방법
RotatingFileHandler
를 사용하면 로그 파일이 특정 크기를 초과했을 때, 새 파일로 자동 전환된다.
코드 예제
import logging
from logging.handlers import RotatingFileHandler
# 로테이팅 파일 핸들러 설정
rotating_handler = RotatingFileHandler(
"rotating.log", maxBytes=1024, backupCount=3
)
rotating_handler.setFormatter(logging.Formatter("%(asctime)s - %(message)s"))
logger = logging.getLogger("RotatingLogger")
logger.setLevel(logging.DEBUG)
logger.addHandler(rotating_handler)
# 여러 로그 메시지 작성
for i in range(100):
logger.info(f"Log message {i}")
결과
rotating.log
: 최신 로그rotating.log.1
,rotating.log.2
등: 백업된 로그 파일
실생활 예제
1. 모듈이 나눠져 있을 때 logging 통합하기
여러 모듈로 나눠진 경우에는 logging
을 어떻게 구현해야 할까?
다음과 같은 프로젝트 구조가 있다고 가정해보자.
.
├── main.py
├── modules
│ ├── basecamp_alert.py
│ ├── basecamp_demolition.py
│ ├── change_bot_status.py
├── README.md
├── requirements.txt
여기서 main.py
와 modules
디렉토리 하위에 있는 각각의 파일에 로깅을 설정하고 싶다면 어떻게 해야할까?
각각의 파일에 로깅을 설정하고 각각 다른 파일로 로그를 생성해야하는걸까?
logging
에서는 전역 로깅 설정을 구성하여 모듈에서 일관된 로깅 포맷과 설정을 사용하도록 구성해줄 수 있다.
2-1. main.py에서 전역 로깅 설정하기
메인 스크립트에서 전역 로깅 설정을 구성해보자. 이를 통해 모든 모듈에서 일관된 로깅 포맷과 설정 사용이 가능하다.
import logging
# 전역 로깅 설정
logging.basicConfig(
level=logging.INFO, # 로그 레벨: INFO, DEBUG, WARNING 등
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
handlers=[
logging.FileHandler("bot.log", encoding="utf-8"), # 파일에 로그 저장
logging.StreamHandler() # 콘솔에 로그 출력
]
)
def start() -> None:
logging.info(msg="start() 함수가 실행되었습니다.)
return "Hi"
if __name__ == "__main__":
start()
2-2. 모듈별로 로거 사용하기
각 모듈 파일에서 logging.getLogger(__name__)
을 사용하여 모듈별 로거를 생성해주자.
modules/basecamp_alert.py
import logging
from discord.ext import commands
# 이 모듈의 로거
logger = logging.getLogger(__name__)
def start() -> None:
logging.info(msg="basecamp_alert.py 의 start() 함수가 실행되었습니다!")
return "basecamp"
if __name__ == '__main__':
start()
2-3. 코드 실행 후 로그 확인해보기
코드를 실행하고 로그를 확인해보면 bot.log
파일에 다음과 같은 로그가 출력될거다.
2024-05-09 12:00:00 [INFO] modules.basecamp_alert: basecamp_alert.py 의 start() 함수가 실행되었습니다!