Pythonで色つきログを - rainbow_logging_handler をPyPIにリリースしました

rainbow_logging_handlerスクリーンショット

rainbow_logging_handlerPyPIパッケージとしてリリースしました. 上のスクショのようにカラフルにPythonでログが表示できます.

売りポイント

☆簡単に使える

デフォルトの使い方でも綺麗に色付けされます.

☆自由度の高い色カスタマイズ

下記のように,色は(変えたければ)細かく指定することができます.

☆ログ内容と色付けが分離されている

標準モジュールのloggingでフォーマットを指定し,その色をrainbow_logging_handler.RainbowLoggingHandlerで調整(あるいはデフォルト色を利用)という風に使います.

☆ログのカラム(時刻,ファイル名,メッセージなど)毎に異なる色が付けられる

対抗馬と思われるlogutils.colorize.ColorizingStreamHandlerはログ1行ごとにしか無理.

☆どこでも使える

Python 2.6, 2.7, 3.2, 3.3 でテストしてます. Linux, Windowsでは色も確認済み.おそらくMac OSとかBSDとかでも動きます. 更に更に,Public Domainです.

インストール

pipとかeasy_installで入ります.

$ pip install rainbow_logging_handler
$ # または
$ easy_install rainbow_logging_handler

使い方

基本の使い方

# -*- coding: utf-8 -*-
import sys
import logging
from rainbow_logging_handler import RainbowLoggingHandler

def main_func():
    # `logging` モジュールを使うための準備
    logger = logging.getLogger('test_logging')
    logger.setLevel(logging.DEBUG)

    # `RainbowLoggingHandler` を使う準備
    handler = RainbowLoggingHandler(sys.stderr)
    logger.addHandler(handler)

    # 多彩なログレベルで出力
    logger.debug("デバッグ")
    logger.info("インフォ")
    logger.warn("警告")
    logger.error("エラー")
    logger.critical("深刻なエラー")
    try:
        raise RuntimeError("例外も色つきます")
    except Exception as e:
        logger.exception(e)

if __name__ == '__main__':
    main_func()

色とログフォーマットのカスタマイズ

# -*- coding: utf-8 -*-
import sys
import logging
from rainbow_logging_handler import RainbowLoggingHandler

def main_func():
    # `logging` モジュールを使うための準備
    logger = logging.getLogger('test_logging')
    logger.setLevel(logging.DEBUG)
    ## フォーマットのカスタマイズ
    formatter = logging.Formatter('%(pathname)s [%(module)s] - %(funcName)s:L%(lineno)d : %(message)s')

    # `RainbowLoggingHandler` を使う準備
    handler = RainbowLoggingHandler(
        sys.stderr,
        ## 色のカスタマイズ.
        ## `pathname`, `module`, ... など,`logging.Formatter()` で使用したカラムの色を調整
        color_pathname=('black', 'red'  , True), color_module=('yellow', None, False),
        color_funcName=('blue' , 'white', True), color_lineno=('green' , None, False),
    )
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # カスタムしたフォーマット,色で出力
    logger.debug("デバッグ")

if __name__ == '__main__':
    main_func()

開発の経緯

Pythonで色付けられそうなロガーを頑張って探した結果,一番よさげなのが http://opensourcehacker.com/2013/03/14/ultima-python-logger-somewhere-over-the-rainbow/ でした.

でもPyPIパッケージじゃないしライセンス的にもあんまり嬉しくなかったので, 作者の@moo9000さんに「パッケージにしてよ」と言ったら「自分でやれ」って言われて作りました・・・

パッケージ化の過程で色のカスタマイズとか小回りをよくした結果が今のrainbow_logging_handlerです.

終わりに,そしてお詫び

ログはカラフルな方が見る気が起きるような気がします. 皆様の開発の助けになれば幸いです.

バグ報告やpullreqはGithub:rainbow_logging_handlerまでお願いします.

この記事はPython Advent Calendar 2013の記事として書きました.

元々は「ユニットテスト, カバレッジ計測, ドキュメント生成なんかの開発ベストプラクティス書きます」と言っていたのですが, それより喜ぶ人の多そうなカラフルなログの話にしちゃいました・・・

ベストプラクティス云々はまたの機会に!

CodeIQでSQL高速化の問題出しました

とある筋から打診いただき,今をときめくCodeIQに10倍速くなる!? SQLの高速化という問題を出しました.

題目通り,遅いSQLを速くする問題です.

締切は12/18までなので,よろしければ解いてみてくだされば喜びます :)

git addしてるファイルだけをwatsonでチェック

githubのissue管理などに便利なwatsonですが,通常だと*~などを含む全ファイルから[todo] -, [fix] -といったタグを探しに行ってしまいます.

これは嬉しくない動作だったので,git addしてあるファイルだけを追跡するようにしました. 以下の1行を$HOME/.bashrcの最後の行にでも書けばOKです.

gitリポジトリでのみ使う場合

alias watson='f=$(git ls-files) && watson -f $f'

gitリポジトリ以外では全ファイルを追跡する場合

alias watson='watson -f $(git ls-files)'

結果

「gitリポジトリでのみ使う場合」の設定での結果です.

before

[~/git/foo] $ watson 
...
[ o ] ./.travis.yml
[ o ] ./.travis.yml~   ## バックアップファイルも含め全ファイルが追跡されている
[ o ] ./CHANGES.txt
...

after

[~/git/foo] $ watson   # gitリポジトリなディレクトリ
...
[ o ] .travis.yml   ## git addされていない .travis.yml~ が除かれた
[ o ] CHANGES.txt
...


