2013年3月アーカイブ

Apache::LogFormat::Compiler のバージョン0.05で、ログフォーマットの %D とか %{..}i の文字を追加できるようになりました。

https://metacpan.org/release/KAZEBURO/Apache-LogFormat-Compiler-0.05/

こちらのticketを実装しました
https://github.com/kazeburo/Apache-LogFormat-Compiler/issues/1

使い方

my $log_handler = Apache::LogFormat::Compiler->new(
    '%z %{HTTP_X_FORWARDED_FOR|REMOTE_ADDR}Z',
    char_handlers => +{
        'z' => sub {
            my ($env,$req) = @_;
            return $env->{HTTP_X_FORWARDED_FOR};
        }
    },
    block_handlers => +{
        'Z' => sub {
            my ($block,$env,$req) = @_;
            # block eq 'HTTP_X_FORWARDED_FOR|REMOTE_ADDR'
            my ($main, $alt) = split('\|', $args);
            return exists $env->{$main} ? $env->{$main} : $env->{$alt};
        }
    },
);

他にもPlackへの依存がなくなったり、いくつか修正が入ってます。

監視をテーマに参加者全員がゆるふわに好き放題しゃべる Monitoring Casual Talk に参加してきました

Zussar: http://www.zusaar.com/event/521056

発表した内容はこちら。監視の話なのかどうかは謎

MHA for MySQLの基本構成と弊社で使っているMHA管理ツールの紹介です。masterha_managerの設定とプロセス管理、そしてオンラインでのマスター切り替えをWebUIから行えるの非常に便利なツールです。オープンソースになってないのに喋りました。すみません。

今回感じたのが、モニカジ参加者かいわいでの監視ツールが zabbix か munin + nagios に固まってきている点。zabbix勢はツールの使いこなしに悩んでいて、nagios勢は設定ファイルの自動生成あたりがホットな話題という感じでした。

弊社は cloudforecast + データセンターの監視サービス + 一部nagios の環境。サーバ管理ツールとの連携とかあまりしていないので、監視漏れは気をつけていないとでてくるし、そろそろツールの改良,自動化などを考えたいと思っているところ。

ちなみに nagiosの設定ファイルは Data::Section::SimpleXslateで生成してる。

#!/usr/bin/env perl

use strict;
use warnings;
use Text::Xslate;
use Data::Section::Simple qw(get_data_section);
use Log::Minimal;
$Log::Minimal::AUTODUMP=1;

my @nodes;
for my $l ( split /\n/, get_data_section('data') ) {
    chomp($l);
    my ($ip, $host, $notify) = split /\s+/, $l;
    push @nodes, {
        ipaddr => $ip,
        hostname => $host,
        is_master => ( $host =~ m!^dbm! ) ? 1 : 0,
        notify => $notify ? 1 : 0,
    };
}

my $tx = Text::Xslate->new();
print $tx->render_string(get_data_section('tmpl'), { nodes => \@nodes });

__DATA__
@@ data
10.xx.xx.74 dbm101.service
10.xx.xx.74 dbs101.service

@@ tmpl
: for $nodes -> $node {
define host{
  use                     generic-host
  max_check_attempts      3
  host_name               <: $node.hostname :>
  alias                   <: $node.hostname :>
  address                 <: $node.ipaddr :>
  contact_groups          ldnsg
}

define service{
  use                             generic-service
  host_name                       <: $node.hostname :>
  service_description             Disk Usage
  max_check_attempts              3
  normal_check_interval           15
  retry_check_interval            15
  notification_options            u,c,r
  notifications_enabled           1
  check_command                   check_mysql5_disk
}
..
:}

define hostgroup{
  hostgroup_name  mysql5
  alias           mysql5
  members         <: $nodes.map(-> $a { $a.hostname }).join(", ") :>
}

サーバが増えても1行足すだけなので、お気楽ですね。

日本語でも書く

Plack::Middleware::AxsLog バージョン 0.10 をリリースしました。

cpan: https://metacpan.org/release/Plack-Middleware-AxsLog

今までのバージョンでは、combined、common、ltsvの3つのログフォーマットしか使えなかったんだけど、新しいバージョンで任意のフォーマットが使えるようになりました。

AxsLogがPM::AccessLogに比べて速いのは、ログ文字列の生成を正規表現ではなく、単純な文字列連結でやっていたためで、その代わりにフォーマットを自由に変更できない制限がありました。

けど、このバージョンから Apache::LogFormat::Compiler を使っているので、速度を犠牲にすることなくフォーマットの変更が可能となりましたぞよ。

使い方

use Plack::Builder;

builder {
    enable 'AxsLog',
        format => '%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i" %D',
        response_time => 1,
        error_only => 1,
    $app
};

ちなみにマイクロベンチマークの結果。AccessLogよりも5倍程度高速

Benchmark: running axslog, axslog_format, error_only_axslog, log, nolog for at least 3 CPU seconds...
    axslog:  3 wallclock secs ( 3.15 usr +  0.01 sys =  3.16 CPU) @ 15955.70/s (n=50420)
