파이썬 2.7.3에 로깅 기능을 사용합니다. 이 Python 버전에 대한 문서는 다음과 같습니다.
로깅 패키지는 str.format () 및 string.Template과 같은 최신 형식화 옵션보다 이전입니다. 이러한 최신 서식 옵션이 지원됩니다 …
중괄호가있는 ‘새’형식을 좋아합니다. 그래서 나는 다음과 같은 것을 시도하고 있습니다.
log = logging.getLogger("some.logger")
log.debug("format this message {0}", 1)
그리고 오류가 발생합니다.
TypeError : 문자열 형식화 중에 일부 인수가 변환되지 않았습니다.
내가 여기서 무엇을 그리워?
PS 나는 사용하고 싶지 않다
log.debug("format this message {0}".format(1))
이 경우 메시지는 로거 레벨에 관계없이 항상 형식화되기 때문입니다.
답변
편집 : 이 StyleAdapter
답변 과 달리 @Dunes의 답변에서 접근 방식을 살펴보십시오 . 로거의 메서드 (debug (), info (), error () 등)를 호출하는 동안 상용구없이 대체 형식화 스타일을 사용할 수 있습니다.
문서에서 — 대체 서식 스타일 사용 :
로깅 호출 (logger.debug (), logger.info () 등)은 실제 로깅 메시지 자체에 대한 위치 매개 변수 만 취하며, 키워드 매개 변수는 실제 로깅 호출을 처리하는 방법에 대한 옵션을 결정하는 데만 사용됩니다 (예 : exc_info 키워드 매개 변수). 추적 정보를 기록해야 함을 나타내거나 로그에 추가 할 추가 컨텍스트 정보를 나타내는 추가 키워드 매개 변수). 따라서 내부적으로 로깅 패키지는 %-포맷을 사용하여 형식 문자열과 변수 인수를 병합하기 때문에 str.format () 또는 string.Template 구문을 사용하여 로깅 호출을 직접 할 수 없습니다. 기존 코드에있는 모든 로깅 호출이 % 형식 문자열을 사용하기 때문에 이전 버전과의 호환성을 유지하면서이를 변경할 수 없습니다.
과:
그러나 {}-및 $-형식을 사용하여 개별 로그 메시지를 구성 할 수있는 방법이 있습니다. 메시지의 경우 임의의 개체를 메시지 형식 문자열로 사용할 수 있으며 로깅 패키지는 해당 개체에서 str ()을 호출하여 실제 형식 문자열을 가져올 수 있습니다.
이것을 wherever
모듈에 복사-붙여 넣기 :
class BraceMessage(object):
def __init__(self, fmt, *args, **kwargs):
self.fmt = fmt
self.args = args
self.kwargs = kwargs
def __str__(self):
return self.fmt.format(*self.args, **self.kwargs)
그때:
from wherever import BraceMessage as __
log.debug(__('Message with {0} {name}', 2, name='placeholders'))
참고 : 실제 포맷은 필요할 때까지 지연됩니다. 예를 들어 DEBUG 메시지가 기록되지 않으면 포맷이 전혀 수행되지 않습니다.
답변
Dunes의 답변에 언급 된 키워드 문제가없는 또 다른 옵션이 있습니다. {0}
키워드 ( {foo}
) 인수가 아닌 위치 ( ) 인수 만 처리 할 수 있습니다 . 또한 형식을 지정하기 위해 두 번의 호출이 필요하지 않습니다 (밑줄 사용). 하위 클래스의 ick-factor가 있습니다 str
.
class BraceString(str):
def __mod__(self, other):
return self.format(*other)
def __str__(self):
return self
class StyleAdapter(logging.LoggerAdapter):
def __init__(self, logger, extra=None):
super(StyleAdapter, self).__init__(logger, extra)
def process(self, msg, kwargs):
if kwargs.pop('style', "%") == "{": # optional
msg = BraceString(msg)
return msg, kwargs
다음과 같이 사용합니다.
logger = StyleAdapter(logging.getLogger(__name__))
logger.info("knights:{0}", "ni", style="{")
logger.info("knights:{}", "shrubbery", style="{")
물론 # optional
어댑터를 통한 모든 메시지가 새 스타일 형식을 사용하도록 강제하기 위해 표시된 확인을 제거 할 수 있습니다 .
몇 년 후이 답변을 읽는 모든 사람을위한 참고 사항 : Python 3.2 부터는 객체 와 함께 스타일 매개 변수 를 사용할 수 있습니다Formatter
.
로깅 (3.2부터)은 이러한 두 가지 추가 서식 스타일에 대한 향상된 지원을 제공합니다. Formatter 클래스는라는 추가 선택적 키워드 매개 변수를 사용하도록 향상되었습니다
style
. 기본값은'%'
이지만 다른 가능한 값은 다른 두 서식 스타일에 해당하는'{'
및'$'
입니다. 이전 버전과의 호환성은 기본적으로 유지되지만 (예상대로) 명시 적으로 스타일 매개 변수를 지정하면str.format()
또는에서
작동하는 형식 문자열을 지정할 수string.Template
있습니다.
문서는 예제를 제공합니다.
logging.Formatter('{asctime} {name} {levelname:8s} {message}', style='{')
이 경우에도 logger
새 형식으로를 호출 할 수 없습니다 . 즉, 다음은 여전히 작동하지 않습니다.
logger.info("knights:{say}", say="ni") # Doesn't work!
logger.info("knights:{0}", "ni") # Doesn't work either
답변
이것은 로깅이 printf 스타일 형식화만을 사용한다는 것을 알았을 때 문제에 대한 나의 해결책이었습니다. 로깅 호출을 동일하게 유지할 수 있습니다 log.info(__("val is {}", "x"))
. 코딩에 필요한 변경 사항은 로거를 StyleAdapter
.
from inspect import getargspec
class BraceMessage(object):
def __init__(self, fmt, args, kwargs):
self.fmt = fmt
self.args = args
self.kwargs = kwargs
def __str__(self):
return str(self.fmt).format(*self.args, **self.kwargs)
class StyleAdapter(logging.LoggerAdapter):
def __init__(self, logger):
self.logger = logger
def log(self, level, msg, *args, **kwargs):
if self.isEnabledFor(level):
msg, log_kwargs = self.process(msg, kwargs)
self.logger._log(level, BraceMessage(msg, args, kwargs), (),
**log_kwargs)
def process(self, msg, kwargs):
return msg, {key: kwargs[key]
for key in getargspec(self.logger._log).args[1:] if key in kwargs}
사용법은 다음과 같습니다.
log = StyleAdapter(logging.getLogger(__name__))
log.info("a log message using {type} substitution", type="brace")
중괄호 대체에 사용되는 핵심 단어를 포함하는 경우이 구현에 문제가 있다는 지적이의 가치 level
, msg
, args
, exc_info
, extra
또는 stack_info
. 의 log
메서드에서 사용하는 인수 이름 입니다 Logger
. 이러한 이름 중 하나가 필요한 경우 이러한 이름 process
을 제외하도록 수정 하거나 호출 log_kwargs
에서 제거 _log
하십시오. 추가로,이 구현은 Logger (예 :)를 의미하는 맞춤법이 틀린 키워드를 조용히 무시합니다 ectra
.
답변
더 쉬운 해결책은 우수한 모듈 을 사용하는 것입니다.logbook
import logbook
import sys
logbook.StreamHandler(sys.stdout).push_application()
logbook.debug('Format this message {k}', k=1)
또는 더 완전한 :
>>> import logbook
>>> import sys
>>> logbook.StreamHandler(sys.stdout).push_application()
>>> log = logbook.Logger('MyLog')
>>> log.debug('Format this message {k}', k=1)
[2017-05-06 21:46:52.578329] DEBUG: MyLog: Format this message 1
답변
다른 답변에서 언급했듯이 Python 3.2에 도입 된 중괄호 스타일 형식 은 실제 로그 메시지가 아닌 형식 문자열에만 사용됩니다.
실제 로그 메시지에서 중괄호 형식의 형식을 사용하려면 로거 코드를 약간 원숭이 패치 할 수 있습니다.
다음은 logging
모듈을 패치하여 get_logger
처리하는 모든 로그 레코드에 대해 새로운 스타일 형식을 사용하는 로거를 반환 하는 함수 를 만듭니다 .
import functools
import logging
import types
def _get_message(record):
"""Replacement for logging.LogRecord.getMessage
that uses the new-style string formatting for
its messages"""
msg = str(record.msg)
args = record.args
if args:
if not isinstance(args, tuple):
args = (args,)
msg = msg.format(*args)
return msg
def _handle_wrap(fcn):
"""Wrap the handle function to replace the passed in
record's getMessage function before calling handle"""
@functools.wraps(fcn)
def handle(record):
record.getMessage = types.MethodType(_get_message, record)
return fcn(record)
return handle
def get_logger(name=None):
"""Get a logger instance that uses new-style string formatting"""
log = logging.getLogger(name)
if not hasattr(log, "_newstyle"):
log.handle = _handle_wrap(log.handle)
log._newstyle = True
return log
용법:
>>> log = get_logger()
>>> log.warning("{!r}", log)
<logging.RootLogger object at 0x4985a4d3987b>
메모:
- 일반 로깅 방법 (바로 교체와 완벽하게 호환
logging.getLogger
과get_logger
) get_logger
함수에 의해 생성 된 특정 로거에만 영향을 미칩니다 (타사 패키지를 손상시키지 않음).- 일반
logging.getLogger()
호출 에서 로거에 다시 액세스하는 경우 새 스타일 형식이 계속 적용됩니다. - kwargs로는 (차종이 불가능와 충돌에 내장에서 지원되지 않습니다
exc_info
,stack_info
,stacklevel
및extra
)를. - 성능 적중은 최소화되어야합니다 (각 로그 메시지에 대해 단일 함수 포인터를 다시 작성).
- 메시지 형식화는 출력 될 때까지 지연됩니다 (또는 로그 메시지가 필터링 된 경우에는 아예 아님).
- Args는
logging.LogRecord
평소와 같이 개체 에 저장됩니다 (사용자 지정 로그 처리기를 사용하는 경우에 유용함). logging
모듈 소스 코드를 살펴보면 Python 2.6str.format
이 도입 되었을 때 다시 작동해야하는 것처럼 보입니다 (하지만 3.5 이상에서만 테스트했습니다).
답변
logging.setLogRecordFactory
Python 3.2 이상에서 사용 해보세요 .
import collections
import logging
class _LogRecord(logging.LogRecord):
def getMessage(self):
msg = str(self.msg)
if self.args:
if isinstance(self.args, collections.Mapping):
msg = msg.format(**self.args)
else:
msg = msg.format(*self.args)
return msg
logging.setLogRecordFactory(_LogRecord)
답변
다음 과 같이 문제를 처리하는 ColorFormatter 라는 사용자 지정 Formatter를 만들었습니다 .
class ColorFormatter(logging.Formatter):
def format(self, record):
# previous stuff, copy from logging.py…
try: # Allow {} style
message = record.getMessage() # printf
except TypeError:
message = record.msg.format(*record.args)
# later stuff…
이것은 다양한 라이브러리와의 호환성을 유지합니다. 단점은 잠재적으로 문자열 형식을 두 번 시도하기 때문에 성능이 떨어질 수 있다는 것입니다.