2011-09-07 35 views
11

Tôi mới sử dụng tính năng ghi nhật ký của Python và tôi có thể dễ dàng thấy cách nó thích hợp hơn với giải pháp pha chế tại nhà mà tôi đã đưa ra.Tắt ghi nhật ký cho mỗi phương thức/chức năng?

Một câu hỏi tôi dường như không thể tìm thấy câu trả lời cho: làm thế nào để tôi squelch đăng nhập tin nhắn trên cơ sở mỗi phương pháp/chức năng?

Mô-đun giả thuyết của tôi chứa một hàm duy nhất. Như tôi đã phát triển, các cuộc gọi đăng nhập là một trợ giúp lớn:

logging.basicConfig(level=logging.DEBUG, 
       format=('%(levelname)s: %(funcName)s(): %(message)s')) 
log = logging.getLogger() 

my_func1(): 
    stuff... 
    log.debug("Here's an interesting value: %r" % some_value) 
    log.info("Going great here!") 
    more stuff... 

Như tôi đã quấn lên công việc của tôi trên 'my_func1' và bắt đầu làm việc trên một chức năng thứ hai, 'my_func2', các thông điệp logging từ 'my_func1' bắt đầu đi từ "hữu ích" đến "lộn xộn".

Có câu lệnh ma thuật một dòng, chẳng hạn như 'logging.disabled_in_this_func()' mà tôi có thể thêm vào đầu 'my_func1' để vô hiệu hóa tất cả các cuộc gọi đăng nhập trong 'my_func1', nhưng vẫn để lại các cuộc gọi ghi nhật ký trong tất cả các hàm/phương thức khác không thay đổi?

Cảm ơn

linux, Python 2.7.1

+0

Liên quan: http://stackoverflow.com/questions/879732/logging-with-filters –

Trả lời

8

Bí quyết là tạo nhiều nhật ký.

Có một số khía cạnh cho việc này.

Trước tiên. Không sử dụng logging.basicConfig() khi bắt đầu mô-đun. Sử dụng nó chỉ bên trong công tắc chính nhập khẩu

if __name__ == "__main__": 
    logging.basicConfig(...) 
    main() 
    logging.shutdown() 

thứ hai. Không bao giờ nhận được trình ghi nhật ký "root", ngoại trừ thiết lập các tùy chọn toàn cục.

Thứ ba. Nhận từng số có tên là nhật ký cho những thứ có thể được bật hoặc tắt.

log = logging.getLogger(__name__) 

