티스토리 뷰

카테고리 없음

python print vs logging

killog 2023. 4. 23. 18:31
반응형

1. 이 글을 어떻게 쓰게 되었냐면..

python 을 주 언어로 사용하고 있는 백엔드 개발자입니다.

이번에, application 에 logging 을 달면서, python logging 에 대한 글을 쓰려고 했는데, 기왕이면 python print 문과 python logging 중에, 어떤 상황에 무엇을 쓰면 더 적합한지 , 그 둘의 차이에 대해 작성해보면 좀 더 재밌는 글이 될 것같이 이 글을 쓰게 되었습니다.

우선, 로그에 대해 이해를 하고, 로그를 언제 쓰는지, 꼭 써야하는지, 그리고 로깅을 한다고 했을때 고려할점에 대해서 이야기를 하겠습니다. 이후, print 에 대해 이야기하고, logging 에 대해 설명한 뒤, 그 둘의 차이점을 비교하는 형태로 글을 이어나가볼까 합니다.

2. 로그 파일

로그 파일이란?

aws 문서를 인용했습니다.

  • 로그 파일은 애플리케이션, 서버 또는 IT 시스템의 작업, 활동 및 사용 패턴에 대한 정보를 포함하는 소프트웨어 생성 파일입니다. 여기에는 모든 프로세스, 이벤트 및 메시지에 대한 기록과 함께 타임스탬프와 같은 추가적인 설명 데이터가 포함되어 이 정보를 상황에 맞게 설명해드립니다. 타임스탬프는 시스템 내부에서 발생한 상황과 발생 시기를 보여줍니다. 따라서 시스템에 문제가 발생한 경우에는 사고 발생 전의 모든 조치에 대한 상세한 기록을 확인할 수 있습니다.

로그 파일 유형

다음은 몇 가지 일반적인 로그 파일 유형입니다.

1. 이벤트 로그

  • 이벤트 로그는 시스템 작업 데이터를 기록하여 문제 해결을 위한 감사 트레일을 제공하는 로그입니다.
  • 이벤트 로그는 특히 사용자 상호 작용이 거의 없는 애플리케이션과 관련해 복잡한 시스템의 동작을 이해하는 데 필수적입니다. 예를 들어 네트워크에서 이벤트 로그는 네트워크 트래픽, 액세스 및 사용량을 기록합니다.

2. 시스템 로그

  • 시스템 로그는 시스템 변경, 시작 메시지, 오류, 경고, 예기치 않은 종료와 같은 운영 체제 이벤트를 기록합니다.

3. 액세스 로그

  • 액세스 로그는 사용자 또는 애플리케이션이 시스템에서 요청하는 개별 파일에 대한 전체 요청 목록을 기록합니다. 여기에는 특정 시스템 파일을 요청한 사용자 인증에 대한 정보, 요청한 시간 및 기타 관련 정보가 포함됩니다.

4. 서버 로그

  • 서버 로그는 서버가 자동으로 작성하고 유지 관리하는 로그 파일입니다. 여기에는 페이지 요청 수, 클라이언트 IP 주소, 요청 유형 등 서버가 수행하는 작업의 목록이 포함됩니다.

5. 변경 로그

  • 변경 로그는 소프트웨어의 변경 내용을 시간순으로 기록한 파일입니다. 예를 들어 여러 버전의 애플리케이션 간 변경 내용을 기록하거나 시스템의 구성 변경 내용을 기록할 수 있습니다.

6. 기타 로그 유형

사용 사례에 따라 다음과 같은 다른 유형의 로그 파일이 있습니다.

  • 시스템 성능 및 가용성을 추적하는 가용성 로그
  • 연결 문제에 대한 정보를 제공하는 리소스 로그
  • 의심스러운 네트워크 프로파일에 대한 정보가 포함된 위협 로그

왜 우리는 로깅을 할까?

