苹果弹出message loggingg干嘛的

博客访问: 4485173
博文数量: 689
博客积分: 2150
博客等级: 上尉
技术积分: 12159
注册时间:
APP发帖 享双倍积分
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Python/Ruby
一、简单将日志打印到屏幕:
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
可见,默认情况下python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,
这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING >&INFO > DEBUG > NOTSET),
默认的日志格式为:
& & &日志级别:Logger名称:用户输出消息。
二、灵活配置日志级别,日志格式,输出位置
查看输出:
cat /tmp/test.log&
Mon, 05 May :53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May :53 test_logging.py[line:10] INFO info message
Mon, 05 May :53 test_logging.py[line:11] WARNING warning message
Mon, 05 May :53 test_logging.py[line:12] ERROR error message
Mon, 05 May :53 test_logging.py[line:13] CRITICAL critical message
可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename: &&用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode: &&文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format: & & &指定handler使用的日志显示格式。
datefmt: & &指定日期时间格式。
level: & & & &设置rootlogger(后边会讲解具体概念)的日志级别
stream: & &&用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。
& & & & & & & & &&若同时列出了filename和stream两个参数,则stream参数会被忽略。
format参数中可能用到的格式化串:
%(name)s & & & & & &&Logger的名字
%(levelno)s & & & & &数字形式的日志级别
%(levelname)s & &&文本形式的日志级别
%(pathname)s & &&调用日志输出函数的模块的完整路径名,可能没有
%(filename)s & & & &调用日志输出函数的模块的文件名
%(module)s & & & & &调用日志输出函数的模块名
%(funcName)s & &&调用日志输出函数的函数名
%(lineno)d & & & & &&调用日志输出函数的语句所在的代码行
%(created)f & & & & &当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d & &输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s & & & & & & & &字符串形式的当前时间。默认格式是 “ 16:49:45,896”。逗号后面的是毫秒
%(thread)d & & & & & & & &&线程ID。可能没有
%(threadName)s & & & &线程名。可能没有
%(process)d & & & & & & &进程ID。可能没有
%(message)s & & & & & &用户输出的消息
若要对logging进行更多灵活的控制有必要了解一下
三、 Logger,Handler,Formatter,Filter的概念
上述几个例子中我们了解到了logging.debug()、()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),
logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),
设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,
另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)
先看一个具体的例子
12:54:43,222 - root - WARNING - logger warning message
12:54:43,223 - root - ERROR - logger error message
12:54:43,224 - root - CRITICAL - logger critical message
12:54:43,224 - mylogger - INFO - logger1 info message
12:54:43,224 - mylogger - INFO - logger1 info message
12:54:43,225 - mylogger - WARNING - logger1 warning message
12:54:43,225 - mylogger - WARNING - logger1 warning message
12:54:43,226 - mylogger - ERROR - logger1 error message
12:54:43,226 - mylogger - ERROR - logger1 error message
12:54:43,227 - mylogger - CRITICAL - logger1 critical message
12:54:43,227 - mylogger - CRITICAL - logger1 critical message
12:54:43,228 - mylogger - INFO - logger2 info message
12:54:43,228 - mylogger - INFO - logger2 info message
12:54:43,229 - mylogger - WARNING - logger2 warning message
12:54:43,229 - mylogger - WARNING - logger2 warning message
12:54:43,230 - mylogger - ERROR - logger2 error message
12:54:43,230 - mylogger - ERROR - logger2 error message
12:54:43,231 - mylogger - CRITICAL - logger2 critical message
12:54:43,231 - mylogger - CRITICAL - logger2 critical message
12:54:43,232 - mylogger.child1 - WARNING - logger3 warning message
12:54:43,232 - mylogger.child1 - WARNING - logger3 warning message
12:54:43,232 - mylogger.child1 - WARNING - logger3 warning message
12:54:43,234 - mylogger.child1 - ERROR - logger3 error message
12:54:43,234 - mylogger.child1 - ERROR - logger3 error message
12:54:43,234 - mylogger.child1 - ERROR - logger3 error message
12:54:43,235 - mylogger.child1 - CRITICAL - logger3 critical message
12:54:43,235 - mylogger.child1 - CRITICAL - logger3 critical message
12:54:43,235 - mylogger.child1 - CRITICAL - logger3 critical message
12:54:43,237 - mylogger.child1.child2 - DEBUG - logger4 debug message
12:54:43,237 - mylogger.child1.child2 - DEBUG - logger4 debug message
12:54:43,237 - mylogger.child1.child2 - DEBUG - logger4 debug message
12:54:43,237 - mylogger.child1.child2 - DEBUG - logger4 debug message
12:54:43,239 - mylogger.child1.child2 - INFO - logger4 info message
12:54:43,239 - mylogger.child1.child2 - INFO - logger4 info message
12:54:43,239 - mylogger.child1.child2 - INFO - logger4 info message
12:54:43,239 - mylogger.child1.child2 - INFO - logger4 info message
12:54:43,240 - mylogger.child1.child2 - WARNING - logger4 warning message
12:54:43,240 - mylogger.child1.child2 - WARNING - logger4 warning message
12:54:43,240 - mylogger.child1.child2 - WARNING - logger4 warning message
12:54:43,240 - mylogger.child1.child2 - WARNING - logger4 warning message
12:54:43,242 - mylogger.child1.child2 - ERROR - logger4 error message
12:54:43,242 - mylogger.child1.child2 - ERROR - logger4 error message
12:54:43,242 - mylogger.child1.child2 - ERROR - logger4 error message
12:54:43,242 - mylogger.child1.child2 - ERROR - logger4 error message
12:54:43,243 - mylogger.child1.child2 - CRITICAL - logger4 critical message
12:54:43,243 - mylogger.child1.child2 - CRITICAL - logger4 critical message
12:54:43,243 - mylogger.child1.child2 - CRITICAL - logger4 critical message
12:54:43,243 - mylogger.child1.child2 - CRITICAL - logger4 critical message
12:54:43,244 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
12:54:43,244 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
12:54:43,244 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
12:54:43,244 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
12:54:43,244 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
12:54:43,246 - mylogger.child1.child2.child3 - INFO - logger5 info message
12:54:43,246 - mylogger.child1.child2.child3 - INFO - logger5 info message
12:54:43,246 - mylogger.child1.child2.child3 - INFO - logger5 info message
12:54:43,246 - mylogger.child1.child2.child3 - INFO - logger5 info message
12:54:43,246 - mylogger.child1.child2.child3 - INFO - logger5 info message
12:54:43,247 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
12:54:43,247 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
12:54:43,247 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
12:54:43,247 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
12:54:43,247 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
12:54:43,249 - mylogger.child1.child2.child3 - ERROR - logger5 error message
12:54:43,249 - mylogger.child1.child2.child3 - ERROR - logger5 error message
12:54:43,249 - mylogger.child1.child2.child3 - ERROR - logger5 error message
12:54:43,249 - mylogger.child1.child2.child3 - ERROR - logger5 error message
12:54:43,249 - mylogger.child1.child2.child3 - ERROR - logger5 error message
12:54:43,250 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
12:54:43,250 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
12:54:43,250 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
12:54:43,250 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
12:54:43,250 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
先简单介绍一下,logging库提供了多个组件:Logger、Handler、Filter、Formatter。
Logger & & &&对象提供应用程序可直接使用的接口,
Handler & & &发送日志到适当的目的地,
Filter & & & & &提供了过滤日志信息的方法,
Formatter &&指定日志显示格式。
Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。
logger = logging.getLogger() & &返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。
当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有:
logging.DEBUG、、logging.WARNING、logging.ERROR、logging.CRITICAL。
Logger.debug()、()、Logger.warning()、Logger.error()、Logger.critical()
输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。
我们看到程序中
12:54:43,222 - root - WARNING - logger warning message
12:54:43,223 - root - ERROR - logger error message
12:54:43,224 - root - CRITICAL - logger critical message
从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。
这里没有用logger.setLevel()显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,
故结果只输出了大于等于WARNIING级别的信息。
另外,我们明明通过 &logger1.setLevel(logging.DEBUG) &将logger1的日志级别设置为了DEBUG,
为何显示的时候没有显示出DEBUG级别的日志信息,而是从INFO级别的日志开始显示呢?
原来logger1和logger2对应的是同一个Logger实例,
只要logging.getLogger(name)中名称参数name相同则返回的Logger实例就是同一个,且仅有一个,也即name与Logger实例一一对应。
在logger2实例中通过logger2.)设置mylogger的日志级别为,
所以最后logger1的输出遵从了后来设置的日志级别。
为什么logger1、logger2对应的每个输出分别显示两次,logger3对应的输出显示3次,logger4对应的输出显示4次......呢?
这是因为我们通过logger = logging.getLogger()显示的创建了root Logger,
而logger1 = logging.getLogger('mylogger')创建了root Logger的孩子(root.)mylogger,logger2同样。
logger3 = logging.getLogger('mylogger.child1')创建了(root.)mylogger.child1
logger4 = logging.getLogger('mylogger.child1.child2')创建了(root.)mylogger.child1.child2
logger5 = logging.getLogger('mylogger.child1.child2.child3')创建了(root.)mylogger.child1.child2.child3
而孩子,孙子,重孙……既会将消息分发给他的handler进行处理也会传递给所有的祖先Logger处理。
试着注释掉如下一行程序,观察程序输出
发现标准输出中每条记录对应两行(因为root Logger默认使用StreamHandler)
15:10:10,980 - mylogger - INFO - logger1 info message
15:10:10,980 - mylogger - INFO - logger1 info message
15:10:10,981 - mylogger - WARNING - logger1 warning message
15:10:10,981 - mylogger - WARNING - logger1 warning message
15:10:10,982 - mylogger - ERROR - logger1 error message
15:10:10,982 - mylogger - ERROR - logger1 error message
15:10:10,984 - mylogger - CRITICAL - logger1 critical message
15:10:10,984 - mylogger - CRITICAL - logger1 critical message
而在文件输出中每条记录对应一行(因为我们注释掉了logger.addHandler(fh),没有对root Logger启用FileHandler)
15:10:10,980 - mylogger - INFO - logger1 info message
15:10:10,981 - mylogger - WARNING - logger1 warning message
15:10:10,982 - mylogger - ERROR - logger1 error message
15:10:10,984 - mylogger - CRITICAL - logger1 critical message
孩子,孙子,重孙……可逐层继承来自祖先的日志级别、Handler、Filter设置,
也可以通过Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。
设置自己特别的日志级别、Handler、Filter。若不设置则使用继承来的值。
2. Handler
上述例子的输出在标准输出和指定的日志文件中均可以看到,这是因为我们定义并使用了两种Handler。
Handler对象负责发送相关的信息到指定目的地,有几个常用的Handler方法:
Handler.setLevel(lel): & & & &指定日志级别,低于lel级别的日志将被忽略
Handler.setFormatter(): &给这个handler选择一个Formatter
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
可以通过addHandler()方法为Logger添加多个Handler:
有多中可用的Handler:
logging.StreamHandler & & & & &可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息
logging.FileHandler & & & & & & & &用于向一个文件输出日志信息
logging.handlers.RotatingFileHandler & & & &类似于上面的FileHandler,但是它可以管理文件大小。
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出
logging.handlers.TimedRotatingFileHandler 和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就自动创建新的日志文件
logging.handlers.SocketHandler & & & & & & & & &使用TCP协议,将日志信息发送到网络。
logging.handlers.DatagramHandler & & & & & &&使用UDP协议,将日志信息发送到网络。
logging.handlers.SysLogHandler & & & & & & & &&日志输出到syslog
logging.handlers.NTEventLogHandler & & & & 远程输出日志到Windows NT/2000/XP的事件日志&
logging.handlers.SMTPHandler & & & & & & & & &&远程输出日志到邮件地址
logging.handlers.MemoryHandler & & & & & & & &日志输出到内存中的制定buffer
logging.handlers.HTTPHandler & & & & & & & & & &通过"GET"或"POST"远程输出到HTTP服务器
各个Handler的具体用法可查看参考书册:
https://docs.python.org/2/library/logging.handlers.html#module-logging.handlers
3. Formatter
Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S。
Formatter参数中可能用到的格式化串参见上文(logging.basicConfig()函数format参数中可能用到的格式化串:)
限制只有满足过滤规则的日志才会输出。
比如我们定义了filter = logging.Filter('a.b.c'),并将这个Filter添加到了一个Handler上,
则使用该Handler的Logger中只有名字带a.b.c前缀的Logger才能输出其日志。
取消下列两行程序的注释
标准输出中输出结果并没有发生变化,但日志文件输出中只显示了如下内容:
15:27:36,227 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:27:36,227 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:27:36,227 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:27:36,227 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:27:36,228 - mylogger.child1.child2 - INFO - logger4 info message
15:27:36,228 - mylogger.child1.child2 - INFO - logger4 info message
15:27:36,228 - mylogger.child1.child2 - INFO - logger4 info message
15:27:36,228 - mylogger.child1.child2 - INFO - logger4 info message
15:27:36,230 - mylogger.child1.child2 - WARNING - logger4 warning message
15:27:36,230 - mylogger.child1.child2 - WARNING - logger4 warning message
15:27:36,230 - mylogger.child1.child2 - WARNING - logger4 warning message
15:27:36,230 - mylogger.child1.child2 - WARNING - logger4 warning message
15:27:36,232 - mylogger.child1.child2 - ERROR - logger4 error message
15:27:36,232 - mylogger.child1.child2 - ERROR - logger4 error message
15:27:36,232 - mylogger.child1.child2 - ERROR - logger4 error message
15:27:36,232 - mylogger.child1.child2 - ERROR - logger4 error message
15:27:36,233 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:27:36,233 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:27:36,233 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:27:36,233 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:27:36,235 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:27:36,235 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:27:36,235 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:27:36,235 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:27:36,235 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:27:36,236 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:27:36,236 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:27:36,236 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:27:36,236 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:27:36,236 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:27:36,238 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:27:36,238 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:27:36,238 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:27:36,238 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:27:36,238 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:27:36,240 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:27:36,240 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:27:36,240 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:27:36,240 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:27:36,240 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:27:36,242 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:27:36,242 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:27:36,242 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:27:36,242 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:27:36,242 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
当然也可以直接给Logger加Filter。
若为Handler加Filter则所有使用了该Handler的Logger都会受到影响。而为Logger添加Filter只会影响到自身。
并取消如下几行的注释
15:32:10,746 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:32:10,746 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:32:10,746 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:32:10,746 - mylogger.child1.child2 - DEBUG - logger4 debug message
15:32:10,748 - mylogger.child1.child2 - INFO - logger4 info message
15:32:10,748 - mylogger.child1.child2 - INFO - logger4 info message
15:32:10,748 - mylogger.child1.child2 - INFO - logger4 info message
15:32:10,748 - mylogger.child1.child2 - INFO - logger4 info message
15:32:10,751 - mylogger.child1.child2 - WARNING - logger4 warning message
15:32:10,751 - mylogger.child1.child2 - WARNING - logger4 warning message
15:32:10,751 - mylogger.child1.child2 - WARNING - logger4 warning message
15:32:10,751 - mylogger.child1.child2 - WARNING - logger4 warning message
15:32:10,753 - mylogger.child1.child2 - ERROR - logger4 error message
15:32:10,753 - mylogger.child1.child2 - ERROR - logger4 error message
15:32:10,753 - mylogger.child1.child2 - ERROR - logger4 error message
15:32:10,753 - mylogger.child1.child2 - ERROR - logger4 error message
15:32:10,754 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:32:10,754 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:32:10,754 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:32:10,754 - mylogger.child1.child2 - CRITICAL - logger4 critical message
15:32:10,755 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:32:10,755 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:32:10,755 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:32:10,755 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:32:10,755 - mylogger.child1.child2.child3 - DEBUG - logger5 debug message
15:32:10,757 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:32:10,757 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:32:10,757 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:32:10,757 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:32:10,757 - mylogger.child1.child2.child3 - INFO - logger5 info message
15:32:10,759 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:32:10,759 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:32:10,759 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:32:10,759 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:32:10,759 - mylogger.child1.child2.child3 - WARNING - logger5 warning message
15:32:10,761 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:32:10,761 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:32:10,761 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:32:10,761 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:32:10,761 - mylogger.child1.child2.child3 - ERROR - logger5 error message
15:32:10,762 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:32:10,762 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:32:10,762 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:32:10,762 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
15:32:10,762 - mylogger.child1.child2.child3 - CRITICAL - logger5 critical message
发现root、mylogger、mylogger.child1的输出全部被过滤掉了。
除了直接在程序中设置Logger,Handler,Filter,Formatter外还可以
四、将这些信息写进配置文件中。
例如典型的logging.conf
程序可以这么写
五、多模块使用logging
logging模块保证在同一个python解释器内,多次调用logging.getLogger('log_name')都会返回同一个logger实例,即使是在多个模块的情况下。
所以典型的多模块场景下使用logging的方式是在main模块中配置logging,这个配置会作用于多个的子模块,
然后在其他模块中直接通过getLogger获取Logger对象即可。
子模块mod.py:
子子模块submod.py:
阅读(21001) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 弹出messages logging 的文章

 

随机推荐