Tệp nhật ký python trống

Python cung cấp một mô-đun ghi nhật ký tích hợp khá mạnh mẽ và linh hoạt với nhiều tính năng nâng cao. Trong bài viết này, tôi muốn chia sẻ 8 tính năng nâng cao sẽ có lợi cho chúng tôi trong việc phát triển phần mềm

Ghi nhật ký 101

Trước khi xem xét các tính năng nâng cao hơn, hãy đảm bảo rằng chúng ta đã hiểu cơ bản về mô-đun

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
4

Tiều phu

Phiên bản mà chúng tôi tạo để tạo nhật ký được gọi là logger. Nó được khởi tạo thông qua

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
5. Cách tốt nhất là sử dụng
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
6 làm tên nhật ký bao gồm tên gói và tên mô-đun. Tên sẽ xuất hiện trong thông báo nhật ký giúp nhà phát triển nhanh chóng tìm ra nơi tạo nhật ký

Trình định dạng & Trình xử lý

Mỗi logger có một số cấu hình có thể được sửa đổi. Các cấu hình nâng cao hơn sẽ được thảo luận sau, nhưng những cấu hình phổ biến nhất là trình định dạng và trình xử lý

Trình định dạng chỉ định cấu trúc của thông điệp tường trình. Mỗi thông điệp bản ghi là một đối tượng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
7 với một số thuộc tính (tên mô-đun là một trong số đó). Khi chúng tôi xác định một trình định dạng, chúng tôi có thể quyết định thông điệp tường trình sẽ trông như thế nào với các thuộc tính này và có thể với các thuộc tính tùy chỉnh. Trình định dạng mặc định trông như thế này

severity:logger name:message
# e.g: WARNING:root:Program starts!

Một trình định dạng tùy chỉnh với nhiều thuộc tính hơn có thể trông như thế này

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!

Trình xử lý chỉ định đích đến của thông điệp tường trình. Một thông điệp bản ghi có thể được gửi đến nhiều hơn một đích. Mô-đun ghi nhật ký thực sự cung cấp khá nhiều trình xử lý tiêu chuẩn. Những cái phổ biến nhất là FileHandler gửi nhật ký tới một tệp và StreamHandler gửi nhật ký tới các luồng như

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
8 hoặc
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
9. Phiên bản nhật ký hỗ trợ 0 hoặc nhiều trình xử lý. Nếu không có trình xử lý nào được xác định, thì nó sẽ gửi nhật ký tới
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
8. Nếu có nhiều hơn 1 trình xử lý được xác định, thì đích đến phụ thuộc vào cấp độ của thông điệp tường trình và cấp độ của trình xử lý

Ví dụ: tôi có Trình xử lý tệp có mức độ CẢNH BÁO và Trình xử lý luồng có mức độ THÔNG TIN. Nếu tôi viết một thông báo nhật ký lỗi thì thông báo đó sẽ được gửi tới cả

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
0 và tệp nhật ký

Thí dụ

Trong ví dụ này, chúng tôi đã tạo một

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
1,
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
2 và
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
3.
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
3 chứa một hàm
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
5 trả về một phiên bản trình ghi nhật ký. Phiên bản trình ghi nhật ký đi kèm với trình định dạng tùy chỉnh và 2 trình xử lý. StreamHandler với mức INFO và FileHandler với mức WARNING. Điều quan trọng là đặt mức cơ bản thành THÔNG TIN hoặc GỠ LỖI (mức ghi nhật ký mặc định là CẢNH BÁO), nếu không, bất kỳ nhật ký nào thấp hơn mức CẢNH BÁO sẽ bị lọc ra. Cả
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
1 và
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
2 tạo đều sử dụng
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
5 để tạo trình ghi nhật ký của riêng họ

diagram Xiaoxu Gao

ghi nhật ký cơ bản. py

Nhật ký CẢNH BÁO được gửi đến cả đầu ra của bảng điều khiển (sys. thiết bị xuất chuẩn) và tệp nhật ký, nhưng nhật ký INFO chỉ được gửi đến đầu ra của bàn điều khiển. Nếu bạn có thể hiểu đầy đủ những gì đang diễn ra trong ví dụ này và tại sao thì chúng ta nên sử dụng các tính năng nâng cao hơn

1. Tạo các thuộc tính LogRecord do người dùng xác định bằng LoggerAdapter

Như tôi đã đề cập trước đây, LogRecord có một số thuộc tính, các nhà phát triển có thể chọn các thuộc tính quan trọng nhất và đặt chúng vào bộ định dạng. Ngoài ra, mô-đun ghi nhật ký cũng cung cấp khả năng thêm các thuộc tính do người dùng xác định vào LogRecord