axslog_format:  3 wallclock secs ( 3.19 usr +  0.01 sys =  3.20 CPU) @ 16036.25/s (n=51316)
error_only_axslog:  4 wallclock secs ( 3.14 usr +  0.01 sys =  3.15 CPU) @ 42440.32/s (n=133687)
       log:  3 wallclock secs ( 3.18 usr +  0.01 sys =  3.19 CPU) @ 3216.61/s (n=10261)
     nolog:  4 wallclock secs ( 3.13 usr +  0.00 sys =  3.13 CPU) @ 432826.20/s (n=1354746)
                      Rate    log axslog axslog_format error_only_axslog   nolog
log                 3217/s     --   -80%          -80%              -92%    -99%
axslog             15956/s   396%     --           -1%              -62%    -96%
axslog_format      16036/s   399%     1%            --              -62%    -96%
error_only_axslog  42440/s  1219%   166%          165%                --    -90%
nolog             432826/s 13356%  2613%         2599%              920%      --

scriptはこれ https://github.com/kazeburo/Plack-Middleware-AxsLog/blob/master/logbench.pl

I released Plack::Middleware::AxsLog version 0.10 at last week.

cpan: https://metacpan.org/release/Plack-Middleware-AxsLog

Plack-Middleware-AxsLog < 0.10 supports only combined, common, ltsv log format. And cannot specify the log format freely.

PM::AxsLog simply joined strings to generate logline. So it’s faster than PM::AccessLog. But does’t have ability to modify the log format.

By using Apache::LogFormat::Compiler, PM::AxsLog version 0.10 can modify log format without performance loss.

usage

use Plack::Builder;

builder {
    enable 'AxsLog',
        format => '%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i" %D',
        response_time => 1,
        error_only => 1,
    $app
};

result of micro-benchmarking

Benchmark: running axslog, axslog_format, error_only_axslog, log, nolog for at least 3 CPU seconds...
    axslog:  3 wallclock secs ( 3.15 usr +  0.01 sys =  3.16 CPU) @ 15955.70/s (n=50420)
axslog_format:  3 wallclock secs ( 3.19 usr +  0.01 sys =  3.20 CPU) @ 16036.25/s (n=51316)
error_only_axslog:  4 wallclock secs ( 3.14 usr +  0.01 sys =  3.15 CPU) @ 42440.32/s (n=133687)
       log:  3 wallclock secs ( 3.18 usr +  0.01 sys =  3.19 CPU) @ 3216.61/s (n=10261)
     nolog:  4 wallclock secs ( 3.13 usr +  0.00 sys =  3.13 CPU) @ 432826.20/s (n=1354746)
                      Rate    log axslog axslog_format error_only_axslog   nolog
log                 3217/s     --   -80%          -80%              -92%    -99%
axslog             15956/s   396%     --           -1%              -62%    -96%
axslog_format      16036/s   399%     1%            --              -62%    -96%
error_only_axslog  42440/s  1219%   166%          165%                --    -90%
nolog             432826/s 13356%  2613%         2599%              920%      --

benchmark script is here: https://github.com/kazeburo/Plack-Middleware-AxsLog/blob/master/logbench.pl

I uploaded Apache::LogFormat::Compiler to CPAN.

cpan: https://metacpan.org/release/Apache-LogFormat-Compiler
github: https://github.com/kazeburo/Apache-LogFormat-Compiler

Apache::LogFormat::Compiler compiles log_format line ‘combined’, ‘common’ or ‘%h %l %u %t “%r” %>s %b’ to perl-code.

It’s faster than Plack::Middleware::AccessLog’s way that parses log_format by regexp each request.

my $log_handler = Apache::LogFormat::Compiler->new();
my $compile_log_app = builder {
    enable sub {
        my $app = shift;
        sub {
            my $env = shift;
            my $res = $app->();
            $env->{psgi.errors}->print($log_handler->log_line($env,$res,6,0));
        }
    };
    sub{ [ 200, [], [ "Hello "] ] };
};

This sample psgiapp is 8 times faster than the app that uses PM::AcccessLog.

I have plan to use Apache::LogFormat::Compiler in Plack::Middleware::AxsLog for customize any log_format.

generated sample perl-code.

% perl -Ilib -ML -E 'say Apache::LogFormat::Compiler->new()->{log_handler_code} '
sub {
        my ($env,$res,$length,$time) = @_;
        my @lt = localtime;
        my $t = sprintf '%02d/%s/%04d:%02d:%02d:%02d %s', $lt[3], $abbr[$lt[4]], $lt[5]+1900, 
          $lt[2], $lt[1], $lt[0], $tz;
        q!! . ($env->{REMOTE_ADDR} || '-')
      . q! ! . '-'
      . q! ! . ($env->{REMOTE_USER} || '-')
      . q! ! . "[" . $t . "]"
      . q! "! . _safe($env->{REQUEST_METHOD}) . " " . _safe($env->{REQUEST_URI}) .
                       " " . $env->{SERVER_PROTOCOL}
      . q!" ! . $res->[0]
      . q! ! . (defined $length ? $length : '-')
      . q! "! . _string($env->{"HTTP_" . uc('Referer')})
      . q!" "! . _string($env->{"HTTP_" . uc('User_agent')})
      . q!"!
    }