문제

오늘 나는 내가 사용한 곳에서 약 1 년 전에 쓴 파이썬 프로젝트에 대해 생각하고있었습니다. logging 꽤 광범위하게. 오버 헤드로 인해 내부 루프와 같은 시나리오 (90% 코드)에서 많은 로깅 호출을 언급해야했던 것을 기억합니다 (hotshot 내 가장 큰 병목 현상 중 하나임을 나타냅니다).

항상 댓글을 달고 무책임하지 않고 Python 응용 프로그램에서 로깅 호출을 프로그래밍 방식으로 제거하는 정식 방법이 있는지 궁금합니다. 검사/재 컴파일 또는 바이트 코드 조작을 사용하여 이와 같은 일을 할 수 있다고 생각합니다. 병목 현상을 일으키는 코드 객체 만 타겟팅하십시오. 이렇게하면 조작 후 단계로 조작기를 추가하고 다음과 같은 중앙 집중식 구성 파일을 사용할 수 있습니다.

[Leave ERROR and above]
my_module.SomeClass.method_with_lots_of_warn_calls

[Leave WARN and above]
my_module.SomeOtherClass.method_with_lots_of_info_calls

[Leave INFO and above]
my_module.SomeWeirdClass.method_with_lots_of_debug_calls

물론, 당신은 그것을 드물게 사용하고 아마도 기능 당 과립과 함께 사용하고 싶을 것입니다. - 표시된 코드 객체에만 해당됩니다 logging 병목 현상. 이런 것을 아는 사람이 있습니까?

메모: 동적 타이핑과 늦은 바인딩으로 인해 성능있는 방식으로 수행하기가 더 어려워지는 몇 가지가 있습니다. 예를 들어, 이름이 지정된 메소드에 대한 호출 debug an으로 싸여 있어야 할 수도 있습니다 if not isinstance(log, Logger). 어쨌든, 나는 신사의 합의 나 런타임 점검으로 모든 사소한 세부 사항을 극복 할 수 있다고 가정합니다. :-)

도움이 되었습니까?

해결책

사용은 어떻습니까 로깅?

나는 또한 내가 사용해야한다는 것을 알았습니다 logging.isenabledfor 로깅 메시지가 작성하는 데 비용이 많이 드는 경우.

다른 팁

사용 pypreprocessor

또한 찾을 수 있습니다 PYPI (파이썬 패키지 색인) PIP를 사용하여 가져 오십시오.

기본 사용 예는 다음과 같습니다.

from pypreprocessor import pypreprocessor

pypreprocessor.parse()

#define nologging

#ifdef nologging
...logging code you'd usually comment out manually...
#endif

기본적으로 전처리 기는 이전에 수동으로 수행하는 방식에 따라 코드를 언급합니다. 그것은 당신이 정의하는 것에 따라 조건부로 즉시 그것을 수행합니다.

import와 parse () 문들 사이에 'pypreprocessor.removemeta = true'를 추가하여 모든 전처리 서자 지시문을 제거하고 후 처리 된 코드에서 코드를 댓글을 달아 줄 수 있습니다.

바이트 코드 출력 (.pyc) 파일에는 최적화 된 출력이 포함됩니다.

Sidenote : PypreProcessor는 Python2X 및 Python3K와 호환됩니다.

면책 조항 : 저는 PypreProcessor의 저자입니다.

나는 또한이 방식으로 사용 된 Assert를 보았다.

assert logging.warn('disable me with the -O option') is None

