PYTHON/etc contents

파이썬 로그(log)와 포매터 사용하기

  • -

실제로 여러 프로그래밍 프로그램(python, C++ 등)들을 사용하다보면 오류가 발생하는 것을 어렵지 않게 확인할 수 있다. 사실 파이썬에 대한 얕은 지식을 바탕으로 한 아주 작고 개인적인 견해를 내놓자면 프로그래밍은 사실 오류를 찾아내고 오류가 없도록 버그를 정리하는 일이 모두라고 봐도 무방하다고 본다. 그렇기 때문에 어떤 오류가 발생했을 경우에 그것을 보다 편리하고 직관적으로 확인할 수 있도록 하는 작업이 필요하다.

하지만 파이썬을 시작한지 얼마 지나지 않은 입문 개발자의 경우에는 아래와 같은 코드를 자주 사용할 것이다.

print("여기에요?")
##### 
코드
#####

print("아님 여기에요?")
#####
코드
#####

이와 같은 코드를 작성해놓고, '여기에요?'가 잘 출력되었다면 그 아래 부분이 문제가 있는 것이고 '아님 여기에요?'가 출력되었다면 그 아래 부분에 문제가 있다는 것을 확인하곤 한다.

따라서 이번 게시글에서는 지금 어느 코드를 진행하고 있는지를 보다 직관적으로 확인할 수 있도록 하는 코드를 작성함으로써 print문을 통한 버그 확인에서 벗어나는 방법에 대해 알아보고자 한다.

 

로그(log)가 뭔데?

파이썬에서의 로그(log)란 단순하게 기록을 남기는 것 정도로 이해하면 된다.
코드의 경우에는 가장 단순한 형태가 아래의 코드와 같은 형태일 것 같다.

import logging
import logging.handlers

log = logging.getLogger('backtest_log')
logging.basicConfig(filename='./log.txt', filemode='w')
log.setLevel(logging.DEBUG)

formatter = logging.Formatter('[%(levelname)s] (%(filename)s:%(lineno)d) %(message)s')

fileHandler = logging.FileHandler('./log.txt')
streamHandler = logging.StreamHandler()

fileHandler.setFormatter(formatter)
streamHandler.setFormatter(formatter)

log.addHandler(fileHandler)
log.addHandler(streamHandler)

if __name__ == '__main__':
    log.debug('debug')
    log.info('info')
    log.warning('warning')
    log.error('error')
    log.critical('critical')

위의 코드를 보면 맨 아래 부분에서 if문을 통해 이 코드가 실행될 경우 debug에 대해서는 debug("~~~")를, info에 대해서는 info("~~~~")를 나타내도록 정의하고 있다.

위 코드를 그대로 실행할 경우에는 아래와 같은 결과물이 나올 것이다.

[DEBUG] (set_logging.py:27) debug
[INFO] (set_logging.py:28) info
[WARNING] (set_logging.py:29) warning
[ERROR] (set_logging.py:30) error
[CRITICAL] (set_logging.py:31) critical

즉, 로그를 사용할 때에는 log.debug, log.info와 같은 형태로 사용한다는 것을 알 수 있다. 이제 이를 다른 파일에서 사용하고 싶다면, 파일이름.log.debug와 같은 형태로 사용할 수 있다. 아래에서 구체적으로 살펴보자.

 

 


728x90

 

 

그래서 그거 어떻게 쓰는 건데?

본인의 경우에는 위의 코드를 하나의 모듈처럼 작성해둔 후, 다른 파일에서 해당 모듈을 임포트한 후에 사용하고 있다.
모듈을 만드는 방법과 모듈을 임포트하는 방법은 아래의 글을 참조하도록 하자!

 

모듈이란 무엇인가?

모듈(module)이란? 파이썬 내에서는 모듈(module)을 잘 사용하게 된다. 흔히 게임을 다운로드 한다던지, 아니면 프로그램을 다운로드 한다던지 하는 경우에 설치 폴더 내에 수많은 파일들이 설치되

trustyou.tistory.com

 

설명에 앞서, 본인의 경우에는 로그 모듈 코드가 들어 있는 파일의 이름을 'set_logging'이라고 설정해두었다. 따라서 특정 코드에서 해당 로그 모듈을 사용하기 위해서는 import set_logging이라는 코드를 작성함으로써 임포트할 수 있고, 해당 모듈을 사용하기 위해서는 set_logging.을 입력하고 그 안에서 사용하고자 하는 것들을 입력하면 된다.

import set_logging

set_logging.log.debug("debug가 발생했습니다.")
set_logging.log.info("info가 발생했습니다.")
set_logging.log.warn("warn이 발생했습니다.")
set_logging.log.error("error가 발생했습니다.")
set_logging.log.critical("critical이 발생했습니다.")

 

 

