Hướng dẫn python logging to kibana - đăng nhập python vào kibana

Các ứng dụng chạy trong sản xuất mất khả năng cho chúng tôi biết trực tiếp những gì đang diễn ra dưới mui xe, chúng trở nên giống như các hộp đen và vì vậy chúng tôi cần một cách để theo dõi và theo dõi hành vi của chúng. Ghi nhật ký là cách tiếp cận đơn giản và đơn giản nhất để làm như vậy. Chúng tôi hướng dẫn chương trình trong quá trình phát triển để phát ra thông tin trong khi chạy sẽ hữu ích cho việc khắc phục sự cố trong tương lai hoặc đơn giản là để phân tích. Khi nói đến Python, mô-đun tích hợp để ghi nhật ký được thiết kế để phù hợp với các ứng dụng với thiết lập tối thiểu. Cho dù bạn đã thành thạo việc đăng nhập vào Python hay bạn bắt đầu phát triển với nó, mục đích của bài viết này là toàn diện nhất có thể và đi sâu vào các phương pháp để tận dụng các tiềm năng khai thác. bài báo. Trong phần thứ hai, chúng tôi sẽ tiếp cận các dịch vụ AWS và sử dụng kết hợp dịch vụ AWS Kinesis Data Firehose và AWS Elaticsearch để cung cấp một cách để hiển thị và gỡ lỗi nhật ký trên bảng điều khiển Kibana cũng như lưu trữ chúng cho S3 để có các bản sao dài hạn. lose their ability to tell us directly what is going on under the hood, they become like black boxes and so we need a way to trace and monitor their behavior. Logging is by far the simplest and most straightforward approach to do so. We instruct the program during development to emit information while running that will be useful for future troubleshooting or simply for analysis.When it comes to Python, the built-in module for logging is designed to fit into applications with minimal setup. Whether you’ve already mastered logging in Python or you are starting to develop with it, the aim of this article is to be as comprehensive as possible and to dive into methodologies to leverage logging potentials. Note that this is a two-part article. In the second part, we will approach AWS services and use a combination of AWS Kinesis Data Firehose and AWS ElasticSearch Service to provide a way to show and debug logs on Kibana Dashboard as well as storing them to S3 to have long term copies at hand.

Những điều cơ bản về mô -đun đăng nhập Python

Trước khi bắt đầu hành trình của chúng tôi, hãy để Lôi tự hỏi mình một câu hỏi đơn giản: Logger là gì? Về cơ bản, chúng là đối tượng là một nhà phát triển tương tác để in thông tin. Chúng là công cụ chúng tôi sử dụng để nói với hệ thống những gì cần đăng nhập và cách thực hiện.what is a logger? Basically, they are objects a developer interacts with in order to print information. They are the instrument we use to tell the system what to log and how to do it.Given an instance of a generic logger, we can deliver messages wherever we want without worrying about underneath implementation.For example, when we write

logger.info["Logging a variable %s", variable1]

Chúng tôi đang mô tả tình huống sau: Thư viện tiêu chuẩn của Python đi kèm với mô -đun đăng nhập mà bạn có thể bắt đầu sử dụng mà không cần cài đặt bất cứ điều gì. Trong việc tuân thủ các thực tiễn tốt nhất yêu cầu tránh chỉ in vào bảng điều khiển bạn muốn báo cáo, mô -đun đăng nhập của Python cung cấp nhiều thuận lợi:

Python’s standard library comes with a logging module that you can start using without installing anything.In order to adhere to best practices which request avoiding to simply print into console whatever you want to report, Python’s logging module offers multiple advantages:

  • Hỗ trợ cho đa luồng;
  • Mức ghi nhật ký;
  • linh hoạt hơn;
  • sự phân tách giữa dữ liệu và định dạng.

