<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>logging &#8211; ChaBug安全</title>
	<atom:link href="/tags/logging/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>一个分享知识、结识伙伴、资源共享的博客</description>
	<lastBuildDate>Sun, 13 Jan 2019 07:06:42 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.5</generator>
	<item>
		<title>Python模块学习之Logging日志模块</title>
		<link>/code/640.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sun, 13 Jan 2019 07:04:57 +0000</pubDate>
				<category><![CDATA[编程学习]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">/?p=640</guid>

					<description><![CDATA[最近一直想自己的批量框架，参考了POC-T框架和sqlmap的框架结构，发现logging模块被大量用来处理控制台输出以及日志记录，鉴于我自己也要写框架，那么本文就记录下我的log...]]></description>
										<content:encoded><![CDATA[<p class="md-end-block" contenteditable="true"><span class="">最近一直想自己的批量框架，参考了POC-T框架和sqlmap的框架结构，发现<span class="wpcom_tag_link"><a href="/tags/logging" title="logging" target="_blank">logging</a></span>模块被大量用来处理控制台输出以及日志记录，鉴于我自己也要写框架，那么本文就记录下我的logging模块学习记录。</span></p>
<h1 class="md-end-block md-heading" contenteditable="true"><span class="">为什么需要logging</span></h1>
<p class="md-end-block" contenteditable="true"><span class="">在开发过程中，如果程序出现了问题，我们可以使用编辑器的Debug模式来检查bug，但是在发布之后，我们的程序相当于在一个黑盒状态去运行，我们只能看到运行效果，可是程序难免出错，这种情况的话我们就需要日志模块来记录程序当前状态、时间状态、错误状态、标准输出等，这样不论是正常运行还是出现报错，都有记录，我们可以针对性的快速排查问题。</span></p>
<p class="md-end-block" contenteditable="true">因此，日志记录对于程序的运行状态以及debug都起到了很高效的作用。如果一个程序没有标准的日志记录，就不能算作一个合格的开发者。</p>
<h1 class="md-end-block md-heading" contenteditable="true">logging和print的对比</h1>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block" contenteditable="true"><span class="">logging对输出进行了分级，print没有</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block" contenteditable="true">logging具有更灵活的格式化功能，比如运行时间、模块信息</p>
</li>
<li class="md-list-item">
<p class="md-end-block" contenteditable="true">print输出都在控制台上，logging可以输出到任何位置，比如文件甚至是远程服务器</p>
</li>
</ul>
<h1 class="md-end-block md-heading" contenteditable="true">logging的结构拆分</h1>
<figure class="md-table-fig" contenteditable="false">
<table class="md-table">
<thead>
<tr class="md-end-block">
<th><span class="td-span" contenteditable="true">模块</span></th>
<th><span class="td-span" contenteditable="true">用途</span></th>
</tr>
</thead>
<tbody>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Logger</span></td>
<td><span class="td-span" contenteditable="true">记录日志时创建的对象，调用其方法来传入日志模板和信息生成日志记录</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Log Record</span></td>
<td><span class="td-span" contenteditable="true">Logger对象生成的一条条记录</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Handler</span></td>
<td><span class="td-span" contenteditable="true">处理日志记录，输出或者存储日志记录</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Formatter</span></td>
<td><span class="td-span" contenteditable="true">格式化日志记录</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Filter</span></td>
<td><span class="td-span" contenteditable="true">日志过滤器</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">Parent Handler</span></td>
<td><span class="td-span" contenteditable="true">Handler之间存在分层关系</span></td>
</tr>
</tbody>
</table>
</figure>
<h1 class="md-end-block md-heading" contenteditable="true">简单的实例</h1>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">import logging
​
logger = logging.getLogger("Your Logger")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
handler.setFormatter(formatter)
logger.addHandler(handler)
​
logger.info("this is info msg")
logger.debug("this is debug msg")
logger.warning("this is warn msg")
logger.error("this is error msg")</pre>
<p class="md-end-block" contenteditable="true">输出</p>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">2019/01/13 13:21:17 - Your Logger - INFO - this is info msg
2019/01/13 13:21:17 - Your Logger - DEBUG - this is debug msg
2019/01/13 13:21:17 - Your Logger - WARNING - this is warn msg
2019/01/13 13:21:17 - Your Logger - ERROR - this is error msg</pre>
<p class="md-end-block" contenteditable="true">我们来理解下这个实例。</p>
<p class="md-end-block" contenteditable="true">首先创建了一个<span spellcheck="false"><code>logger</code></span>对象作为生成日志记录的对象，然后设置输出级别为<span spellcheck="false"><code>DEBUG</code></span>，然后创建了一个<span spellcheck="false"><code>StreamHandler</code></span>对象<span spellcheck="false"><code>handler</code></span>，来处理日志，随后创建了一个<span spellcheck="false"><code>formatter</code></span>对象来格式化输出日志记录，然后把<span spellcheck="false"><code>formatter</code></span>赋给<span spellcheck="false"><code>handler</code></span>，最后把<span spellcheck="false"><code>handler</code></span>处理器添加到我们的<span spellcheck="false"><code>logger</code></span>对象中，完成了整个处理流程。</p>
<p class="md-end-block" contenteditable="true">知道整个流程之后我们来看一些细的东西。</p>
<h2 class="md-end-block md-heading" contenteditable="true">Level</h2>
<p class="md-end-block" contenteditable="true"><span class="" spellcheck="false"><code>logging</code></span>模块中自带了几个日志级别</p>
<figure class="md-table-fig" contenteditable="false">
<table class="md-table">
<thead>
<tr class="md-end-block">
<th><span class="td-span" contenteditable="true">等级</span></th>
<th><span class="td-span" contenteditable="true">数值</span></th>
<th><span class="td-span" contenteditable="true">对应方法</span></th>
</tr>
</thead>
<tbody>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">CRITICAL</span></td>
<td><span class="td-span" contenteditable="true">50</span></td>
<td><span class="td-span" contenteditable="true">logger.critical(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">FATAL</span></td>
<td><span class="td-span" contenteditable="true">50</span></td>
<td><span class="td-span" contenteditable="true">logger.fatal(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">ERROR</span></td>
<td><span class="td-span" contenteditable="true">40</span></td>
<td><span class="td-span" contenteditable="true">logger.error(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">WARNING</span></td>
<td><span class="td-span" contenteditable="true">30</span></td>
<td><span class="td-span" contenteditable="true">logger.warning(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">WARN</span></td>
<td><span class="td-span" contenteditable="true">30</span></td>
<td><span class="td-span" contenteditable="true"><del>logger.warn(&#8220;msg&#8221;)</del>废弃</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">INFO</span></td>
<td><span class="td-span" contenteditable="true">20</span></td>
<td><span class="td-span" contenteditable="true">logger.info(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">DEBUG</span></td>
<td><span class="td-span" contenteditable="true">10</span></td>
<td><span class="td-span" contenteditable="true">logger.debug(&#8220;msg&#8221;)</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">NOTSET</span></td>
<td><span class="td-span" contenteditable="true">0</span></td>
<td><span class="td-span" contenteditable="true">无</span></td>
</tr>
</tbody>
</table>
</figure>
<p class="md-end-block" contenteditable="true">在我们的实例中我们设置了输出级别为<span class="" spellcheck="false"><code>DEBUG</code></span></p>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">logger.setLevel(logging.DEBUG)</pre>
<p class="md-end-block" contenteditable="true">那么在<span class="" spellcheck="false"><code>DEBUG</code></span><span class="">级别之下的也就是</span><span spellcheck="false"><code>NOTSET</code></span>级别的不会被输出。</p>
<p class="md-end-block" contenteditable="true">如果我们把级别设置为<span spellcheck="false"><code>INFO</code></span>，那么我们实例的输出应该是</p>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">2019/01/13 13:21:17 - Your Logger - INFO - this is info msg
2019/01/13 13:21:17 - Your Logger - WARNING - this is warn msg
2019/01/13 13:21:17 - Your Logger - ERROR - this is error msg</pre>
<p class="md-end-block" contenteditable="true">只会输出比INFO级别高的日志。</p>
<h2 class="md-end-block md-heading" contenteditable="true">Handler</h2>
<p class="md-end-block" contenteditable="true"><span class="">logging提供的Handler有很多，我简单列举几种</span></p>
<figure class="md-table-fig" contenteditable="false">
<table class="md-table">
<thead>
<tr class="md-end-block">
<th><span class="td-span" contenteditable="true">种类</span></th>
<th><span class="td-span" contenteditable="true">位置</span></th>
<th><span class="td-span" contenteditable="true"><span class="">用途</span></span></th>
</tr>
</thead>
<tbody>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">StreamHandler</span></td>
<td><span class="td-span" contenteditable="true">logging.StreamHandler</span></td>
<td><span class="td-span" contenteditable="true">日志输出到流，可以是 sys.stderr，sys.stdout 或者文件</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">FileHandler</span></td>
<td><span class="td-span" contenteditable="true">logging.FileHandler</span></td>
<td><span class="td-span" contenteditable="true">日志输出到文件</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">SMTPHandler</span></td>
<td><span class="td-span" contenteditable="true">logging.handlers.SMTPHandler</span></td>
<td><span class="td-span" contenteditable="true">远程输出日志到邮件地址</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">SysLogHandler</span></td>
<td><span class="td-span" contenteditable="true">logging.handlers.SysLogHandler</span></td>
<td><span class="td-span" contenteditable="true">日志输出到syslog</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">HTTPHandler</span></td>
<td><span class="td-span" contenteditable="true">logging.handlers.HTTPHandler</span></td>
<td><span class="td-span" contenteditable="true">通过”GET”或者”POST”远程输出到HTTP服务器</span></td>
</tr>
</tbody>
</table>
</figure>
<h2 class="md-end-block md-heading" contenteditable="true">Formatter</h2>
<p class="md-end-block" contenteditable="true">fmt参数和datefmt两个参数分别对应日志记录的格式化和时间的格式化。</p>
<p class="md-end-block" contenteditable="true">fmt可用的占位符简单列举几种，更多请参考<span class=" md-link"><a spellcheck="false" href="https://docs.python.org/3/library/logging.html?highlight=logging%20threadname#logrecord-attributes">这里</a></span></p>
<figure class="md-table-fig" contenteditable="false">
<table class="md-table">
<thead>
<tr class="md-end-block">
<th><span class="td-span" contenteditable="true"><span class="">占位符</span></span></th>
<th><span class="td-span" contenteditable="true">作用</span></th>
</tr>
</thead>
<tbody>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(levelname)s</span></td>
<td><span class="td-span" contenteditable="true">打印日志级别的名称</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(pathname)s</span></td>
<td><span class="td-span" contenteditable="true">打印当前执行程序的路径，其实就是sys.argv[0]。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(filename)s</span></td>
<td><span class="td-span" contenteditable="true"><span class="">打印当前执行程序名。</span></span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(funcName)s</span></td>
<td><span class="td-span" contenteditable="true">打印日志的当前函数。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(lineno)d</span></td>
<td><span class="td-span" contenteditable="true">打印日志的当前行号。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(asctime)s</span></td>
<td><span class="td-span" contenteditable="true">打印日志的时间。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(thread)d</span></td>
<td><span class="td-span" contenteditable="true">打印线程ID。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(threadName)s</span></td>
<td><span class="td-span" contenteditable="true">打印线程名称。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(process)d</span></td>
<td><span class="td-span" contenteditable="true">打印进程ID。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(processName)s</span></td>
<td><span class="td-span" contenteditable="true">打印线程名称。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(module)s</span></td>
<td><span class="td-span" contenteditable="true">打印模块名称。</span></td>
</tr>
<tr class="md-end-block">
<td><span class="td-span" contenteditable="true">%(message)s</span></td>
<td><span class="td-span" contenteditable="true">打印日志信息。</span></td>
</tr>
</tbody>
</table>
</figure>
<h1 class="md-end-block md-heading" contenteditable="true">捕获Traceback</h1>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">try:
    result = 10 / 0
except Exception:
    logger.error('Faild to get result', exc_info=True)
    # 或者用下面这个
    # logging.exception('Error')
logger.info('Finished')</pre>
<p class="md-end-block" contenteditable="true">输出</p>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">2019/01/13 14:11:18 - Your Logger - ERROR - Faild to get result
Traceback (most recent call last):
  File "E:/Python/test.py", line 22, in &lt;module&gt;
    result = 10 / 0
ZeroDivisionError: division by zero
2019/01/13 14:11:18 - Your Logger - INFO - Finished</pre>
<p class="md-end-block" contenteditable="true"><span class="">这样会更合理的捕获异常信息。</span></p>
<h1 class="md-end-block md-heading" contenteditable="true">自定义日志级别</h1>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">import logging
​
INFO, WARN, ERROR, SUCCESS = range(1, 5)
# print(SYSINFO, WARN, ERROR, SUCCESS)
logging.addLevelName(INFO, '*')
logging.addLevelName(WARN, '!')
logging.addLevelName(ERROR, 'x')
logging.addLevelName(SUCCESS, '+')
​
logger = logging.getLogger('LOGGER')
handler = logging.StreamHandler()
formatter = logging.Formatter(fmt='%(asctime)s [%(levelname)s] %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(INFO)
​
logger.log(INFO, "INFO")
logger.log(WARN, "WARN")
logger.log(ERROR, "ERROR")
logger.log(SUCCESS, "SUCCESS")</pre>
<p class="md-end-block" contenteditable="true">输出</p>
<pre class="lang:default decode:true">2019/01/13 14:17:59 [*] INFO
2019/01/13 14:17:59 [!] WARN
2019/01/13 14:17:59 [x] ERROR
2019/01/13 14:17:59 [+] SUCCESS</pre>
<p>&nbsp;</p>
<p class="md-end-block" contenteditable="true">先定义级别和数值，然后调用<span class="" spellcheck="false"><code>addLevelName(级别名,'输出名')</code></span><span class="">。记得</span><span class=""><strong>数值不能小于等于0</strong></span>，注意输出日志的级别。</p>
<h1 class="md-end-block md-heading" contenteditable="true">给输出加上颜色</h1>
<p class="md-end-block" contenteditable="true">用到了一个第三方的脚本<span class="" spellcheck="false"><code>ansistrm.py</code></span><span class="">，下载地址</span><span class="md-link" spellcheck="false"><a href="https://gist.github.com/Y4er/6300ccff3a6628ea7bda24e514013476">https://gist.github.com/Y4er/6300ccff3a6628ea7bda24e514013476</a></span><span class=""> 原作者脚本不支持win10，我修复了一下。</span></p>
<p class="md-end-block" contenteditable="true">将这个脚本<span spellcheck="false"><code>ansistrm.py</code></span>和你的<span spellcheck="false"><code>log.py</code></span>放到同一目录，然后<span spellcheck="false"><code>log.py</code></span>如下内容</p>
<pre class="lang:default decode:true md-fences md-end-block ty-contain-cm modeLoaded">#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 
# @Time : 2019/1/12 21:01 
# @Author : Y4er 
# @Site : http://Y4er.com/
# @File : log.py 
​
​
import logging
​
INFO, WARN, ERROR, SUCCESS = range(1, 5)
# print(SYSINFO, WARN, ERROR, SUCCESS)
logging.addLevelName(INFO, '*')
logging.addLevelName(WARN, '!')
logging.addLevelName(ERROR, 'x')
logging.addLevelName(SUCCESS, '+')
​
logger = logging.getLogger('YOUR LOGGER')
try:
    from ansistrm import ColorizingStreamHandler
​
    handle = ColorizingStreamHandler()
    handle.level_map[logging.getLevelName('*')] = (None, 'cyan', False)
    handle.level_map[logging.getLevelName('+')] = (None, 'green', False)
    handle.level_map[logging.getLevelName('x')] = (None, 'red', False)
    handle.level_map[logging.getLevelName('!')] = (None, 'yellow', False)
except Exception as e:
    print(e)
    handle = logging.StreamHandler()
​
formatter = logging.Formatter('%(asctime)s - [%(levelname)s]  %(message)s', '%Y/%m/%d %H:%M:%S')
handle.setFormatter(formatter)
logger.addHandler(handle)
logger.setLevel(INFO)
​
​
class LOGGER:
    @staticmethod
    def info(msg):
        return logger.log(INFO, msg)
​
    @staticmethod
    def warning(msg):
        return logger.log(WARN, msg)
​
    @staticmethod
    def error(msg):
        return logger.log(ERROR, msg)
​
    @staticmethod
    def success(msg):
        return logger.log(SUCCESS, msg)
​
​
LOGGER.info("INFO msg")
LOGGER.warning("warning msg")
LOGGER.error("error msg")
LOGGER.success("success msg")</pre>
<p class="md-end-block md-focus" contenteditable="true"><span class="md-expand">在这个脚本中，我写了一个类以及其下的四个静态方法，那么可以这么调用</span></p>
<pre class="lang:default decode:true  ">LOGGER.info("INFO msg")
LOGGER.warning("warning msg")
LOGGER.error("error msg")
LOGGER.success("success msg")</pre>
<p>&nbsp;</p>
<p class="md-end-block" contenteditable="true"><span class="">运行效果：</span></p>
<p class="md-end-block" contenteditable="true"><span class="md-image md-img-loaded" contenteditable="false" data-src="https://ws1.sinaimg.cn/large/006xriynly1fz4y1l55w9j30bo038dfx.jpg"><img src="https://ws1.sinaimg.cn/large/006xriynly1fz4y1l55w9j30bo038dfx.jpg" /></span></p>
<h1 class="md-end-block md-heading" contenteditable="true">写在文后</h1>
<p class="md-end-block" contenteditable="true">是时候抛弃<span spellcheck="false"><code>print</code></span><span class="">了！</span></p>
<p class="md-end-block" contenteditable="true"><span class="">参考链接</span></p>
<p class="md-end-block" contenteditable="true"><span class="md-link"><a spellcheck="false" href="https://cuiqingcai.com/6080.html">Python中logging模块的基本用法 &#8211; 崔庆才老师</a></span></p>
<p class="md-end-block" contenteditable="true"><span class="md-link"><a spellcheck="false" href="https://gist.github.com/vsajip/758430">原版ansistrm.py &#8211; vsajip</a></span></p>
<p class="md-end-block" contenteditable="true"><span class="md-link md-expand"><a spellcheck="false" href="https://gist.github.com/vsajip/758430#gistcomment-2764744">修复ansistrm.py以支持win10</a></span></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