(나는 항상 경고가 없다고 생각합니다.

그러나 실제로 그것은 이것을하는 재미있는 방법입니다.

if __debug__: logging.warn('disable me with the -O option')

-o 옵션으로 해당 라인이있는 스크립트를 실행하면 최적화 된 .pyo 코드에서 라인이 제거됩니다. 대신 다음과 같이 자신의 변수가있는 경우, 조건부가 함수 호출보다 더 빨리 실행해야하지만 (변수의 가치에 관계없이) 항상 실행되는 조건부가 있습니다.

my_debug = True
...
if my_debug: logging.warn('disable me by setting my_debug = False')

그래서 내 이해가 있다면 디버그 맞습니다. 불필요한 벌목 통화를 제거하는 좋은 방법 인 것 같습니다. 플립 사이드는 모든 어설 션을 비활성화한다는 것입니다. 어서 필요하면 문제가됩니다.

불완전한 지름길로서 조롱하는 것은 어떻습니까? logging 같은 것을 사용하는 특정 모듈에서 미니 콕?

예를 들어, if my_module.py 였다:

import logging
class C(object):
    def __init__(self, *args, **kw):
        logging.info("Instantiating")

당신은 당신의 사용을 대체 할 것입니다 my_module 와 함께:

from minimock import Mock
import my_module
my_module.logging = Mock('logging')
c = my_module.C()

모듈의 초기 가져 오기 전에 한 번만이 작업을 수행하면됩니다.

특정 방법을 조롱하거나 logging.getLogger 무의미한 방법으로 모의 물체를 반환하고 다른 방법은 실제에 위임하는 다른 방법을 반환합니다. logging 기준 치수.

실제로, 당신은 아마도 Minimock을 더 단순하고 빠른 것으로 바꾸고 싶을 것입니다. 최소한 Stdout에 사용을 인쇄하지 않는 것! 물론 이것은 모듈의 문제를 다루지 않습니다. logging 모듈 B에서 (따라서 A는 B의 로그 세분화를 가져 오는 A) ... ...

이것은 로그 문을 전혀 실행하지 않는 것만 큼 빠르지 않지만,이 레코드가 결국 기록되지 않아야한다는 것을 발견하기 위해 로깅 모듈의 깊이로 들어가는 것보다 훨씬 빠릅니다.

당신은 다음과 같은 것을 시도 할 수 있습니다 :

# Create something that accepts anything
class Fake(object):
    def __getattr__(self, key):
        return self
    def __call__(self, *args, **kwargs):
        return True

# Replace the logging module
import sys
sys.modules["logging"] = Fake()

기본적으로 로깅 모듈의 공간을 인스턴스로 대체 (또는 처음에 채우는) Fake 단순히 무엇이든 가져갑니다. 로깅 모듈이 어디에서나 사용되기 전에 위의 코드를 실행해야합니다 (한 번만!). 테스트는 다음과 같습니다.

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(levelname)-8s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='/temp/myapp.log',
                    filemode='w')
logging.debug('A debug message')
logging.info('Some information')
logging.warning('A shot across the bows')

위의 경우, 예상대로 아무것도 기록되지 않았습니다.

나는 멋진 로깅 데코레이터를 사용하거나 많은 것들을 사용합니다.

def doLogging(logTreshold):
    def logFunction(aFunc):
        def innerFunc(*args, **kwargs):
            if LOGLEVEL >= logTreshold:
                print ">>Called %s at %s"%(aFunc.__name__, time.strftime("%H:%M:%S"))
                print ">>Parameters: ", args, kwargs if kwargs else "" 
            try:
                return aFunc(*args, **kwargs)
            finally:
                print ">>%s took %s"%(aFunc.__name__, time.strftime("%H:%M:%S"))
        return innerFunc
    return logFunction

각 모듈에서 로그 레벨 상수를 선언하는 것만으로도 (또는 전역으로 단지 모든 모듈에서 가져 오기 만하면) 다음과 같이 사용할 수 있습니다.

@doLogging(2.5)
def myPreciousFunction(one, two, three=4):
    print "I'm doing some fancy computations :-)"
    return

그리고 로그 레벨이 2.5 이상인 경우 다음과 같이 출력됩니다.

>>Called myPreciousFunction at 18:49:13
>>Parameters:  (1, 2) 
I'm doing some fancy computations :-)
>>myPreciousFunction took 18:49:13

보시다시피, Kwargs를 더 잘 처리하려면 일부 작업이 필요하므로 기본값이있는 경우 기본값이 인쇄되지만 또 다른 질문입니다.

아마 일부를 사용해야합니다 logger RAW 대신 모듈 print 진술이지만, 나는 데코레이터 아이디어에 집중하고 코드를 너무 길게 만드는 것을 피하고 싶었습니다.

어쨌든 - 이러한 데코레이터를 사용하면 기능 수준 로깅, 임의로 많은 로그 레벨, 새로운 기능에 대한 적용의 용이성, 로깅을 비활성화하려면 로그 레벨 만 설정하면됩니다. 원하는 경우 각 기능에 대해 다른 출력 스트림/파일을 정의 할 수 있습니다. dologging을 다음과 같이 쓸 수 있습니다.

 def doLogging(logThreshold, outStream=sys.stdout):
      .....
      print >>outStream, ">>Called %s at %s" etc.

기능별로 정의 된 로그 파일을 사용합니다.

