Gói Python
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
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 riêng bạn thực hiện. Việc 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 lệnh gọi import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
6 không cần thiếtTuy nhiên, gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python có thể phức tạp ở một số điểm nhất định. Trình xử lý, trình ghi nhật ký, cấp độ, không gian tên, bộ lọc. không dễ để theo dõi tất cả các phần này và cách chúng tương tácMột cách để giải quyết các vấn đề còn lỏng lẻo trong hiểu biết của bạn về
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là xem qua mã nguồn CPython của nó. Mã Python đằng sau import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 ngắn gọn và theo mô-đun, và việc đọc qua mã này có thể giúp bạn có được giây phút sảng khoái đóBài viết này nhằm bổ sung cho tài liệu HOWTO ghi nhật ký cũng như Ghi nhật ký bằng Python, đây là 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
5 cấp độ và cách chúng hoạt độngimport logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
- An toàn luồng so với an toàn quy trình trong
5import logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
- Thiết kế của
5 từ góc độ OOPimport logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
- Đăng nhập vào thư viện so với ứng dụng
- Các phương pháp hay nhất và các mẫu thiết kế để sử dụng
5import logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
Đối với hầu hết các trường hợp, chúng ta sẽ đi từng dòng mô-đun cốt lõi trong gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python để xây dựng một bức tranh về cách nó được trình bàyTiền thưởng miễn phí. 5 Suy nghĩ về Làm chủ Python, một khóa học miễn phí dành cho các nhà phát triển Python cho bạn thấy lộ trình và tư duy mà bạn sẽ cần để đưa các kỹ năng Python của mình lên một tầm cao mới
Làm thế nào để theo cùng
Vì mã nguồn
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là trọng tâm của bài viết này, nên bạn có thể cho rằng bất kỳ khối mã hoặc liên kết nào đều dựa trên một cam kết cụ thể trong Python 3. 7 Kho lưu trữ CPython, cụ thể là cam kết >>> import logging
>>> import pdb
>>> def f[x]:
.. logging.error["bad vibes"]
.. return x / 0
..
>>> pdb.run["f[1]"]
6. Bạn có thể tìm thấy gói import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 trong thư mục >>> import logging
>>> import pdb
>>> def f[x]:
.. logging.error["bad vibes"]
.. return x / 0
..
>>> pdb.run["f[1]"]
8 trong nguồn CPythonTrong gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5, hầu hết công việc nặng nhọc diễn ra trong vòng [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'}
0, đây là tệp bạn sẽ dành nhiều thời gian nhất ở đâycpython/
│
├── Lib/
│ ├── logging/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ └── handlers.py
│ ├── ...
├── Modules/
├── Include/
...
.. [truncated]
Với điều đó, chúng ta hãy nhảy vào
Loại bỏ các quảng cáosơ bộ
Trước khi chúng ta chuyển sang hạng nặng, hàng trăm dòng trên cùng 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'}
1 giới thiệu một số khái niệm tinh tế nhưng quan trọngSơ bộ #1. Trình độ 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': '',
'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'}
2
[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'}
Các đối tượng như
[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'}
3 hoặc [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'}
4 có vẻ hơi mờ. Các biến nội bộ này là gì và chúng được định nghĩa như thế nào?Trên thực tế, các hằng số viết hoa từ
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python, tạo thành một tập hợp các cấp số giống như enumCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
Tại sao không chỉ sử dụng các chuỗi
[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 hoặc [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'}
7? . Họ cũng được đặt tên để cho họ mượn ý nghĩa ngữ nghĩa. Nói rằng một thông báo có mức độ nghiêm trọng là 50 có thể không rõ ràng ngay lập tức, nhưng nói rằng nó có mức độ [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'}
9 cho bạn biết rằng bạn đã có một đèn đỏ nhấp nháy ở đâu đó trong chương trình của mìnhBây giờ, về mặt kỹ thuật, bạn chỉ có thể vượt qua dạng cấp độ
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
0 ở một số nơi, chẳng hạn như 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
1. Trong nội bộ, điều này sẽ gọi 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
2, mà cuối cùng sẽ thực hiện 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
3 cho [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'}
2 tương ứng_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
Bạn nên chọn cái nào? . Ngoài ra, việc chuyển biểu mẫ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
0 không phải là một tùy chọn trong Python 2 và một số phương thức import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 chẳng hạn như >>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent
>>> logger.parent.level
30
1 sẽ chỉ chấp nhận 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': '',
'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'}
2, không phải người anh em họ 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
0 của nóSơ bộ #2. Ghi nhật ký an toàn cho luồng nhưng không an toàn cho quy trình
Sau một vài dòng, bạn sẽ tìm thấy đoạn ngắn sau đây, điều này rất quan trọng đối với toàn bộ gói
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
Đối tượng
>>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent
>>> logger.parent.level
30
4 là một nằm trong không gian tên chung của mô-đun [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'}
0. Nó làm cho gần như mọi đối tượng và hoạt động trong toàn bộ gói import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 an toàn cho luồng, cho phép các luồng thực hiện các thao tác đọc và ghi mà không có mối đe dọa về điều kiện chạy đua. Bạn có thể thấy trong mã nguồn mô-đun rằng >>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent
>>> logger.parent.level
30
7 và >>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent
>>> logger.parent.level
30
8 phổ biến đối với mô-đun và các lớp của nóTuy nhiên, có một cái gì đó không được tính ở đây. những gì về quá trình an toàn? . Đây vốn dĩ không phải là lỗi của
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5—nói chung, hai quy trình không thể ghi vào cùng một tệp nếu không có nhiều nỗ lực chủ động thay mặt cho lập trình viên trướcĐiều này có nghĩa là bạn sẽ muốn cẩn thận trước khi sử dụng các lớp như
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
01 có liên quan đến đa xử lý. Nếu hai quy trình muốn đọc và ghi đồng thời vào cùng một tệp cơ bản, thì bạn có thể gặp phải một lỗi khó chịu giữa chừng trong một quy trình dài hạnNếu bạn muốn khắc phục hạn chế này, có một hướng dẫn kỹ lưỡng trong Sổ ghi nhật ký chính thức. Bởi vì điều này đòi hỏi một số lượng lớn thiết lập, nên một giải pháp thay thế là mỗi quy trình ghi nhật ký vào một tệp riêng biệt dựa trên ID quy trình của nó, mà bạn có thể lấy bằng
Kiến trúc gói. Ghi nhật ký của MRO
Bây giờ, chúng tôi đã đề cập đến một số mã thiết lập sơ bộ, hãy cùng xem xét cách trình bày của
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Gói import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 sử dụng liều OOP lành mạnh và tính kế thừa. Dưới đây là cái nhìn một phần về thứ tự phân giải phương thức [MRO] đối với một số lớp quan trọng nhất trong góiobject
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
Sơ đồ cây ở trên không bao gồm tất cả các lớp trong mô-đun, chỉ những lớp đáng làm nổi bật nhất
Ghi chú. Bạn có thể sử dụng thuộc tính dunder
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
05 để xem chuỗi thừa kế. Có thể tìm thấy hướng dẫn cụ thể về MRO trong tài liệu Python 2, mặc dù hướng dẫn này cũng có thể áp dụng cho Python 3Chuỗi lớp học này thường là một nguồn gây nhầm lẫn vì có rất nhiều thứ đang diễn ra và tất cả đều nặng về biệt ngữ.
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 so với CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07? . Một bức tranh đáng giá ngàn lời nói, vì vậy đây là sơ đồ của một tình huống trong đó một người ghi nhật ký có hai trình xử lý được gắn vào nó viết một thông điệp nhật ký có cấp độ _______15_______3Trong mã Python, mọi thứ ở trên sẽ trông như thế này
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
Có một bản đồ chi tiết hơn về dòng chảy này trong. Những gì hiển thị ở trên là một kịch bản đơn giản hóa
Mã của bạn chỉ định nghĩa một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, cùng với hai phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09, CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
14 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
15Khi bạn gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16, đối tượng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 đóng vai trò là bộ lọc vì nó cũng có một _______22_______18 được liên kết với nó. Chỉ khi mức độ tin nhắn đủ nghiêm trọng thì thiết bị ghi nhật ký mới làm bất cứ điều gì với tin nhắn. Bởi vì trình ghi nhật ký có cấp độ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19 và thông báo mang cấp độ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20 cao hơn, nó sẽ tiếp tụcTrong nội bộ, các cuộc gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 để đặt chuỗi thông báo CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23 và các đối số của nó CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24 vào một thể hiện lớp thực sự của một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, chỉ là một vùng chứa cho thông báo và siêu dữ liệu của nóĐối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 tìm kiếm các bộ xử lý của nó [ví dụ về CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09], có thể được liên kết trực tiếp với chính CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 hoặc với cha mẹ của nó [một khái niệm mà chúng ta sẽ đề cập sau]. Trong ví dụ này, nó tìm thấy hai trình xử lý- Một với cấp độ
20 kết xuất dữ liệu nhật ký vào một tệp tạiCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
30CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
- Một thư gửi tới
31 nhưng chỉ khi thư đến ở cấp độCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
32 trở lênCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Tại thời điểm này, có một đợt kiểm tra khác bắt đầu. Bởi vì
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và thông báo của nó chỉ mang cấp độ ____22_______20, nên bản ghi được ghi vào Trình xử lý 1 [mũi tên xanh lục], chứ không phải luồng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 của Trình xử lý 2 [mũi tên đỏ]. Đối với Trình xử lý, việc ghi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 vào luồng của họ được gọi là phát ra nó, được ghi lại trongTiếp theo, hãy mổ xẻ thêm mọi thứ từ phía trên
Loại bỏ các quảng cáoLớp học CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 là gì? . Nó được tạo cho bạn bởi một phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và gói gọn tất cả thông tin thích hợp về sự kiện đó. Bên trong, nó không chỉ là một trình bao bọc xung quanh một 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
3 chứa các thuộc tính cho bản ghi. Phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 gửi phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 về 0 hoặc nhiều hơn phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 chứa một số siêu dữ liệu, chẳng hạn như sau- Một cái tên
- Thời gian tạo dưới dạng dấu thời gian Unix
- Bản thân tin nhắn
- Thông tin về chức năng nào đã thực hiện cuộc gọi ghi nhật ký
Dưới đây là thông tin sơ lược về siêu dữ liệu mà nó mang theo, bạn có thể xem xét nội dung này bằng cách thực hiện cuộc gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
47 với mô-đun CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
48>>>
>>> import logging
>>> import pdb
>>> def f[x]:
.. logging.error["bad vibes"]
.. return x / 0
..
>>> pdb.run["f[1]"]
Sau khi bước qua một số chức năng cấp cao hơn, bạn sẽ kết thúc
[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'}
Một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, bên trong, chứa một kho siêu dữ liệu được sử dụng theo cách này hay cách khácBạn sẽ hiếm khi cần phải giải quyết trực tiếp với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, vì CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 sẽ làm việc này cho bạn. Vẫn đáng để biết thông tin nào được gói gọn trong một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, bởi vì đây là nơi mà tất cả thông tin hữu ích đó, chẳng hạn như dấu thời gian, đến từ khi bạn xem thông báo nhật ký bản ghiGhi chú. Bên dưới lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, bạn cũng sẽ tìm thấy các hàm xuất xưởng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
55, CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
56 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
57. Bạn sẽ không cần những thứ này trừ khi bạn muốn sử dụng một lớp tùy chỉnh thay vì CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 để đóng gói các thông điệp tường trình và siêu dữ liệu của chúngLớp học CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
Các lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đều là trung tâm của cách thức hoạt động của import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và chúng tương tác với nhau thường xuyên. Một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09, và một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, mỗi người có một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 liên kết với chúngCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 lấy CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và chuyển nó cho CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09, nhưng chỉ khi mức độ hiệu quả của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 bằng hoặc cao hơn mức của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08. Điều tương tự cũng xảy ra với bài kiểm tra CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 so với CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09. Đây được gọi là lọc theo cấp độ, mà CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 thực hiện theo những cách hơi khác nhauNói cách khác, có một [ít nhất] thử nghiệm hai bước được áp dụng trước khi thông báo mà bạn đăng nhập được gửi đi bất cứ đâu. Để được chuyển hoàn toàn từ trình ghi nhật ký sang trình xử lý và sau đó được ghi vào luồng cuối [có thể là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
77, tệp hoặc email qua SMTP], một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 phải có cấp ít nhất cao bằng cả trình ghi và trình xử lýPEP 282 mô tả cách thức hoạt động của nó
Mỗi đối tượng
08 theo dõi cấp độ nhật ký [hoặc ngưỡng] mà nó quan tâm và loại bỏ các yêu cầu nhật ký bên dưới cấp độ đó. [Nguồn]CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Vậy việc lọc dựa trên cấp độ này thực sự xảy ra ở đâu cho cả
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09?Đối với lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, giả định đầu tiên hợp lý là bộ ghi nhật ký sẽ so sánh thuộc tính CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 của nó với cấp độ của lớp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và được thực hiện ở đó. Tuy nhiên, nó liên quan nhiều hơn thế một chútQuá trình lọc dựa trên cấp độ dành cho trình ghi nhật ký diễn ra trong
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85, từ đó gọi tới ____22_______86. Luôn sử dụng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
87 thay vì chỉ hỏi ý kiến của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
88. Lý do liên quan đến việc tổ chức các đối tượng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 trong một không gian tên phân cấp. [Bạn sẽ thấy nhiều hơn về điều này sau. ]Theo mặc định, phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 có cấp độ là CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
91 [CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
92]. Tuy nhiên, các logger cũng có các logger cha, một trong số đó là logger gốc, có chức năng như cha của tất cả các logger khác. Một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 sẽ đi lên trong hệ thống phân cấp của nó và đạt được cấp độ hiệu quả so với cha mẹ của nó [cuối cùng có thể là ____22_______94 nếu không tìm thấy cha mẹ nào khác]Đây là trong lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08class 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
Tương ứng, đây là một ví dụ gọi mã nguồn mà bạn thấy ở trên
>>>
>>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent
>>> logger.parent.level
30
Đây là bài học rút ra. đừng dựa vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67. Nếu bạn chưa đặt một mức độ rõ ràng cho đối tượng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 của mình và bạn đang phụ thuộc vào CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 vì một số lý do, thì thiết lập ghi nhật ký của bạn có thể sẽ hoạt động khác với mong đợi của bạn.Còn về
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 thì sao? CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
0Đối với một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 nhất định [có tên 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
03 trong mã nguồn ở trên], trình ghi nhật ký kiểm tra với từng trình xử lý đã đăng ký của nó và kiểm tra nhanh thuộc tính CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 của phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đó. 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
06 của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 lớn hơn hoặc bằng của người xử lý, chỉ khi đó bản ghi mới được chuyển qua. A trong import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 đề cập đến điều này là “phát ra [ting] bản ghi nhật ký được chỉ định một cách có điều kiện. ”Trình xử lý và những nơi chúng đếnHiển thị/Ẩn
Thuộc tính quan trọng nhất đối với thể hiện của lớp con
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 là thuộc tí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
10 của nó. Đây là điểm đến cuối cùng nơi các bản ghi được ghi vào và có thể là bất kỳ đối tượng giống như tệp nào. Đây là một ví dụ với , là luồng trong bộ nhớ [bộ đệm] cho văn bản I/OĐầu tiên, thiết lập một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 với cấp độ là CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19. Bạn sẽ thấy rằng, theo mặc định, nó không có trình xử lý trực tiếp>>>
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
1Tiếp theo, bạn có thể phân lớp
_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
14 để thực hiện cuộc gọ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
15 không hoạt động. Chúng tôi muốn xóa CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31 hoặc CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
77, nhưng không phải bộ đệm trong bộ nhớ trong trường hợp nàyCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
2Bây giờ, hãy khai báo chính đối tượng bộ đệm và gắn nó dưới dạng
_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
10 cho trình xử lý tùy chỉnh của bạn với cấp độ là CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20, sau đó buộc trình xử lý đó vào bộ ghi>>>
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
3Đoạn cuối cùng này là một minh họa khác về lọc dựa trên cấp độ
Ba thông điệp cấp độ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
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
21 và [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'}
9 được chuyển qua chuỗi. Lúc đầu, có vẻ như họ không đi đâu cả, nhưng hai trong số họ thì có. Cả ba người họ đều ra khỏi cổng từ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 [có cấp độ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19]Tuy nhiên, chỉ có hai trong số chúng được phát ra bởi trình xử lý vì nó có cấp độ cao hơn là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20, vượt quá CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19. Cuối cùng, bạn nhận được toàn bộ nội dung của bộ đệm dưới dạng 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
0 và đóng bộ đệm để giải phóng tài nguyên hệ thống một cách rõ ràngLoại bỏ các quảng cáoLớp học CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
Ở trên, chúng tôi đã đặt câu hỏi, "Lọc theo cấp độ xảy ra ở đâu?" . Nghịch lý thay, lọc dựa trên cấp độ cho các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 xảy ra mà không có sự trợ giúp của một trong hai lớp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 hoặc CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07 được thiết kế để cho phép bạn thêm các bộ lọc dựa trên chức năng bổ sung bên trên bộ lọc dựa trên cấp độ được thực hiện theo mặc định. Tôi thích nghĩ về nó như một bộ lọc gọi mónCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07 là lớp cơ sở cho CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 vì cả hai lớp này đều đủ điều kiện để nhận các bộ lọc tùy chỉnh bổ sung mà bạn chỉ định. Bạn thêm các phiên bản của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 vào chúng bằng _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
42 hoặ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
43, đó là những gì mà _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
44 đề cập đến trong phương pháp sauCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
4Đưa ra một
_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
03 [là một phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25], _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
47 trả 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
48 hoặ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
49 tùy thuộc vào việc bản ghi đó có được bộ lọc của lớp này chấp nhận hay khôngĐây là. Lần lượt 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
50, cho các lớp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
5Cả
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đều không đi kèm với bất kỳ bộ lọc bổ sung nào theo mặc định, nhưng đây là một ví dụ nhanh về cách bạn có thể thêm một bộ lọc>>>
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
6Ở trên, bạn định nghĩa một lớp
_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
55 và ghi đè lớp _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
47 của nó. 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
57, bạn cũng có thể chuyển một hàm có thể gọi được, chẳng hạn như một hàm hoặc lambda hoặc một lớp định nghĩ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
58Lớp họ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
59
_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
Còn một diễn viên hậu trường của
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 đáng để động vào. lớp _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
59. Điều quan trọng nhất không phải là lớp _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
59 mà là một phiên bản duy nhất của nó hoạt động như một thùng chứa cho hệ thống phân cấp ngày càng tăng của các trình ghi nhật ký được xác định trên các gói. Bạn sẽ thấy trong phần tiếp theo làm thế nào mà chỉ một phiên bản duy nhất của lớp này là trung tâm để gắn mô-đun lại với nhau và cho phép các phần của nó giao tiếp với nhauTrình ghi gốc cực kỳ quan trọng
Khi nói đến
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 trường hợp, một trường hợp nổi bật. Nó được gọi là bộ ghi gốcCRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
7Ba dòng cuối cùng của khối mã này là một trong những thủ thuật khéo léo được sử dụng bởi gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Dưới đây là một vài điểmBộ ghi gốc chỉ là một đối tượng Python đơn giản với mã định danh
94. Nó có cấp độ làCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
66 và cấp độ 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
67 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
68. Đối với lớp_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
69, cái tên duy nhất này là tất cả những gì đặc biệt về 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
Đối tượng
94 lần lượt trở thành một thuộc tính lớp cho lớpCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
08. Điều này có nghĩa là tất cả các phiên bản củaCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
08 và chính lớpCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
08 đều có một thuộc tínhCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
74 là trình ghi nhật ký gốc. Đây là một ví dụ khác về mẫu giống như singleton được thi hành trong gó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
5import logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
Phiên bản
59 được đặt làm thuộc tính lớp_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
77 cho_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
08. Điều này cuối cùng phát huy tác dụng trongCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
79._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
77 thực hiện tất cả việc tạo thuận lợi cho việc tìm kiếm các trình ghi nhật ký hiện có với tê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
81 và tạo chúng nếu chúng không tồn tạ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
Hệ thống phân cấp Logger
Mọi thứ đều là con của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
94 trong không gian tên logger và ý tôi là mọi thứ. Điều đó bao gồm các trình ghi nhật ký mà bạn tự chỉ định cũng như các trình ghi từ thư viện bên thứ ba mà bạn nhậpHãy nhớ lại trước đó cách mà
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
86 cho các trường hợp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 của chúng tôi là 30 [_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
21] mặc dù chúng tôi đã không đặt nó một cách rõ ràng? >>>
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
8Logic tương tự áp dụng cho việc tìm kiếm trình xử lý của trình ghi nhật ký. Tìm kiếm thực sự là tìm kiếm theo thứ tự đảo ngược trên cây của cha mẹ của người khai thác gỗ
Loại bỏ các quảng cáoThiết kế nhiều tay cầm
Hệ thống phân cấp logger có vẻ gọn gàng về mặt lý thuyết, nhưng nó có lợi như thế nào trong thực tế?
Hãy tạm dừng việc khám phá mã
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và chuyển sang viết ứng dụng nhỏ của riêng chúng ta—một ứng dụng tận dụng hệ thống phân cấp trình ghi nhật ký theo cách làm giảm mã soạn sẵn và giữ cho mọi thứ có thể mở rộng nếu cơ sở mã của dự án phát triểnĐây là cấu trúc dự án
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
9Đừng lo lắng về các chức năng chính của ứng dụng 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
89. Điều chúng ta chú ý nhiều hơn ở đây là sự tương tác trong các đối tượng import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 giữa các mô-đun 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
91Trong trường hợp này, giả sử bạn muốn thiết kế một thiết lập ghi nhật ký nhiều nhánh
Mỗi mô-đun nhận được một
12 với nhiều trình xử lýCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Một số trình xử lý được chia sẻ giữa các phiên bản
12 khác nhau trong các mô-đun khác nhau. Những trình xử lý này chỉ quan tâm đến việc lọc dựa trên cấp độ chứ không phải mô-đun nơi bản ghi nhật ký bắt nguồn từ đó. Có một trình xử lý cho các thưCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
19, một choCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
20, một choCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
21, v.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
Mỗi
12 cũng được liên kết với một trình xử lý bổ sung khác chỉ nhận các phiên bảnCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
25 từ một trình xử lý duy nhất đó làCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
12. Bạn có thể gọi đây là trình xử lý tệp dựa trên mô-đunCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Trực quan, những gì chúng ta đang chụp sẽ trông giống như thế này
Hai đối tượng màu ngọc lam là các phiên bản của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, được thiết lập với import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
01 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
09Ý tưởng đằng sau thiết kế này là nó được ngăn cách gọn gàng. Bạn có thể thuận tiện xem các tin nhắn đến từ một bộ ghi hoặc xem các tin nhắn ở cấp độ nhất định trở lên đến từ bất kỳ bộ ghi hoặc mô-đun nào
Các thuộc tính của hệ thống phân cấp bộ ghi làm cho nó phù hợp để thiết lập bố cục trình xử lý bộ ghi nhiều nhánh này. Điều đó nghĩa là gì?
Tại sao thứ bậc lại quan trọng? . Theo cách này, bạn có thể xác định một bộ trình xử lý duy nhất ở gốc của cây ghi nhật ký và nắm bắt tất cả các lệnh gọi ghi nhật ký trong cây con của trình ghi nhật ký. Trình xử lý ghi nhật ký được xác định trong không gian tên
03 sẽ bắt tất cả các thông báo ghi nhật ký được phát hành trên bộ ghi nhật kýimport threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
04 vàimport threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
05. [Nguồn]import threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
Thuật ngữ tuyên truyền đề cập đến cách một người khai thác gỗ tiếp tục đi lên chuỗi cha mẹ của nó để tìm kiếm người xử lý. Theo mặc định, thuộc tính
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
06 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
48 cho phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08>>>
_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
0Trong
_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
00, nếu import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
10 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
48, mỗi cha kế tiếp được gán lại cho biến cục bộ import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
12 cho đến khi hệ thống phân cấp cạn kiệt_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
1Đây là ý nghĩa của nó. bởi vì biến dunder
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
13 trong mô-đun [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'}
1 của gói chỉ là tên của gói, một trình ghi nhật ký ở đó sẽ trở thành cha mẹ của bất kỳ trình ghi nhật ký nào có trong các mô-đun khác trong cùng một góiDưới đây là kết quả thuộc tí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
67 từ việc gán cho CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 với import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
01Module
_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
67 Attributeimport threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
19import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
20import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
21import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
22import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
23import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
24Bởi vì những người khai thác gỗ
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
22 và import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
24 là con của import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
20, chúng sẽ bám lấy không chỉ những người xử lý trực tiếp của chúng mà còn với bất kỳ người xử lý nào được gắn với import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
20Hãy xây dựng các mô-đun. Đến trước
[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'}
1_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[]
03 đượ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
19 đế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'}
9, sau đó đính kèm nó vào một trình ghi nhật ký duy nhất ở đầu hệ thống phân cấpBạn cũng xác định một hàm tiện ích bổ sung thêm một
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
33 vào bộ ghi nhật ký, trong đó import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
34 của trình xử lý tương ứng với tên mô-đun nơi bộ ghi được xác định. [Điều này giả sử bộ ghi nhật ký được xác định bằng import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
13. ]Sau đó, bạn có thể thêm một số thiết lập bộ ghi soạn sẵn 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
89 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
88. 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[]
38 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'}
1. Bạn không cần phải lo lắng về các trình xử lý định hướng theo cấp độ vì chúng đã được thêm vào trình ghi gốc của chúng có tên là import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
20_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 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
88_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 xem cách tất cả những thứ 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ý thu được rằng hệ thống lọc của chúng tôi hoạt động như dự kiến. Trình xử lý hướng mô-đun hướng một trình ghi tới một tệp cụ thể, trong khi trình xử lý hướng cấp hướng nhiều trình ghi tới 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ư thừa. Một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 có thể chuyển đến không ít hơn sáu tệp. Đó cũng là một lượng tệp I/O không đáng kể có thể tăng lên trong một ứng dụng quan trọng về hiệu suấtBây giờ, bạn đã xem một ví dụ thực tế, hãy chuyển hướng và tìm hiểu nguyên nhân có thể gây nhầm lẫn trong
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5Loại bỏ các quảng cáoThông báo “Tại sao Thông điệp Nhật ký của tôi không đi đến đâu?”
Có hai tình huống phổ biến với
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 khi bạn dễ vấp ngã- Bạn đã ghi một tin nhắn dường như chẳng đi đến đâu và bạn không chắc tại sao
- Thay vì bị chặn, một thông báo tường trình xuất hiện ở một nơi mà bạn không ngờ tớ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 đã ghi một tin nhắn dường như chẳng đi đến đâu và bạn không chắc tại sao
Đừng quên rằng cấp độ hiệu quả của trình ghi nhật ký mà bạn không đặt mức tùy chỉnh theo cách khác 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
21, bởi vì trình ghi nhật ký sẽ đi lên cấp bậc của nó cho đến khi tìm thấy trình ghi nhật ký gốc có cấp độ _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
21 của chính 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
7Vì 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[]
47 không đi đến đâuThay vì bị chặn, một thông báo tường trình xuất hiện ở một nơi mà bạn không ngờ tới
Khi bạn xác định
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 ở trên, bạn đã không thêm bất kỳ trình xử lý nào vào nó. Vì vậy, tại sao nó ghi vào bàn điều khiển?Lý do cho điều này là vì một trình xử lý tên là
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 có tên là import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
50 sẽ viết thư cho CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31 nếu không tìm thấy trình xử lý nào 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
8Điều này khởi động khi một người ghi nhật ký đi tìm người xử lý của 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
9Nếu trình ghi nhật ký từ bỏ việc tìm kiếm trình xử lý [cả trình xử lý trực tiếp của chính nó và thuộc tính của trình ghi nhật ký mẹ], thì nó sẽ chọn trình xử lý
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
50 và sử dụng trình đóCó một chi tiết tinh tế hơn đáng để biết về. Phần này chủ yếu nói về các phương thức cá thể [các phương thức mà một lớp định nghĩa] hơn là các hàm cấp mô-đun của gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 có cùng tênNếu bạn sử dụng các hàm, chẳng hạn như
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
54 thay vì import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
55, thì nội bộ sẽ xảy ra điều gì đó hơi khác một chút. Hàm gọi import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
56, hàm này thêm một số import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
57 để ghi vào CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31. Cuối cùng, hành vi hầu như giống nhau>>>
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
0Tận dụng lợi thế của định dạng lười biếng
Đã đến lúc chuyển hướng và xem xét kỹ hơn cách bản thân các tin nhắn được kết hợp với dữ liệu của chúng. Mặc dù nó đã được thay thế bởi và chuỗi f, nhưng có lẽ bạn đã sử dụng định dạng kiểu phần trăm của Python để làm điều gì đó như thế này
>>>
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
1Kết quả là, bạn có thể bị cám dỗ làm điều tương tự trong một cuộc gọi
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5>>>
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
2Điều này sử dụng toàn bộ chuỗi định dạng và các đối số của nó làm đối số
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
61 cho import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
62Đây là giải pháp thay thế được đề xuất,
>>>
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
3Nó trông hơi kỳ lạ, phải không? . Đây là ý nghĩa của nó
Chữ ký phương thức cho
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
64 trông như thế nàyimport threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
4Điều tương tự cũng áp dụng cho các phương pháp khác, chẳng hạn như
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
47. Khi bạn gọi import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
66, cả import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
67 và import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
68 đều bị bắt là import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
69 và, trong phạm vi nội dung của phương thức, import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
70 bằng với import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
71Tương phản điều này với cuộc gọi đầu tiên ở trên
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
5Ở dạng này, mọi thứ trong ngoặc đơn ngay lập tức được hợp nhất với nhau thành
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
72 và được chuyển thành import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
61, trong khi import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
70 là một bộ trốngVì sao vấn đề này? . 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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
25 được yêu cầu bởi một CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09Điều này xảy ra trong , vì vậy chỉ sau khi
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 xét thấy rằng CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 sẽ thực sự được chuyển cho một trình xử lý thì nó mới trở thành chính nó được hợp nhất hoàn toànTất cả điều đó có nghĩa là gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 thực hiện một số tối ưu hóa hiệu suất rất tinh vi ở đúng nơi. Điều này có vẻ như là chi tiết vụn vặt, nhưng nếu bạn đang thực hiện cùng một lệnh gọi import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
83 hàng 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[]
70 là các lệnh gọi hàm, thì bản chất lười biếng của cách định dạng chuỗi của ___________ có thể tạo ra sự khác biệtTrước khi thực hiện bất kỳ việc 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[]
61 và import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
70, một phiên bản CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 sẽ kiểm tra CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85 của nó để xem liệu việc hợp nhất đó có nên được thực hiện ngay từ đầu khôngLoại bỏ các quảng cáoHàm vs Phương thức
Về phía cuố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'}
0 là các chức năng cấp mô-đun được quảng cáo trước trong API công khai của import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Bạn đã thấy các phương thức CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 như import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
47, import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
94 và import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
95. Các hàm cấp cao nhất là các hàm bao 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ọngHọ luôn gọi phương thức tương ứng từ bộ ghi gốc,
94CRITICAL = 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 ghi nhật ký gốc, chúng gọi
56 mà không có đối số nếuimport threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
94 không có bất kỳ trình xử lý nào. Như bạn đã thấy trước đó, lệnh gọi này thiết lập trình xử lýCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
77 cho trình ghi nhật ký gốcCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
Để minh họa, đây là
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
6Bạn sẽ tìm thấy mẫu tương tự cho
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
83, import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
54 và cả những mẫu khác nữa. Truy tìm chuỗi lệnh thật thú vị. Cuối cùng, bạn sẽ kết thúc ở cùng một nơi, đó là nơi mà object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
03 bên trong được gọi làCác cuộc gọi đến
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
04, object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
05, object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
06 và các chức năng dựa trên cấp độ khác đều hướng đến đây. object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
07 chủ yếu có hai mục đíchGọi _______53_______08. Tạo một ví dụ
25 từCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
61 và các đối số khác mà bạn chuyển đến nóimport threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
Gọi
11. Đ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 đi đâu?object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Đây là toàn bộ quá trình trong một sơ đồ
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
48Theo dõi cuộc gọi để ghi nhật ký. cảnh báo[]Hiện/Ẩn
>>>
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
13 thực sự làm gì?
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
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
13, bao bọc object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
15import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
8Đây là điểm khởi đầu để thực thi thiết kế bộ ghi đơn
Nếu bạn chỉ định một
16, thì ____53_______17 bên dưới sẽ thực hiện tra cứu ____27_______3 trên chuỗi _______53_______16. Điều này dẫn đến việc tra cứu trongobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
20 củaobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
21. Đây là từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các phiên bản trung gianobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
22 được tạo khi bạn tham chiếu trình ghi nhật ký ở xa trong hệ thống phân cấp trước khi tham chiếu cha mẹ của nóobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Mặt khác,
94 được trả lại. Chỉ có mộtCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
94—trường hợp củaCRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
69 đã 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à thứ nằm sau một thủ thuật có thể cho phép bạn xem qua tất cả những người ghi nhật ký đã đăng ký
>>>
import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
9Chờ đã. Điều gì đang xảy ra ở đây?
Đầu tiên, hãy nhớ lại rằng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
27 là một thuộc tính của lớp, trong đó một thể hiện 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
59 được gắn vào lớp CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08. object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
30 được thiết kế để theo dõi và quản lý tất cả các phiên bản đơn lẻ của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08. Chúng được đặt trong object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
32Bây giờ, khi bạn nhập
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 lần đầu tiên, từ điển này trống. Nhưng sau khi bạn nhập object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
34, cùng một từ điển sẽ có ba trình ghi nhật ký. Đây là một ví dụ về một mô-đun thiết lập các thuộc tính của một mô-đun khác tại chỗ. Chắc chắn rồi, bên trong object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
35, bạn sẽ tìm thấy những thứ sauobject
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
0Cặp khóa-giá trị nằm trong
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
36 để object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
30 có thể giám sát toàn bộ không gian tên của logger. Điều này có nghĩa là đối tượng object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
38 được đăng ký trong từ điển logger thuộc gói import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Điều tương tự cũng xảy ra với gói object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
40, được nhập bởi object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
34Bạn có thể thấy sức mạnh của thiết kế đơn lẻ trong một thử nghiệm tương đương
>>>
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
1Sự so sánh này minh họa [che đậy một vài chi tiết] cuối cùng thì
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
13 làm gìLoại bỏ các quảng cáoGhi nhật ký thư viện và ứng dụng. object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
43 là gì?
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
Điều đó đưa chúng ta đến khoảng một 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'}
0, trong đó object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
43 được định nghĩa. Đây là đị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
43 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 ứng dụng. Hãy xem điều đó có nghĩa là gìThư viện là một gói Python có thể mở rộng, có thể khái quát hóa, dành cho những 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à phân phối cho người dùng. 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
47 và object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
48Ứ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à nhóm người dùng nhỏ hơn nhiều [có thể chỉ một người dùng]. Đó là một chương trình hoặc bộ chương trình được người dùng tùy chỉnh cao để thực hiện một số việc hạn chế. Một ví dụ về ứng dụng là ứng dụng Django nằm phía sau trang web. Các ứng dụng thường sử dụng [
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
49] thư viện và các công cụ chứa trong đóKhi nói đến ghi nhật ký, có các phương pháp hay nhất khác nhau trong thư viện so với ứng dụng
Đó là nơi mà
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
43 phù hợp. Về cơ bản, nó là một lớp sơ khai không làm gì cảNếu bạn đang viết một thư viện Python, bạn thực sự cần thực hiện một phần thiết lập tối giản này trong ____15_______1 của gói của bạn
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 trình ghi nhật ký thư viện được khai báo với
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
52 [không có bất kỳ cấu hình nào khác] sẽ đăng nhập vào ____22_______31 theo mặc định, ngay cả khi đó không phải là điều người dùng cuối muốn. Điều này có thể được mô tả như một phương pháp từ chối, trong đó người dùng cuối của thư viện phải truy cập 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.Thay vào đó, sự khôn ngoan thông thường nói rằng hãy sử dụng phương pháp chọn tham gia. khô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 các trình ghi nhật ký của thư viện hay không và thêm các trình xử lý cho chúng. Đây là triết lý được diễn đạt thẳng thắn hơn bởi tác giả của gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5, Vinay SajipTheo mặc định, thư viện của bên thứ ba sử dụng
5 sẽ không tạo ra đầu ra ghi nhật ký, điều mà nhà phát triển/người dùng ứng dụng sử dụng nó có thể không mong muốn. [Nguồn]import logging import sys logger = logging.getLogger["pylog"] logger.setLevel[logging.DEBUG] h1 = logging.FileHandler[filename="/tmp/records.log"] h1.setLevel[logging.INFO] h2 = logging.StreamHandler[sys.stderr] h2.setLevel[logging.ERROR] logger.addHandler[h1] logger.addHandler[h2] logger.info["testing %d. %d. %d..", 1, 2, 3]
Điều này cho phép người dùng thư viện, chứ 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
56 hoặc object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
57Lý do thứ hai mà
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
43 tồn tại cổ xưa hơn. Trong Python 2. 7 trở về trước, việc cố gắng ghi nhật ký CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 từ trình ghi nhật ký không có bộ xử lý sẽ. Thêm lớp no-op object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
43 sẽ ngăn chặn điều nàyĐây là những gì cụ thể xảy ra trong dòng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
61 từ phía trênPython nhận [tạo] phiên bản
08 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
63, trong khoảngobject │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
1, 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'}
13 sẽ bằng vớiimport threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
66object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager
Phiên bản
43 được đính kèm với bộ ghi 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
50import threading _lock = threading.RLock[] def _acquireLock[]: if _lock: _lock.acquire[] def _releaseLock[]: if _lock: _lock.release[]
Hãy nhớ rằng bất kỳ trình ghi nhật ký nào được tạo trong bất kỳ mô-đun
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
69 nào khác của gói sẽ là con của trình ghi nhật ký này trong hệ thống phân cấp trình ghi nhật ký và vì trình xử lý này cũng thuộc về họ nên 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[]
50 và giành chiến thắng Ví dụ nhanh, giả sử 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
72, với tư cách là nhà phát triển thư viện, bạn được tự do thực hiện những việc sauobject
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
5Bây giờ, một người dùng đã đến và cài đặt thư viện của bạn từ PyPI qua
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
73. Họ sử dụng object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
74 trong một số mã ứng dụng. Người dùng này được 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
12 từ thư viện giống như bất kỳ đối tượng Python nào khác, theo ý muốn của họLoại bỏ các quảng cáoGhi 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à sự nguy hiểm của các trường hợp ngoại lệ xuất phát từ các cuộc gọi của bạn tới
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
47 đượ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 bản thân cuộc gọi đó vì lý do nào đó lại tạo ra một ngoại lệ, đó sẽ là đỉnh điểm của sự trớ trêu, phải không?Khéo léo, nếu gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 gặp phải một ngoại lệ liên quan đến việc ghi nhật ký, thì nó sẽ in truy nguyên nhưng không tự đưa ra ngoại lệ đóĐây là 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 nhìn thấy bên dưới không phải là một ngoại lệ được nêu ra, mà là một dấu vết được in đẹp hơn của ngoại lệ bên trong, chính ngoại lệ này đã bị chặn
>>>
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 tiếp tục một cách duyên dáng với luồng chương trình thực tế của nó. Cơ sở lý luận là bạn sẽ không muốn một ngoại lệ chưa được phát hiện đến từ chính lệnh gọi
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và dừng một chương trình đang chết dởTracbacks có thể lộn xộn, nhưng điều này là thông tin và tương đối đơn giản. Điều gì cho phép loại bỏ các trường hợp ngoại lệ liên quan đến
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
81. Khi trình xử lý gọi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
37, đây là phương thức mà nó cố gắng ghi lại bản ghi, nó sẽ quay trở lại object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
83 nếu có gì đó không ổn. Đây là triển khai của CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
37 cho lớp import threading
_lock = threading.RLock[]
def _acquireLock[]:
if _lock:
_lock.acquire[]
def _releaseLock[]:
if _lock:
_lock.release[]
57object
│
├── 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à cách viết đều bị bắt thay vì được nêu ra và
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
86 viết truy nguyên một cách duyên dáng tới CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31Ghi nhật ký Truy nguyên Python
Nói về ngoại lệ và dấu vết của chúng, còn các trường hợp chương trình của bạn gặp phải chúng nhưng nên ghi lại ngoại lệ và tiếp tục thực hiện thì sao?
Hãy xem qua một vài cách để làm điều này
Đây là một ví dụ giả định về trình giả lập xổ số sử dụng mã không phải là mục đích của Pythonic. Bạn đang phát triển trò chơi xổ số trực tuyến nơi người dùng có thể đặt cược vào con số may mắn của họ
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
8Đằng sau ứng dụng giao diện người dùng là mã quan trọng bên dưới. Bạn muốn đảm bảo rằng bạn theo dõi bất kỳ lỗi nào do trang web gây ra có thể khiến người dùng mất tiền. Cách đầu tiên [dưới mức tối ưu] là sử dụng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
47 và ghi lại biểu mẫ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
0 của chính trường hợp ngoại lệobject
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
9Điều này sẽ chỉ giúp bạn nhận được thông báo ngoại lệ thực tế, thay vì truy nguyên. Bạn kiểm tra nhật ký trên máy chủ trang web của mình và tìm thấy thông báo khó hiểu này
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
0Hừm. Là nhà phát triển ứng dụng, bạn đã gặp phải một vấn đề nghiêm trọng và kết quả là một người dùng đã bị gạt. Nhưng có lẽ bản thân thông báo ngoại lệ này không có nhiều thông tin. Thật tuyệt khi thấy dòng truy nguyên dẫn đến ngoại lệ này phải không?
Giải pháp thích hợp là sử dụng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
90, ghi nhật ký một thông báo có cấp độ CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
32 và cũng hiển thị truy nguyên ngoại lệ. Thay thế hai dòng cuối cùng ở trên bằng những dòng nàyimport logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
1Bây giờ bạn có một dấu hiệu tốt hơn về những gì đang xảy ra
>>>
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
2Việc sử dụng
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
92 giúp bạn không phải tự mình tham chiếu ngoại lệ vì import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
94Đ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
95, 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
96 của chúng tôi chuyển một trình tạo cho object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
97, nó sẽ được giữ và tăng trước khi nhóm có thể được xáo trộn, ít tạo ra vé trúng thưởng hơn nhiềuTrong 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
90 thậm chí còn hữu ích hơn khi có liên quan đến truy nguyên sâu, nhiều thư viện và bạn không thể can thiệp vào chúng bằng 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
48Mã cho
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
00, và do đó là object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
90, chỉ là một dòng duy nhấtimport logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
90 chỉ gọi CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
47 với import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
04, nếu không thì 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
49 theo mặc định. Nếu bạn muốn ghi lại một truy nguyên ngoại lệ nhưng ở cấp độ khác với import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
06, chỉ cần gọi hàm hoặc phương thức đó với ____0__04Hãy nhớ rằng chỉ nên gọi
object
│
├── LogRecord
├── Filterer
│ ├── Logger
│ │ └── RootLogger
│ └── Handler
│ ├── StreamHandler
│ └── NullHandler
├── Filter
└── Manager
92 trong ngữ cảnh của trình xử lý ngoại lệ, bên trong khối import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
09import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
4Sử dụng mô hình này một cách tiết kiệm thay vì như một phương tiện để loại bỏ bất kỳ ngoại lệ nào. Nó có thể hữu ích nhất khi bạn đang gỡ lỗi một ngăn lệnh gọi hàm dài mà nếu không thì bạn sẽ thấy một lỗi mơ hồ, không rõ ràng và khó theo dõi
Loại bỏ các quảng cáoPhần kết luận
Hãy tự vỗ về mình vì bạn vừa xem qua gần 2.000 dòng mã nguồn dày đặc. Bây giờ bạn đã đượ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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5Hãy nhớ rằng hướng dẫn này vẫn chưa đầy đủ trong việc bao gồm tất cả các lớp có trong gói
import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Thậm chí còn có nhiều máy móc dán 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 các lớp học import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
12 và các mô-đun riêng biệt import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
13 và import logging
import sys
logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
14Đánh dấu là đã hoàn thành
🐍 Thủ thuật Python 💌
Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python
Gửi cho tôi thủ thuật Python »
Giới thiệu về Brad Solomon
Brad là một kỹ sư phần mềm và là thành viên của Nhóm hướng dẫn Python thực sự
» Thông tin thêm về BradMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là
Aldren
Jim
Joanna
Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Chuyên gia Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Bạn nghĩ sao?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi