python 打印堆栈和参数_Python CLog——打印日志的同时打印被调用的方法、类和文件名...

CLog的一个例子

我在文章开头,先告诉大家,CLog是干什么的,看下面的例子:

__author__ = 'baniu.yao'

from CLog import CLog

class FooClass(object):

def foo(self, text):

log = CLog()

log.write('hello world')

if __name__ == '__main__':

fc = FooClass()

fc.foo('def')

运行python example.py后,日志如下:

2014-03-30 19:09:35,582 [example.py:FooClass() --> example.py:foo('def')] hello world

CLog的作用,就是在打印日志的同时,把文件名,类名,方法名和方法的参数都打印出来了。而我们在使用CLog的时候,是完全透明的,不需要关心这些细节,这一切都是CLog完成的。

为什么我要开发一个Python日志模块

之前我一直使用Python自带的logging模块来打印日志,他功能强大,可以定制非常多的东西,但唯一让我不爽的,就是当我在看我打印的日志的时候,我根本不知道这条日志是在哪个地方打印的。特别是最近我在开发一个报警系统,设计到报警规则的解析,算是一个比较复杂的系统。我需要一个强大的日志能够帮我追踪程序的每一次关键的逻辑判断,简而言之,我要知道我的这条日志,是在哪个文件的哪个类里的哪个方法中打印的,最好还能知道方法调用的参数。

比如一个foo.py:

def Foo(object):

def foo(self):

log.log('hello world')

if __name__ == '__main__':

f = Foo()

f.foo()

然后日志中是这样的:

foo.py:Foo() --> foo.py:foo() hello world

是不是很棒?

基于这个需求,我开发了Python-CLog。其中的CLog是Chain Log的简称,因为CLog的目的是打印出整个调用链。

Python logging模块和CLog对比

logging模块支持打印调用logging方法的函数名和模块名,但这个功能非常的简陋,只支持当前调用这个logging方法所在的函数,不支持链式的追踪。我们看下面这个例子。

代码Foo1_logging.py:

import logging

from Foo2 import Foo2

logging.basicConfig(filename="./use_logging.log",

format='%(asctime)-6s: %(name)s - %(levelname)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s',

level=logging.DEBUG)

class Foo1(object):

def foo(self, text):

f2 = Foo2()

f2.foo('foo2')

logging.info('use logging in foo1')

if __name__ == '__main__':

f = Foo1()

f.foo('foo1')

代码Foo2_logging.py:

import logging

logging.basicConfig(filename="./use_logging.log",

format='%(asctime)-6s: %(name)s - %(levelname)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s',

level=logging.DEBUG)

class Foo2(object):

def foo(self, text):

logging.info('use logging in foo2')

使用logging模块的结果

我运行了Foo1_logging.py,获取到的use_logging.log如下:

2014-03-30 23:28:25,795: root - INFO - Foo2 - foo - 11 - use logging in foo2

2014-03-30 23:28:34,619: root - INFO - Foo2 - foo - 11 - use logging in foo2

2014-03-30 23:28:34,619: root - INFO - Foo1 - foo - 14 - use logging in foo1

如果说不看代码内容,我想能看懂Foo1和Foo2的依赖关系是非常困难的吧。如果还有并发的请求,那么日志几乎是没有用处的。而且,Foo1和Foo2的foo方法都接受一个参数,这个参数,也没有在日志里反应出来。

我们看看CLog对于这种情况,日志是怎样的,代码有稍许变动。

Foo1_cl.py:

from Foo2_cl import Foo2

from CLog import CLog

class Foo1(object):

def foo(self, text):

f2 = Foo2()

f2.foo('foo2')

cl = CLog()

cl.write('use CL in foo1')

if __name__ == '__main__':

f = Foo1()

f.foo('foo1')

Foo2_cl.py:

from CLog import CLog

class Foo2(object):

def foo(self, text):

cl = CLog()

cl.write('use clog in foo2')

使用CLog的日志:

2014-03-30 23:35:18,630 [Foo1_cl.py:Foo2() --> Foo1_cl.py:foo('foo1') --> Foo2_cl.py:foo('foo2')] use clog in foo2