우선 굳이, 로깅을 왜하는 걸까요? 왜 굳이 로그를 모아 저장하고 처리해야하는 걸까요? 위에서 정리했던 로그 파일 유형과 결국 이어지지만, 굳이, 중요성을 위해 다시 정리해보겠습니다.

  1. 디버깅용
    1. 로깅은 개발자가 코드에서 발생한 문제를 식별하고 해결하는 데 도움이 됩니다. 로그 메시지를 통해 개발자는 코드의 실행 경로와 변수 값, 시스템 상태 등을 확인할 수 있습니다.
    2. 이건 운영 중이 아니라, 개발 과정에서 저희가 pdb 외에도 간단하게 지금 python 변수들의 상태값을 찾기 위해서도 많이 이용합니다.
  2. 오류 추적 및 모니터링
    1. 로깅을 통해 개발자는 시스템에서 발생하는 오류 및 예외를 실시간으로 추적하고 모니터링할 수 있습니다. 이를 통해 개발자는 문제를 빠르게 인지하고 즉시 대응할 수 있습니다.
  3. 성능 분석
    1. 로깅을 사용하면 시스템의 성능에 관한 정보를 수집할 수 있습니다. 이를 통해 개발자는 애플리케이션의 성능 저하 원인을 찾아 개선할 수 있습니다.
    2. 예를들어 메모리가 11:00~ 11:15 사이에 갑자기 비정상적으로 많이 사용됐다고 하면, 로그 추적을 통해 해당 시간에서의 유저들이 보낸 쿼리를 이용해서 성능 저하 원인을 찾을 수 있습니다.
  4. 보안 감사
    1. 로깅은 사용자의 활동, 시스템 접근, 데이터 변경 등을 기록함으로써 보안 감사에 필요한 정보를 제공합니다. 이를 통해 개발자와 보안 전문가는 시스템 내의 부적절한 활동이나 침입 시도를 감지하고 대응할 수 있습니다.
  5. 문제 해결 지원
    1. 로깅은 사용자가 겪는 문제를 이해하고 해결하는 데 도움이 됩니다. 사용자가 문제를 제기할 때 로그를 제공하면, 개발자는 해당 문제의 원인을 더 빠르게 파악하고 해결 방법을 찾을 수 있습니다.
  6. 기록 보관
    1. 로깅을 통해 시스템의 동작 이력을 저장할 수 있습니다. 이 기록은 나중에 시스템의 이전 상태를 확인하거나, 문제 발생 시점을 찾아내는 데 사용될 수 있습니다.

로깅은 따라서 소프트웨어 개발의 여러 측면에서 중요한 역할을 하며, 애플리케이션의 안정성, 성능, 보안 및 사용자 지원에 기여합니다.

로그 파일 관리를 위해 고려할 점

1. 볼륨

  • 최신 IT 시스템은 모든 작업을 기록하므로 로그 파일의 수와 크기가 빠르게 증가합니다. 적절한 절차를 마련하지 않으면, 실질적으로 유용한 수동 분석을 수행하는 데 필요한 로그의 양이 엄청나게 커질 수 있습니다.

2. 형식의 차이

  • 여러 시스템에서 정형, 반정형 또는 비정형과 같은 다양한 형식의 로그 파일 데이터가 생성됩니다. 하지만 개발자와 관리자가 로그를 정확하게 사용하려면, 로그를 한 줄씩 구문 분석하거나 분석해야 합니다. 로깅 표준이 없기 때문에 구문 분석이 복잡해지고 시간이 많이 소요됩니다.

3. 처리 속도

  • 많은 양의 로깅 정보와 그에 따른 구문 분석 요구 사항으로 인해, 로그 관리 시간이 늘어날 수 있습니다. 비효율적인 로그 관리 시스템은 느린 로그 처리 속도로 인해 조직이 실시간으로 조치를 취하기 어렵게 만듭니다.

2. print 함수

print 함수와 기본 사용법 소개

