HOWTO · Python
Python에서 stdout에 로깅
logging.basicConfig() 및 logging.StreamHandler() 함수를 사용하여 Python에서 stdout에 로깅 할 수 있습니다.
이 페이지의 내용
Python 로그 메시지를 표준 출력(stdout)으로 보내려면 logging.basicConfig()의 stream을 sys.stdout으로 설정합니다. 더 세밀하게 제어하려면 로거에 logging.StreamHandler(sys.stdout)를 연결하세요. 같은 로그 레코드를 콘솔과 파일에 모두 보내려면 스트림 핸들러와 별도의 FileHandler를 함께 사용합니다.
Python에서 logging.basicConfig() 함수로 stdout에 로그 출력하기
애플리케이션 전체에 간단히 로깅을 설정할 때 logging.basicConfig()를 사용하면 루트 로거를 구성할 수 있습니다. stream 매개변수는 출력 스트림을 지정하며, 기본값은 sys.stderr입니다. 로그 레코드를 표준 출력으로 보내려면 sys.stdout으로 설정하세요. level은 루트 로거를 통과하는 레코드를 결정하고, format은 출력되는 각 줄의 형식을 정합니다.
import logging
import sys
logging.basicConfig(
level=logging.INFO,
format="%(levelname)s: %(message)s",
stream=sys.stdout,
)
logging.info("Application started")
INFO: Application started
basicConfig()는 루트 로거를 한 번 간편하게 설정하기 위한 함수입니다. 애플리케이션의 다른 부분에서 루트 로거에 핸들러를 이미 추가했다면 이후 호출은 기존 설정을 그대로 두므로, 여기서 stream을 바꿔도 출력 대상이 바뀌지 않습니다. Python 3.8 이상에서는 force=True를 지정해 기존 루트 핸들러를 제거한 뒤 설정을 적용할 수 있습니다. 애플리케이션의 로깅 설정을 교체할 책임이 있는 경우에만 사용하세요. 그렇지 않다면 애플리케이션 진입점에서 로깅을 한 번 설정하는 편이 좋습니다.
filename과 filemode 옵션은 파일 출력을 설정합니다. filename은 파일 이름을 지정하고, filemode는 파일을 여는 방식을 지정하며 기본값은 추가 모드("a")입니다. basicConfig()에 filename과 stream을 함께 전달하면 안 됩니다. 여기서는 출력 대상을 하나만 선택하세요. 표준 출력과 파일에 모두 로그를 보내려면 아래와 같이 핸들러를 별도로 사용합니다. 또한 force=True를 사용하지 않는 한 basicConfig()는 기존 핸들러가 없을 때만 루트 로거를 설정합니다. force=True는 Python 3.8 이상에서 사용할 수 있습니다.
Python에서 logging.StreamHandler() 함수로 stdout에 로그 출력하기
이름이 지정된 로거를 제어하거나 출력 대상을 조합해야 한다면 핸들러를 직접 사용하세요. logging.StreamHandler()는 기본적으로 sys.stderr에 쓰므로 sys.stdout을 명시적으로 전달해야 합니다. 로거 수준과 핸들러 수준은 모두 출력할 레코드에 영향을 줍니다. 레코드는 두 수준을 모두 통과해야 합니다. 다음 예제에서는 stdout 핸들러 하나와 파일 핸들러 하나를 만들고 둘 다 같은 로거에 연결합니다.
import logging
import sys
import tempfile
from pathlib import Path
log_path = Path(tempfile.gettempdir()) / "python-logging-example.log"
logger = logging.getLogger("example")
logger.setLevel(logging.INFO)
logger.propagate = False
formatter = logging.Formatter("%(levelname)s: %(message)s")
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.INFO)
stdout_handler.setFormatter(formatter)
file_handler = logging.FileHandler(log_path, mode="w", encoding="utf-8")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
logger.addHandler(stdout_handler)
logger.addHandler(file_handler)
logger.info("Application started")
for handler in (stdout_handler, file_handler):
handler.close()
logger.removeHandler(handler)
INFO: Application started
각 핸들러는 레코드의 형식을 지정한 뒤 각자의 출력 대상에 씁니다. 파일은 시스템 임시 디렉터리에 생성되며, mode="w"를 사용하면 실행할 때마다 예제 파일을 덮어씁니다. 오래 실행되는 애플리케이션에서는 핸들러를 반복해서 추가하지 말고 한 번만 설정하세요. 핸들러가 중복되면 각 레코드가 여러 번 출력될 수 있습니다. 실제 운영 환경에서는 애플리케이션에 맞게 파일 경로와 핸들러의 수명 주기를 관리하세요.
결론
빠르게 루트 로거를 설정하려면 stream=sys.stdout과 함께 logging.basicConfig()를 사용하세요. 이름이 지정된 로거를 제어하거나 핸들러 설정을 맞춤화하거나 여러 출력 대상을 사용해야 한다면 logging.StreamHandler(sys.stdout)를 선택합니다. 스트림을 명시하지 않은 StreamHandler는 stderr에 쓰며, 파일과 콘솔에 함께 로그를 보내려면 스트림 핸들러와 파일 핸들러를 각각 사용해야 합니다.