Chúng tôi tận dụng tiềm năng của việc ghi nhật ký bằng cách tách những gì được ghi lại với cách nó được thực hiện. Khi xem xét cách thức của người Viking, chúng ta nên chăm sóc ba khía cạnh chính:

  1. Cấp độ: Mức độ ưu tiên tối thiểu của tin nhắn để ghi nhật ký. Để tăng mức độ nghiêm trọng, các mức nhật ký có sẵn là: gỡ lỗi, thông tin, cảnh báo, lỗi và quan trọng. Theo mặc định, cấp độ được đặt thành cảnh báo, có nghĩa là mô -đun ghi nhật ký Python sẽ lọc bất kỳ tin nhắn gỡ lỗi hoặc thông tin nào.: the minimum priority level of messages to log. In order of increasing severity, the available log levels are: DEBUG, INFO, WARNING, ERROR, and CRITICAL. By default, the level is set to WARNING, meaning that Python’s logging module will filter out any DEBUG or INFO messages.
  2. Handler: Xác định nơi nhật ký của bạn sẽ được đưa vào. Trừ khi được chỉ định, thư viện ghi nhật ký sẽ sử dụng StreamHandler gửi tin nhắn đến sys.stderr hoặc, chỉ cần nói, bảng điều khiển. Nó cũng xử lý định dạng.: determines where your logs will be put into. Unless specified, the logging library will use a StreamHandler sending messages to sys.stderr or, simply speaking, the console. It also handles formatting.
  3. Định dạng: Theo mặc định, thư viện ghi nhật ký sẽ ghi nhật ký tin nhắn ở định dạng sau: ::. Tất nhiên, có khả năng tùy chỉnh giao diện của các dòng nhật ký của bạn thêm thông tin tùy chỉnh, chúng tôi sẽ che đậy điều đó sau.: by default, the logging library will log messages in the following format: ::. There is, of course, the possibility to customize the look of your log lines adding custom information, we will cover that up later.

Mô -đun ghi nhật ký Python cung cấp cho bạn các cách khác nhau để tạo các trình ghi nhật ký phù hợp với nhu cầu cụ thể của bạn, kết hợp trình xử lý, định dạng và cấp độ. Hãy bắt đầu với phương thức cấu hình logger đơn giản nhất:provides you different ways to create loggers tailored to your specific needs, combining handlers, formats, and levels. Let’s start with the simplest logger configuration method:

basicConfig[]

basicConfig[]

Bằng cách sử dụng phương thức basicConfig [], bạn có thể nhanh chóng định cấu hình hành vi mong muốn của bộ ghi gốc của bạn. Các cách tiếp cận có thể quản lý khác cho các dự án lớn hơn bao gồm sử dụng cấu hình ghi nhật ký dựa trên tệp hoặc từ điển thay thế. Không có gì, BasicConfig [] là cách ưa thích để bắt đầu mô tả cách tiếp cận tốt hơn với mô-đun ghi nhật ký của bạn. rằng trong một số tình huống nhất định, bạn có thể thiếu khả năng hiển thị khi truy tìm các lỗi hoặc nói chung khi tiến hành phân tích nguyên nhân gốc. Theo tiêu chuẩn của nó, mô -đun ghi nhật ký, như chúng tôi đã nói trước đây, gửi nhật ký trực tiếp đến bảng điều khiển, nhưng các tùy chọn khả thi khác, và cũng được đề xuất, đang sử dụng StreamHandler hoặc Sockethandler để truyền phát trên mạng và kết hợp cũng bằng cách sử dụng FileHandler để ghi nhật ký Trực tiếp trên đĩa. Ngay cả khi đăng nhập vào tệp có những ưu điểm của nó như tránh các lỗi liên quan đến mạng tiềm ẩn và dễ dàng thiết lập, trong những ngày này và thời đại, nơi các ứng dụng được phân phối trên mạng và tỷ lệ nhanh chóng, quản lý một máy mỗi máy Nhóm các tập tin được lưu trữ cục bộ có lẽ không phải là một lựa chọn thực tế. Thay vào đó, cách tiếp cận này có thể được coi là một cách thiết thực để sao lưu các tệp nhật ký song song với việc có thể tập trung và theo dõi chúng qua mục tiêu mạng.basicConfig[] method you can quickly configure the desired behavior of your root logger. Other manageable approaches for larger projects include using file-based or dictionary-based logging configuration instead.Nonetheless, basicConfig[] is the preferred way to start describing how to better approach your logging.Logging module has WARNING as its default logging level, which means that in certain situations you may lack visibility when tracing down bugs or in general when conducting a root cause analysis. By its standards the logging module, as we said before, sends logs directly to the console, but other viable options, and also recommended ones, are using a StreamHandler or a SocketHandler to stream over the network and in conjunction also using a FileHandler to log directly on disk.Even if logging to a file has its advantages like avoiding potential network-related errors and being easy to set up, in these days and era, where applications are distributed over the network and scale fast, managing a single per-machine group of files stored locally is probably not a practical choice. Instead, this approach can be seen as a practical way to backup log files which goes in parallel with being able to centralize and monitor them over a network target.