print("Hello World!")
  • 간단하고 사용하기 쉽습니다.
  • 메시지를 표준 출력(일반적으로 콘솔)에 직접 작성하는 구조인데요,
  • 대규모 애플리케이션 또는 프로덕션 환경에 적합하지 않습니다.
    • 이유라고 하면, 멀티스레드 애플리케이션에서는 print 문이 섞일 수 있어 읽기 어려울 수 있습니다. logging 과 비교했을 때, 메시지 서식 및 필터링에 대한 제어가 제한되고 print 를 레벨을 지정해서, 다른 파일 등에 로깅을 하고자하는 경우에도, logging 모듈을 이용하는 것이 나을 수 있습니다. 파일이나 기타 출력에 메시지를 작성하는 기본 지원이 없는데, FileHandler 를 이용한 logging 과 비교할때, 대화형이 아닌 환경(예: 백그라운드 프로세스나 서비스로 실행되는 경우)에서 애플리케이션이 실행될 때 print 문이 손실될 수 있습니다.

3. 파이썬 로깅 모듈

파이썬 logging 모듈 및 이점 소개

https://docs.python.org/ko/3/howto/logging.html

파이썬 도큐먼트에서 소개하는 Logging 의 개념은 아래와 같습니다.

로깅은 어떤 소프트웨어가 실행될 때 발생하는 이벤트를 추적하는 수단입니다. 소프트웨어 개발자는 코드에 로깅 호출을 추가하여 특정 이벤트가 발생했음을 나타냅니다. 이벤트는 선택적으로 가변 데이터 (즉, 이벤트 발생마다 잠재적으로 다른 데이터)를 포함할 수 있는 설명 메시지로 기술됩니다. 이벤트는 또한 개발자가 이벤트에 부여한 중요도를 가지고 있습니다; 중요도는 수준(level) 또는 심각도(severity) 라고도 부를 수 있습니다.

logging 흐름

로거 및 처리기에서 로그 이벤트 정보의 흐름은 다음 도표에 설명되어 있습니다.

../_images/logging_flow.png

logging 모듈 사용시 장점

logging 모듈을 이용하면 장점은 크게 6가지 있습니다.

  1. log 의 출처를 쉽게 파악할 수 있습니다.
  2. timestamp 이용 가능합니다.
  3. 로그 레벨을 지정할 수 있습니다.
    • 로그 수준에 숫자가 존재하고, 특정 레벨 이상의 로그만 출력 가능하기 때문에, 좀더 로그 관리가 용이합니다.
  4. RotateHandler , FileHandler 등을 이용해, 다량의 로그 처리를 좀더 용이하게 할 수 있습니다.
  5. 로그 포맷이 존재하기때문에, 한번 지정해주면, 별다른 노력을 기울이지 않아도 항상, 원하는 메타 정보를 출력 가능합니다. (예 . timestamp, levelname, threadname ..)
  6. 스레드 안정성
    1. 로깅 모듈은 클라이언트가 수행할 특별한 작업 없이 스레드로부터 안전하도록 설계되었습니다. 스레딩 잠금을 사용하여 이를 달성합니다. 모듈의 공유 데이터에 대한 액세스를 직렬화하는 하나의 잠금이 있으며 각 핸들러는 기본 I/O에 대한 액세스를 직렬화하는 잠금도 생성합니다.
    2. 모듈을 사용하여 비동기 신호 처리기를 구현하는 경우 signal 이러한 처리기 내에서 로깅을 사용하지 못할 수 있습니다. threading모듈의 잠금 구현이 항상 재진입하는 것은 아니므로 이러한 신호 처리기에서 호출할 수 없기 때문입니다 .
import logging

class OneLineExceptionFormatter(logging.Formatter):
    def formatException(self, exc_info):
        """
        Format an exception so that it prints on a single line.
        """
        result = super().formatException(exc_info)
        return repr(result)  # or format into one line however you want to

    def format(self, record):
        s = super().format(record)
        if record.exc_text:
            s = s.replace('\n', '') + '|'
        return s