잘 로깅이 프로파일 러 보고서에 매우 일관되게 진행되면서 프로젝트의 문제입니다.

Pyflakes 포크에서 _ast 모듈을 사용했습니다.http://github.com/kevinw/pyflakes) ... 그리고 당신의 질문에서 제안한 일을 할 수 있습니다. 로깅 방법에 대한 호출 전에 경비원을 검사하고 주입하는 것이 가능합니다 (런타임 유형 확인을 수행해야한다는 승인 된 경고와 함께). 보다 http://pyside.blogspot.com/2008/03/ast-compilation-from-python.html 간단한 예를 위해.

편집하다: 방금 눈치 채 셨습니다 Metapython My My My Planetpython.org 피드-예제 사용 사례는 가져 오기 시간에 로그 문을 제거하는 것입니다.

아마도 가장 좋은 해결책은 누군가가 C 모듈로 벌목을 다시 구현하는 것이지만, 나는 그런 기회를 가장 먼저 뛰어 넘지 않을 것입니다 ... P는 다음과 같습니다.

:-) 우리는 그것을 사전 처리기라고 부르 곤했고 C의 사전 처리기는 그 역할 중 일부를 가지고 있었지만 "언덕의 왕"은 IBM Mainframe PL/i의 전처리 자였습니다. 사전 처리기 (전체 과제, 조건부, 루핑 등)에서 광범위한 언어 지원을 제공했으며 PL/I PP 만 사용하여 "프로그램을 작성하는 프로그램"을 작성할 수있었습니다.

나는 완전한 정교한 프로그램과 데이터 추적 (당시 백엔드 프로세스에 대한 괜찮은 디버거가 없었 음)을 사용하여 개발 및 테스트에 사용하여 적절한 "런타임 플래그"로 컴파일 될 때 많은 응용 프로그램을 작성했습니다. 성능 영향없이 모든 추적 코드를 깨끗하게 제거했습니다.

데코레이터 아이디어가 좋은 생각이라고 생각합니다. 로깅이 필요한 기능을 감싸기 위해 데코레이터를 작성할 수 있습니다. 그런 다음 런타임 배포의 경우 데코레이터가 "No-OP"로 바뀌어 디버깅 문을 제거합니다.

존 r

Pandas 라이브러리를 사용하여 데이터 분석 API에 대한 로직 및 실행 시간을 테스트하기 위해 광범위한 로깅을 사용하는 프로젝트를 수행하고 있습니다.

비슷한 우려 사항이있는이 문자열을 찾았습니다. 예 : 로깅의 오버 헤드는 무엇입니까.

배포 전에 다음 스크립트를 작성하거나 디버그 로깅을 댓글을 달아주는 데 의지했습니다.

import os
import fileinput

comment = True

# exclude files or directories matching string
fil_dir_exclude = ["__","_archive",".pyc"]

if comment :
    ## Variables to comment
    source_str = 'logging.debug'
    replace_str = '#logging.debug'
else :
    ## Variables to uncomment
    source_str = '#logging.debug'
    replace_str = 'logging.debug'

# walk through directories
for root, dirs, files in os.walk('root/directory') :
    # where files exist
    if files:
        # for each file
        for file_single in files :
            # build full file name
            file_name = os.path.join(root,file_single)
            # exclude files with matching string
            if not any(exclude_str in file_name for exclude_str in fil_dir_exclude) :
                # replace string in line
                for line in fileinput.input(file_name, inplace=True):
                    print "%s" % (line.replace(source_str, replace_str)),

이것은 기준 목록을 기반으로 파일을 제외하고 여기에 찾은 답변을 기반으로 대체를 수행하는 파일 재귀입니다. 파이썬의 파일에서 줄 검색 및 교체

나는 '__debug_'솔루션을 좋아하는 것을 좋아합니다. 나는이 같은 문제가 있었고 소스 파일을 자동으로 구문 분석하고 로깅 문을 패스 명령문으로 대체하는 스크립트를 작성하여이를 극복했습니다 (및 로깅 진술의 사본을 주평한). 또한이 변환을 취소 할 수 있습니다.

프로덕션 환경에서 필요하지 않은 로깅 진술이 많고 성능에 영향을 미치는 로깅 진술이 많을 때 프로덕션 환경에 새 코드를 배포 할 때 사용합니다.

여기에서 스크립트를 찾을 수 있습니다. http://dound.com/2010/02/python-logging-performance/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top