python生成时间分割的日志

日常写应用写日志是再常见不过的事情,用python的时候发现python自带一个日志模块还挺好用的,不仅支持常见的日志分隔方案,还支持输出到各种位置(比如文件、SMTP、内存)。

网上有大量的logging模块使用教程(可以见后面的参考),这里仅说说按照时间分割的方案。

logging模块按照时间分隔可以使用TimedRotatingFileHandler,logging模块提供三个基本的handler:StreamHandlerFileHandlerNullHandler,其他的handler放在logging.handlers里面,所以需要使用TimedRotatingFileHandler则需要import logging.handlers

logging分割日志用先往默认的文件(test.log)里打,等到分割条件的时候,把之前打的那部分日志转移到对应的分割文件里(上例中就是test.log.20141016.18),这样的好处就是每次最新的都在test.log中,不过你想统一后缀(比如test.2014101618.log)似乎有点困难了,而且应该会有额外的开销。

这里仅仅是简单解释了一下logging的时间分割文件方法,不是一个十分基础和详细的文章,如果您需要更详细的内容还请看下面的参考文章。

参考:

python logging使用方法(官方)
python logging模块文档(官方文档)
python logging TimedRotatingFileHandler(官方文档)
使用python的logging模块
python标准日志模块logging及日志系统设计
python logging现学现用 – TimedRotatingFileHandler使用方法

python-snappy编译安装遇到的问题

最近使用snappy压缩数据,编译python-snappy的时候,因为没有root权限,只好自己来指定链接的地址。

build的时候发现没有可以指定的选项,只好通过指定CPLUS_INCLUDE_PATH到snappy库的include目录,指定LIBRARY_PATH到snappy的lib目录。

成功安装snappy。

之后引入snappy模块的时候,发现没有安装ffi库,真是杯具呀。编译libffi到指定目录,启动python发现python找不到这个库。

python不是查找LIBRARY_PATH和CPLUS_INCLUDE_PATH的,是通过查找C_INCLUDE_PATH和LD_LIBRARY_PATH来找到对应的头文件和库文件的。

所以我们需要把libffi和snappy的路径指定上:

snappy终于可以用啦。

如果需要每次都生效就把export语句放到.bashrc中就可以了。

pymongo保存snappy压缩数据

在使用python snappy压缩以后的数据,保存到mongo时报字符串编码错误,错误内容和下面的差不多:

bson.errors.InvalidStringData
strings in documents must be valid UTF-8

这时候可以使用bson binary格式来保存这类数据:

以上,希望能对你起到帮助。

几个语言中的迭代器

上次有朋友说python的迭代器很好用,就是不好理解,我说其实php也有迭代器的,只是很多人不知道而已。

python迭代器:

先说说python的迭代器,python的迭代器使用yield关键字来实现,可以被for调用。

还是来拿读文件来说事,我们有一个文件,里面的数据都是TAB分隔,如果我们想实现一个一行行读取的库核心的地方可以使用迭代器来写:

tab文件(html输出后估计tab变成了空格,复制的同学请注意):

迭代器代码:

这里涉及迭代器的部分在于read方法中的yield迭代器,虽然是for循环,在yield调用一次以后会挂起等待下一次调用yield,所以很多人在这里需要理解很久。所以yield在while内自然也是一样的效果。

继续阅读

php的traits和单例

最近和同事聊天时发现很多同事并不了解php的一些特性。有时他们会说python的某些特性非常有趣,确实,但我提到php中也存在一些类似特性的时候,他们表示并不了解,于是考虑写几篇关于php特性的文章。如果其他语言有这类特性,我会尝试着对比来讲解。

phper们应该都知道在5.4以后增加了一个新特性叫做traits,其文档如下:

http://php.net/manual/zh/language.oop5.traits.php

traits感觉像是让你更方便的复制粘贴代码,这些代码统一的管理着。你可以使用trait_exists方法来检查traits是否存在,使用class_uses列出所有使用traits的方法。

网上有些文章吐槽traits这个特性破坏了封装或是如何,我的层次不高,只能默默表示有时候用这东西还是比较舒服的。

比如我们写单例方法,这东西我们的项目中经常性的用到:

为了不让别人初始化,我们需要控制构造函数好克隆方法的权限,然后让类自己检查和初始化自己。

继续阅读

说说python的__del__方法

python中提供一个__del__方法,这个方法在实例释放的时候被调用,被称为析构器。

但最近使用中发现这个析构器和其他语言的析构方法不太一样,存在着一些不确定性。

比如我们在php中可以这样销毁一个对象:

此时php的析构方法__destruct()被调用。

python中我们经常会这样做

标量的销毁是没有任何问题的,但是对于对象来说,因为存在着比较复杂的引用关系,del只是把对象的引用计数减一,而不是直接调用__del__方法,这导致del方法没有达到预期内的效果。

而且,在对象的引用计数为0的时候,垃圾回收也不一定会回收此对象,而__del__方法在垃圾回收的时候才被调用。

同时,使用了__del__以后,python似乎不再追踪和释放循环引用(这点还没有经过确认)。

更多关于__del__的问题可以参考这个stack overflow question : how to call the __del__ method ? 

所以,当我们想像某些其他语言一样在调用完以后执行一些小动作的时候,比如关闭文件句柄、写点小日志之类。可以考虑使用python提供的with方案。下面是一个with的调用方法:

这个demo比较简单,python的open也支持with,但这个重复造的不完整轮子也比较容易解释with结构。这段代码在with语句结束的时候会调用__exit__方法。__enter__方法的返回值会返回给as作为f的值。

当然,__del__早晚会被调用的,如果你不着急而且控制得当,应该是没有任何问题的。

python2.7 libpython2.7.so.1.0载入问题

今天使用scons的时候遇到下面一个错误:

/home/vincent/bin/python: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory

google了一下,按照上面的方法执行了如下语句:

export LD_LIBRARY_PATH=/home/vincent/lib/python

python倒是能正常用了,但是奇怪的是跑了scons还是报上面的错误!

继续google,找了找规律,发现大家都增加了这个选项:

--enable-shared

去掉这个选项重新编译(别忘了make clean),python又能用了(本地python版本为2.7.6)。

此方法只适合不需要这个选项的情况,如果有人知道怎么回事,希望能够指出。