def configure_logging():
    fh = logging.FileHandler('output.txt', 'w')
    f = OneLineExceptionFormatter('%(asctime)s|%(levelname)s|%(message)s|',
                                  '%d/%m/%Y %H:%M:%S')
    fh.setFormatter(f)
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)
    root.addHandler(fh)

def main():
    configure_logging()
    logging.info('Sample message')
    try:
        x = 1 / 0
    except ZeroDivisionError as e:
        logging.exception('ZeroDivisionError: %s', e)

if __name__ == '__main__':
    main()

실행하면 정확히 두 줄의 파일이 생성됩니다.

28/01/2015 07:21:23|INFO|Sample message|
28/01/2015 07:21:23|ERROR|ZeroDivisionError: integer division or modulo by zero|'Traceback (most recent call last):\n  File "logtest7.py", line 30, in main\n    x = 1 / 0\nZeroDivisionError: integer division or modulo by zero'|

기본 로깅 구성 및 사용법의 예시 제시

아주 간단한 예는 이렇습니다:

import logging
logging.warning('Watch out!')  # will print a message to the console
logging.info('I told you so')  # will not print anything

이 줄들을 스크립트에 입력하고 실행하면:

WARNING:root:Watch out!

이 콘솔에 출력됩니다. 기본 수준이 WARNING 이므로, INFO 메시지는 나타나지 않습니다. 인쇄된 메시지에는 수준 표시와 로깅 호출에 제공된 이벤트의 설명(즉, ‘Watch out!’)이 포함됩니다. 당장은 ‘root’ 부분에 대해서는 걱정하지 마십시오: 나중에 설명합니다. 필요한 경우 실제 출력을 매우 유연하게 포맷 할 수 있습니다

다양한 로깅 레벨 (DEBUG, INFO, WARNING, ERROR, CRITICAL)

로깅 함수는 추적되는 이벤트의 수준 또는 심각도를 따라 명명됩니다. 표준 수준과 그 용도는 아래에 설명되어 있습니다 (심각도가 높아지는 순서대로).

수준 사용할 때
DEBUG 상세한 정보. 보통 문제를 진단할 때만 필요합니다.
INFO 예상대로 작동하는지에 대한 확인.
WARNING 예상치 못한 일이 발생했거나 가까운 미래에 발생할 문제(예를 들어 ‘디스크 공간 부족’)에 대한 표시. 소프트웨어는 여전히 예상대로 작동합니다.
ERROR 더욱 심각한 문제로 인해, 소프트웨어가 일부 기능을 수행하지 못했습니다.
CRITICAL 심각한 에러. 프로그램 자체가 계속 실행되지 않을 수 있음을 나타냅니다.

기본 수준은 WARNING 입니다. 이는 logging 패키지가 달리 구성되지 않는 한, 이 수준 이상의 이벤트만 추적된다는 것을 의미합니다.

로깅 수준

로깅 수준의 숫자 값은 다음 표에 나와 있습니다. 이것은 주로 여러분 자신의 수준을 정의하고 사전 정의된 수준에 상대적인 특정 값을 갖도록 하려는 경우 관심의 대상입니다. 같은 숫자 값을 가진 수준을 정의하면 미리 정의된 값을 덮어씁니다; 사전 정의된 이름이 유실됩니다.

수준 숫자 값
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

로깅 모듈의 구성 요소 (Loggers, Handlers, Formatters, Filters) 논의

logging 라이브러리는 모듈 방식으로 구성되며, Loggers, Handlers, Formatters, Filters와 같은 여러 범주의 구성 요소를 제공합니다.

  • Loggers는 응용 프로그램 코드가 직접 사용하는 인터페이스를 노출합니다.
  • Handlers는 (Logger에 의해 만들어진) 로그 레코드를 적절한 목적지로 보냅니다.
  • Filter는 출력할 로그 레코드를 결정하기 위한 보다 정밀한 기능을 제공합니다.
  • Formatter는 최종 출력에서 로그 레코드의 배치를 지정합니다.