Một ví dụ về basicconfig []

Theo một ví dụ sử dụng BasicConfig [] với một số tham số mặc định để đăng nhập vào tệp đĩa. Các tùy chọn đặt cấp độ để gỡ lỗi để truyền phát từ gỡ lỗi đến các tin nhắn cấp cao hơn. Khi thông tin bổ sung, một số tùy chọn định dạng đơn giản được cung cấp.basicConfig[] with some default parameters to log to a disk file. The options set the level to DEBUG in order to stream from debug to higher-level messages. As extra information, some simple formatting options are provided.

import logging

logging.basicConfig[level=logging.DEBUG,
                    filename='basic_config_test1.log',
                    format='%[asctime]s %[levelname]s:%[message]s']


def basic_config_test1[]:
   logging.debug["debug log test"]
   logging.error["error log test"]

Chạy mã trước đó, tệp basic_config_test1.log mới sẽ được tạo bằng nội dung sau, ngoại trừ ngày, phụ thuộc rõ ràng vào thời gian thực hiện.basic_config_test1.log file will be generated with the following content, except for the date, which depends obviously on the execution time.

2020-05-08 17:19:29,220 DEBUG:debug log test
2020-05-08 17:19:29,221 ERROR:error log test

Lưu ý: BasicConfig chỉ hoạt động trong lần đầu tiên nó được gọi trong thời gian chạy. Nếu bạn đã cấu hình logger gốc của mình, hãy gọi BasicConfig sẽ không có hiệu lực.Debug-Level Nhật ký hiện hiển thị và nhật ký được in với cấu trúc tùy chỉnh sau:: basicConfig only works the first time it is called in a runtime. If you have already configured your root logger, calling basicConfig will have no effect.DEBUG-level logs are now visible, and logs are printed with the following custom structure:

  • %[ASCTIME] S: Ngày và giờ thời gian địa phương của hàng nhật ký
  • %[LevelName] S: Mức độ nghiêm trọng của thông báo
  • %[Tin nhắn] S: Tin nhắn thực tế

Để hoàn thành thông tin ở đây, một bảng mô tả các tùy chọn BasicConfig: Đây là một cách đơn giản và thực tế để định cấu hình các tập lệnh nhỏ. Theo các thực tiễn tốt nhất của Python, chúng tôi khuyên bạn nên quản lý một phiên bản logger cho từng mô -đun trong ứng dụng của bạn, nhưng có thể hiểu rằng điều này có thể là thách thức và ô uế bằng cách chỉ sử dụng các khả năng BasicConfig []. Vì vậy, chúng tôi sẽ tập trung tiếp theo vào cách cải thiện một giải pháp ghi nhật ký cơ bản.

This is a simple and practical way to configure small scripts. Following Python best practices we recommend managing a logger instance for each module of your application, but it is understandable that this can be challenging and unclean by using basicConfig[] capabilities alone. So we will next focus on how to improve a basic logging solution.

Thực hành tốt nhất: Một thể hiện logger cho mỗi mô -đun

Để tuân theo các thực tiễn tốt nhất tiêu chuẩn, chúng tôi có thể thiết lập một logger cho mỗi giải pháp mô -đun. Một cách tiếp cận tốt có quy mô rất tốt, nó dễ dàng thiết lập và do đó nên được xem xét khi xử lý các ứng dụng lớn cần mở rộng, là tận dụng phương thức GetLogger [] tích hợp.large applications that need to scale, is to take advantage of the built-in getLogger[] method.

logger = logging.getLogger[__name__]