func1_log = logging.getLogger("{0}.{1}".format(__name__, "my_func1") 

Bây giờ bạn có thể đặt mức ghi nhật ký trên mỗi trình ghi nhật ký được đặt tên.

log.setLevel(logging.INFO) 
func1_log.setLevel(logging.ERROR) 
+0

Cảm ơn bạn đã đề xuất đặt cấu hình ghi nhật ký bên trong công tắc nhập chính. Tốt để biết. Có sử dụng trình ghi nhật ký gốc không được đề xuất ngay cả đối với một tập lệnh mô-đun đơn như tôi đang làm việc ngay bây giờ không? Bạn có thể làm rõ các khuyết điểm để làm như vậy? –

+2

"sử dụng trình ghi nhật ký gốc không được khuyến nghị". Giai đoạn. Không sử dụng nó. Đó là "ẩn danh". Bạn chỉ muốn có tên logger để có thể cấu hình và lọc. –

+0

Để xây dựng trên thông điệp rõ ràng của @ S.Lott: Nếu bạn thêm trình xử lý vào trình ghi nhật ký, bạn sẽ bắt đầu nhận thư từ ** tất cả ** các gói khác mà bạn sử dụng, có thể rất lộn xộn (ví dụ: 'yêu cầu'). Và ngược lại, khi một gói khác sử dụng gói của bạn, các tin nhắn từ gói của bạn cũng không thể được xử lý riêng. Thiết kế xấu. – j08lue

2

Bạn có thể sử dụng một trang trí:

import logging 
import functools 

def disable_logging(func): 
    @functools.wraps(func) 
    def wrapper(*args,**kwargs): 
     logging.disable(logging.DEBUG) 
     result = func(*args,**kwargs) 
     logging.disable(logging.NOTSET) 
     return result 
    return wrapper 

@disable_logging 
def my_func1(...): 
+0

Hah! Bạn đánh tôi bằng giây. Hãy cẩn thận bên trong 'wrapper' vì nó sẽ không kích hoạt lại việc ghi nhật ký cuộc gọi' func() 'ném một ngoại lệ. Đó là lý do tại sao tôi sử dụng cụm từ 'try/finally' để đảm bảo rằng việc ghi nhật ký được kích hoạt lại cho dù' func() 'thành công hay không. –

6

Bạn có thể tạo một trang trí tạm thời sẽ ngừng khai thác gỗ, ala:

from functools import wraps 

def suspendlogging(func): 
    @wraps(func) 
    def inner(*args, **kwargs): 
     previousloglevel = log.getEffectiveLevel() 
     try: 
      return func(*args, **kwargs) 
     finally: 
      log.setLevel(previousloglevel) 
    return inner 

@suspendlogging 
def my_func1(): ... 

Lưu ý: điều đó cũng sẽ tạm dừng ghi nhật ký cho bất kỳ hàm nào được gọi từ my_func 1 vì vậy hãy cẩn thận cách bạn sử dụng nó.

+0

Cách tiếp cận tốt cho rất nhiều ứng dụng. Cảm ơn! –

+0

Tôi đoán điều này đáng lẽ phải là nhà máy trang trí để người đăng nhập đình chỉ. –

+0

Xin vui lòng sửa tôi nếu tôi sai, nhưng nhìn với tôi rằng điều này sẽ chỉ vô hiệu hóa một logger tên là 'log'. Nếu có một số nhật ký đang được sử dụng cùng một lúc, ví dụ: trong một ứng dụng Django, làm thế nào điều này có thể vô hiệu hóa tất cả các logger? –

0

Tôi đã dành chút thời gian để tìm hiểu cách triển khai trình ghi nhật ký theo đề xuất của S.Lott.

Với mức độ khó khăn khi tìm hiểu cách thiết lập ghi nhật ký khi tôi bắt đầu, tôi đã biết thời gian dài để chia sẻ những gì tôi đã học được từ đó.

Hãy ghi nhớ rằng đây không phải là cách duy nhất để thiết lập logger/logger, cũng không phải là tốt nhất. Đó chỉ là cách tôi sử dụng để hoàn thành công việc cho phù hợp với nhu cầu của mình. Tôi hy vọng điều này là hữu ích cho một ai đó. Xin vui lòng bình luận/chia sẻ/phê bình.


Giả sử chúng tôi có một thư viện đơn giản mà chúng tôi muốn sử dụng. Từ chương trình chính, chúng tôi muốn có thể kiểm soát các thông điệp đăng nhập mà chúng tôi nhận được từ thư viện. Tất nhiên, chúng tôi là những người sáng tạo thư viện chu đáo, vì vậy chúng tôi định cấu hình thư viện của mình để làm việc này dễ dàng.

Thứ nhất, chương trình chính:

# some_prog.py 

import os 
import sys 

# Be sure to give Vinay Sajip thanks for his creation of the logging module 
# and tireless efforts to answer our dumb questions about it. Thanks Vinay! 
import logging 

# This module will make understanding how Python logging works so much easier. 
# Also great for debugging why your logging setup isn't working. 
# Be sure to give it's creator Brandon Rhodes some love. Thanks Brandon! 
import logging_tree 

# Example library 
import some_lib 

# Directory, name of current module 
current_path, modulename = os.path.split(os.path.abspath(__file__)) 
modulename = modulename.split('.')[0] # Drop the '.py' 


# Set up a module-local logger 
# In this case, the logger will be named 'some_prog' 
log = logging.getLogger(modulename) 

# Add a Handler. The Handler tells the logger *where* to send the logging 
# messages. We'll set up a simple handler that send the log messages 
# to standard output (stdout) 
stdout_handler = logging.StreamHandler(stream=sys.stdout) 
log.addHandler(stdout_handler) 


def some_local_func(): 
    log.info("Info: some_local_func()") 
    log.debug("Debug: some_local_func()") 


if __name__ == "__main__": 

    # Our main program, here's where we tie together/enable the logging infra 
    # we've added everywhere else. 

    # Use logging_tree.printout() to see what the default log levels 
    # are on our loggers. Make logging_tree.printout() calls at any place in 
    # the code to see how the loggers are configured at any time. 
    # 
    # logging_tree.printout() 

    print("# Logging level set to default (i.e. 'WARNING').") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 

    # We know a reference to our local logger, so we can set/change its logging 
    # level directly. Let's set it to INFO: 
    log.setLevel(logging.INFO) 
    print("# Local logging set to 'INFO'.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    # Next, set the local logging level to DEBUG: 
    log.setLevel(logging.DEBUG) 
    print("# Local logging set to 'DEBUG'.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    # Set the library's logging level to DEBUG. We don't necessarily 
    # have a reference to the library's logger, but we can use 
    # logging_tree.printout() to see the name and then call logging.getLogger() 
    # to create a local reference. Alternately, we could dig through the 
    # library code. 
    lib_logger_ref = logging.getLogger("some_lib") 
    lib_logger_ref.setLevel(logging.DEBUG) 

    # The library logger's default handler, NullHandler() won't output anything. 
    # We'll need to add a handler so we can see the output -- in this case we'll 
    # also send it to stdout. 
    lib_log_handler = logging.StreamHandler(stream=sys.stdout) 
    lib_logger_ref.addHandler(lib_log_handler) 
    lib_logger_ref.setLevel(logging.DEBUG) 

    print("# Logging level set to DEBUG in both local program and library.") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 


    print("# ACK! Setting the library's logging level to DEBUG output") 
    print("# all debug messages from the library. (Use logging_tree.printout()") 
    print("# To see why.)") 
    print("# Let's change the library's logging level to INFO and") 
    print("# only some_special_func()'s level to DEBUG so we only see") 
    print("# debug message from some_special_func()") 

    # Raise the logging level of the libary and lower the logging level 
    # of 'some_special_func()' so we see only some_special_func()'s 
    # debugging-level messages. 
    # Since it is a sub-logger of the library's main logger, we don't need 
    # to create another handler, it will use the handler that belongs 
    # to the library's main logger. 
    lib_logger_ref.setLevel(logging.INFO) 
    special_func_sub_logger_ref = logging.getLogger('some_lib.some_special_func') 
    special_func_sub_logger_ref.setLevel(logging.DEBUG) 

    print("# Logging level set to DEBUG in local program, INFO in library and") 
    print("# DEBUG in some_lib.some_special_func()") 
    some_local_func() 
    some_lib.some_lib_func() 
    some_lib.some_special_func() 

Tiếp theo, thư viện của chúng tôi:

# some_lib.py 

import os 
import logging 

# Directory, name of current module 
current_path, modulename = os.path.split(os.path.abspath(__file__)) 
modulename = modulename.split('.')[0] # Drop the '.py' 

# Set up a module-local logger. In this case the logger will be 
# named 'some_lib' 
log = logging.getLogger(modulename) 

# In libraries, always default to NullHandler so you don't get 
# "No handler for X" messages. 
# Let your library callers set up handlers and set logging levels 
# in their main program so the main program can decide what level 
# of messages they want to see from your library. 
log.addHandler(logging.NullHandler()) 

def some_lib_func(): 
    log.info("Info: some_lib.some_lib_func()") 
    log.debug("Debug: some_lib.some_lib_func()") 

def some_special_func(): 
    """ 
    This func is special (not really). It just has a function/method-local 
    logger in addition to the library/module-level logger. 
    This allows us to create/control logging messages down to the 
    function/method level. 

    """ 
    # Our function/method-local logger 
    func_log = logging.getLogger('%s.some_special_func' % modulename) 

    # Using the module-level logger 
    log.info("Info: some_special_func()") 

    # Using the function/method-level logger, which can be controlled separately 
    # from both the library-level logger and the main program's logger. 
    func_log.debug("Debug: some_special_func(): This message can be controlled at the function/method level.") 

Bây giờ chúng ta hãy chạy chương trình, cùng với các ca khúc bình luận:

# Logging level set to default (i.e. 'WARNING'). 

Thông báo có không có đầu ra ở mức mặc định vì chúng tôi chưa tạo bất kỳ thông báo mức cảnh báo nào.

# Local logging set to 'INFO'. 
Info: some_local_func() 

Trình xử lý của thư viện mặc định là NullHandler(), vì vậy chúng tôi chỉ thấy đầu ra từ chương trình chính. Điều này là tốt.

# Local logging set to 'DEBUG'. 
Info: some_local_func() 
Debug: some_local_func() 

Bộ ghi nhật ký chương trình chính được đặt thành DEBUG. Chúng tôi vẫn không thấy đầu ra từ thư viện. Điều này là tốt.

# Logging level set to DEBUG in both local program and library. 
Info: some_local_func() 
Debug: some_local_func() 
Info: some_lib.some_lib_func() 
Debug: some_lib.some_lib_func() 
Info: some_special_func() 
Debug: some_special_func(): This message can be controlled at the function/method level. 

Rất tiếc.

# ACK! Setting the library's logging level to DEBUG output 
# all debug messages from the library. (Use logging_tree.printout() 
# To see why.) 
# Let's change the library's logging level to INFO and 
# only some_special_func()'s level to DEBUG so we only see 
# debug message from some_special_func() 
# Logging level set to DEBUG in local program, INFO in library and 
# DEBUG in some_lib.some_special_func() 
Info: some_local_func() 
Debug: some_local_func() 
Info: some_lib.some_lib_func() 
Info: some_special_func() 
Debug: some_special_func(): This message can be controlled at the function/method level. 

Cũng có thể để có được chỉ thông điệp debug chỉ từ some_special_func(). Sử dụng logging_tree.printout() để tìm ra mức độ ghi nhật ký nào để tinh chỉnh để thực hiện điều đó!

Các vấn đề liên quan