로그(log)의 순위

로그를 보면 디버그(debug)부터 크리티컬(critical)까지 총 5개의 로그 방법이 있는데, 단순하게 말하자면 위험도의 순위라고 생각하면 된다. 가장 낮은 단계인 디버그(debug)는 단순하게 작성한 코드를 실행하면서 지금 어느 함수를 사용하고 있는지 등을 확인하고자 할 때 사용하면 되고, 그 다음 단계인 정보(info) 같은 경우에는 해당 함수에서 얻은 변수는 무엇이고 현재 어떤 변수에 어떤 값이 들어가있는지를 확인하고자 할 때 사용하면 된다.

마찬가지로 error나 critical같은 경우에는 반드시 있어야 하는 변수가 입력이 안 되었다거나 할 경우에 사용하면 적절한 로그를 남길 수 있게 된다.

그리고 맨 위에서 로그 코드 전체를 올려두었는데, 그 부분을 잘 보면 아래와 같은 부분이 있다.

logging.basicConfig(filename='./log.txt', filemode='w')

이는 파일 이름을 무엇으로 할 것인지, 그리고 파일의 모드는 무엇으로 할 것인지를 선택하는 부분인데,  filename=' XXX '에서는 발생한 로그들을 어떤 파일에 입력하여 저장할 것인지를 지정할 수 있으며, filemode=' '에서는 쓰기 모드를 a와 w 중 선택할 수 있는데, a는 append의 약자로 기존에 저장된 내용에 이어서 입력하는 것이고 w는 write의 약자로 작성한 부분이 있다면 삭제한 후 새롭게 작성하는 방법이다.

 

 

로그를 통해 나타내고자 하는 정보의 유형과 형태들

위의 전체 코드 내에서 아래와 같은 부분이 있다.

formatter = logging.Formatter('[%(levelname)s] (%(filename)s:%(lineno)d) %(message)s')

이는 로그를 어떤 형태로 나타낼 것인지를 지정하는 것인데, 일단 대괄호([, ])나 소괄호((, )) 또는 땡땡이(:) 같은 경우에는 로그 내에 그대로 나타나는 단순 로그의 구조를 예쁘게 만들어주는 수식어구로 생각하면 되고, 그를 제외한 %(levelname)s, %(filename)s, %(lineno)d, %(message)s 등등이 로그로 표현하고자 하는 정보의 형태를 나타내는 부분에 해당한다. 로그 코드 내에서 "이러한 형태와 이러한 정보를 가진 로그를 표시해라"라는 명령을 내리는 것이 바로 formatter로 이해하면 된다. 

위의 코드 내에서 사용된 정보 외에도 정말 다양한 formatter들을 지정할 수 있다.

이름 형태 내용
asctime %(asctime)s 날짜와 시간 표시
created %(created)s 로그 새성 시간 표시
filename %(filename)s 로그가 발생한 파일의 이름
funcName %(funcName)s 로그가 포함된 함수 코드의 이름
levelname %(levelname)s 로그 단계 표시
lineno %(lineno)d 로그가 몇 번째 줄에 있는지
module %(module)s 해당 모듈의 이름
message %(message)s 로그를 통해 나타내고자 하는 메시지
pathname %(pathname)s 코드의 경로
processName %(processName)s 프로세스의 이름

위 표 내의 형태 열에 있는 것들을 그대로 로그 안에 나타낼 위치에 놓으면, 그 정보를 나타내준다.
※ levelname은 로그 단계 표시로, debug인지 info인지 등을 나타낸다.

 

 

asctime의 표시 형태 변경

actime()의 경우에는 기본적으로 YYYY-MM-DD HH:MM:SS,PPP의 형태로 출력된다. 하지만 연도와 일자 등의 데이터가 필요없다거나, 시간 데이터가 필요 없는 경우에는 아래와 같은 코드를 통해 해당 내용이 출력되지 않도록 수정할 수 있다.

formatter = logging.Formatter('[%(levelname)s:%(asctime)s] (%(funcName)s:%(lineno)d) %(message)s', datefmt="%H:%M:%S")

여기서 사용한 datefmt는 actime의 표시 형식을 설정하는 것으로, time.strftime()에서 사용되는 메서드와 동일한 형태의 메서드를 입력함으로써 데이터를 변경할 수 있다. 

datefmt="%y/%m/%D"를 사용하게 되면 시간 데이터를 제외한 일자 데이터만 22/12/22와 같은 형태로 출력되며, 위의 예시처럼 datefmt="%H:%M:%S"를 사용하게 되면 일자 데이터를 제외한 시간 데이터만 14:00:00과 같은 형태로 출력된다.

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.