Phương thức này tạo ra một logger tùy chỉnh mới, khác với phương thức gốc. Đối số ß tương ứng với tên đủ điều kiện của mô -đun mà phương thức này được gọi. Điều này cho phép bạn cũng xem xét tên logger, một phần của mỗi hàng nhật ký bằng cách cài đặt tự động tên đó để khớp với một trong các mô -đun hiện tại mà bạn đang làm việc. Có thể khôi phục thuộc tính tên của Logger với & NBSP; %[tên] s như thể hiện trong ví dụ sau.ß argument corresponds to the fully qualified name of the module from which this method is called. This allows you to also take into consideration the logger’s name as part of each log row by dynamically setting that name to match the one of the current modules you’re working with.It is possible to recover a logger's name property with  %[name]s as shown in the following example.

# logging_test1.py

import logging

logging.basicConfig[level=logging.DEBUG,
                   filename='basic_config_test1.log',
                   format='%[asctime]s %[name]s %[levelname]s:%[message]s']

logger = logging.getLogger[__name__]


def basic_config_test1[]:
   logger.debug["debug log test 1"]
   logger.error["error log test 1"]


# logging_test2.py

import logging
import logging_test1

logger = logging.getLogger[__name__]



def basic_config_test2[]:
   logger.debug["debug log test 2"]
   logger.error["error log test 2"]

Chúng tôi có một cấu hình tốt hơn bây giờ, mỗi mô -đun đang mô tả chính nó bên trong luồng nhật ký và mọi thứ rõ ràng hơn, nhưng dù sao, logger được khởi tạo trong mô -đun logging_test2 sẽ sử dụng cùng một cấu hình như logger được khởi động trong mô -đun logging_test1, tức là logger gốc cấu hình. Như đã nêu trước đây, phương thức gọi thứ hai của phương thức basicConfig [] sẽ không có hiệu lực. Do đó, việc thực thi cả hai phương thức basic_config_test1 [] và basic_config_test2 [] sẽ dẫn đến việc tạo một tệp basic_config_test1.log duy nhất với nội dung sau.better configuration now, each module is describing itself inside the log stream and everything is more clear, but nonetheless, the logger instantiated in the logging_test2 module will use the same configuration as the logger instantiated in the logging_test1 module, i.e. the root logger’s configuration. As stated before, the second invocation of basicConfig[] method will have no effect. Therefore, executing both basic_config_test1[] and basic_config_test2[]methods will result in the creation of a single basic_config_test1.log file with the following content.

2020-05-09 19:37:59,607 logging_test1 DEBUG:debug log test 1

2020-05-09 19:37:59,607 logging_test1 ERROR:error log test 1

2020-05-09 19:38:05,183 logging_test2 DEBUG:debug log test 2

2020-05-09 19:38:05,183 logging_test2 ERROR:error log test 2

Tùy thuộc vào ngữ cảnh của ứng dụng của bạn, sử dụng một cấu hình duy nhất cho các trình ghi nhật ký được khởi tạo trong các mô -đun khác nhau có thể không đủ. Trong phần tiếp theo, chúng tôi sẽ xem cách cung cấp cấu hình ghi nhật ký trên nhiều trình ghi nhật ký thông qua fileconfig [] hoặc dictConfig [].

Sử dụng fileconfig [] và dictconfig []

Ngay cả khi basicconfig [] là một cách nhanh chóng để bắt đầu tổ chức các cấu hình ghi nhật ký, tệp hoặc từ điển của bạn cung cấp nhiều tùy chọn hơn để tinh chỉnh nhu cầu của bạn, cho phép nhiều hơn một logger trong ứng dụng của bạn và có thể gửi nhật ký của bạn đến các điểm đến khác nhau dựa trên Về các yếu tố cụ thể. Đây cũng là khung cách sử dụng Django và Flask để thiết lập đăng nhập vào các dự án của bạn. Trong các phần tiếp theo, chúng tôi sẽ xem xét kỹ hơn về cách thiết lập một cấu hình dựa trên tệp hoặc từ điển thích hợp.how to set up a proper file or dictionary-based configuration.

fileConfig[]