로그 이벤트 정보는 LogRecord 인스턴스를 통해 로거, 처리기, 필터 및 포매터 간에 전달됩니다.

로깅은 Logger 클래스 인스턴스의 메서드를 호출하여 수행됩니다. 각 인스턴스에는 이름이 있으며, 점(마침표)을 구분 기호로 사용하여 개념적으로는 이름 공간 계층 구조로 배열됩니다. 예를 들어, ‘scan’이라는 로거는 ‘scan.text’, ‘scan.html’ 및 ‘scan.pdf’ 로거의 부모입니다. 로거 이름은 원하는 어떤 것이건 될 수 있으며, 로그 된 메시지가 시작된 응용 프로그램 영역을 나타냅니다.

Handler

https://docs.python.org/ko/3/howto/logging.html#handlers

Handler 객체는 (로그 메시지의 심각도를 기반으로) 적절한 로그 메시지를 처리기의 지정된 대상으로 전달하는 역할을 합니다. Logger 객체는 addHandler() 메서드를 사용하여 0개 이상의 처리기 객체를 자신에게 추가 할 수 있습니다. 예를 들어, 응용 프로그램은 모든 로그 메시지를 로그 파일로 보내고, 에러(error)와 그 이상의 모든 로그 메시지를 표준 출력으로 보내고, 모든 심각한 에러(critical) 메시지를 전자 메일 주소로 보낼 수 있습니다. 이 시나리오에서는 각 처리기가 특정 심각도의 메시지를 특정 위치로 보내는 3개의 개별 처리기가 필요합니다.

베이스 Handler 클래스 외에도 많은 유용한 서브 클래스가 제공됩니다

https://docs.python.org/ko/3/howto/logging.html#useful-handlers

  1. StreamHandler 인스턴스는 스트림(파일류 객체)에 메시지를 보냅니다.
  2. FileHandler 인스턴스는 디스크 파일에 메시지를 보냅니다.
  3. BaseRotatingHandler 는 특정 지점에서 로그 파일을 회전시키는 처리기의 베이스 클래스입니다. 직접 인스턴스화하는 것은 아닙니다. 대신 RotatingFileHandler 또는 TimedRotatingFileHandler 를 사용하십시오.
  4. RotatingFileHandler 인스턴스는 디스크 파일에 메시지를 보내는데, 최대 로그 파일 크기와 로그 파일 회전을 지원합니다.
  5. TimedRotatingFileHandler 인스턴스는 디스크 파일에 메시지를 보내는데, 일정한 시간 간격으로 로그 파일을 회전시킵니다.
  6. SocketHandler 인스턴스는 TCP/IP 소켓에 메시지를 보냅니다. 3.4부터, 유닉스 도메인 소켓도 지원됩니다.
  7. DatagramHandler 인스턴스는 UDP 소켓에 메시지를 보냅니다. 3.4부터, 유닉스 도메인 소켓도 지원됩니다.
  8. SMTPHandler 인스턴스는 지정된 전자 우편 주소로 메시지를 보냅니다.
  9. SysLogHandler 인스턴스는 유닉스 syslog 데몬(원격 기계에 있는 것도 가능합니다)에 메시지를 보냅니다.
  10. NTEventLogHandler 인스턴스는 윈도우 NT/2000/XP 이벤트 로그에 메시지를 보냅니다.
  11. MemoryHandler 인스턴스는 메모리에 있는 버퍼에 메시지를 보내는데, 특정 기준이 만족 될 때마다 플러시 됩니다.
  12. HTTPHandler 인스턴스는 GET 또는 POST 을 사용해서 HTTP 서버에 메시지를 보냅니다.
  13. WatchedFileHandler 인스턴스는 그들이 로깅하고 있는 파일을 감시합니다. 파일이 변경되면 닫히고 파일 이름을 사용하여 다시 열립니다. 이 처리기는 유닉스 계열 시스템에서만 유용합니다; 윈도우는 사용된 하부 메커니즘을 지원하지 않습니다.
  14. QueueHandler 인스턴스는 queue 또는 multiprocessing 모듈에 구현된 것과 같은 큐로 메시지를 보냅니다.
  15. NullHandler 인스턴스는 에러 메시지로 아무것도 하지 않습니다. 라이브러리 개발자가 로깅을 사용하지만, 라이브러리 사용자가 로깅을 구성하지 않으면 표시될 수 있는 ‘No handlers could be found for logger XXX’ 라는 메시지를 피하려고 할 때 사용합니다. 자세한 정보는 라이브러리 로깅 구성 를 보시면 됩니다.