[~/tmp] $ watson   # gitリポジトリでないディレクトリではエラーを吐いて停止
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

Version::NextっぽいPythonパッケージnextversion作りました

バージョン番号の管理に使えそうなPythonパッケージ, nextversion を作りました.

今のバージョン番号を文字列で与えると,次のバージョン番号(の最有力候補)が帰ってきます.

from nextversion import nextversion
nextversion('1.0a2')    # => '1.0a3'
nextversion('v1.0a2')   # => '1.0a3'  (normalized to compatible version with PEP 386)
nextversion('foo.0.3')  # => None     (impossible to normalize)

インストール

PyPI から拾ってこれます.

$ pip install nextversion

生成されるバージョン番号の規則

PEP 386 で提唱されているバージョン番号のフォーマットに従い, 次のバージョン番号が生成されます.

自分のつけているバージョン番号が PEP 386 に従ってるか調べるのにも便利かも.

使い所

Perlには同様の動作をするモジュール Version::Next があります. これがどう使われているかというと,例えば Minilla が使ってます.

Minillaは, minil release というPerlのモジュールをアップロードするコマンドを提供していて,このコマンドは自動的に次のバージョン番号をサジェストしてくれます. minnil release の役割はそれだけではなく,色んなファイルの中にある古いバージョン番号を新しいバージョン番号に変えてくれたり,ChangeLogを忘れずに編集するようにエディタを開いてくれたりします.

PythonにもPyPIへのリリース時に minil release みたいにできると便利だなと思い,その足がかりとして nextversion を作りました.

バグ報告など

https://github.com/laysakura/nextversion でお待ちしてます.

Perlで日本語全文検索できるCPANモジュール作りました

Perl全文検索を手軽にできるようにするCPANモジュール,Search::Fulltext をリリースしました.
これ単品だと英語での全文検索ができるのですが,これまた拙作の Search::Fulltext::Tokenizer::MeCab と組み合わせて使うと 日本語全文検索 ができるようになります.

ここでは日本語全文検索をするためのインストール方法と簡単な使い方などについて記述します.
尚,この記事を書いている時点での最新版は Search::Fulltext-1.02, Search::Fulltext::Tokenizer::MeCab-1.04 です.
最新の情報についてはperldocで確認するようにしてください.

セールスポイントまとめ

  • すごくシンプルに使える.メイン部分はこれだけ.
    my $fts = Search::Fulltext->new({
        docs      => \@docs,
        tokenizer => "perl 'Search::Fulltext::Tokenizer::MeCab::tokenizer'",
    });
    my $results = $fts->search($query);
    is_deeply($results, [0, 2]);
  • AND, OR, NOT, NEAR 検索などをサポート
  • メモリをはみ出しても大丈夫.SQLiteがバックエンドなので.
  • トーカナイザがPerlだけでプラガブル開発できる.

詳しくはperldocを参照してください.この記事では導入方法までを説明します.

まずは英文全文検索

Search::Fulltextのインストール

$ cpanm Search::Fulltext

Search::Fulltextの動作チェック (または使い方の確認)

以下のファイルを "check.t" という名前で保存して,

$ prove check.t

でテストしてみてください.

use strict;
use warnings;
use utf8;
use Test::More;

use Search::Fulltext;
use Search::Fulltext::TestSupport;

plan tests => 1;

my $query = 'beer';
my @docs = (
    'I like beer the best',
    'Wine makes people saticefied',  # does not include beer
    'Beer makes people happy',
);

# Common usage
{
    my $fts = Search::Fulltext->new({
        docs => \@docs,
    });
    my $results = $fts->search($query);
    is_deeply($results, [0, 2]);
}

この例では,'beer' という単語を含む0番目と2番目の文字列がヒットしています.

いよいよ日本語全文検索

MeCabのインストール

MeCabのライブラリと実行ファイルをインストールします.
もしかしたらライブラリだけでいいのかもしれませんが,よく調べてません.

$ sudo apt-get install mecab libmecab2

Search::Fulltext::Tokenizer::MeCab のインストール

$ cpanm Search::Fulltext::Tokenizer::MeCab

Search::Fulltext::Tokenizer::MeCab の動作確認 & 使い方

以下のファイルを "check-jp.t" という名前で UTF-8 で保存して,

$ prove check-jp.t

でテストしてみてください.

use strict;
use warnings;
use utf8;
use Test::More;

use Search::Fulltext;
use Search::Fulltext::Tokenizer::MeCab;

plan tests => 1;

my $query = '猫';
my @docs = (
    '我輩は猫である',
    '犬も歩けば棒に当る',
    '実家でてんちゃんって猫を飼ってまして,ものすっごい可愛いんですよほんと',
);

{
    my $fts = Search::Fulltext->new({
        docs      => \@docs,
        tokenizer => "perl 'Search::Fulltext::Tokenizer::MeCab::tokenizer'",
    });
    my $results = $fts->search($query);
    is_deeply($results, [0, 2]);
}

動きましたか?

仕組み

DBD::SQLiteを通してSQLiteのFTS4という全文検索機能を使用しています.
単なるSQLiteのラッパーだと言うこともできます.

また,日本語トークンはMeCab形態素解析で拾ってます.
MeCab形態素解析なトーカナイザの開発は,DBD::SQLiteの機能のPerl Tokenizerを使ってPerlだけで行えました.
詳しくは,'perldoc Search::Fulltext' の 'CUSTOM TOKENIZERS' のセクションを参照してください.

おわりに

気に入っていただけたでしょうか?
バグ報告やpullreqは

でウェルカムです!