Một cách là sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
9. Khi bạn tạo một bộ điều hợp, bạn chuyển phiên bản trình ghi nhật ký và các thuộc tính của bạn (trong từ điển) cho nó. Lớp này cung cấp giao diện giống như
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
20, vì vậy bạn vẫn có thể gọi các phương thức như
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
21

Thuộc tính mới với giá trị cố định

Nếu bạn muốn có một loại thuộc tính giá trị cố định trong thông báo nhật ký, chẳng hạn như tên ứng dụng, thì bạn có thể sử dụng lớp

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
9 mặc định và nhận giá trị thuộc tính khi bạn tạo trình ghi nhật ký. Đừng quên thêm thuộc tính này vào bộ định dạng, bạn có thể tự do chọn vị trí của nó. Trong đoạn mã sau, tôi thêm thuộc tính
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
23, giá trị này được xác định khi tôi tạo logger

giá trị cố định của bộ điều hợp ghi nhật ký. py

Thuộc tính mới có giá trị động

Trong các tình huống khác, bạn có thể muốn các thuộc tính động, chẳng hạn như một loại ID động. Sau đó, bạn có thể mở rộng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
9 cơ bản và tạo của riêng mình. Phương thức
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
25 là nơi các thuộc tính bổ sung được thêm vào thông điệp tường trình. Trong đoạn mã sau, tôi thêm một thuộc tính động
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
26, thuộc tính này có thể khác nhau trong mỗi thông báo tường trình. Trong trường hợp này, bạn không cần thêm thuộc tính vào bộ định dạng

giá trị động của bộ điều hợp ghi nhật ký. py

2. Tạo thuộc tính LogRecord do người dùng xác định bằng Bộ lọc

Một cách khác để thêm các thuộc tính động do người dùng xác định là sử dụng Bộ lọc tùy chỉnh. Bộ lọc cung cấp logic bổ sung để xác định thông điệp nhật ký nào sẽ xuất ra. Đây là một bước sau khi kiểm tra mức ghi nhật ký cơ bản, nhưng trước khi chuyển thông báo tường trình tới trình xử lý. Ngoài việc xác định xem thông điệp bản ghi có nên tiếp tục hay không, chúng ta cũng có thể chèn các thuộc tính mới vào phương thức

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
27

sơ đồ từ tài liệu chính thức của Python

Trong ví dụ này, chúng tôi thêm một thuộc tính mới

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
28 trong
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
27 có giá trị được xác định dựa trên tên cấp độ của thông điệp tường trình. Trong trường hợp này, nên thêm lại tên thuộc tính vào bộ định dạng

thuộc tính động của bộ lọc ghi nhật ký. py

3. Đa luồng với mô-đun ghi nhật ký

Mô-đun ghi nhật ký thực sự được triển khai theo cách an toàn cho luồng, vì vậy chúng tôi không cần nỗ lực thêm. Đoạn mã dưới đây cho thấy MainThread và WorkThread đang chia sẻ cùng một phiên bản trình ghi nhật ký mà không gặp vấn đề về tình trạng tương tranh. Ngoài ra còn có một thuộc tính tích hợp sẵn

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
40 cho trình định dạng

đăng nhập đa luồng. py

Về cơ bản, mô-đun ghi nhật ký sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
41 khá nhiều ở mọi nơi. Sự khác biệt giữa
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
42 từ
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
43 là

  1. Chỉ có thể mua
    "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
    43 một lần và không thể mua được nữa cho đến khi nó được phát hành. Mặt khác,
    "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
    42 có thể được mua nhiều lần trước khi phát hành, nhưng số lần phát hành phải bằng nhau
  2. "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
    43 có thể được giải phóng bởi bất kỳ luồng nào, nhưng
    "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
    42 chỉ có thể được giải phóng bởi cùng một luồng có được nó

Bất kỳ trình xử lý nào mở rộng từ lớp

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
48 đều có phương thức
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
49 để gửi bản ghi. Đây là một khối mã của
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
50. Như bạn có thể thấy, trình xử lý sẽ nhận và giải phóng khóa trước và sau khi gửi bản ghi. Phương pháp
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
51 có thể được triển khai khác nhau trong các trình xử lý khác nhau

xử lý. py

4. Đa xử lý với mô-đun ghi nhật ký — QueueHandler

Mặc dù mô-đun ghi nhật ký an toàn cho luồng nhưng không an toàn cho quy trình. Nếu bạn muốn nhiều quy trình ghi vào cùng một tệp nhật ký, thì bạn phải quản lý quyền truy cập vào tệp của mình theo cách thủ công. Theo nhật ký Cookbook, có một số tùy chọn

QueueHandler + quy trình “người tiêu dùng”

Một tùy chọn đang sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
52. Ý tưởng là tạo một phiên bản
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
53 và chia sẻ nó giữa nhiều quy trình. Trong ví dụ bên dưới, chúng tôi có 2 quy trình "nhà sản xuất" gửi nhật ký đến hàng đợi và quy trình "người tiêu dùng" đọc nhật ký từ hàng đợi và ghi chúng vào tệp nhật ký

Nhật ký trong hàng đợi có thể sẽ có các cấp độ khác nhau, do đó trong

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
54, chúng tôi sử dụng
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
55 thay vì
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
56 hoặc
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
57. Cuối cùng, chúng tôi gửi tín hiệu để cho
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
54 dừng lại. Chia sẻ một phiên bản hàng đợi giữa nhiều quy trình hoặc luồng không phải là một điều mới, nhưng các loại mô-đun ghi nhật ký giúp chúng tôi xử lý tình huống này

trình xử lý hàng đợi đăng nhập. py

QueueHandler + QueueListener

Trong mô-đun

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
59, có một lớp đặc biệt gọi là
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
60. Lớp này tạo một phiên bản trình nghe với hàng đợi thông điệp tường trình và danh sách các trình xử lý để xử lý các bản ghi nhật ký.
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
61 có thể thay thế quy trình
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
62 mà chúng ta đã tạo trong ví dụ trước với ít mã hơn

người nghe hàng đợi đăng nhập. py

SocketHandler

Một giải pháp khác do Cookbook cung cấp là gửi nhật ký từ nhiều quy trình đến

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
63 và có một quy trình riêng triển khai máy chủ ổ cắm đọc nhật ký và gửi đến đích. Văn bản có cách thực hiện khá chi tiết

Tất cả các giải pháp này về cơ bản đều tuân theo cùng một nguyên tắc. gửi nhật ký từ các quy trình khác nhau đến một nơi tập trung, hàng đợi hoặc máy chủ từ xa. Người nhận ở phía bên kia chịu trách nhiệm ghi các bản ghi nhật ký vào các đích

5. Không phát ra bất kỳ nhật ký thư viện nào theo mặc định — NullHandler

Cho đến nay, chúng tôi đã đề cập đến một số trình xử lý được triển khai bởi mô-đun ghi nhật ký. Một trình xử lý tích hợp hữu ích khác là

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
64. Việc triển khai NullHandler về cơ bản không có gì. Tuy nhiên, nó giúp các nhà phát triển phân biệt nhật ký thư viện với nhật ký ứng dụng

Đây là triển khai của

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
65

nullhandler. py

Tại sao chúng ta cần phân biệt nhật ký thư viện với nhật ký ứng dụng?

Theo tác giả của mô-đun ghi nhật ký, Vinay Sajip

Theo mặc định, thư viện của bên thứ ba sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
4 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

Cách tốt nhất là không phát ra nhật ký thư viện theo mặc định và để người dùng thư viện xác định xem họ có muốn nhận và xử lý nhật ký trong ứng dụng hay không

Là nhà phát triển thư viện, chúng tôi chỉ cần một dòng mã bên trong

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
67 để thêm
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
65. Trong các gói con và mô-đun con, bộ ghi nhật ký vẫn như bình thường. Khi chúng tôi cài đặt gói này trong ứng dụng của mình qua
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
69, chúng tôi sẽ không thấy nhật ký từ thư viện theo mặc định

đăng nhập ví dụ nullhandler. py

Cách để hiển thị các nhật ký này là thêm trình xử lý vào trình ghi nhật ký thư viện trong ứng dụng của bạn

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
2

Nếu thư viện không sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
65, nhưng bạn muốn tắt nhật ký thư viện, thì bạn có thể đặt
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
71. Nếu tuyên truyền được đặt thành Sai, thì nhật ký sẽ không được chuyển đến trình xử lý

6. Xoay các tệp nhật ký của bạn — RotatingFileHandler, TimedRotatingFileHandler

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
72 hỗ trợ xoay tệp nhật ký, giúp trình xử lý có khả năng xoay tệp nhật ký dựa trên kích thước tối đa của nó. 2 tham số nên được xác định ở đây. maxBytes và backupCount. maxBytes cho trình xử lý biết khi nào xoay nhật ký. backupCount là số lượng tệp nhật ký, mỗi tệp nhật ký mở rộng có hậu tố “. 1”, “. 2” ở cuối tên tệp. Nếu thông báo nhật ký hiện tại sắp cho phép tệp nhật ký vượt quá kích thước tối đa, thì trình xử lý sẽ đóng tệp hiện tại và mở tệp tiếp theo

Đây là một ví dụ rất giống với Cookbook. Bạn sẽ nhận được 6 tệp nhật ký

xoay vòng tệp nhật ký. py

Một trình xử lý xoay tệp khác là

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
73, cho phép nhà phát triển tạo nhật ký xoay vòng dựa trên thời gian đã trôi qua. Điều kiện về thời gian bao gồm. giây, phút, giờ, ngày, w0-w6 (0=thứ Hai) và nửa đêm (chuyển hạn lúc nửa đêm)

Trong ví dụ sau, chúng tôi xoay tệp nhật ký mỗi giây với 5 tệp sao lưu. Mỗi tệp sao lưu có dấu thời gian làm hậu tố

xoay vòng tập tin thời gian. py

7. Ngoại lệ trong quá trình đăng nhập

Trong nhiều trường hợp, chúng tôi sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
74 hoặc
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
75 khi xử lý các trường hợp ngoại lệ. Nhưng nếu logger tự đưa ra một ngoại lệ, điều gì sẽ xảy ra với chương trình?

Lỗi logger được xử lý khi trình xử lý gọi

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
51, có nghĩa là bất kỳ ngoại lệ nào liên quan đến định dạng hoặc viết đều bị trình xử lý bắt thay vì được nêu ra. Cụ thể hơn, phương thức
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
77 sẽ in ra trackback tới
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
78 và chương trình sẽ tiếp tục. Nếu bạn có một trình xử lý tùy chỉnh mở rộng từ lớp
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
48, bạn có thể triển khai lớp
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
77 của riêng mình

Trong ví dụ này, thông điệp tường trình thứ hai có quá nhiều đối số. Vì vậy, trong đầu ra của bảng điều khiển, chúng tôi đã nhận được trackback và chương trình vẫn có thể tiếp tục

Tuy nhiên, nếu ngoại lệ xảy ra bên ngoài

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
51, thì ngoại lệ đó có thể được nêu ra và chương trình sẽ dừng lại. Ví dụ: trong mã bên dưới, chúng tôi thêm một thuộc tính bổ sung
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
26 trong
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
56 mà không xử lý nó trong LoggerAdapter. Lỗi này không được xử lý và khiến chương trình dừng lại

tăng ngoại lệ đăng nhập. py

8. 3 cách khác nhau để định cấu hình bộ ghi của bạn

Điểm cuối cùng tôi muốn chia sẻ là về cấu hình logger của bạn. Có 3 cách để cấu hình một logger

sử dụng mã

Tùy chọn đơn giản nhất là sử dụng mã để định cấu hình bộ ghi của bạn, giống như tất cả các ví dụ mà chúng tôi đã thấy cho đến nay trong bài viết này. Nhưng nhược điểm của tùy chọn này là mọi sửa đổi đều yêu cầu thay đổi mã nguồn

sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
84

Tùy chọn thứ hai là viết cấu hình trong từ điển và sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
85 để đọc nó. Bạn cũng có thể lưu từ điển vào tệp JSON và đọc từ đó. Ưu điểm là nó có thể được tải như một cấu hình bên ngoài, nhưng nó có thể dễ bị lỗi do cấu trúc của nó

đăng nhập cấu hình json. py

sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
86

Cuối cùng nhưng không kém phần quan trọng, tùy chọn thứ ba là sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
87. Cấu hình được ghi vào một tệp
"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
88 riêng

đăng nhập tập tin cấu hình. py

Có thể cập nhật cấu hình trong thời gian chạy thông qua máy chủ cấu hình. Cookbook hiển thị một ví dụ về cả phía máy khách và phía máy chủ. Cấu hình được cập nhật thông qua kết nối ổ cắm và ở phía máy khách, chúng tôi sử dụng

"%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"# 2020-07-26 23:37:15,374 - [INFO] -  __main__ - (main.py).main(18) - Program starts!
89 để nhận cấu hình mới nhất

Tôi hy vọng những mẹo và thủ thuật ghi nhật ký này có thể giúp bạn thiết lập một khung ghi nhật ký tốt xung quanh ứng dụng của mình mà không ảnh hưởng đến hiệu suất. Nếu có gì muốn chia sẻ hãy để lại bình luận bên dưới