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! :-)
Bạn sẽ làm gì sau đó nếu bạn muốn ghi đè bộ lọc? – agf
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
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