2011-07-27 18 views
7

Từ đoạn 15.7.4 của python logging documentation:Tại sao bộ lọc không được gắn vào bộ ghi gốc để truyền tới logger hậu duệ?

Lưu ý rằng bộ lọc gắn liền với xử lý được hỏi ý kiến ​​bất cứ khi nào một sự kiện được phát ra bởi các handler, trong khi bộ lọc gắn liền với logger được hỏi ý kiến ​​bất cứ khi nào một sự kiện được đăng nhập vào Điều này có nghĩa là các sự kiện đã được tạo ra bởi logger hậu duệ sẽ không được lọc bởi thiết lập bộ lọc của trình ghi nhật ký, trừ khi bộ lọc cũng đã được áp dụng cho các logger hậu duệ đó.

Tôi không hiểu quyết định thiết kế này. Nó sẽ không có ý nghĩa hơn đối với bộ lọc của trình ghi nhật ký được áp dụng cho các logger hậu duệ không?

+1

Bạn sẽ làm gì sau đó nếu bạn muốn ghi đè bộ lọc? – agf

+0

Không được ghi đè. Nếu bạn muốn có bộ lọc hạn chế hơn trong trình ghi hậu duệ, bạn luôn có thể thêm bộ lọc. Không nên thư giãn các hạn chế của bộ lọc của bộ ghi log cha. Có lẽ tôi nên giải thích lý do tại sao tôi yêu cầu điều này - Tôi đang cố gắng để thiết lập đăng nhập để không có vấn đề gì logger được tạo ra trong dự án, thông tin nhất định luôn được lọc ra. Nó sẽ là tầm thường nếu các bộ lọc được truyền dọc theo chuỗi logger. – svintus

+0

Tôi không đồng ý, bạn luôn có thể ghi đè hành vi của một lớp cơ sở. Nếu bạn không bao giờ muốn một cái gì đó được đăng nhập - tại sao nó được gửi đến logger? – agf

Trả lời

3

Tôi đồng ý: đây là quyết định thiết kế phản trực giác, IMHO.

Giải pháp dễ nhất là đính kèm bộ lọc của bạn vào mọi trình xử lý có thể. Ví dụ: giả sử bạn có trình xử lý bảng điều khiển, trình xử lý thư và trình xử lý cơ sở dữ liệu, bạn nên đính kèm bộ lọc "root" của mình vào từng bộ lọc. : -/

import logging 
import logging.config 

class MyRootFilter(logging.Filter): 
    def filter(self, record): 
     # filter out log messages that include "secret" 
     if "secret" in record.msg: 
      return False 
     else: 
      return True 

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'filters': { 
     'my_root_filter': { 
      '()': MyRootFilter, 
     }, 
    }, 
    'handlers': { 
     'stderr': { 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      'filters': ['my_root_filter'], 
     }, 
     'mail_admins': { 
      'level': 'ERROR', 
      'class': 'some.kind.of.EmailHandler', 
      'filters': ['my_root_filter'], 
     }, 
     'database': { 
      'level': 'ERROR', 
      'class': 'some.kind.of.DatabaseHandler', 
      'filters': ['my_root_filter'], 
     }, 
    }, 
    'loggers': { 
     'some.sub.project': { 
      'handlers': ['stderr'], 
      'level': 'ERROR', 
     }, 
    }, 
} 

logging.config.dictConfig(LOGGING) 
logging.getLogger("some.sub.project").error("hello")  # logs 'hello' 
logging.getLogger("some.sub.project").error("hello secret") # filtered out! :-) 

Nếu có nhiều trình xử lý, bạn có thể muốn đính kèm bộ lọc gốc của mình vào mọi trình xử lý theo cách thủ công thay vì theo cách thủ công. Tôi khuyên bạn nên thực hiện điều này trực tiếp trên từ điển cấu hình (hoặc tệp của bạn, tùy thuộc vào cách bạn tải cấu hình đăng nhập), thay vì thực hiện việc này sau khi cấu hình đã được tải, vì dường như không có cách nào được tài liệu để có danh sách tất cả các trình xử lý. Tôi tìm thấy logger.handlers và logging._handlers, nhưng vì chúng không được ghi lại, chúng có thể bị phá vỡ trong tương lai. Ngoài ra, không có gì đảm bảo rằng chúng an toàn.

Giải pháp trước (gắn bộ lọc gốc của bạn vào mọi bộ xử lý trực tiếp trong cấu hình trước khi được tải) giả định rằng bạn có quyền kiểm soát cấu hình ghi nhật ký trước khi được tải và cũng không có trình xử lý nào được thêm động (sử dụng Logger #addHandler()). Nếu điều này không đúng, thì bạn có thể muốn khỉ vá mô-đun đăng nhập (chúc may mắn với điều đó!).

chỉnh sửa

Tôi mất một shot tại khỉ vá Logger # AddHandler, chỉ để cho vui. Nó thực sự hoạt động tốt và đơn giản hóa cấu hình, nhưng tôi không chắc chắn tôi sẽ khuyên bạn nên làm điều này (Tôi ghét khỉ-vá, nó làm cho nó rất khó để gỡ lỗi khi một cái gì đó đi sai). Sử dụng các rủi ro của riêng bạn ...

import logging 
import logging.config 

class MyRootFilter(logging.Filter): 
    [...] # same as above 

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'handlers': { 
     'stderr': { 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      # it's shorter: there's no explicit reference to the root filter 
     }, 
     [...] # other handlers go here 
    }, 
    'loggers': { 
     'some.sub.project': { 
      'handlers': ['stderr'], 
      'level': 'ERROR', 
     }, 
    }, 
} 

def monkey_patched_addHandler(self, handler): 
    result = self.old_addHandler(handler) 
    self.addFilter(MyRootFilter()) 
    return result 

logging.Logger.old_addHandler = logging.Logger.addHandler 
logging.Logger.addHandler = monkey_patched_addHandler 

logging.config.dictConfig(LOGGING) 
logging.getLogger("some.sub.project").error("hello")  # logs 'hello' 
logging.getLogger("some.sub.project").error("hello secret") # filtered out! :-) 
+0

Tôi đã từ lâu không thể quan tâm đến việc đăng nhập bằng Python, nhưng câu trả lời của bạn là đúng. Nhiều như tôi ghét khỉ-vá, nó sẽ là giải pháp ưa thích của tôi trong tình huống này :) – svintus

0

Hãy suy nghĩ theo cách này. Logger giống như các ống thoát nước ra khỏi nhà của bạn. Một bộ lọc trên một logger ngăn cản bạn đổ rác vào cống, nó không lọc toàn bộ hệ thống thoát nước. Nơi bạn đang ở trong dòng chảy (thượng lưu, hạ lưu) không thay đổi hành vi này.

Trình xử lý là các đường ống. Ống tích lũy dòng chảy ngược dòng. Đường ống mặc định là "skip, pass to parent". Nếu bạn muốn ảnh hưởng đến luồng ngược dòng, bạn cần đặt một bộ lọc không có đường ống (bộ xử lý). Nếu bạn nhìn vào logging flowchart, bạn có thể thêm NullHandler (không có định dạng hoặc đầu ra) mà các bộ lọc sẽ truyền bá thông điệp.

Đây là hành vi bạn mong muốn.

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