猿教程 Logo

如何使用Python中的登录3 (How To Use Logging in Python 3)


Introduction

The logging module is part of the standard Python library and provides tracking for events that occur while software runs. You can add logging calls to your code to indicate what events have happened.

The logging module allows for both diagnostic logging that records events related to an application’s operation, as well as audit logging which records the events of a user’s transactions for analysis. It is especially used to record events to a file.


Why Use the logging Module

The logging module keeps a record of the events that occur within a program, making it possible to see output related to any of the events that occur throughout the runtime of a piece of software.

You may be more familiar with checking that events are occurring by using the print() statement throughout your code. The print() statement does provide a basic way to go about debugging your code to resolve issues. While embedding print() statements throughout your code can track the execution flow and the current state of your program, this solution proves to be less maintainable than using the logging module for a few reasons:

  • It becomes difficult to distinguish between debugging output and normal program output because the two are mixed
  • When using print() statements dispersed throughout code, there is no easy way to disable the ones that provide debugging output
  • It becomes difficult to remove all the print() statements when you are done with debugging
  • There is no log record that contains readily available diagnostic information

It is a good idea to get in the habit of using the logging module in your code as this is more suitable for applications that grow beyond simple Python scripts and provides a sustainable approach to debugging.

Because logs can show you behavior and errors over time, they also can give you a better overall picture of what is going on in your application development process.


Printing Debug Messages to Console

If you are used to using the print() statement to see what is occurring in a program, you may be used to seeing a program that defines a class and instantiates objects that looks something like this:

class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        print("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        print("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        print("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

The code above has an __init__ method to define the name and price of an object of the Pizza class. It then has two methods, one called make() for making pizzas, and one called eat() for eating pizzas. These two methods take in the parameter of quantity, which is initialized at 1.

Now let’s run the program:

$ python pizza.py
python pizza.py

We’ll receive the following output:

Output
       Pizza created: artichoke ($15)
Made 1 artichoke pizza(s)
Ate 1 pizza(s)
Pizza created: margherita ($12)
Made 2 margherita pizza(s)
Ate 1 pizza(s)

While the print() statement allows us to see that the code is working, we can use the logging module to do this instead.

Let’s remove or comment out the print() statements throughout the code, and add import logging to the top of the file:

import logging


class Pizza():
    def __init__(self, name, value):
        self.name = name
        self.value = value
...

The logging module has a default level of WARNING, which is a level above DEBUG. Since we’re going to use the logging module for debugging in this example, we need to modify the configuration so that the level of logging.DEBUG will return information to the console for us. We can do that by adding the following line below the import statement:

import logging

logging.basicConfig(level=logging.DEBUG)


class Pizza():
...

This level of logging.DEBUG refers to a constant integer value that we reference in the code above to set a threshold. The level of DEBUG is 10.

Now, we will replace all of the print() statements with logging.debug() statements instead. Unlike logging.DEBUG which is a constant, logging.debug() is a method of the logging module. When working with this method, we can make use of the same string passed to print(), as shown below.

import logging

logging.basicConfig(level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

At this point, when we run the program with the python pizza.py command, we’ll receive this output:

Output
       DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)

The log messages have the severity level DEBUG as well as the word root embedded in them, which refers to the level of your Python module. The logging module can be used with a hierarchy of loggers that have different names, so that you can use a different logger for each of your modules.

For example, you can set loggers equal to different loggers that have different names and different output:

logger1 = logging.getLogger("module_1")
logger2 = logging.getLogger("module_2")

logger1.debug("Module 1 debugger")
logger2.debug("Module 2 debugger")
Output
       DEBUG:module_1:Module 1 debugger
DEBUG:module_2:Module 2 debugger

Now that we have an understanding of how to use the logging module to print messages to the console, let’s move on to using the logging module to print messages out to a file.


Logging Messages to a File

The primary purpose of the logging module is to log messages to a file rather than to a console. Keeping a file of messages provides you with data over time that you can consult and quantify so that you can see what changes need to be made to your code.

To start logging to a file, we can modify the logging.basicConfig() method to include a filename parameter. In this case, let’s call the filename test.log:

import logging

logging.basicConfig(filename="test.log", level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

The code above is the same as it was in the previous section, except that now we added the filename for the log to print to. Once we run the code with the python pizza.py command, we should have a new file in our directory called test.log.

Let’s open the test.log file with nano (or the text editor of your choice):

$ nano test.log
nano test.log

When the file opens, we’ll see the following:

DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)

This is similar to the console output that we encountered in the previous section, except now it is in the test.log file.

Let’s close the file with CTRL + x and move back into the pizza.py file so that we can modify the code.

We’ll keep much of the code the same, but modify the parameters in the two pizza instances, pizza_01 and pizza_02:

import logging

logging.basicConfig(filename="test.log", level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

# Modify the parameters of the pizza_01 object
pizza_01 = Pizza("Sicilian", 18)
pizza_01.make(5)
pizza_01.eat(4)

# Modify the parameters of the pizza_02 object
pizza_02 = Pizza("quattro formaggi", 16)
pizza_02.make(2)
pizza_02.eat(2)

With these changes, let’s run the program again with the python pizza.py command.

Once the program has run, we can open our test.log file again with nano:

$ nano test.log
nano test.log

When we look at the file, we’ll see that several new lines were added, and that the previous lines from the last time that the program ran were retained:

DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)

While this information is certainly useful, we can make the log more informative by adding additional LogRecord attributes. Primarily, we would like to add a human-readable time stamp that tells us when the LogRecord was created.

We can add that attribute to a parameter called format, referencing it as shown in the table with the string %(asctime)s. Additionally, to keep the DEBUG level name, we’ll need to include the string %(levelname)s and to keep the string message that we ask the logger to print out we’ll include %(message)s. Each of these attributes will be separated by a colon, as shown in the code added below.

import logging

logging.basicConfig(
    filename="test.log",
    level=logging.DEBUG,
    format="%(asctime)s:%(levelname)s:%(message)s"
    )


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("Sicilian", 18)
pizza_01.make(5)
pizza_01.eat(4)

pizza_02 = Pizza("quattro formaggi", 16)
pizza_02.make(2)
pizza_02.eat(2)

When we run the code above with the added attributes with the python pizza.py command, we’ll get new lines added to our test.log file that include the human-readable time stamp in addition to the level name of DEBUG and the associated messages that are passed into the logger as strings.

Output
       DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)
2017-05-01 16:28:54,593:DEBUG:Pizza created: Sicilian ($18)
2017-05-01 16:28:54,593:DEBUG:Made 5 Sicilian pizza(s)
2017-05-01 16:28:54,593:DEBUG:Ate 4 pizza(s)
2017-05-01 16:28:54,593:DEBUG:Pizza created: quattro formaggi ($16)
2017-05-01 16:28:54,593:DEBUG:Made 2 quattro formaggi pizza(s)
2017-05-01 16:28:54,593:DEBUG:Ate 2 pizza(s)

Depending on your needs, you may want to make use of additional LogRecord attributes in your code in order to make your program files’ logs relevant to you.

Logging debugging and other messages into separate files provides you with a holistic understanding of your Python program over time, giving you the opportunity to troubleshoot and modify your code in a manner that is informed by the historical work put into the program, as well as the events and transactions that occur.


Table of Logging Levels

As a developer, you can ascribe a level of importance to the event that is captured in the logger by adding a severity level. The severity levels are shown in the table below.

Logging levels are technically integers (a constant), and they are all in increments of 10, starting with NOTSET which initializes the logger at the numeric value of 0.

You can also define your own levels relative to the predefined levels. If you define a level with the same numeric value, you will overwrite the name associated with that value.

The table below shows the various level names, their numeric value, what function you can use to call the level, and what that level is used for.

The logging module sets the default level at WARNING, so WARNING, ERROR, and CRITICAL will all be logged by default. In the example above, we modified the configuration to include the DEBUG level with the following code:

logging.basicConfig(level=logging.DEBUG)

You can read more about the commands and working with the debugger from the official logging documentation.


Conclusion

Debugging is an important step of any software development project. The logging module is part of the standard Python library, provides tracking for events that occur while software runs, and can output these events to a separate log file to allow you to keep track of what occurs while your code runs. This provides you with the opportunity to debug your code based on understanding the various events that occur from running your program over time.

介绍

日志记录模块是标准Python库的一部分,并为软件运行时发生的事件提供跟踪。 您可以在代码中添加记录调用,以指示发生了什么事件。

记录模块允许记录与应用程序操作相关的事件的诊断日志记录,以及记录用户事务事件以进行分析的审核记录。 它特别用于将事件记录到文件中。


为什么要使用日志记录模块

记录模块保存程序中发生的事件的记录,使得可以看到与一个软件的整个运行时间中发生的任何事件相关的输出。

您可能会更加熟悉使用整个代码中的print()语句来检查事件是否发生。 print()语句确实提供了一个基本的方法来调试代码来解决问题。 尽管在整个代码中嵌入print()语句可以跟踪程序的执行流程和当前状态,但是由于以下几个原因,该解决方案证明比使用日志记录模块的可维护性更低:

  • 由于两者混合,因此难以区分调试输出和正常程序输出
  • 当使用分散在代码中的print()语句时,没有简单的方法来禁用提供调试输出的那些
  • 完成调试后,很难删除所有的print()语句
  • 没有包含可用的诊断信息的日志记录

习惯于在代码中使用日志记录模块是一个好主意,因为这更适合于超越简单Python脚本的应用程序,并提供可持续的调试方法。

因为日志可以显示您的行为和错误随着时间的推移,它们还可以让您更好地了解应用程序开发过程中发生的情况。


将调试消息打印到控制台

如果习惯于使用print()语句来查看程序中出现的情况,可能会用于查看定义类的程序,并实例化如下所示的对象:

class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        print("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        print("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        print("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

上面的代码有一个__init__方法来定义Pizza类的对象的名称和价格。 然后有两种方法,一种叫做make()做比萨饼,一种叫做eat(),用于吃比萨饼。 这两种方法采用数量参数,初始化为1。

现在我们来运行程序:

$ python pizza.py
python pizza.py

我们将收到以下输出:

Output
       Pizza created: artichoke ($15)
Made 1 artichoke pizza(s)
Ate 1 pizza(s)
Pizza created: margherita ($12)
Made 2 margherita pizza(s)
Ate 1 pizza(s)

虽然print()语句允许我们看到代码正在运行,但我们可以使用日志记录模块来代替。

我们在整个代码中删除或注释掉print()语句,并将导入日志记录添加到文件的顶部:

import logging


class Pizza():
    def __init__(self, name, value):
        self.name = name
        self.value = value
...

日志记录模块的默认级别为WARNING,高于DEBUG。 由于我们将在此示例中使用日志记录模块进行调试,因此我们需要修改配置,以便logging.DEBUG的级别将信息返回给我们的控制台。 我们可以通过在import语句下方添加以下行:

import logging

logging.basicConfig(level=logging.DEBUG)


class Pizza():
...

这个级别的logging.DEBUG是指在上面的代码中引用的一个常量整数值来设置一个阈值。 DEBUG的级别是10。

现在,我们将用logging.debug()语句替换所有的print()语句。 与logging.DEBUG不同的是logging.debug(),它是日志记录模块的一种方法。 使用此方法时,可以使用传递给print()的相同字符串,如下所示。

import logging

logging.basicConfig(level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

此时,当我们使用python pizza.py命令运行程序时,我们将收到此输出:

Output
       DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)

日志消息具有严重性级别DEBUG以及嵌入在其中的单词root,它指的是Python模块的级别。 日志记录模块可以与具有不同名称的记录器层次结合使用,以便您可以为每个模块使用不同的记录器。

例如,您可以将记录器设置为具有不同名称和不同输出的不同记录器:

logger1 = logging.getLogger("module_1")
logger2 = logging.getLogger("module_2")

logger1.debug("Module 1 debugger")
logger2.debug("Module 2 debugger")
Output
       DEBUG:module_1:Module 1 debugger
DEBUG:module_2:Module 2 debugger

现在我们了解如何使用日志记录模块将消息打印到控制台,接下来我们继续使用日志记录模块将消息打印到文件中。


将消息记录到文件

记录模块的主要目的是将消息记录到文件而不是控制台。 保存邮件文件为您提供一段时间内的数据,您可以查询和量化数据,以便您可以看到需要对代码进行哪些更改。

要开始记录到文件,我们可以修改logging.basicConfig()方法以包含一个filename参数。 在这种情况下,我们来调用文件名test.log:

import logging

logging.basicConfig(filename="test.log", level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

上面的代码与上一节中的代码相同,只是现在我们添加了要打印的日志的文件名。 一旦我们使用python pizza.py命令运行代码,我们应该在我们的目录中有一个名为test.log的新文件。

让我们用nano(或你选择的文本编辑器)打开test.log文件:

$ nano test.log
nano test.log

当文件打开时,我们将看到以下内容:

DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)

这与上一节中遇到的控制台输出类似,只不过它现在位于test.log文件中。

我们用CTRL + x关闭文件,然后移回pizza.py文件,以便我们可以修改代码。

我们将保留大部分代码相同,但修改两个比萨实例中的参数pizza_01和pizza_02:

import logging

logging.basicConfig(filename="test.log", level=logging.DEBUG)


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

# Modify the parameters of the pizza_01 object
pizza_01 = Pizza("Sicilian", 18)
pizza_01.make(5)
pizza_01.eat(4)

# Modify the parameters of the pizza_02 object
pizza_02 = Pizza("quattro formaggi", 16)
pizza_02.make(2)
pizza_02.eat(2)

通过这些更改,我们再次使用python pizza.py命令运行该程序。

一旦程序运行,我们可以再次使用nano打开我们的test.log文件:

$ nano test.log
nano test.log

当我们查看文件时,我们将看到添加了几行新行,并且上次运行该程序的行保留:

DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)

虽然这些信息肯定是有用的,但我们可以通过添加其他LogRecord属性来使日志更加翔实。 首先,我们想添加一个可读的时间戳,告诉我们LogRecord何时被创建。

我们可以将该属性添加到称为格式的参数中,如表中所示,使用字符串%(asctime)s引用它。 另外,为了保持DEBUG级别的名称,我们需要包含字符串%(levelname),并保留我们要求记录器打印的字符串消息,我们将包含%(message)。 这些属性中的每一个将被冒号分隔,如下面添加的代码所示。

import logging

logging.basicConfig(
    filename="test.log",
    level=logging.DEBUG,
    format="%(asctime)s:%(levelname)s:%(message)s"
    )


class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("Sicilian", 18)
pizza_01.make(5)
pizza_01.eat(4)

pizza_02 = Pizza("quattro formaggi", 16)
pizza_02.make(2)
pizza_02.eat(2)

当我们使用python pizza.py命令运行带有添加属性的代码时,我们将在test.log文件中添加包含人类可读时间戳的新行,除了DEBUG的级别名称和相关联的 作为字符串传递到记录器的消息。

Output
       DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)
2017-05-01 16:28:54,593:DEBUG:Pizza created: Sicilian ($18)
2017-05-01 16:28:54,593:DEBUG:Made 5 Sicilian pizza(s)
2017-05-01 16:28:54,593:DEBUG:Ate 4 pizza(s)
2017-05-01 16:28:54,593:DEBUG:Pizza created: quattro formaggi ($16)
2017-05-01 16:28:54,593:DEBUG:Made 2 quattro formaggi pizza(s)
2017-05-01 16:28:54,593:DEBUG:Ate 2 pizza(s)

根据您的需要,您可能希望在代码中使用其他LogRecord属性,以使程序文件的日志与您相关。

将调试和其他消息记录到单独的文件中可以让您全面了解您的Python程序随着时间的推移,让您有机会以通过程序中的历史工作通知的方式对代码进行故障排除和修改,以及 发生的事件和事务。


记录级别表

作为开发人员,您可以通过添加严重性级别将重要级别归因于记录器中捕获的事件。 严重程度如下表所示。

记录级别在技术上是整数(常数),它们都以10的增量开始,从NOTSET开始,它以数字值0初始化记录器。

您还可以根据预定义的级别定义自己的级别。 如果您定义具有相同数值的级别,则将覆盖与该值相关联的名称。

下表显示了各种级别名称,它们的数值,可用于调用级别的功能以及该级别的用途。

记录模块将默认级别设置为WARNING,因此默认情况下将记录WARNING,ERROR和CRITICAL。 在上面的示例中,我们修改了配置,将DEBUG级别包含以下代码:

logging.basicConfig(level=logging.DEBUG)

您可以从官方日志记录文档中阅读有关命令的更多信息,并使用调试器。


结论

调试是任何软件开发项目的重要一步。 日志记录模块是标准Python库的一部分,提供跟踪软件运行时发生的事件,并可以将这些事件输出到单独的日志文件,以便跟踪代码运行时发生的情况。 这为您提供了根据理解随时间运行程序而发生的各种事件的代码调试代码的机会。