Các tệp cấu hình phải tuân thủ cấu trúc này, chứa một số yếu tố chính. [Loggers]: Tên của các trình ghi nhật ký mà chúng ta cần cấu hình. : Các định dạng bạn muốn áp dụng cho mỗi phần logger.each của tệp [được đặt tên trong số nhiều] nên bao gồm một danh sách được phân tách bằng dấu phẩy của một hoặc nhiều khóa để liên kết cấu hình thực tế:key elements.[loggers]: the names of the loggers we need to configure.[handlers]: the handlers we want to use for specific loggers [e.g. consoleHandler, fileHandler].[formatters]: the formats you want to apply to each logger.Each section of the file [named in plural] should include a comma-separated list of one or more keys to link the actual configuration:

[loggers]

keys=root,secondary 

Các khóa được sử dụng để đi qua tệp và đọc các cấu hình phù hợp cho mỗi phần. Các khóa được định nghĩa là [_], trong đó tên phần là logger, người xử lý hoặc định dạng được xác định trước như đã nói trước. Một tệp cấu hình ghi nhật ký mẫu [logging.ini] được hiển thị bên dưới.

[loggers]
keys=root,custom

[handlers]
keys=fileHandler,streamHandler

[formatters]
keys=formatter
 
[logger_root]
level=DEBUG
handlers=fileHandler

[logger_custom]
level=ERROR
handlers=streamHandler
 
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=formatter
args=["/path/to/log/test.log",]

[handler_streamHandler]
class=StreamHandler
level=ERROR
formatter=formatter

[formatter_formatter]
format=%[asctime]s %[name]s - %[levelname]s:%[message]s

Các thực tiễn tốt nhất của Python, khuyến nghị chỉ duy trì một người xử lý trên mỗi logger dựa vào sự thừa kế của logger trẻ em để nhân giống tài sản. Điều này về cơ bản có nghĩa là bạn chỉ cần gắn một cấu hình cụ thể vào bộ ghi nhật ký cha, để nó được thừa hưởng bởi tất cả các trình ghi nhật ký con mà không phải thiết lập nó cho mỗi người trong số chúng. Một ví dụ điển hình về điều này là việc sử dụng thông minh của logger root làm cha mẹ.one handler per logger relying on the inheritance of child logger for properties propagation. This basically means that you just have to attach a specific configuration to a parent logger, to have it inherited by all the child loggers without having to set it up for every single one of them. A good example of this is a smart use of the root logger as the parent.Back on track, once you have prepared a configuration file, you can attach it to a logger with these simple lines of code:

import logging.config

logging.config.fileConfig['/path/to/logging.ini',
                          disable_existing_loggers=False]
logger = logging.getLogger[__name__]

Trong ví dụ này, chúng tôi cũng bao gồm vô hiệu hóa_existing_loggers được đặt thành sai, đảm bảo rằng các trình ghi nhật ký đã tồn tại trước không được xóa khi đoạn trích này được thực thi; Đây thường là một mẹo tốt, vì nhiều mô -đun tuyên bố một logger toàn cầu sẽ được khởi tạo trước khi fileconfig [] được gọi.

dictConfig[]

The logging configuration with all the properties we have described can be also defined as a standard dictionary object. This dictionary should follow the structure presented for the fileConfig[] with sections covering loggers, handlers, and formatters with some global parameters.Here’s an example:

basicConfig[]
0

To apply this configuration simply pass it as the parameter for the dict config:

basicConfig[]
1

dictConfig[] will also disable all existing loggers unless disable_existing_loggers is set to False like we did in the fileConfig[] example before.This configuration can be also stored in a YAML file and configured from there. Many developers often prefer using dictConfig[] over fileConfig[], as it offers more ways to customize parameters and is more readable and maintainable.

Formatting logs the JSON way

Thanks to the way it is designed, it is easy to extend the logging module. Because our goal is to automate logging and integrate it with Kibana we want a format more suitable for adding custom properties and more compatible with custom workloads. So we want to configure a JSON formatter.If we want, we can log JSON by creating a custom formatter that transforms the log records into a JSON-encoded string:

basicConfig[]
2

If you don’t want to create your own custom formatter, you can rely on various libraries, developed by the Python Community, that can help you convert your logs into JSON format.One of them is python-json-logger to convert log records into JSON.First, install it in your environment:

basicConfig[]
3

