Đang ghi nhật ký HOWTO¶
- tác giả:
Vinay Sajip <vinay_sajip tại red-dove dot com>
Trang này chứa thông tin hướng dẫn. Để biết các liên kết đến thông tin tham khảo và sách nấu ăn ghi nhật ký, vui lòng xem Các tài nguyên khác.
Hướng dẫn ghi nhật ký cơ bản¶
Ghi nhật ký là phương tiện theo dõi các sự kiện xảy ra khi một số phần mềm chạy. Nhà phát triển phần mềm thêm lệnh gọi ghi nhật ký vào mã của họ để cho biết rằng một số sự kiện nhất định đã xảy ra. Một sự kiện được mô tả bằng một thông báo mô tả có thể tùy ý chứa dữ liệu thay đổi (tức là dữ liệu có khả năng khác nhau đối với mỗi lần xảy ra sự kiện). Các sự kiện cũng có tầm quan trọng mà nhà phát triển gán cho sự kiện đó; tầm quan trọng cũng có thể được gọi là level hoặc severity.
Khi nào nên sử dụng tính năng ghi nhật ký¶
Bạn có thể truy cập chức năng ghi nhật ký bằng cách tạo một trình ghi nhật ký thông qua logger = logging.getLogger(__name__), sau đó gọi các phương thức debug(), info(), warning(), error() và critical() của trình ghi nhật ký. Để xác định thời điểm sử dụng tính năng ghi nhật ký và xem phương pháp ghi nhật ký nào sẽ sử dụng khi nào, hãy xem bảng bên dưới. Nó nêu rõ, đối với mỗi nhóm nhiệm vụ chung, công cụ tốt nhất để sử dụng cho nhiệm vụ đó là gì.
Nhiệm vụ bạn muốn thực hiện |
Công cụ tốt nhất cho nhiệm vụ |
|---|---|
Hiển thị đầu ra của bảng điều khiển để sử dụng thông thường tập lệnh hoặc chương trình dòng lệnh |
|
Báo cáo các sự kiện xảy ra trong quá trình vận hành bình thường của một chương trình (ví dụ: để theo dõi trạng thái hoặc điều tra lỗi) |
Phương pháp |
Đưa ra cảnh báo liên quan đến một sự kiện thời gian chạy cụ thể |
Phương pháp |
Báo cáo lỗi liên quan đến một sự kiện thời gian chạy cụ thể |
Đưa ra một ngoại lệ |
Báo cáo việc ngăn chặn lỗi mà không đưa ra ngoại lệ (ví dụ: trình xử lý lỗi trong quy trình máy chủ chạy dài) |
Phương pháp |
Các phương thức ghi nhật ký được đặt tên theo cấp độ hoặc mức độ nghiêm trọng của các sự kiện mà chúng được sử dụng để theo dõi. Các mức tiêu chuẩn và khả năng áp dụng của chúng được mô tả dưới đây (theo thứ tự mức độ nghiêm trọng tăng dần):
Cấp độ |
Khi nó được sử dụng |
|---|---|
|
Thông tin chi tiết, thường chỉ được quan tâm khi chẩn đoán vấn đề. |
|
Xác nhận rằng mọi thứ đang hoạt động như mong đợi. |
|
Dấu hiệu cho thấy điều gì đó không mong muốn đã xảy ra hoặc cho thấy sự cố nào đó trong tương lai gần (ví dụ: 'dung lượng ổ đĩa sắp hết'). Phần mềm vẫn hoạt động như mong đợi. |
|
Do một sự cố nghiêm trọng hơn nên phần mềm không thể thực hiện được một số chức năng. |
|
Một lỗi nghiêm trọng cho thấy bản thân chương trình có thể không thể tiếp tục chạy. |
Mức mặc định là WARNING, có nghĩa là chỉ những sự kiện có mức độ nghiêm trọng này trở lên mới được theo dõi, trừ khi gói ghi nhật ký được định cấu hình để thực hiện khác.
Các sự kiện được theo dõi có thể được xử lý theo nhiều cách khác nhau. Cách đơn giản nhất để xử lý các sự kiện được theo dõi là in chúng ra bảng điều khiển. Một cách phổ biến khác là ghi chúng vào một tập tin đĩa.
Một ví dụ đơn giản¶
Một ví dụ rất đơn giản là:
nhập nhật ký
logging.warning('Coi chừng!') # will in một thông báo tới bảng điều khiển
logging.info('Tôi đã bảo rồi mà') # will không in gì cả
Nếu bạn nhập những dòng này vào một tập lệnh và chạy nó, bạn sẽ thấy:
WARNING:root:Coi chừng!
được in ra trên bảng điều khiển. Thông báo INFO không xuất hiện do cấp độ mặc định là WARNING. Thông báo được in bao gồm chỉ báo về cấp độ và mô tả sự kiện được cung cấp trong lệnh gọi ghi nhật ký, tức là 'Hãy cẩn thận!'. Đầu ra thực tế có thể được định dạng khá linh hoạt nếu bạn cần; các tùy chọn định dạng cũng sẽ được giải thích sau.
Lưu ý rằng trong ví dụ này, chúng tôi sử dụng các hàm trực tiếp trên mô-đun logging, như logging.debug, thay vì tạo một trình ghi nhật ký và gọi các hàm trên đó. Các hàm này hoạt động trên trình ghi nhật ký gốc nhưng có thể hữu ích vì chúng sẽ gọi basicConfig() cho bạn nếu nó chưa được gọi, như trong ví dụ này. Tuy nhiên, trong các chương trình lớn hơn, bạn thường muốn kiểm soát cấu hình ghi nhật ký một cách rõ ràng - vì lý do đó cũng như các lý do khác, tốt hơn hết bạn nên tạo trình ghi nhật ký và gọi các phương thức của chúng.
Đăng nhập vào một tập tin¶
Một tình huống rất phổ biến là ghi lại các sự kiện ghi nhật ký vào một tệp, vì vậy chúng ta hãy xem xét vấn đề đó tiếp theo. Hãy nhớ thử cách sau trong trình thông dịch Python mới khởi động và không chỉ tiếp tục từ phiên được mô tả ở trên:
nhập nhật ký
logger = log.getLogger(__name__)
logging.basicConfig(tên tệp='example.log', mã hóa='utf-8', cấp độ=logging.DEBUG)
logger.debug('Thông báo này sẽ được chuyển tới tệp nhật ký')
logger.info('Điều này cũng vậy')
logger.warning('Và cái này nữa')
logger.error('Và cả những thứ không phải ASCII, như Øresund và Malmö')
Thay đổi trong phiên bản 3.9: Đối số encoding đã được thêm vào. Trong các phiên bản Python cũ hơn hoặc nếu không được chỉ định, mã hóa được sử dụng là giá trị mặc định được open() sử dụng. Mặc dù không được hiển thị trong ví dụ trên, nhưng giờ đây, một đối số errors cũng có thể được truyền để xác định cách xử lý lỗi mã hóa. Để biết các giá trị có sẵn và giá trị mặc định, hãy xem tài liệu về open().
Và bây giờ nếu chúng ta mở tệp và xem những gì chúng ta có, chúng ta sẽ tìm thấy thông báo tường trình:
DEBUG:__main__:Thông báo này sẽ được chuyển tới tệp nhật ký
INFO:__main__:Điều này cũng vậy
WARNING:__main__:Và cái này nữa
ERROR:__main__:Và cả những thứ không phải ASCII, như Øresund và Malmö
Ví dụ này cũng cho thấy cách bạn có thể đặt mức ghi nhật ký đóng vai trò là ngưỡng để theo dõi. Trong trường hợp này, vì chúng tôi đặt ngưỡng thành DEBUG nên tất cả tin nhắn đều được in.
Nếu bạn muốn đặt mức ghi nhật ký từ tùy chọn dòng lệnh, chẳng hạn như:
--log=INFO
và bạn có giá trị của tham số được truyền cho --log trong một số biến loglevel, bạn có thể sử dụng
getattr(ghi nhật ký, loglevel.upper())
để nhận giá trị mà bạn sẽ chuyển tới basicConfig() thông qua đối số level. Bạn có thể muốn kiểm tra lỗi bất kỳ giá trị đầu vào nào của người dùng, có thể như trong ví dụ sau:
# assuming loglevel được liên kết với giá trị chuỗi thu được từ
đối số dòng # command. Chuyển sang chữ hoa để cho phép người dùng
# specify --log=DEBUG hoặc --log=debug
số_level = getattr(ghi nhật ký, loglevel.upper(), Không có)
nếu không phải là isinstance(numeric_level, int):
raise ValueError('Mức nhật ký không hợp lệ: %s' % loglevel)
logging.basicConfig(level=numeric_level, ...)
Lệnh gọi tới basicConfig() sẽ đến before bất kỳ lệnh gọi nào tới các phương thức của trình ghi nhật ký như debug(), info(), v.v. Nếu không, sự kiện ghi nhật ký đó có thể không được xử lý theo cách mong muốn.
Nếu bạn chạy đoạn mã trên nhiều lần, các thông báo từ các lần chạy liên tiếp sẽ được thêm vào tệp example.log. Nếu bạn muốn mỗi lần chạy bắt đầu lại từ đầu mà không nhớ các thông báo từ các lần chạy trước đó, bạn có thể chỉ định đối số filemode bằng cách thay đổi lệnh gọi trong ví dụ trên thành:
logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)
Kết quả đầu ra sẽ giống như trước đây nhưng tệp nhật ký không còn được thêm vào nữa nên các thông báo từ các lần chạy trước đó sẽ bị mất.
Ghi dữ liệu biến¶
Để ghi dữ liệu biến, hãy sử dụng chuỗi định dạng cho thông báo mô tả sự kiện và nối dữ liệu biến làm đối số. Ví dụ:
nhập nhật ký
logging.warning('%s trước bạn %s', 'Nhìn', 'nhảy!')
sẽ hiển thị:
WARNING:root:Hãy quan sát trước khi nhảy!
Như bạn có thể thấy, việc hợp nhất dữ liệu biến đổi vào thông báo mô tả sự kiện sử dụng định dạng chuỗi kiểu % cũ. Điều này là để tương thích ngược: gói ghi nhật ký có trước các tùy chọn định dạng mới hơn như str.format() và string.Template. Các tùy chọn định dạng mới hơn này được are hỗ trợ nhưng việc khám phá chúng nằm ngoài phạm vi của hướng dẫn này: xem Sử dụng các kiểu định dạng cụ thể trong toàn bộ ứng dụng của bạn để biết thêm thông tin.
Thay đổi định dạng tin nhắn hiển thị¶
Để thay đổi định dạng được sử dụng để hiển thị thông báo, bạn cần chỉ định định dạng bạn muốn sử dụng:
nhập nhật ký
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('Thông báo này sẽ xuất hiện trên bảng điều khiển')
logging.info('Điều này cũng nên như vậy')
logging.warning('Và cả cái này nữa')
cái nào sẽ in:
DEBUG:Thông báo này sẽ xuất hiện trên bảng điều khiển
INFO:Điều này cũng nên như vậy
WARNING:Và cái này nữa
Lưu ý rằng 'root' xuất hiện trong các ví dụ trước đã biến mất. Để có bộ đầy đủ những thứ có thể xuất hiện ở dạng chuỗi định dạng, bạn có thể tham khảo tài liệu về Thuộc tính LogRecord, nhưng để sử dụng đơn giản, bạn chỉ cần levelname (mức độ nghiêm trọng), message (mô tả sự kiện, bao gồm dữ liệu biến đổi) và có thể hiển thị thời điểm sự kiện xảy ra. Điều này được mô tả trong phần tiếp theo.
Hiển thị ngày/giờ trong tin nhắn¶
Để hiển thị ngày và giờ của một sự kiện, bạn sẽ đặt '%(asctime)s' trong chuỗi định dạng của mình:
nhập nhật ký
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('là khi sự kiện này được ghi lại.')
cái nào sẽ in một cái gì đó như thế này:
2010-12-12 11:41:42,612 là thời điểm sự kiện này được ghi lại.
Định dạng mặc định để hiển thị ngày/giờ (hiển thị ở trên) giống như ISO8601 hoặc RFC 3339. Nếu bạn cần kiểm soát nhiều hơn đối với định dạng ngày/giờ, hãy cung cấp đối số datefmt cho basicConfig, như trong ví dụ này:
nhập nhật ký
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('là khi sự kiện này được ghi lại.')
sẽ hiển thị một cái gì đó như thế này:
12/12/2010 11:46:36 AM là thời điểm sự kiện này được ghi lại.
Định dạng của đối số datefmt giống như được hỗ trợ bởi time.strftime().
Các bước tiếp theo¶
Thế là kết thúc phần hướng dẫn cơ bản. Nó là đủ để giúp bạn bắt đầu và chạy với việc ghi nhật ký. Còn nhiều tính năng khác mà gói ghi nhật ký cung cấp, nhưng để tận dụng tối đa gói này, bạn sẽ cần đầu tư thêm một chút thời gian để đọc các phần sau. Nếu bạn đã sẵn sàng cho việc đó, hãy lấy một ít đồ uống yêu thích của bạn và tiếp tục.
Nếu nhu cầu ghi nhật ký của bạn đơn giản thì hãy sử dụng các ví dụ trên để kết hợp đăng nhập vào tập lệnh của riêng bạn và nếu bạn gặp vấn đề hoặc không hiểu điều gì đó, vui lòng đăng câu hỏi trong danh mục Trợ giúp của Python discussion forum và bạn sẽ nhận được trợ giúp sớm thôi.
Vẫn ở đây à? Bạn có thể tiếp tục đọc một số phần tiếp theo, trong đó cung cấp hướng dẫn nâng cao/chuyên sâu hơn một chút so với phần cơ bản ở trên. Sau đó, bạn có thể xem Ghi nhật ký sách dạy nấu ăn.
Hướng dẫn ghi nhật ký nâng cao¶
Thư viện ghi nhật ký sử dụng cách tiếp cận mô-đun và cung cấp một số danh mục thành phần: trình ghi nhật ký, trình xử lý, bộ lọc và trình định dạng.
Trình ghi nhật ký hiển thị giao diện mà mã ứng dụng trực tiếp sử dụng.
Trình xử lý gửi bản ghi nhật ký (do người ghi nhật ký tạo) đến đích thích hợp.
Bộ lọc cung cấp phương tiện chi tiết hơn để xác định bản ghi nhật ký nào sẽ được xuất ra.
Trình định dạng chỉ định cách bố trí các bản ghi nhật ký ở đầu ra cuối cùng.
Thông tin sự kiện nhật ký được truyền giữa các trình ghi nhật ký, trình xử lý, bộ lọc và trình định dạng trong phiên bản LogRecord.
Việc ghi nhật ký được thực hiện bằng cách gọi các phương thức trên các phiên bản của lớp Logger (sau đây gọi là loggers). Mỗi phiên bản có một tên và chúng được sắp xếp theo khái niệm theo hệ thống phân cấp không gian tên bằng cách sử dụng dấu chấm (dấu chấm) làm dấu phân cách. Ví dụ: trình ghi nhật ký có tên 'scan' là cấp độ gốc của trình ghi nhật ký 'scan.text', 'scan.html' và 'scan.pdf'. Tên trình ghi nhật ký có thể là bất cứ điều gì bạn muốn và cho biết khu vực của ứng dụng nơi bắt nguồn thông báo đã ghi.
Một quy ước tốt để sử dụng khi đặt tên trình ghi nhật ký là sử dụng trình ghi nhật ký cấp mô-đun, trong mỗi mô-đun sử dụng tính năng ghi nhật ký, được đặt tên như sau:
logger = log.getLogger(__name__)
Điều này có nghĩa là tên trình ghi nhật ký theo dõi hệ thống phân cấp gói/mô-đun và bằng trực giác, có thể thấy rõ nơi các sự kiện được ghi lại chỉ từ tên trình ghi nhật ký.
Gốc của hệ thống phân cấp của logger được gọi là root logger. Đó là trình ghi nhật ký được các hàm debug(), info(), warning(), error() và critical() sử dụng, các hàm này chỉ gọi phương thức cùng tên của trình ghi nhật ký gốc. Các hàm và phương thức có cùng chữ ký. Tên của trình ghi nhật ký gốc được in dưới dạng 'root' trong kết quả đã ghi.
Tất nhiên, có thể ghi tin nhắn đến các đích khác nhau. Hỗ trợ được bao gồm trong gói để ghi thông điệp tường trình vào tệp, vị trí HTTP GET/POST, email qua SMTP, ổ cắm chung, hàng đợi hoặc cơ chế ghi nhật ký dành riêng cho hệ điều hành như nhật ký hệ thống hoặc nhật ký sự kiện Windows NT. Các điểm đến được phục vụ bởi các lớp handler. Bạn có thể tạo lớp đích nhật ký của riêng mình nếu bạn có các yêu cầu đặc biệt mà bất kỳ lớp xử lý tích hợp sẵn nào không đáp ứng được.
Theo mặc định, không có đích nào được đặt cho bất kỳ thông báo ghi nhật ký nào. Bạn có thể chỉ định đích (chẳng hạn như bảng điều khiển hoặc tệp) bằng cách sử dụng basicConfig() như trong các ví dụ hướng dẫn. Nếu bạn gọi các hàm debug(), info(), warning(), error() và critical(), chúng sẽ kiểm tra xem liệu có đích đến nào được đặt hay không; và nếu một cái không được đặt, họ sẽ đặt đích của bảng điều khiển (sys.stderr) và định dạng mặc định cho thông báo được hiển thị trước khi ủy quyền cho trình ghi nhật ký gốc để thực hiện đầu ra thông báo thực tế.
Định dạng mặc định do basicConfig() đặt cho tin nhắn là:
mức độ nghiêm trọng: tên logger: tin nhắn
Bạn có thể thay đổi điều này bằng cách chuyển chuỗi định dạng tới basicConfig() với đối số từ khóa format. Để biết tất cả các tùy chọn liên quan đến cách tạo chuỗi định dạng, hãy xem Đối tượng định dạng.
Luồng ghi nhật ký¶
Luồng thông tin sự kiện nhật ký trong trình ghi nhật ký và trình xử lý được minh họa trong sơ đồ sau.
Máy ghi nhật ký¶
Các đối tượng Logger có ba nhiệm vụ. Đầu tiên, chúng hiển thị một số phương thức cho mã ứng dụng để ứng dụng có thể ghi nhật ký thông báo khi chạy. Thứ hai, các đối tượng logger xác định thông điệp nhật ký nào sẽ hành động dựa trên mức độ nghiêm trọng (phương tiện lọc mặc định) hoặc đối tượng bộ lọc. Thứ ba, các đối tượng logger chuyển các thông điệp tường trình có liên quan đến tất cả các trình xử lý nhật ký quan tâm.
Các phương thức được sử dụng rộng rãi nhất trên các đối tượng logger thuộc hai loại: cấu hình và gửi tin nhắn.
Đây là những phương pháp cấu hình phổ biến nhất:
Logger.setLevel()chỉ định thông báo nhật ký có mức độ nghiêm trọng thấp nhất mà trình ghi nhật ký sẽ xử lý, trong đó gỡ lỗi là mức độ nghiêm trọng tích hợp thấp nhất và quan trọng là mức độ nghiêm trọng tích hợp cao nhất. Ví dụ: nếu mức độ nghiêm trọng là INFO, trình ghi nhật ký sẽ chỉ xử lý các tin nhắn INFO, WARNING, ERROR và CRITICAL và sẽ bỏ qua các tin nhắn DEBUG.Logger.addHandler()vàLogger.removeHandler()thêm và xóa các đối tượng xử lý khỏi đối tượng logger. Trình xử lý được đề cập chi tiết hơn trong Trình xử lý.Logger.addFilter()vàLogger.removeFilter()thêm và xóa các đối tượng bộ lọc khỏi đối tượng logger. Các bộ lọc được đề cập chi tiết hơn trong Lọc đối tượng.
Bạn không cần phải luôn gọi các phương thức này trên mọi trình ghi nhật ký mà bạn tạo. Xem hai đoạn cuối trong phần này.
Với đối tượng logger được cấu hình, các phương thức sau sẽ tạo thông điệp tường trình:
Logger.debug(),Logger.info(),Logger.warning(),Logger.error()vàLogger.critical()đều tạo bản ghi nhật ký kèm theo thông báo và cấp độ tương ứng với tên phương thức tương ứng của chúng. Thông báo thực chất là một chuỗi định dạng, có thể chứa cú pháp thay thế chuỗi tiêu chuẩn của%s,%d,%f, v.v. Phần đối số còn lại của họ là danh sách các đối tượng tương ứng với các trường thay thế trong thông báo. Đối với**kwargs, các phương pháp ghi nhật ký chỉ quan tâm đến từ khóaexc_infovà sử dụng nó để xác định xem có ghi thông tin ngoại lệ hay không.Logger.exception()tạo thông điệp tường trình tương tự nhưLogger.error(). Sự khác biệt làLogger.exception()đưa ra dấu vết ngăn xếp cùng với nó. Chỉ gọi phương thức này từ trình xử lý ngoại lệ.Logger.log()lấy mức nhật ký làm đối số rõ ràng. Việc ghi nhật ký thông báo sẽ dài dòng hơn một chút so với việc sử dụng các phương pháp tiện lợi ở cấp độ nhật ký được liệt kê ở trên, nhưng đây là cách ghi nhật ký ở cấp độ nhật ký tùy chỉnh.
getLogger() trả về tham chiếu đến phiên bản trình ghi nhật ký với tên được chỉ định nếu tên đó được cung cấp hoặc root nếu không. Tên là các cấu trúc phân cấp được phân tách bằng dấu chấm. Nhiều lệnh gọi tới getLogger() có cùng tên sẽ trả về một tham chiếu đến cùng một đối tượng logger. Những người ghi nhật ký ở vị trí thấp hơn trong danh sách phân cấp là con của những người ghi nhật ký ở vị trí cao hơn trong danh sách. Ví dụ: với một trình ghi nhật ký có tên foo, các trình ghi nhật ký có tên foo.bar, foo.bar.baz và foo.bam đều là hậu duệ của foo.
Người ghi nhật ký có khái niệm về effective level. Nếu một cấp độ không được đặt rõ ràng trên bộ ghi nhật ký thì cấp độ gốc của nó sẽ được sử dụng thay thế làm cấp độ hiệu quả của nó. Nếu cấp độ gốc không được đặt rõ ràng, thì its gốc sẽ được kiểm tra, v.v. - tất cả cấp độ gốc đều được tìm kiếm cho đến khi tìm thấy cấp độ được đặt rõ ràng. Trình ghi nhật ký gốc luôn có một mức rõ ràng được đặt (WARNING theo mặc định). Khi quyết định có xử lý một sự kiện hay không, mức hiệu quả của trình ghi nhật ký sẽ được sử dụng để xác định xem sự kiện có được chuyển đến bộ xử lý của trình ghi nhật ký hay không.
Trình ghi nhật ký con truyền các thông báo đến trình xử lý được liên kết với trình ghi nhật ký tổ tiên của chúng. Do đó, không cần thiết phải xác định và định cấu hình trình xử lý cho tất cả các trình ghi nhật ký mà ứng dụng sử dụng. Chỉ cần định cấu hình trình xử lý cho trình ghi nhật ký cấp cao nhất và tạo trình ghi nhật ký con nếu cần. (Tuy nhiên, bạn có thể tắt truyền bá bằng cách đặt thuộc tính propagate của trình ghi nhật ký thành False.)
Trình xử lý¶
Các đối tượng Handler chịu trách nhiệm gửi các thông điệp tường trình thích hợp (dựa trên mức độ nghiêm trọng của thông điệp tường trình) đến đích được chỉ định của trình xử lý. Các đối tượng Logger có thể thêm 0 hoặc nhiều đối tượng xử lý vào chính chúng bằng phương thức addHandler(). Như một tình huống ví dụ, một ứng dụng có thể muốn gửi tất cả các thông báo nhật ký đến một tệp nhật ký, tất cả các thông báo nhật ký có lỗi hoặc cao hơn tới thiết bị xuất chuẩn và tất cả các thông báo quan trọng đối với một địa chỉ email. Kịch bản này yêu cầu ba trình xử lý riêng lẻ, trong đó mỗi trình xử lý chịu trách nhiệm gửi thông báo có mức độ nghiêm trọng cụ thể đến một vị trí cụ thể.
Thư viện chuẩn bao gồm khá nhiều loại trình xử lý (xem Trình xử lý hữu ích); các hướng dẫn chủ yếu sử dụng StreamHandler và FileHandler trong các ví dụ của nó.
Có rất ít phương pháp trong trình xử lý mà các nhà phát triển ứng dụng phải quan tâm. Các phương thức xử lý duy nhất có vẻ phù hợp với các nhà phát triển ứng dụng đang sử dụng các đối tượng xử lý tích hợp (nghĩa là không tạo các trình xử lý tùy chỉnh) là các phương thức cấu hình sau:
Phương thức
setLevel(), giống như trong các đối tượng logger, chỉ định mức độ nghiêm trọng thấp nhất sẽ được gửi đến đích thích hợp. Tại sao có hai phương phápsetLevel()? Cấp độ được đặt trong trình ghi nhật ký sẽ xác định mức độ nghiêm trọng của thông báo mà nó sẽ chuyển đến bộ xử lý. Cấp độ được đặt trong mỗi trình xử lý sẽ xác định thông báo nào mà trình xử lý sẽ gửi đi.setFormatter()chọn một đối tượng Formatter để trình xử lý này sử dụng.addFilter()vàremoveFilter()lần lượt định cấu hình và giải cấu hình các đối tượng bộ lọc trên trình xử lý.
Mã ứng dụng không được khởi tạo trực tiếp và sử dụng các phiên bản của Handler. Thay vào đó, lớp Handler là lớp cơ sở xác định giao diện mà tất cả các trình xử lý nên có và thiết lập một số hành vi mặc định mà các lớp con có thể sử dụng (hoặc ghi đè).
Trình định dạng¶
Các đối tượng định dạng cấu hình thứ tự, cấu trúc và nội dung cuối cùng của thông điệp tường trình. Không giống như lớp logging.Handler cơ sở, mã ứng dụng có thể khởi tạo các lớp trình định dạng, mặc dù bạn có thể phân lớp trình định dạng nếu ứng dụng của bạn cần hành vi đặc biệt. Hàm tạo có ba đối số tùy chọn -- một chuỗi định dạng thông báo, một chuỗi định dạng ngày và một chỉ báo kiểu.
- logging.Formatter.__init__(fmt=None, datefmt=None, style='%')¶
Nếu không có chuỗi định dạng tin nhắn thì mặc định là sử dụng tin nhắn thô. Nếu không có chuỗi định dạng ngày thì định dạng ngày mặc định là:
%Y-%m-%d %H:%M:%S
với phần nghìn giây được xử lý ở cuối. Zz000zz là một trong các '%', '{' hoặc '$'. Nếu một trong những điều này không được chỉ định thì '%' sẽ được sử dụng.
Nếu style là '%', chuỗi định dạng thông báo sử dụng thay thế chuỗi theo kiểu %(<dictionary key>)s; các khóa có thể được ghi lại trong Thuộc tính LogRecord. Nếu kiểu là '{' thì chuỗi định dạng thông báo được coi là tương thích với str.format() (sử dụng đối số từ khóa), trong khi nếu kiểu là '$' thì chuỗi định dạng thông báo sẽ tuân theo những gì string.Template.substitute() mong đợi.
Thay đổi trong phiên bản 3.2: Đã thêm tham số style.
Chuỗi định dạng tin nhắn sau đây sẽ ghi lại thời gian ở định dạng mà con người có thể đọc được, mức độ nghiêm trọng của tin nhắn và nội dung của tin nhắn theo thứ tự đó:
'%(asctime)s - %(levelname)s - %(message)s'
Trình định dạng sử dụng chức năng do người dùng định cấu hình để chuyển đổi thời gian tạo bản ghi thành bộ dữ liệu. Theo mặc định, time.localtime() được sử dụng; để thay đổi điều này cho một phiên bản trình định dạng cụ thể, hãy đặt thuộc tính converter của phiên bản đó thành một hàm có cùng chữ ký như time.localtime() hoặc time.gmtime(). Để thay đổi thuộc tính này cho tất cả các trình định dạng, ví dụ: nếu bạn muốn tất cả thời gian ghi nhật ký được hiển thị bằng GMT, hãy đặt thuộc tính converter trong lớp Formatter (thành time.gmtime để hiển thị GMT).
Định cấu hình ghi nhật ký¶
Lập trình viên có thể định cấu hình ghi nhật ký theo ba cách:
Tạo trình ghi nhật ký, trình xử lý và trình định dạng một cách rõ ràng bằng cách sử dụng mã Python gọi các phương thức cấu hình được liệt kê ở trên.
Tạo tệp cấu hình ghi nhật ký và đọc nó bằng hàm
fileConfig().Tạo từ điển thông tin cấu hình và chuyển nó tới hàm
dictConfig().
Để biết tài liệu tham khảo về hai tùy chọn cuối cùng, hãy xem Chức năng cấu hình. Ví dụ sau đây định cấu hình trình ghi nhật ký rất đơn giản, trình xử lý bảng điều khiển và trình định dạng đơn giản bằng mã Python
nhập nhật ký
trình ghi nhật ký # create
logger = log.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
Trình xử lý bảng điều khiển # create và đặt mức độ gỡ lỗi
ch = ghi nhật ký.StreamHandler()
ch.setLevel(logging.DEBUG)
định dạng # create
formatter = log.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add định dạng sang ch
ch.setFormatter(trình định dạng)
# add ch để ghi nhật ký
logger.addHandler(ch)
# mã 'ứng dụng'
logger.debug('thông báo gỡ lỗi')
logger.info('tin nhắn thông tin')
logger.warning('thông báo cảnh báo')
logger.error('thông báo lỗi')
logger.cript('thông báo quan trọng')
Chạy mô-đun này từ dòng lệnh sẽ tạo ra kết quả sau:
$ python simple_logging_module.py
2005-03-19 15:10:26,618 - simple_example - DEBUG - thông báo gỡ lỗi
2005-03-19 15:10:26,620 - simple_example - INFO - thông báo thông tin
2005-03-19 15:10:26,695 - simple_example - WARNING - thông báo cảnh báo
2005-03-19 15:10:26,697 - simple_example - ERROR - thông báo lỗi
2005-03-19 15:10:26,773 - simple_example - CRITICAL - thông báo quan trọng
Mô-đun Python sau đây tạo trình ghi nhật ký, trình xử lý và trình định dạng gần giống với các trình ghi trong ví dụ được liệt kê ở trên, với điểm khác biệt duy nhất là tên của các đối tượng:
nhập nhật ký
nhập log.config
logging.config.fileConfig('logging.conf')
trình ghi nhật ký # create
logger = log.getLogger('simpleExample')
# mã 'ứng dụng'
logger.debug('thông báo gỡ lỗi')
logger.info('tin nhắn thông tin')
logger.warning('thông báo cảnh báo')
logger.error('thông báo lỗi')
logger.cript('thông báo quan trọng')
Đây là tệp log.conf:
[người khai thác gỗ]
phím=root,đơn giảnVí dụ
[người xử lý]
phím=consoleHandler
[trình định dạng]
phím=simpleFormatter
[logger_root]
cấp độ=DEBUG
handlers=consoleHandler
[logger_simpleVí dụ]
cấp độ=DEBUG
handlers=consoleHandler
qualname=simpleVí dụ
tuyên truyền=0
[handler_consoleHandler]
class=StreamHandler
cấp độ=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
Đầu ra gần giống với ví dụ không dựa trên tệp cấu hình:
$ python simple_logging_config.py
2005-03-19 15:38:55,977 - ví dụ đơn giản - DEBUG - thông báo gỡ lỗi
2005-03-19 15:38:55,979 - simpleVí dụ - INFO - thông báo thông tin
2005-03-19 15:38:56,054 - simpleVí dụ - WARNING - thông báo cảnh báo
2005-03-19 15:38:56,055 - ví dụ đơn giản - ERROR - thông báo lỗi
2005-03-19 15:38:56,130 - simpleVí dụ - CRITICAL - thông báo quan trọng
Bạn có thể thấy rằng cách tiếp cận tệp cấu hình có một số ưu điểm so với cách tiếp cận mã Python, chủ yếu là tách biệt cấu hình và mã cũng như khả năng của những người không lập trình có thể dễ dàng sửa đổi các thuộc tính ghi nhật ký.
Cảnh báo
Hàm fileConfig() lấy tham số mặc định, disable_existing_loggers, mặc định là True vì lý do tương thích ngược. Đây có thể là hoặc không phải là điều bạn muốn, vì nó sẽ khiến bất kỳ trình ghi nhật ký không phải root nào tồn tại trước lệnh gọi fileConfig() đều bị vô hiệu hóa trừ khi chúng (hoặc tổ tiên) được đặt tên rõ ràng trong cấu hình. Vui lòng tham khảo tài liệu tham khảo để biết thêm thông tin và chỉ định False cho tham số này nếu bạn muốn.
Từ điển được truyền tới dictConfig() cũng có thể chỉ định một giá trị Boolean với khóa disable_existing_loggers, nếu không được chỉ định rõ ràng trong từ điển thì cũng mặc định được hiểu là True. Điều này dẫn đến hành vi vô hiệu hóa trình ghi nhật ký được mô tả ở trên, hành vi này có thể không phải là điều bạn muốn - trong trường hợp đó, hãy cung cấp khóa rõ ràng với giá trị False.
Lưu ý rằng tên lớp được tham chiếu trong tệp cấu hình cần phải liên quan đến mô-đun ghi nhật ký hoặc giá trị tuyệt đối có thể được giải quyết bằng cơ chế nhập thông thường. Do đó, bạn có thể sử dụng WatchedFileHandler (liên quan đến mô-đun ghi nhật ký) hoặc mypackage.mymodule.MyHandler (đối với lớp được xác định trong gói mypackage và mô-đun mymodule, trong đó mypackage có sẵn trên đường dẫn nhập Python).
Trong Python 3.2, một phương tiện ghi nhật ký định cấu hình mới đã được giới thiệu, sử dụng từ điển để lưu giữ thông tin cấu hình. Điều này cung cấp một tập hợp lớn các chức năng của phương pháp tiếp cận dựa trên tệp cấu hình được nêu ở trên và là phương pháp cấu hình được đề xuất cho các ứng dụng và hoạt động triển khai mới. Bởi vì từ điển Python được sử dụng để chứa thông tin cấu hình và vì bạn có thể điền từ điển đó bằng các phương tiện khác nhau nên bạn có nhiều tùy chọn hơn cho cấu hình. Ví dụ: bạn có thể sử dụng tệp cấu hình ở định dạng JSON hoặc nếu bạn có quyền truy cập vào chức năng xử lý YAML, hãy sử dụng tệp ở định dạng YAML để điền từ điển cấu hình. Hoặc, tất nhiên, bạn có thể xây dựng từ điển bằng mã Python, nhận nó ở dạng được lưu trữ trên ổ cắm hoặc sử dụng bất kỳ cách tiếp cận nào có ý nghĩa đối với ứng dụng của bạn.
Dưới đây là ví dụ về cấu hình tương tự như trên, ở định dạng YAML cho phương pháp tiếp cận dựa trên từ điển mới:
phiên bản: 1
trình định dạng:
đơn giản:
định dạng: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
người xử lý:
bảng điều khiển:
lớp: log.StreamHandler
cấp độ: DEBUG
định dạng: đơn giản
luồng: ext://sys.stdout
người khai thác gỗ:
đơn giảnVí dụ:
cấp độ: DEBUG
trình xử lý: [bàn điều khiển]
tuyên truyền: không
gốc:
cấp độ: DEBUG
trình xử lý: [bàn điều khiển]
Để biết thêm thông tin về cách ghi nhật ký bằng từ điển, hãy xem Chức năng cấu hình.
Điều gì xảy ra nếu không có cấu hình nào được cung cấp¶
Nếu không cung cấp cấu hình ghi nhật ký, có thể xảy ra trường hợp cần xuất sự kiện ghi nhật ký nhưng không tìm thấy trình xử lý nào để xuất sự kiện.
Sự kiện được xuất ra bằng cách sử dụng 'trình xử lý cuối cùng', được lưu trữ trong lastResort. Trình xử lý nội bộ này không được liên kết với bất kỳ trình ghi nhật ký nào và hoạt động giống như một StreamHandler ghi thông báo mô tả sự kiện vào giá trị hiện tại của sys.stderr (do đó tôn trọng mọi chuyển hướng có thể có hiệu lực). Không có định dạng nào được thực hiện trên thông báo - chỉ có thông báo mô tả sự kiện đơn giản được in. Cấp độ của trình xử lý được đặt thành WARNING, vì vậy tất cả các sự kiện ở mức này và mức độ nghiêm trọng hơn sẽ được xuất ra.
Thay đổi trong phiên bản 3.2: Đối với các phiên bản Python trước 3.2, hoạt động như sau:
Nếu
raiseExceptionslàFalse(chế độ sản xuất), sự kiện sẽ bị hủy bỏ một cách âm thầm.Nếu
raiseExceptionslàTrue(chế độ phát triển), thông báo 'Không tìm thấy trình xử lý nào cho trình ghi nhật ký X.Y.Z' sẽ được in một lần.
Để có được hành vi trước 3.2, lastResort có thể được đặt thành None.
Định cấu hình ghi nhật ký cho thư viện¶
Khi phát triển một thư viện sử dụng tính năng ghi nhật ký, bạn nên chú ý ghi lại cách thư viện sử dụng tính năng ghi nhật ký - ví dụ: tên của các trình ghi nhật ký được sử dụng. Một số cân nhắc cũng cần được đưa ra đối với cấu hình ghi nhật ký của nó. Nếu ứng dụng đang sử dụng không sử dụng tính năng ghi nhật ký và mã thư viện thực hiện lệnh gọi ghi nhật ký thì (như được mô tả trong phần trước) các sự kiện có mức độ nghiêm trọng WARNING trở lên sẽ được in thành sys.stderr. Đây được coi là hành vi mặc định tốt nhất.
Nếu vì lý do nào đó, bạn don't muốn những thông báo này được in mà không có bất kỳ cấu hình ghi nhật ký nào, bạn có thể đính kèm trình xử lý không làm gì vào trình ghi nhật ký cấp cao nhất cho thư viện của mình. Điều này tránh việc in thông báo vì sẽ luôn tìm thấy một trình xử lý cho các sự kiện của thư viện: nó không tạo ra bất kỳ đầu ra nào. Nếu người dùng thư viện định cấu hình ghi nhật ký để sử dụng ứng dụng, có lẽ cấu hình đó sẽ thêm một số trình xử lý và nếu các mức được định cấu hình phù hợp thì các cuộc gọi ghi nhật ký được thực hiện bằng mã thư viện sẽ gửi đầu ra đến các trình xử lý đó như bình thường.
Trình xử lý không làm gì được bao gồm trong gói ghi nhật ký: NullHandler (kể từ Python 3.1). Một phiên bản của trình xử lý này có thể được thêm vào trình ghi nhật ký cấp cao nhất của không gian tên ghi nhật ký được thư viện sử dụng (if bạn muốn ngăn các sự kiện đã ghi trong thư viện của mình được xuất ra sys.stderr trong trường hợp không có cấu hình ghi nhật ký). Nếu tất cả việc ghi nhật ký bằng thư viện foo được thực hiện bằng cách sử dụng trình ghi nhật ký có tên khớp với 'foo.x', 'foo.x.y', v.v. thì mã:
nhập nhật ký
logging.getLogger('foo').addHandler(logging.NullHandler())
nên có hiệu quả mong muốn. Nếu một tổ chức tạo ra một số thư viện thì tên trình ghi nhật ký được chỉ định có thể là 'orgname.foo' thay vì chỉ là 'foo'.
Ghi chú
Chúng tôi khuyên bạn nên do not log to the root logger trong thư viện của mình. Thay vào đó, hãy sử dụng trình ghi nhật ký có tên duy nhất và dễ nhận dạng, chẳng hạn như __name__ cho gói hoặc mô-đun cấp cao nhất của thư viện của bạn. Việc đăng nhập vào trình ghi nhật ký gốc sẽ khiến nhà phát triển ứng dụng gặp khó khăn hoặc không thể định cấu hình mức độ chi tiết hoặc trình xử lý ghi nhật ký của thư viện của bạn theo ý muốn.
Ghi chú
Chúng tôi khuyên bạn nên do not add any handlers other than NullHandler to your library's loggers. Điều này là do cấu hình của trình xử lý là đặc quyền của nhà phát triển ứng dụng sử dụng thư viện của bạn. Nhà phát triển ứng dụng biết đối tượng mục tiêu của họ và trình xử lý nào phù hợp nhất cho ứng dụng của họ: nếu bạn thêm trình xử lý 'dưới mui xe', bạn có thể ảnh hưởng đến khả năng thực hiện kiểm tra đơn vị và cung cấp nhật ký phù hợp với yêu cầu của họ.
Cấp độ ghi nhật ký¶
Các giá trị số của mức ghi nhật ký được đưa ra trong bảng sau. Những điều này chủ yếu được quan tâm nếu bạn muốn xác định cấp độ của riêng mình và cần chúng có các giá trị cụ thể liên quan đến các cấp độ được xác định trước. Nếu bạn xác định một mức có cùng giá trị số, nó sẽ ghi đè giá trị được xác định trước; tên được xác định trước bị mất.
Cấp độ |
Giá trị số |
|---|---|
|
50 |
|
40 |
|
30 |
|
20 |
|
10 |
|
0 |
Các cấp độ cũng có thể được liên kết với trình ghi nhật ký, do nhà phát triển đặt hoặc thông qua việc tải cấu hình ghi nhật ký đã lưu. Khi một phương thức ghi nhật ký được gọi trên một trình ghi nhật ký, trình ghi nhật ký sẽ so sánh cấp độ của chính nó với cấp độ được liên kết với lệnh gọi phương thức. Nếu mức của trình ghi nhật ký cao hơn mức của lệnh gọi phương thức thì không có thông báo ghi nhật ký nào thực sự được tạo. Đây là cơ chế cơ bản kiểm soát mức độ chi tiết của kết quả ghi nhật ký.
Thông báo ghi nhật ký được mã hóa dưới dạng phiên bản của lớp LogRecord. Khi một trình ghi nhật ký quyết định thực sự ghi nhật ký một sự kiện, một phiên bản LogRecord sẽ được tạo từ thông báo ghi nhật ký.
Thông báo ghi nhật ký phải tuân theo cơ chế gửi thông qua việc sử dụng handlers, là phiên bản của các lớp con của lớp Handler. Người xử lý có trách nhiệm đảm bảo rằng tin nhắn được ghi lại (dưới dạng LogRecord) kết thúc ở một vị trí cụ thể (hoặc tập hợp các vị trí) hữu ích cho đối tượng mục tiêu của tin nhắn đó (chẳng hạn như người dùng cuối, nhân viên bộ phận hỗ trợ, quản trị viên hệ thống, nhà phát triển). Trình xử lý được chuyển qua các phiên bản LogRecord dành cho các đích cụ thể. Mỗi logger có thể có 0, một hoặc nhiều trình xử lý được liên kết với nó (thông qua phương thức addHandler() của Logger). Ngoài bất kỳ trình xử lý nào được liên kết trực tiếp với trình ghi nhật ký, all handlers associated with all ancestors of the logger được gọi để gửi tin nhắn (trừ khi cờ propagate cho trình ghi nhật ký được đặt thành giá trị sai, tại thời điểm đó quá trình truyền tới trình xử lý tổ tiên sẽ dừng lại).
Cũng giống như đối với trình ghi nhật ký, trình xử lý có thể có các cấp độ liên quan đến chúng. Cấp độ của trình xử lý hoạt động như một bộ lọc giống như cấp độ của trình ghi nhật ký. Nếu trình xử lý quyết định thực sự gửi một sự kiện, phương thức emit() sẽ được sử dụng để gửi tin nhắn đến đích của nó. Hầu hết các lớp con do người dùng định nghĩa của Handler sẽ cần ghi đè emit() này.
Cấp độ tùy chỉnh¶
Bạn có thể xác định cấp độ của riêng mình nhưng không cần thiết vì các cấp độ hiện có đã được chọn trên cơ sở kinh nghiệm thực tế. Tuy nhiên, nếu bạn tin rằng mình cần các cấp độ tùy chỉnh, bạn nên hết sức cẩn thận khi thực hiện việc này và đó có thể là a very bad idea to define custom levels if you are developing a library. Đó là bởi vì nếu nhiều tác giả thư viện đều xác định cấp độ tùy chỉnh của riêng họ thì có khả năng là kết quả ghi nhật ký từ nhiều thư viện như vậy được sử dụng cùng nhau sẽ khó để nhà phát triển sử dụng kiểm soát và/hoặc diễn giải, vì một giá trị số nhất định có thể có ý nghĩa khác nhau đối với các thư viện khác nhau.
Trình xử lý hữu ích¶
Ngoài lớp Handler cơ bản, nhiều lớp con hữu ích cũng được cung cấp:
Các phiên bản
StreamHandlergửi tin nhắn đến các luồng (đối tượng giống như tệp).Các phiên bản
FileHandlergửi tin nhắn tới các tập tin trên đĩa.BaseRotatingHandlerlà lớp cơ sở dành cho các trình xử lý xoay tệp nhật ký tại một điểm nhất định. Nó không có nghĩa là được khởi tạo trực tiếp. Thay vào đó, hãy sử dụngRotatingFileHandlerhoặcTimedRotatingFileHandler.Các phiên bản
RotatingFileHandlergửi tin nhắn tới tệp đĩa, có hỗ trợ kích thước tệp nhật ký tối đa và xoay vòng tệp nhật ký.Các phiên bản
TimedRotatingFileHandlergửi tin nhắn đến tệp đĩa, xoay tệp nhật ký theo những khoảng thời gian nhất định.Các phiên bản
SocketHandlergửi tin nhắn đến ổ cắm TCP/IP. Kể từ phiên bản 3.4, ổ cắm tên miền Unix cũng được hỗ trợ.Các phiên bản
DatagramHandlergửi tin nhắn đến ổ cắm UDP. Kể từ phiên bản 3.4, ổ cắm tên miền Unix cũng được hỗ trợ.Các phiên bản
SMTPHandlergửi tin nhắn đến một địa chỉ email được chỉ định.Các phiên bản
SysLogHandlergửi tin nhắn đến daemon nhật ký hệ thống Unix, có thể trên một máy từ xa.Các phiên bản
NTEventLogHandlergửi tin nhắn tới nhật ký sự kiện Windows NT/2000/XP.Các phiên bản
MemoryHandlergửi tin nhắn tới bộ đệm trong bộ nhớ, bộ đệm này sẽ bị xóa bất cứ khi nào đáp ứng các tiêu chí cụ thể.Các phiên bản
HTTPHandlergửi tin nhắn đến máy chủ HTTP bằng cách sử dụng ngữ nghĩaGEThoặcPOST.Các phiên bản
WatchedFileHandlerxem tệp mà chúng đang đăng nhập. Nếu tệp thay đổi, nó sẽ bị đóng và mở lại bằng tên tệp. Trình xử lý này chỉ hữu ích trên các hệ thống giống Unix; Windows không hỗ trợ cơ chế cơ bản được sử dụng.Các phiên bản
QueueHandlergửi tin nhắn đến hàng đợi, chẳng hạn như những tin nhắn được triển khai trong mô-đunqueuehoặcmultiprocessing.Các phiên bản
NullHandlerkhông làm gì với thông báo lỗi. Chúng được sử dụng bởi các nhà phát triển thư viện muốn sử dụng tính năng ghi nhật ký nhưng muốn tránh thông báo 'Không thể tìm thấy trình xử lý nào cho logger XXX'. Thông báo này có thể được hiển thị nếu người dùng thư viện chưa định cấu hình tính năng ghi nhật ký. Xem Định cấu hình ghi nhật ký cho thư viện để biết thêm thông tin.
Added in version 3.1: Lớp NullHandler.
Added in version 3.2: Lớp QueueHandler.
Các lớp NullHandler, StreamHandler và FileHandler được xác định trong gói ghi nhật ký lõi. Các trình xử lý khác được xác định trong mô-đun phụ, logging.handlers. (Ngoài ra còn có một mô-đun phụ khác, logging.config, dành cho chức năng cấu hình.)
Tin nhắn đã ghi được định dạng để trình bày thông qua các phiên bản của lớp Formatter. Chúng được khởi tạo bằng chuỗi định dạng phù hợp để sử dụng với toán tử % và từ điển.
Để định dạng nhiều thư trong một đợt, có thể sử dụng phiên bản BufferingFormatter. Ngoài chuỗi định dạng (được áp dụng cho từng thư trong lô), còn có cung cấp chuỗi định dạng tiêu đề và đuôi.
Khi việc lọc dựa trên cấp độ trình ghi nhật ký và/hoặc cấp độ trình xử lý là không đủ, thì các phiên bản của Filter có thể được thêm vào cả hai phiên bản Logger và Handler (thông qua phương thức addFilter() của chúng). Trước khi quyết định xử lý thêm tin nhắn, cả người ghi nhật ký và người xử lý đều tham khảo tất cả các bộ lọc của họ để xin phép. Nếu bất kỳ bộ lọc nào trả về giá trị sai, thông báo sẽ không được xử lý thêm.
Chức năng Filter cơ bản cho phép lọc theo tên logger cụ thể. Nếu tính năng này được sử dụng, các tin nhắn được gửi đến trình ghi nhật ký có tên và các phần tử con của nó sẽ được phép đi qua bộ lọc và tất cả các tin nhắn khác sẽ bị loại bỏ.
Các ngoại lệ được nêu ra trong quá trình ghi nhật ký¶
Gói ghi nhật ký được thiết kế để xử lý các trường hợp ngoại lệ xảy ra khi đăng nhập vào sản xuất. Điều này là để các lỗi xảy ra trong khi xử lý các sự kiện ghi nhật ký - chẳng hạn như ghi sai cấu hình, lỗi mạng hoặc các lỗi tương tự khác - không khiến ứng dụng sử dụng tính năng ghi nhật ký chấm dứt sớm.
Ngoại lệ SystemExit và KeyboardInterrupt không bao giờ được nuốt. Các trường hợp ngoại lệ khác xảy ra trong phương thức emit() của lớp con Handler được chuyển sang phương thức handleError() của nó.
Việc triển khai mặc định của handleError() trong Handler sẽ kiểm tra xem biến cấp mô-đun, raiseExceptions, có được đặt hay không. Nếu được đặt, truy nguyên sẽ được in thành sys.stderr. Nếu không được đặt, ngoại lệ sẽ bị nuốt.
Ghi chú
Giá trị mặc định của raiseExceptions là True. Điều này là do trong quá trình phát triển, bạn thường muốn được thông báo về bất kỳ trường hợp ngoại lệ nào xảy ra. Bạn nên đặt raiseExceptions thành False để sử dụng sản xuất.
Sử dụng các đối tượng tùy ý làm tin nhắn¶
Trong các phần và ví dụ trước, giả định rằng thông báo được truyền khi ghi sự kiện là một chuỗi. Tuy nhiên, đây không phải là khả năng duy nhất. Bạn có thể truyền một đối tượng tùy ý dưới dạng tin nhắn và phương thức __str__() của nó sẽ được gọi khi hệ thống ghi nhật ký cần chuyển đổi nó thành biểu diễn chuỗi. Trên thực tế, nếu muốn, bạn có thể tránh hoàn toàn việc tính toán biểu diễn chuỗi - ví dụ: SocketHandler phát ra một sự kiện bằng cách chọn nó và gửi nó qua dây.
Tối ưu hóa¶
Việc định dạng các đối số thông báo được trì hoãn cho đến khi không thể tránh khỏi. Tuy nhiên, việc tính toán các đối số được truyền cho phương thức ghi nhật ký cũng có thể tốn kém và bạn có thể muốn tránh thực hiện việc đó nếu trình ghi nhật ký sẽ loại bỏ sự kiện của bạn. Để quyết định việc cần làm, bạn có thể gọi phương thức isEnabledFor(), phương thức này nhận đối số cấp độ và trả về true nếu sự kiện được Trình ghi nhật ký tạo cho cấp độ cuộc gọi đó. Bạn có thể viết mã như thế này:
nếu logger.isEnabledFor(logging.DEBUG):
logger.debug('Tin nhắn với %s, %s', cost_func1(),
đắt_func2())
để nếu ngưỡng của trình ghi nhật ký được đặt trên DEBUG thì các lệnh gọi đến expensive_func1 và expensive_func2 sẽ không bao giờ được thực hiện.
Ghi chú
Trong một số trường hợp, bản thân isEnabledFor() có thể đắt hơn mức bạn muốn (ví dụ: đối với các trình ghi nhật ký được lồng sâu trong đó mức rõ ràng chỉ được thiết lập ở mức cao trong hệ thống phân cấp của trình ghi nhật ký). Trong những trường hợp như vậy (hoặc nếu bạn muốn tránh gọi một phương thức trong vòng lặp chặt chẽ), bạn có thể lưu kết quả của lệnh gọi đến isEnabledFor() trong một biến cục bộ hoặc biến thể hiện và sử dụng biến đó thay vì gọi phương thức mỗi lần. Giá trị được lưu trong bộ nhớ đệm như vậy chỉ cần được tính toán lại khi cấu hình ghi nhật ký thay đổi linh hoạt trong khi ứng dụng đang chạy (điều này không phổ biến lắm).
Có những tối ưu hóa khác có thể được thực hiện cho các ứng dụng cụ thể cần kiểm soát chính xác hơn những thông tin ghi nhật ký nào được thu thập. Dưới đây là danh sách những điều bạn có thể làm để tránh xử lý trong quá trình ghi nhật ký mà bạn không cần:
Những gì bạn không muốn thu thập |
Làm thế nào để tránh thu thập nó |
|---|---|
Thông tin về nơi các cuộc gọi được thực hiện. |
Đặt |
Thông tin luồng. |
Đặt |
ID tiến trình hiện tại ( |
Đặt |
Tên quy trình hiện tại khi sử dụng |
Đặt |
Tên |
Đặt |
Cũng lưu ý rằng mô-đun ghi nhật ký lõi chỉ bao gồm các trình xử lý cơ bản. Nếu bạn không nhập logging.handlers và logging.config, chúng sẽ không chiếm bất kỳ bộ nhớ nào.
Các tài nguyên khác¶
Xem thêm
- Mô-đun
logging tham chiếu API cho mô-đun ghi nhật ký.
- Mô-đun
logging.config Cấu hình API cho mô-đun ghi nhật ký.
- Mô-đun
logging.handlers Trình xử lý hữu ích đi kèm với mô-đun ghi nhật ký.