logging shiny

Published by onesixx on

https://docs.python.org/3/library/logging.html

기본 Logging

import logging

# 로그 설정
logging.basicConfig(
    level=logging.DEBUG,  # 출력할 로그의 레벨 설정
    format="%(asctime)s - %(levelname)s - %(message)s",  # 로그 출력 형식
    datefmt="%Y-%m-%d %H:%M:%S",  # 날짜 형식
)

# 로그 출력
logging.debug("이것은 디버그 메시지입니다.")
logging.info("이것은 정보 메시지입니다.")
logging.warning("이것은 경고 메시지입니다.")
logging.error("이것은 에러 메시지입니다.")
logging.critical("이것은 치명적인 에러 메시지입니다.")

Logger사용

import logging

logger = logging.getLogger(__name__)

logging.basicConfig(
    level=logging.WARNING,
    format = '%(asctime)s | %(levelname)s | %(message)s',
    datefmt = '%m-%d-%Y %H:%M:%S',
    # filename='example.log',
    # encoding='utf-8',
)

logger.debug('This message should go to the log file')
logger.info('So should this')
logger.warning('And this, too')
logger.error('And non-ASCII stuff, too, like Øresund and Malmö')
logger.critical("Critical")

dict사용

Introduction to Modern Logging (00:00 – 00:21)

  • The video introduces best practices for logging in Python.
  • Emphasizes that best practices are general guidelines, not strict rules.

Problems with Python’s Built-in Logging (00:38 – 01:18)

  • The logging package is old, poorly documented, and often misused.
  • Despite flaws, it is the de facto standard for Python logging.

Why Basic Logging is Not Enough (01:36 – 02:05)

  • Basic logging.basicConfig() setups are too simple.
  • Multiple log destinations (stdout, files, email alerts) require better configuration.

Using dictConfig for Logging Setup (02:05 – 02:49)

  • dictConfig from logging.config is the preferred way to configure logging.
  • Explicitly defines loggers, handlers, filters, and formatters.

Logging Workflow and Components (03:12 – 03:54)

  • Loggers create log records with severity levels and metadata.
  • Handlers determine where logs go (stdout, files, email).
  • Formatters define the log message structure.

Logger Hierarchy and Propagation (05:19 – 05:55)

  • Loggers form a hierarchical tree structure.
  • Logs propagate up the hierarchy unless explicitly dropped.

Simplifying Logging Configuration (06:17 – 07:28)

  • Keep all handlers at the root logger for simplicity.
  • Use logging.getLogger(name) instead of top-level logging functions.

Configuring Logging with dictConfig (08:05 – 09:35)

  • Use external JSON or YAML files for configuration.
  • JSON is preferred due to Python’s built-in support.

Advanced Logging: File Handlers & Formatting (10:37 – 11:55)

  • Logs can be split between stderr and files using RotatingFileHandler.
  • Use detailed formatters to include timestamps and structured data.

Logging in JSON Format for Better Parsing (12:34 – 14:49)

  • Plain text logs can be difficult to parse.
  • Writing logs in JSON allows structured storage and easier analysis.
  • Custom formatters may be required since Python lacks a built-in JSON formatter.

기본 logging

import logging –> logger만들기 –> 기본설정 지정 –> Message 기록

https://onesixx.com/logging/

여기서 log를 console과 file에 기록하고 싶거나, level별로 따로 log를 저장하거나, 추가적으로 이메일 발송등을 하려면, handler와 filter가 필요하다.

하지만, Handler와 filter 대신 dictConfig을 활용한다.

Logging의 구조

Logger → Log Record → Handlers → Formatters → Output (stdout, file, etc.)

Logger

logger 객체는 logger.info(), logger.debug(), logger.exception() 등을 호출하여 로그를 남깁니다.
로그를 기록할 때, 로그 레코드(log record)라는 객체가 생성됩니다.

Log Record

Log Message 뿐만 아니라, severity, current time, current thread 나 async task, 소스코드에서의 location 등의 유용한 정보를 포함하는 객체입니다.
Logger는 특정 로그 레벨보다 낮은 메시지를 필터링할 수도 있습니다.

Handler

로그를 출력할 위치(예: 표준 출력, 파일, 이메일 전송 등)를 결정합니다.
핸들러는 각 로그 메시지를 받을 때 필터링을 수행할 수도 있습니다.

Formatter

로그 레코드를 문자열로 변환하여 출력 형식을 지정하는 역할을 합니다.
예를 들어, 로그 메시지 앞에 타임스탬프를 추가하거나 JSON 형식으로 변환할 수 있습니다.
이 구조를 그림으로 표현하면 다음과 같습니다.

Logging 설정 방법

로그를 JSON 형식으로 저장하면 분석이 쉬워집니다.
불필요한 로거와 핸들러를 만들지 않고, root logger에서 핸들링하는 것이 좋습니다.

실용적인 로깅 설정 방법
Handler를 root logger에만 배치하세요.
– 불필요한 하위 핸들러를 만들지 마세요.( 이렇게 하면 서드파티 라이브러리에서 생성된 로그도 동일한 방식으로 처리됩니다)
– 필터(filter)는 가급적 사용하지 마세요.
필요하다면 루트 로거 또는 핸들러에서만 사용하세요.

루트 로거를 직접 사용하지 마세요.
logging.getLogger(“my_logger”)를 사용하여 로거를 생성하고, 해당 로거를 사용하세요.
모든 로그는 루트 로거로 전파(propagation)되도록 설정하세요.

handler의 종류

Python의 logging 모듈에서 제공하는 주요 handler는 다음과 같습니다:

Handler설명
StreamHandler콘솔(터미널)에 로그 출력
FileHandler파일에 로그 저장
RotatingFileHandler용량이 넘으면 새로운 파일로 자동 변경
TimedRotatingFileHandler일정 시간이 지나면 새로운 파일로 자동 변경
SocketHandler네트워크로 로그 전송 (TCP/IP)
SMTPHandler이메일로 로그 전송
HTTPHandlerHTTP 요청을 통해 로그 전송

app.py

import logging

formatter_s = logging.Formatter('!!!%(asctime)s|%(levelname)s|%(message)s')
formatter_c = logging.Formatter('%(asctime)s|%(levelname)s|%(message)s')

logger = logging.getLogger("shinylog")

handler_s = logging.StreamHandler()
logger.setLevel(logging.DEBUG)
handler_s.setFormatter(formatter_s)
logger.addHandler(handler_s)

handler_c = logging.FileHandler(ASSET_DIR.joinpath("log_event.log"))
handler_c.setLevel(logging.CRITICAL)
handler_c.setFormatter(formatter_c)
logger.addHandler(handler_c)


# logger
logger.info("Is working well?")
logger.critical("AAAAAAAAAAA")

server.py

import logging
logger = logging.getLogger('shinylog')
logger.info(f"bropress endend {p} loading \n {temp_dr}")
logger.critical("bropress start")

기본 Logger

# assets/log_set.py
import logging

def get_logger(name):
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)  # 로그 레벨 설정

    # 콘솔 핸들러 설정
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)

    # 로그 포맷 설정
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    ch.setFormatter(formatter)

    # 핸들러를 로거에 추가
    logger.addHandler(ch)

    return logger

app.py

# app.py
from assets.log_set import get_logger
logger = get_logger("my_app")  
# logger.info("app start")

logger.debug("debug message", extra={"x": "hello"})
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")
try:
    1 / 0
except ZeroDivisionError:
    logger.exception("exception message")

server.py

# basic_server.py
from assets.log_set import get_logger
logger = get_logger(__name__)
logger.info("server start")

import logging

def get_logger(name):
    logger = logging.getLogger(name)
    logging_config = {
        "level": logging.DEBUG,
        "format": "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
        "datefmt": "%Y-%m-%d %H:%M:%S",
    }
    logging.basicConfig(**logging_config)

    return logger

dictConfig를 통해 config

import logging

def get_logger(name):
    logger = logging.getLogger(name)
    logging_config = {
        "level": logging.DEBUG,
        "format": "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
        "datefmt": "%Y-%m-%d %H:%M:%S",
    }
    logging.basicConfig(**logging_config)

    return logger
import logging
from shared import LOG_DIR
# print(f">>>>>>{LOG_DIR}")

logging_config = {
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {},
    "formatters": {
        "simple": {
            "format": "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S"
        },
        "verbose": {
            "format": " [%(asctime)s | %(levelname)s | %(module)s | L%(lineno)d ] %(message)s",
            "datefmt": "%Y-%m-%dT%H:%M:%S%z"
        }
    },
    "handlers": {
        "stdout": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "simple",
            "stream": "ext://sys.stdout"
        },
        "file": {
            "class": "logging.handlers.RotatingFileHandler",
            "level": "WARNING",
            "formatter": "verbose",
            "filename": "template/multipage/logs/xxx_app.log",
            "maxBytes": 10485760,
            "backupCount": 20,
            "encoding": "utf8"
        }
    },
    "loggers": {
        "root": {
            "level": "DEBUG",
            "handlers": ["stdout", "file"]
        }
    }
}
def get_logger(name):
    logger = logging.getLogger(name)
    logging.config.dictConfig(config=logging_config)
    return logger

Categories: shiny

onesixx

Blog Owner

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x