Now update the logging configuration dictionary to customize an existing formatter or create a new formatter that will format logs in JSON like in the example below. To use the JSON formatter add pythonjsonlogger.jsonlogger.JsonFormatter as the reference for "class" property. In the formatter’s "format" property, you can define the attributes you’d like to have in the log’s JSON record:

basicConfig[]
4

Logs that get sent to the console, through the standard handler, will get written in JSON format.Once you’ve included the pythonjsonlogger.jsonlogger.JsonFormatter class in your logging configuration file, the dictConfig[] function should be able to create an instance of it as long as you run the code from an environment where it can import python-json-logger module.

Add contextual information to your logs

If you need to add some context to your logs, Python’s logging module gives you the possibility to inject custom attributes to them. An elegant way to enrich your logs involves the use of the LoggerAdapter class.

basicConfig[]
5

This effectively adds custom attributes to all the records that go through that logger.Note that this impacts all log records in your application, including libraries or other frameworks that you might be using and for which you are emitting logs. It can be used to log things like a unique request ID on all log lines to track requests or to add extra contextual information.

Python exception handling and tracebacks

By default, errors don’t include any traceback information. The log will simply show the exception as an error, without any other information. To make sure that logging.error[] prints the entire traceback, add the exc_info property with True value. To show the difference, let’s try logging an exception with and without exc_info.

basicConfig[]
6

If you run test[] method, it will generate the following output:

basicConfig[]
7

As we can see the first line doesn’t provide much information about the error apart from a generic message fake NameError; instead the second line, by adding the property exc_info=True, shows the full traceback, which includes information about methods involved and line numbers to follow back and see where the exception was raised.As an alternative you can achieve the same result by using logger.exception[] from an exception handler like in the example below:

basicConfig[]
8

This can retrieve the same traceback information by using exc_info=True. This has also the benefit of setting the priority level of the log to logging.ERROR.Regardless of which method you use to capture the traceback, having the full exception information available in your logs is critical for monitoring and troubleshooting the performance of your applications.

Capturing unhandled exceptions

Even by thinking about every possible scenario, it's guaranteed that you can never catch every exception in your application nor is it a recommended behavior but still you can log uncaught exceptions so you can investigate them later on.An unhandled exception can be outside of a try/except block, or when you don’t include the correct type in your except block.If an exception is not handled in the method it occurs it starts bubbling up until it reaches a fitting except block or until it reaches the main block.If it is not catched it becomes an unhandled exception and the interpreter will invoke sys.excepthook[]. The information given by the method usually appears in sys.stderr but the traceback information won’t get logged there if you haven’t explicitly set the traceback to be shown in a non default handler [e.g. a fileHandler].You can use Python’s standard traceback library to format the traceback and include it in the log message.Let’s revise our example function to raise an exception not managed by our try except block to see the behavior we’ve described above:

basicConfig[]
9

Chạy mã này sẽ ném một ngoại lệ Oserror mà không được xử lý trong logic Try-Except, nhưng nhờ có mã Tracback, nó sẽ được ghi lại, như chúng ta có thể thấy trong lần thứ hai ngoại trừ mệnh đề: mệnh đề:

import logging

logging.basicConfig[level=logging.DEBUG,
                    filename='basic_config_test1.log',
                    format='%[asctime]s %[levelname]s:%[message]s']


def basic_config_test1[]:
   logging.debug["debug log test"]
   logging.error["error log test"]
0

Ghi nhật ký toàn bộ dấu vết trong mỗi ngoại lệ được xử lý và chưa được xử lý cung cấp khả năng hiển thị quan trọng vào các lỗi khi chúng xảy ra trong thời gian thực, để bạn có thể điều tra khi nào và tại sao chúng xảy ra.critical visibility into errors as they occur in real time, so that you can investigate when and why they occurred.

Đây là kết thúc cho phần một của bài viết hai phần này, trong phần tiếp theo, chúng tôi sẽ đề cập đến cách tổng hợp nhật ký bằng cách sử dụng Kinesis Stream và Elaticsearch và kết hợp tất cả trong bảng điều khiển Kibana có thể tùy chỉnh cao.how to aggregate logs using Kinesis Stream and ElasticSearch and putting all together in a highly customizable Kibana Dashboard.

Giữ nguyên :]

Chuyển đến Phần II

Bài Viết Liên Quan

Chủ Đề