2014-03-30 23:35:18,630 [Foo1_cl.py:Foo1() --> Foo1_cl.py:foo('foo1')] use CL in foo1

是不是清楚多了呢?调用链非常清楚,也知道foo的参数是什么,相比logging的日志,大家可以比较一下。

CLog是怎么工作的

不知道有多少人读过《Python源码分析》,Python在执行代码的时候,有一个栈帧frame的概念,我们把它理解成一张纸片,而运行一段Python代码,就是用线把一串纸片串起来执行。CLog就是调用了Python自带的inspect模块,来获取到执行时代码的frame,从中找到我们需要的信息,我们还是看example.py,这次我把CLog模块的代码改了一下,将调用write时候的frames全部打印出来:

(, '/python-chain-log/CLog.py', 28, 'get_meta_data', [' frames = inspect.stack()\n'], 0)

(, '/python-chain-log/CLog.py', 46, 'write', [' chain = self.get_meta_data()\n'], 0)

(, 'example.py', 9, 'foo', [" log.write('hello world')\n"], 0)

(, 'example.py', 13, '', [" fc.foo('def')\n"], 0)

从里面我们获取的信息,就能够得到CLog获取到的信息了。

TOOD

CLog是我在上周五花了半天开发的,下一步我会添加CLog在终端打印日志的功能,目前仅仅支持打印到日志文件。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: iostream和iostream.h是C++中用于输入输出的头文件。iostream.h是早期C++标准中使用的头文件,而iostream是现代C++标准中使用的头文件。两者的功能相同,都包含了用于输入输出的和函数,如cin、cout、cerr、clog等。但是,iostream.h已经被废弃,不再被现代C++标准所支持,建议使用iostream头文件。 ### 回答2: iostream和iostream.h都是C++编程语言中用于输入输出的库文件。 iostream是C++标准库中的一个头文件,其全称为Input/Output Stream,含有各种管理流输入输出的。iostream中定义了三个基本的I/O:istream(输入流)、ostream(输出流)和iostream(输入输出流)。其功能非常强大,可以用来读取和写入各种数据型,包括字符、数字、字符串、结构体等。 iostream.h也是一个头文件,它是C++早期用来管理输入输出的库文件,属于非标准库。它中定义了一些输入输出的函数,如cout、cin和cerr等。与iostream相比,iostream.h使用的对象和方法名要更加简单,但其使用方式已经不符合C++标准化发展的趋势,因此现在已经不再推荐使用iostream.h来进行输入输出操作。 基于上述的描述可知,iostream和iostream.h都是用于进行输入输出操作的库文件,但是前者属于标准库,后者是早期非标准化的库文件。建议在编写C++程序时,优先选择使用标准库中的iostream。 ### 回答3: iostream和iostream.h都是C++标准库中用于输入输出的头文件,它们功能相同但语法略有不同。 在C++早期版本中,iostream.h是唯一的输入输出头文件。然而,从C++标准库的更新中,iostream.h已被iostream所取代。因此,在现代的C++编程中,iostream.h已被废弃,容易出现编译问题。 iostream头文件是C++标准库的一部分,包含了4个输入输出流:istream(输入流),ostream(输出流),iostream(输入输出流)和streambuf(流缓冲区),同时还有一些基础型和函数声明。由于iostream.h和iostream都定义了相同的输入输出对象和函数,所以iostream头文件中的函数和操作符可以直接使用,而无需使用特殊的命名空间。 iostream包含了提供了标准输入流和输出流,比如cout(控制台输出)、cin(控制台输入)和cerr(标准错误输出)。此外,iostream还支持使用文件进行输入输出,以及通过网络等方式进行输入输出。它还提供了与各种数据型交互的功能,比如字节序列和文本字符串。 总的来说,iostream目前是C++标准库中常用的输入输出头文件,而iostream.h已经被废弃,推荐使用iostream。这两个头文件的主要区别在于编译问题,所以现代C++编程中应当使用iostream以保证代码的兼容性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值