Hướng dẫn python performance logging - ghi nhật ký hiệu suất python
Gói Stdlib 5 cung cấp rất nhiều tính linh hoạt và chức năng cho các nhà phát triển / DevOps / nhân viên hỗ trợ, và sự linh hoạt đó có một số chi phí, rõ ràng. Nếu nhu cầu về hiệu suất vượt qua sự cần thiết phải linh hoạt, bạn cần phải đi với một thứ khác. Bạn đã thực hiện các bước để tối ưu hóa mô tả trong tài liệu? Một cuộc gọi ghi nhật ký điển hình theo thứ tự hàng chục micro giây trên phần cứng hợp lý, điều mà hầu như không có vẻ quá mức. Tuy nhiên, việc đăng nhập vào các vòng lặp chặt chẽ hiếm khi được khuyến khích, nếu chỉ vì lượng thông tin được tạo ra có thể mất quá nhiều thời gian để lội qua. Show
Mã để tìm người gọi có thể khá đắt, nhưng là cần thiết nếu bạn muốn, ví dụ: Tên tệp và số dòng nơi thực hiện cuộc gọi ghi nhật ký. 6 được dành cho các kịch bản trong đó I/O khai thác sẽ mất thời gian đáng kể và không thể thực hiện theo băng tần. Ví dụ: một ứng dụng web có nhật ký cần được gửi qua email cho quản trị viên trang web không thể rủi ro bằng cách sử dụng trực tiếp 7, vì cái bắt tay email có thể chậm.Đừng quên rằng việc chuyển đổi ngữ cảnh trong Python là chậm. Bạn đã thử 8 chưa? Có một điểm bắt đầu phù hợp trong tài liệu cho một quy trình nhận riêng thực hiện I/O thực tế để nộp, email, v.v. để quy trình của bạn chỉ thực hiện ổ cắm I/O và không thực hiện chuyển đổi ngữ cảnh chỉ để ghi nhật ký. Và sử dụng ổ cắm tên miền hoặc UDP có thể vẫn nhanh hơn, mặc dù sau đó là mất mát.Có nhiều cách khác để tối ưu hóa. Ví dụ, các trình xử lý tiêu chuẩn trong việc ghi nhật ký làm khóa xung quanh 9, đối với an toàn chủ đề - nếu trong một kịch bản cụ thể dưới sự kiểm soát của bạn, không có sự tranh chấp nào đối với người xử lý, bạn có thể có một lớp con xử lý không thu nhận và phát hành khóa. Và như thế. Gói Python 5 là một gói nhẹ nhưng có thể mở rộng để theo dõi tốt hơn những gì mã của bạn làm. Sử dụng nó mang lại cho bạn sự linh hoạt hơn nhiều so với việc chỉ xả mã của bạn bằng các cuộc gọi 1 thừa.Tuy nhiên, gói Python từ 5 có thể phức tạp ở một số điểm nhất định. Trình xử lý, logger, cấp độ, không gian tên, bộ lọc: Nó không dễ để theo dõi tất cả các phần này và cách chúng tương tác.Một cách để buộc các kết thúc lỏng lẻo trong sự hiểu biết của bạn về 5 là nhìn trộm dưới mui xe vào mã nguồn cpython của nó. Mã Python đằng sau 5 là súc tích và mô -đun, và đọc qua nó có thể giúp bạn có được khoảnh khắc đó.Bài viết này có nghĩa là để bổ sung cho việc ghi nhật ký tài liệu cũng như đăng nhập vào Python, đây là một hướng dẫn về cách sử dụng gói. Đến cuối bài viết này, bạn sẽ quen thuộc với những điều sau đây::
Đối với hầu hết các phần, chúng tôi sẽ đi theo mô-đun cốt lõi trong gói Python, ____ ____55 để xây dựng một bức tranh về cách mà nó đặt ra. Làm thế nào để theo dõiBởi vì mã nguồn 5 là trung tâm của bài viết này, bạn có thể giả sử rằng bất kỳ khối mã hoặc liên kết nào cũng dựa trên một cam kết cụ thể trong kho lưu trữ CPython Python 3.7, cụ thể là cam kết 1. Bạn có thể tìm thấy gói 5 trong thư mục 3 trong nguồn cpython.Trong gói 5, hầu hết các lần nâng nặng xảy ra trong 5, đó là tệp bạn sẽ dành nhiều thời gian nhất ở đây:
Với điều đó, hãy để nhảy vào. Sơ bộTrước khi chúng tôi đến các lớp học hạng nặng, hàng trăm dòng hàng đầu của 6 giới thiệu một vài khái niệm tinh tế nhưng quan trọng.Sơ bộ số 1: Một cấp độ chỉ là một (Pdb) l
1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515 elif not isinstance(exc_info, tuple):
1516 exc_info = sys.exc_info()
1517 record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518 exc_info, func, extra, sinfo)
1519 -> self.handle(record)
1520
1521 def handle(self, record):
1522 """
1523 Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
'created': 1550671851.660067,
'exc_info': None,
'exc_text': None,
'filename': ' |
Hãy cùng nghỉ ngơi khi khám phá mã 5 và đưa vào việc viết ứng dụng nhỏ của riêng chúng tôi, một người tận dụng phân cấp logger theo cách giảm mã nồi hơi và giữ cho mọi thứ có thể mở rộng nếu dự án CodeBase phát triển. | Ở đây, cấu trúc dự án: |
---|---|
Don Tiết lo lắng về các chức năng chính của ứng dụng trong 87 và 88. Những gì chúng tôi chú ý nhiều hơn ở đây là sự tương tác trong các đối tượng 5 giữa các mô -đun trong 90. | Trong trường hợp này, hãy nói rằng bạn muốn thiết kế một thiết lập ghi nhật ký nhiều lần: |
Mỗi mô -đun nhận được 16 với nhiều trình xử lý. | Một số trình xử lý được chia sẻ giữa các trường hợp 16 khác nhau trong các mô -đun khác nhau. Các trình xử lý này chỉ quan tâm đến bộ lọc dựa trên cấp độ, chứ không phải mô-đun trong đó bản ghi nhật ký phát ra từ. Có một trình xử lý cho các tin nhắn 23, một cho 24, một cho 20, v.v. |
Mỗi 16 cũng được gắn với một trình xử lý bổ sung khác mà chỉ nhận được các trường hợp ____129 từ Lone 16 đó. Bạn có thể gọi đây là một trình xử lý tệp dựa trên mô-đun. | Trực quan, những gì chúng tôi chụp cho sẽ trông giống như thế này: |
Một thiết kế ghi nhật ký nhiều người (hình ảnh: Real Python)
Hai đối tượng màu ngọc lam là các trường hợp của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, được thiết lập với import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
00 cho mỗi mô -đun trong một gói. Mọi thứ khác là một ví dụ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13._nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
2Mô -đun này được nhập khi gói
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
02 được nhập. Bạn thêm một trình xử lý cho mỗi cấp độ trong CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23 đến class Logger(Filterer):
# ...
def getEffectiveLevel(self):
logger = self
while logger:
if logger.level:
return logger.level
logger = logger.parent
return NOTSET
def isEnabledFor(self, level):
try:
return self._cache[level]
except KeyError:
_acquireLock()
if self.manager.disable >= level:
is_enabled = self._cache[level] = False
else:
is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
_releaseLock()
return is_enabled
4, sau đó gắn nó vào một logger duy nhất ở đầu phân cấp.Bạn cũng xác định chức năng tiện ích thêm một
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
32 vào logger, trong đó import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
33 của trình xử lý tương ứng với tên mô -đun nơi xác định logger. (Điều này giả sử logger được xác định với import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
12.)Sau đó, bạn có thể thêm một số thiết lập logger nồi hơi tối thiểu trong
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
88 và _nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
87. Lưu ý rằng bạn chỉ cần thêm một trình xử lý bổ sung với import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
37 từ (Pdb) l
1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515 elif not isinstance(exc_info, tuple):
1516 exc_info = sys.exc_info()
1517 record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518 exc_info, func, extra, sinfo)
1519 -> self.handle(record)
1520
1521 def handle(self, record):
1522 """
1523 Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
'created': 1550671851.660067,
'exc_info': None,
'exc_text': None,
'filename': '',
'funcName': 'f',
'levelname': 'ERROR',
'levelno': 40,
'lineno': 2,
'module': '',
'msecs': 660.067081451416,
'msg': 'bad vibes',
'name': 'root',
'pathname': '',
'process': 2360,
'processName': 'MainProcess',
'relativeCreated': 295145.5490589142,
'stack_info': None,
'thread': 4372293056,
'threadName': 'MainThread'}
6. Bạn không cần phải lo lắng về các trình xử lý định hướng cấp độ vì họ đã được thêm vào logger cha mẹ của họ có tên import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
19:_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
3Ở đây, ____ ____287:
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
4Hãy cùng xem cách tất cả những điều này hoạt động cùng nhau từ một phiên Python mới:
>>>
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
5Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
6Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.Bây giờ, bạn đã thấy một ví dụ thực tế, hãy để chuyển đổi bánh răng và đi sâu vào một nguồn nhầm lẫn có thể xảy ra trong
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5.Tại sao không có tin nhắn nhật ký của tôi đi đâu? Tình trạng khó xử
Có hai tình huống phổ biến với
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 khi nó dễ bị vấp ngã:- Bạn đã đăng nhập một tin nhắn dường như không đi đến đâu và bạn không chắc tại sao.
- Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.
Mỗi trong số này có một hoặc hai lý do thường được liên kết với nó.
Bạn đã đăng nhập một tin nhắn dường như không đi đến đâu và bạn không chắc tại sao.
Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.effective level of a logger for which you don’t otherwise set a custom level is
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
20, because a logger will walk up its hierarchy until it finds the root logger with its own _nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
20 level:>>>
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
7Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:
Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.
Mỗi trong số này có một hoặc hai lý do thường được liên kết với nó.
Don Tiết quên rằng mức độ hiệu quả của một logger mà bạn không nên đặt cấp độ tùy chỉnh là
_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
20, bởi vì một bộ ghi sẽ đi lên thứ bậc của nó cho đến khi tìm thấy bộ ghi gốc với mức ____220 của riêng mình:_nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
8Vì mặc định này, cuộc gọi
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
46 không đi đến đâu._nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
9Khi bạn xác định
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 của mình ở trên, bạn đã không thêm bất kỳ trình xử lý nào vào đó. Vì vậy, tại sao nó viết vào bảng điều khiển?Lý do cho điều này là
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 Sneaking sử dụng một trình xử lý có tên là import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
49 ghi vào CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 nếu không tìm thấy người xử lý nào khác:Điều này khởi động khi một logger đi tìm trình xử lý của nó:
>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
0Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:
Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
1Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:
>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
2Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:
Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
3Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:lazily rather than greedily. Here’s what that means.
Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
4Bây giờ, bạn đã thấy một ví dụ thực tế, hãy để chuyển đổi bánh răng và đi sâu vào một nguồn nhầm lẫn có thể xảy ra trong
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5.Tại sao không có tin nhắn nhật ký của tôi đi đâu? Tình trạng khó xử
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
5Có hai tình huống phổ biến với
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 khi nó dễ bị vấp ngã:Vì sao vấn đề này? Các cuộc gọi ghi nhật ký lặp đi lặp lại có thể làm giảm hiệu suất thời gian chạy một chút, nhưng gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 thực hiện tốt nhất để kiểm soát điều đó và kiểm tra nó. Bằng cách không hợp nhất chuỗi định dạng với các đối số của nó ngay lập tức, import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 đang trì hoãn định dạng chuỗi cho đến khi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 được yêu cầu bởi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13.Điều này xảy ra trong ____378, vì vậy chỉ sau khi
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 thấy rằng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 sẽ thực sự được chuyển cho một người xử lý, nó mới trở thành bản thân được hợp nhất đầy đủ.Tất cả những gì có nghĩa là gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 làm cho một số tối ưu hóa hiệu suất rất tinh chỉnh ở đúng nơi. Điều này có vẻ giống như Minutia, nhưng nếu bạn thực hiện cùng một import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
82 gọi một triệu lần trong một vòng lặp và import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
69 là các cuộc gọi chức năng, thì bản chất lười biếng của cách import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 định dạng chuỗi có thể tạo ra sự khác biệt.Trước khi thực hiện bất kỳ sự hợp nhất nào của
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
60 và import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
69, một ví dụ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 sẽ kiểm tra CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
84 của nó để xem liệu việc hợp nhất có nên được thực hiện ngay từ đầu không.Chức năng so với phương pháp
Về phía dưới của
(Pdb) l
1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515 elif not isinstance(exc_info, tuple):
1516 exc_info = sys.exc_info()
1517 record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518 exc_info, func, extra, sinfo)
1519 -> self.handle(record)
1520
1521 def handle(self, record):
1522 """
1523 Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
'created': 1550671851.660067,
'exc_info': None,
'exc_text': None,
'filename': '',
'funcName': 'f',
'levelname': 'ERROR',
'levelno': 40,
'lineno': 2,
'module': '',
'msecs': 660.067081451416,
'msg': 'bad vibes',
'name': 'root',
'pathname': '',
'process': 2360,
'processName': 'MainProcess',
'relativeCreated': 295145.5490589142,
'stack_info': None,
'thread': 4372293056,
'threadName': 'MainThread'}
5, hãy đặt các chức năng cấp độ mô-đun được quảng cáo lên phía trước trong API công khai của import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Bạn đã thấy các phương pháp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 như import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
46, import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
93 và import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
94. Các chức năng cấp cao nhất là các trình bao bọc xung quanh các phương thức tương ứng cùng tên, nhưng chúng có hai tính năng quan trọng:Họ luôn gọi phương thức tương ứng của họ từ logger gốc,
93.CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Trước khi gọi các phương thức logger gốc, họ gọi
55 không có đối số nếuimport threading _lock = threading.RLock() def _acquireLock(): if _lock: _lock.acquire() def _releaseLock(): if _lock: _lock.release()
93 không có trình xử lý. Như bạn đã thấy trước đó, đó là cuộc gọi này đặt ra một trình xử lýCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
76 cho bộ ghi gốc.CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Để minh họa, ở đây, ____ ____151:
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
6Bạn sẽ tìm thấy cùng một mẫu cho
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
82, import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
53 và các mẫu khác là tốt. Truy tìm chuỗi các lệnh là thú vị. Cuối cùng, bạn sẽ kết thúc ở cùng một nơi, đó là nơi được gọi là object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
02 bên trong.Các cuộc gọi đến
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
03, object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
04, object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
05 và các chức năng dựa trên cấp độ khác tất cả các chức năng đến đây. object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
06 chủ yếu có hai mục đích:Gọi
07: Tạo một thể hiệnobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
29 từCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
60 và các đối số khác mà bạn chuyển cho nó. Make aimport threading _lock = threading.RLock() def _acquireLock(): if _lock: _lock.acquire() def _releaseLock(): if _lock: _lock.release()
29 instance from theCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
60 and other arguments you pass to it.import threading _lock = threading.RLock() def _acquireLock(): if _lock: _lock.acquire() def _releaseLock(): if _lock: _lock.release()
Gọi
10: Điều này xác định những gì thực sự được thực hiện với hồ sơ. Nó được gửi ở đâu? Nó làm cho nó ở đó hoặc được lọc ra? This determines what actually gets done with the record. Where does it get sent? Does it make it there or get filtered out?object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Ở đây, toàn bộ quá trình trong một sơ đồ:
Nội bộ của một cuộc gọi đăng nhập (hình ảnh: Python thật)Bạn cũng có thể theo dõi ngăn xếp cuộc gọi với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
52.>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
7object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager 12 thực sự làm gì?
Cũng ẩn trong phần này của mã nguồn là cấp cao nhất
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
12, kết thúc object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
14:import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
8Đây là điểm nhập cảnh để thực thi thiết kế Singleton Logger:
Nếu bạn chỉ định
15, thìobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
16 bên dưới sẽ tra cứuobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
8 trên chuỗiclass Logger(Filterer): # ... def getEffectiveLevel(self): logger = self while logger: if logger.level: return logger.level logger = logger.parent return NOTSET def isEnabledFor(self, level): try: return self._cache[level] except KeyError: _acquireLock() if self.manager.disable >= level: is_enabled = self._cache[level] = False else: is_enabled = self._cache[level] = level >= self.getEffectiveLevel() _releaseLock() return is_enabled
15. Những gì điều này xuất hiện là một tra cứu trongobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
19 củaobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
20. Đây là một từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các trường hợpobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
21 trung gian được tạo khi bạn tham chiếu một logger từ xa trong hệ thống phân cấp trước khi tham khảo cha mẹ của nó.object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Nếu không,
93 được trả lại. Chỉ có một ____ 193, ví dụ củaCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
68 đã thảo luận ở trên._nameToLevel = { 'CRITICAL': CRITICAL, 'FATAL': FATAL, 'ERROR': ERROR, 'WARN': WARNING, 'WARNING': WARNING, 'INFO': INFO, 'DEBUG': DEBUG, 'NOTSET': NOTSET, } def _checkLevel(level): if isinstance(level, int): rv = level elif str(level) == level: if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv
Tính năng này là những gì nằm đằng sau một mẹo có thể cho phép bạn nhìn trộm tất cả các loggers đã đăng ký:
>>>
import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
9object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
12 thực sự làm gì?Cũng ẩn trong phần này của mã nguồn là cấp cao nhất
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
12, kết thúc object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
14:Đây là điểm nhập cảnh để thực thi thiết kế Singleton Logger:
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
0Nếu bạn chỉ định
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
15, thì object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
16 bên dưới sẽ tra cứu class Logger(Filterer):
# ...
def getEffectiveLevel(self):
logger = self
while logger:
if logger.level:
return logger.level
logger = logger.parent
return NOTSET
def isEnabledFor(self, level):
try:
return self._cache[level]
except KeyError:
_acquireLock()
if self.manager.disable >= level:
is_enabled = self._cache[level] = False
else:
is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
_releaseLock()
return is_enabled
8 trên chuỗi object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
15. Những gì điều này xuất hiện là một tra cứu trong object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
19 của object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
20. Đây là một từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các trường hợp object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
21 trung gian được tạo khi bạn tham chiếu một logger từ xa trong hệ thống phân cấp trước khi tham khảo cha mẹ của nó.Nếu không,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
93 được trả lại. Chỉ có một ____ 193, ví dụ của _nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
68 đã thảo luận ở trên.>>>
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
1object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
12 thực sự làm gì?Thư viện vs đăng nhập ứng dụng: object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager 42 là gì?
Điều đó đưa chúng ta đến hàng trăm dòng cuối cùng trong nguồn
(Pdb) l
1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515 elif not isinstance(exc_info, tuple):
1516 exc_info = sys.exc_info()
1517 record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518 exc_info, func, extra, sinfo)
1519 -> self.handle(record)
1520
1521 def handle(self, record):
1522 """
1523 Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
'created': 1550671851.660067,
'exc_info': None,
'exc_text': None,
'filename': '',
'funcName': 'f',
'levelname': 'ERROR',
'levelno': 40,
'lineno': 2,
'module': '',
'msecs': 660.067081451416,
'msg': 'bad vibes',
'name': 'root',
'pathname': '',
'process': 2360,
'processName': 'MainProcess',
'relativeCreated': 295145.5490589142,
'stack_info': None,
'thread': 4372293056,
'threadName': 'MainThread'}
5, trong đó object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
42 được xác định. Ở đây, định nghĩa trong tất cả vinh quang của nó:object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
2object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
42 là tất cả về sự khác biệt giữa việc đăng nhập vào thư viện so với một ứng dụng. Hãy để xem điều đó có nghĩa là gì.Một thư viện là một gói Python có thể tổng quát, có thể khái quát, dành cho người dùng khác để cài đặt và thiết lập. Nó được xây dựng bởi một nhà phát triển với mục đích rõ ràng là được phân phối cho người dùng. Các ví dụ bao gồm các dự án nguồn mở phổ biến như Numpy,
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
46 và object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
47.library is an extensible, generalizable Python package that is intended for other users to install and set up. It is built by a developer with the express purpose of being distributed to users. Examples
include popular open-source projects like NumPy, object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
46, and object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
47.Một ứng dụng (hoặc ứng dụng hoặc chương trình) được thiết kế cho mục đích cụ thể hơn và một bộ người dùng nhỏ hơn nhiều (có thể chỉ là một người dùng). Nó có một chương trình hoặc bộ chương trình được người dùng điều chỉnh cao để thực hiện một loạt mọi thứ. Một ví dụ về một ứng dụng là một ứng dụng Django nằm phía sau một trang web. Các ứng dụng thường sử dụng thư viện (
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
48) và các công cụ chúng chứa.application (or app, or program) is designed for a more specific purpose and a much smaller set of users (possibly just one user). It’s a program or set of programs highly tailored by the user to do a
limited set of things. An example of an application is a Django app that sits behind a web page. Applications commonly use (object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
48) libraries and the tools they contain.Khi nói đến việc ghi nhật ký, có các thực tiễn tốt nhất khác nhau trong thư viện so với một ứng dụng.
Đó là nơi mà
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
42 phù hợp. Nó về cơ bản là một lớp sở hữu không có gì.Nếu bạn đang viết một thư viện Python, bạn thực sự cần phải thực hiện một phần thiết lập tối giản này trong gói của bạn ____ ____ ____76:
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
3Điều này phục vụ hai mục đích quan trọng.
Đầu tiên, một bộ ghi thư viện được khai báo với
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
51 (không có bất kỳ cấu hình nào khác) sẽ đăng nhập vào CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 theo mặc định, ngay cả khi đó không phải là những gì người dùng cuối muốn. Điều này có thể được mô tả như là một cách tiếp cận từ chối, trong đó người dùng cuối của thư viện phải đi vào và vô hiệu hóa việc đăng nhập vào bảng điều khiển của họ nếu họ không muốn nó.Thay vào đó, trí tuệ thông thường cho biết sử dụng cách tiếp cận chọn tham gia thay thế: don lồng phát ra bất kỳ thông báo nhật ký nào theo mặc định và để người dùng cuối của thư viện xác định xem họ có muốn định cấu hình thêm trình ghi nhật ký thư viện và thêm người xử lý cho họ không. Ở đây, triết lý mà tác giả của gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5, Vinay Sajip: Vinay Sajip:Thư viện của bên thứ ba sử dụng
5 không nên phun ra đầu ra ghi nhật ký theo mặc định mà không thể mong muốn bởi nhà phát triển/người dùng ứng dụng sử dụng nó. (Nguồn)import logging import sys logger = logging.getLogger("pylog") logger.setLevel(logging.DEBUG) h2 = logging.FileHandler(filename="/tmp/records.log") h2.setLevel(logging.INFO) h2 = logging.StreamHandler(sys.stderr) h2.setLevel(logging.ERROR) logger.addHandler(h2) logger.addHandler(h2) logger.info("testing %d.. %d.. %d..", 1, 2, 3)
Điều này để lại cho người dùng thư viện, không phải nhà phát triển thư viện, để gọi các phương thức tăng dần như
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
55 hoặc object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
56.Lý do thứ hai mà
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
42 tồn tại là cổ xưa hơn. Trong Python 2.7 và trước đó, cố gắng đăng nhập CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 từ một logger không có bộ xử lý sẽ đưa ra cảnh báo. Thêm lớp NO-OP object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
42 sẽ ngăn chặn điều này.Tại đây, những gì đặc biệt xảy ra trong dòng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
60 từ trên:Python được (tạo) phiên bản
12 có cùng tên với gói của bạn. Nếu bạn đang thiết kế góiCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
62, trong vòngobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
6, thì(Pdb) l 1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__) 1515 elif not isinstance(exc_info, tuple): 1516 exc_info = sys.exc_info() 1517 record = self.makeRecord(self.name, level, fn, lno, msg, args, 1518 exc_info, func, extra, sinfo) 1519 -> self.handle(record) 1520 1521 def handle(self, record): 1522 """ 1523 Call the handlers for the specified record. 1524 (Pdb) from pprint import pprint (Pdb) pprint(vars(record)) {'args': (), 'created': 1550671851.660067, 'exc_info': None, 'exc_text': None, 'filename': '
', 'funcName': 'f', 'levelname': 'ERROR', 'levelno': 40, 'lineno': 2, 'module': '', 'msecs': 660.067081451416, 'msg': 'bad vibes', 'name': 'root', 'pathname': '', 'process': 2360, 'processName': 'MainProcess', 'relativeCreated': 295145.5490589142, 'stack_info': None, 'thread': 4372293056, 'threadName': 'MainThread'}
12 sẽ bằngimport threading _lock = threading.RLock() def _acquireLock(): if _lock: _lock.acquire() def _releaseLock(): if _lock: _lock.release()
65.object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Một ví dụ
42 được gắn vào logger này. Điều đó có nghĩa là Python sẽ không mặc định sử dụng trình xử lýobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
49.import threading _lock = threading.RLock() def _acquireLock(): if _lock: _lock.acquire() def _releaseLock(): if _lock: _lock.release()
Hãy nhớ rằng bất kỳ logger nào được tạo trong bất kỳ mô -đun
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
68 nào khác của gói sẽ là trẻ em của bộ ghi này trong hệ thống phân cấp logger và vì người xử lý này cũng thuộc về chúng, họ sẽ không cần sử dụng trình xử lý import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
49 và giành được 'T mặc định để đăng nhập vào lỗi tiêu chuẩn (CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
39).Ví dụ nhanh, hãy để nói rằng thư viện của bạn có cấu trúc sau:
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
4Trong
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
71, với tư cách là nhà phát triển thư viện, bạn có thể tự do thực hiện như sau:object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
5Bây giờ, người dùng xuất hiện và cài đặt thư viện của bạn từ PYPI thông qua
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
72. Họ sử dụng object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
73 trong một số mã ứng dụng. Người dùng này có thể tự do thao tác và định cấu hình đối tượng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 từ thư viện như bất kỳ đối tượng Python nào khác, đến nội dung trái tim của họ.Ghi nhật ký làm gì với ngoại lệ
Một điều mà bạn có thể cảnh giác là nguy cơ ngoại lệ xuất phát từ các cuộc gọi của bạn đến
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Nếu bạn có một cuộc gọi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 được thiết kế để cung cấp cho bạn một số thông tin gỡ lỗi dài dòng hơn, nhưng đó là một số lý do sẽ làm tăng một ngoại lệ, đó sẽ là chiều cao của sự trớ trêu, phải không?Thông minh, nếu gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 gặp phải một ngoại lệ có liên quan đến việc ghi lại, thì nó sẽ in dấu vết nhưng không tự tăng ngoại lệ.Ở đây, một ví dụ liên quan đến một lỗi đánh máy phổ biến: chuyển hai đối số cho một chuỗi định dạng chỉ mong đợi một đối số. Sự khác biệt quan trọng là những gì bạn thấy dưới đây không phải là một ngoại lệ được nêu ra, mà là một dấu vết in được in của ngoại lệ nội bộ, mà chính nó đã bị đàn áp:
>>>
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
6Điều này cho phép chương trình của bạn duyên dáng tiếp tục với luồng chương trình thực tế của nó. Lý do là bạn sẽ không muốn một ngoại lệ không được nhận ra từ một cuộc gọi
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 và ngăn chặn một chương trình chết trong các bài hát của nó.Tracebacks có thể lộn xộn, nhưng cái này là thông tin và tương đối đơn giản. Điều cho phép đàn áp các ngoại lệ liên quan đến
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
80. Khi người xử lý gọi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41, đó là phương pháp mà nó cố gắng ghi lại bản ghi, nó sẽ trở lại object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
82 nếu có điều gì đó tồi tệ. Tại đây, việc triển khai CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41 cho lớp import threading
_lock = threading.RLock()
def _acquireLock():
if _lock:
_lock.acquire()
def _releaseLock():
if _lock:
_lock.release()
56:
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
7Bất kỳ ngoại lệ nào liên quan đến định dạng và văn bản đều bị bắt thay vì được nuôi dưỡng, và
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
85 duyên dáng viết dấu vết lên CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35.Ghi nhật ký Python Tracebacks
Nói về các trường hợp ngoại lệ và dấu vết của họ, những trường hợp chương trình của bạn gặp họ nhưng nên đăng nhập ngoại lệ và tiếp tục theo dõi trong việc thực hiện của nó?
Hãy cùng đi qua một vài cách để làm điều này.
Ở đây, một ví dụ giả định về một trình mô phỏng xổ số bằng cách sử dụng mã không có mục đích. Bạn đang phát triển một trò chơi xổ số trực tuyến, nơi người dùng có thể đặt cược vào số may mắn của họ:
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
8Đằng sau ứng dụng Frontend nằm trong mã quan trọng dưới đây. Bạn muốn đảm bảo rằng bạn theo dõi bất kỳ lỗi nào do trang web có thể khiến người dùng mất tiền. Cách đầu tiên (tối ưu) là sử dụng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 và đăng nhập hình thức class Logger(Filterer):
# ...
def getEffectiveLevel(self):
logger = self
while logger:
if logger.level:
return logger.level
logger = logger.parent
return NOTSET
def isEnabledFor(self, level):
try:
return self._cache[level]
except KeyError:
_acquireLock()
if self.manager.disable >= level:
is_enabled = self._cache[level] = False
else:
is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
_releaseLock()
return is_enabled
5 của trường hợp ngoại lệ:object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
9Điều này sẽ chỉ nhận được thông báo ngoại lệ thực tế, thay vì truy tìm. Bạn kiểm tra nhật ký trên máy chủ trang web của bạn và tìm tin nhắn khó hiểu này:
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
0Hmm. Là nhà phát triển ứng dụng, bạn đã gặp vấn đề nghiêm trọng và kết quả là người dùng đã bị gạt ra. Nhưng có lẽ thông điệp ngoại lệ này là rất nhiều thông tin. Sẽ rất vui khi thấy dòng dõi của dấu vết dẫn đến ngoại lệ này?
Giải pháp thích hợp là sử dụng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
89, ghi lại một thông điệp với cấp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
36 và cũng hiển thị truy tìm ngoại lệ. Thay thế hai dòng cuối cùng ở trên bằng những điều này:import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
1Bây giờ bạn nhận được một dấu hiệu tốt hơn về những gì đang diễn ra:
>>>
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
2Sử dụng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
91 giúp bạn không phải tự tham khảo ngoại lệ vì import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 kéo nó vào với object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
93.Điều này làm cho mọi thứ rõ ràng hơn rằng vấn đề bắt nguồn từ
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
94, cần biết độ dài của đối tượng mà nó đang xáo trộn. Bởi vì lớp object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
95 của chúng tôi chuyển một máy phát điện đến object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
96, nó sẽ được giữ và tăng trước khi hồ bơi có thể bị xáo trộn, ít tạo ra một vé chiến thắng.Trong các ứng dụng lớn, toàn diện, bạn sẽ thấy
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
89 thậm chí còn hữu ích hơn khi các dấu vết đa thư viện sâu thẳm có liên quan và bạn có thể bước vào chúng với một trình gỡ lỗi trực tiếp như CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
52.Mã cho
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
99, và do đó object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
89, chỉ là một dòng duy nhất:import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
3Nghĩa là,
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
89 chỉ gọi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 với import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
03, nếu không thì _nameToLevel = {
'CRITICAL': CRITICAL,
'FATAL': FATAL,
'ERROR': ERROR,
'WARN': WARNING,
'WARNING': WARNING,
'INFO': INFO,
'DEBUG': DEBUG,
'NOTSET': NOTSET,
}
def _checkLevel(level):
if isinstance(level, int):
rv = level
elif str(level) == level:
if level not in _nameToLevel:
raise ValueError("Unknown level: %r" % level)
rv = _nameToLevel[level]
else:
raise TypeError("Level not an integer or a valid string: %r" % level)
return rv
48 theo mặc định. Nếu bạn muốn đăng nhập một dấu vết ngoại lệ nhưng ở cấp độ khác với import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
05, chỉ cần gọi hàm đó hoặc phương thức với import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
03.Hãy nhớ rằng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
91 chỉ nên được gọi trong bối cảnh của một trình xử lý ngoại lệ, bên trong một khối import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
08:import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
4Sử dụng mẫu này một cách tiết kiệm hơn là một phương tiện để đàn áp bất kỳ ngoại lệ nào. Nó có thể hữu ích nhất khi bạn gỡ lỗi một ngăn xếp gọi chức năng dài nơi bạn có thể thấy một lỗi mơ hồ, không rõ ràng và khó theo dõi.
Sự kết luận
Hãy vỗ nhẹ vào lưng, bởi vì bạn đã đi qua gần 2.000 dòng mã nguồn dày đặc. Bạn bây giờ được trang bị tốt hơn để đối phó với gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5!Hãy nhớ rằng hướng dẫn này đã không còn toàn bộ trong việc bao gồm tất cả các lớp học được tìm thấy trong gói
import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Có nhiều máy móc thậm chí còn gắn kết mọi thứ lại với nhau. Nếu bạn muốn tìm hiểu thêm, thì bạn có thể xem xét các lớp import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
11 và các mô -đun riêng biệt import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
12 và import logging
import sys
logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
13.