ラベル Perl の投稿を表示しています。 すべての投稿を表示
ラベル Perl の投稿を表示しています。 すべての投稿を表示

2010年12月26日日曜日

[Maintenance] 改行を含むログの解析手法

デバッグログによくあるようにログが複数行に跨がって出力されている場合、単純にエラーコードでgrepが行えないわけです。

そんなときは、如何に複数行のログを1行として扱うか検討する必要があります。

ログの出力はシステムごとにポリシーが違うため、統一的なコマンドは存在しないと思いますが、コマンド作成の道筋は同様だと考えています。

方針:
1行と見なす開始点の文字列をパターン化すること、そして行末と見なす文字列をパターン化することです。

以下のようなログについて考えてみます。

2010-12-26 23:00:14 [3300] CRIT (GetData.php 30) DB error
SQL= Select test_id from Table_name Where test_id = ?
array {
0=>1000
}
2010-12-26 23:00:14 [3300] ~~~~~~

この場合、日付部(2010~~~)が開始点となり、SQL文の末尾の配列の閉じ括弧が行末です。
したがって、閉じ括弧が登場するまでが1行ですので、途中の改行は不要となります。

そこで、調査時のコマンドは以下のようになります。

Perlが使える環境ならコレ

perl -pe 's/[^}]\n//' awk_test.log | grep 'CRIT'


perl -オプション 'スクリプト' 入力ファイル
  文字列の検索: perl -ne 'print if (m/検索文字列/[i])' 入力ファイル
  文字の置換:  perl -pe 'tr/文字列1/文字列2/' 入力ファイル
  文字列の置換: perl -pe 's/検索文字列/置換文字列/[ig]' 入力ファイル

sedを使うならコレ

sed ':loop; N; $!b loop; ;s/\n/\x20/g' awk_test.log | grep 'CRIT'

ただし、回りくどい上に、1度全体行を読み込んでからの処理となるため、それなりの容量があるテキストファイルを扱うのは難しいと思われる。また、環境によっては使用できない可能性もある。

awkは全体の改行コードを変換することはできるが、部分的にはできないようです。
例えば、以下の置換はうまくいかない。どうしても改行コードが基点になるようです。

awk '{sub(/[^}]\x0A/,"\x20"); print;}' awk_test.log

全体の改行をスペースに変換(というか出力時の区切りを変更するだけ)

awk -F\n -v ORS='' '{print}' filename

# 改行
$kaigyou = '\x0A';

# 半角スペース
$space = '\x20';

# 全角スペース
$Zspace = '(?:\xA1\xA1)'; # EUC-JP
$Zspace_sjis = '(?:\x81\x40)'; # SJIS

Mac のファイルは改行コードが 0x0D (8進で 015) だが、これを UNIX の改行コード 0x0A (8進で 012) に変換する


以上です。

2009年10月5日月曜日

[MySQL] いろいろな実行手法

ストアドプロシージャを使用することで、SQLをファイル読み込み、実行できます(MySQL5.0~)

#/bin/sh
mysql -u username -p -D データベース < filename.sql(sql記述のみのファイル)



参考URL:
http://www.atmarkit.co.jp/flinux/special/mysql5/mysql5d.html

ヒアドキュメントを使用する方法です。
#!/bin/sh

mysql -u username --password='password' falcon << EOF use falcon; select c_date_ss from falcon.eagle_log; EOF 結果を格納する RESULT=`mysql -u username --password='password' falcon << EOF use falcon; select c_date_ss from falcon.eagle_log; EOF`


Perlのドライバを使った方が扱いやすいかも。ということで書いてみました。

#!/usr/bin/perl
use strict;
use warnings;
use DBI;

my $conn = DBI->connect(
"dbi:mysql:dbname:localhost", "username", "password") or die "Cannot connect\n";

my $cursor = $conn->prepare(
"SELECT column1, coulumn2 FROM table_name WHERE column1=''") or die $conn->errstr;

$cursor->execute or die $conn->errstr;

while (my ($name, $region) = $cursor->fetchrow_array()){
print "$name\t$region\n";
}

$conn->disconnect;

以上です。