6. 멀티스레드 환경에서의 로깅

멀티스레드 환경에서 로깅

멀티 쓰레드 환경에서 여러 동시에 요청이 처리되기 때문에 동일한 요청에 대한 로그가 연속적으로 쌓이는 것이 아니라, 순서없이 쌓일 수 있습니다

Python의 logging 모듈은 스레드 안전한 로깅을 지원합니다. 내부적으로 ,Logger 객체는 스레드 간 동기화를 위해 락을 사용하여 서로 다른 스레드에서 동시에 액세스가 발생해도 충돌이나 데이터 경쟁이 발생하지 않도록 합니다.

스레드 안전성

https://docs.python.org/ko/3/library/logging.html#thread-safety

로깅 모듈은 클라이언트가 특별한 주의를 기울이지 않아도 스레드 안전하도록 만들어졌습니다. 이렇게 하려고 threading lock을 사용합니다; 모듈의 공유 데이터에 대한 액세스를 직렬화하는 lock 이 하나 있고, 각 처리기 또한 하부 I/O에 대한 액세스를 직렬화하는 lock을 만듭니다.

signal 모듈을 사용하여 비동기 시그널 처리기를 구현한다면, 그 처리기 내에서는 logging을 사용할 수 없을 수도 있습니다. 이는 threading 모듈의 록 구현이 언제나 재진입할 수 있지는 않아서 그러한 시그널 처리기에서 호출할 수 없기 때문입니다.

7. printlogging 비교

which is faster? print vs logging.info

  1. 간단함: print는 표준 출력으로 메시지를 전송하는 간단한 작업을 수행합니다. 반면에 logging.info는 로깅 프레임워크를 통해 메시지를 전달하고, 이에 따라 추가적인 처리와 오버헤드가 발생할 수 있습니다.
  2. 로깅 레벨 확인: logging.info는 메시지를 출력하기 전에 로거의 로깅 레벨을 확인하며, 이로 인해 추가적인 처리 시간이 소요됩니다. 반면에 print는 이러한 확인 과정이 없습니다.

그러나 이러한 속도 차이는 대부분의 경우 실제 애플리케이션에서 성능에 큰 영향을 미치지 않습니다. 애플리케이션의 요구 사항, 디버깅 및 로깅 필요성을 고려하여 printlogging 중 적절한 방법을 선택하는 것이 중요합니다.

print 함수와 logging 모듈의 주요 차이점 요약

결론적으로 차이는, 로깅 프레임워크를 거치냐 안거치냐 차이입니다.

  1. 스레드 safe 를 제공하는지
  2. 로그 레벨 , 필터를 제공하는지
  3. 일반 메시지 포맷이 존재하는지
  4. 파일이나 기타 출력에 메시지를 작성하는 기본 지원하는지 여부 차이

로 보면 될 것같습니다.

따라서, 대규모 애플리케이션 또는 프로덕션 환경이다! 호출이 빈번한 경우에는 logging 모듈을 이용하는 것이 좀 더 권장 되고, 그에 대비, 호출횟수가 적고, 로그 레벨 관리 등이 필요 없는 대비 간단한 상황에서는 print 문을 이용하는, 상황에 맞는 선택을 하는 것이 좋아보입니다.


참고 문헌

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함