SSLサイトでのCSVダウンロード不具合

SYSLOG検索くんをSSL対応した所、CSVダウンロードに不具合が発生しました。

IEのみの問題のようでfirefox、chromeでは普通にダウンロードできます。

既知の問題のようでググったら結構同じ症状で困ってる人がいました。

どうもセッションを引き継ぐ所に問題があるようです。
なのでsession_start();の上にsession_cache_limiter(‘public’);
を記述してやればOKです。

IEは正直ブラウザとしての機能は低いと思います。
自分は使わなくてもwindowsに標準搭載されているのでシェアは圧倒的なんですよね・・・

SYSLOG検索くん リンクページの追加

久しぶりのSYSLOG検索くんの機能追加になります。

第6回目のsyslog.phpのページ表示は100件づつで次のページと前のページへのリンクしか作っていませんでした。
ログが多くなれば当然1ページ毎では間に合わないので4つ前後まで表示させれるようにして、さらに最初のページと最後のページも表示できるようにします。

syslog.php

ページリンク部分↓

//ページ表示
if ($all_rows < 100) {
print(“1ページ中1ページ目を表示<br>”);
} else {
print(ceil($all_rows/100).”ページ中”.ceil($page/100 + 1).”ページ目を表示<br>”);
}

//最初のページ
if ($page > 0) {
print(“<a href = syslog.php?page=0> &lt 最初のページ</a>”);
}
//4つ前の100件
if ($page > 300) {
print(“<a href = syslog.php?page=”.($page – ($page_rows * 4)).”> &lt 4つ前</a>”);
}
//3つ前の100件
if ($page > 200) {
print(“<a href = syslog.php?page=”.($page – ($page_rows * 3)).”> &lt 3つ前</a>”);
}
//2つ前の100件
if ($page > 100) {
print(“<a href = syslog.php?page=”.($page – ($page_rows * 2)).”> &lt 2つ前</a>”);
}
//前の100件
if ($page > 0) {
print(“<a href = syslog.php?page=”.($page – $page_rows).”> &lt 1つ前</a>”);
}

print (“     ”);

//次の100件
if ( $last_rows < ($all_rows-1)) {
print (“<a href = syslog.php?page=”.($page + $page_rows).”>次 &gt </a>”);
}
//2つ次の100件
if ( $last_rows + 100 < ($all_rows-1)) {
print (“<a href = syslog.php?page=”.($page + $page_rows * 2).”>2つ次 &gt </a>”);
}
//3つ次の100件
if ( $last_rows + 200 < ($all_rows-1)) {
print (“<a href = syslog.php?page=”.($page + $page_rows * 3).”>3つ次 &gt </a>”);
}
//4つ次の100件
if ( $last_rows + 300 < ($all_rows-1)) {
print (“<a href = syslog.php?page=”.($page + $page_rows * 4).”>4つ次 &gt </a>”);
}
//最後のページ
if ( $last_rows < ($all_rows-1)) {
print (“<a href = syslog.php?page=”.($all_rows – ($all_rows%100)).”>最後のページ &gt </a>”);
}

4つ前や後は単純に100件分追加しています。
最初のページに戻るのもpageを0指定してやれば問題ありません。
最後のページについてはちょっと計算する必要があります。
$all_rowsでクエリ全行を確認します。
そして全行を100行ずつ表示させるので100で割って余る値を出して
全行から余り行を引いた値を指定しています。
最後のページって基本的に100行ずつ表示して余った分のページになりますからね。

SYSLOG検索くん 第8回(最終回)

今回は最終回です。今までに作ったスクリプトやPHPファイルを
整理していきます。

まずスクリプトの保管場所は
/var/local/slog
取得ログの保管場所は
/var/local/slog/logs
HTMLファイルの保管場所は
/var/www/syslog

この3つにファイルが配置されます。

作成したスクリプトファイルは下記の通りです。
・syslogpick.sh 前日のログを取得する
・split.sh   取得したログを加工してMySQLに登録する
・today.sh   当日のログを取得してMySQLに登録する

まず日時で取得する為にcronに登録します。

# crontab -e
10 1 * * * /usr/local/slog/syslogpick.sh > /dev/null 2>&1

一応時間を少しおいて1時10分に起動するようにしました。
また、取得後にすぐMySQL登録したいのでsyslogpick.shに少し追記しました。

# vi syslogpick.sh
後ろの方です。

/var/local/slog/split.sh ←スクリプトを実行するようにしました。

echo ${DATE} syslog inport sucsess !! >> ${DIR}slog.log
echo =============================== >> ${DIR}slog.log

exit

続いてHTMLのファイルですが、
・header.html 全ページ共通のヘッダーHTML
・footer.html 全ページ共通のフッターHTML
・index.php  最初の画面
・syslog.css  CSSファイル
・syslog.php  syslog集計したのを表示させる
・csv.php   csv出力用
・pick.php   当日ログを取得する為のページ
・today.php  当日ログの取得スクリプトを実行する

今回はCSSファイルだけ./css配下にしていますが、あとはホームディレクトリに配置します。

場所を変えるときはパスを変えるように気をつけて下さい。

また、logsにログが溜まってしまいますので定期的に削除します。
logrotateにてローテートさせてもいいですが、頭に日付を付けているのでそこで
2ヶ月前のログを削除するようにします。

# vi split.sh

## tmp log delete
rm -f ${DIR}${DATEDAY}_syslog.tmp1
rm -f ${DIR}${DATEDAY}_syslog.tmp2

## 2 manths ago log dalete
rm -f ${DIR}${DELDATE}_syslog
rm -f ${DIR}${DELDATE}_syslog.txt

## 2 manths ago data dalete
mysql -u root -psystem syslogdb -e “delete from syslogtable where DATE = ${DELDATE};”

## check date clear
echo > ${DIR}syslog_check.txt

slogについてはさほど大きくならないので何もしていませんが、logrotateで月1か週1位でローテート
させて4世代後に削除等にしたらいいと思います。

以上でSYSLOG検索くんの製作を終了します。

SYSLOG検索くん 第7回

今回は当日のログの取り込みを実施する部分になりますが、
まずは前回の残りであるcsv.phpを作ります。

<?php
/* セッション作成 */
session_start();

/* セッションからの展開 */
$node = $_SESSION[‘node’];
$moji = $_SESSION[‘moji’];
$years = $_SESSION[‘years’];
$months = $_SESSION[‘months’];
$days = $_SESSION[‘days’];
$yeare = $_SESSION[‘yeare’];
$monthe = $_SESSION[‘monthe’];
$daye = $_SESSION[‘daye’];

header(“Content-Type: application/octet-stream”);
header(“Content-Disposition: attachment; filename=syslog.csv”);

/* ヘッダー作成 */
print( “date,time,node,log,\n”);

/* ログイン */
$link = mysql_connect(‘localhost’, ‘root’, ‘system’);
if (!$link) {
die(‘接続失敗です。’.mysql_error());
}

/* データベース選択 */
$db_selected = mysql_select_db(‘syslogdb’, $link);
if (!$db_selected){
die(‘データベース選択失敗です。’.mysql_error());
}

mysql_set_charset(‘utf8’);

/* 検索用2桁登録 */
$months = sprintf(“%02d”,$months);
$days = sprintf(“%02d”,$days);
$monthe = sprintf(“%02d”,$monthe);
$daye = sprintf(“%02d”,$daye);

$select_all = “select * from syslogtable where date between ‘$years$months$days’ and ‘$yeare$monthe$daye’ and node like ‘%$node%’ and log like ‘%$moji%'”;
$result_all = mysql_query($select_all);

//値を取得
while($row = mysql_fetch_assoc($result_all)){

//本文出力
print($row[‘date’].”,”.$row[‘time’].”,”.$row[‘node’].”,”.$row[‘log’].”,\n”);
}

?>

csv出力で重要なのは下記の2文だけです。

header(“Content-Type: application/octet-stream”);
header(“Content-Disposition: attachment; filename=syslog.csv”);

MIMEタイプを設定して(octet-streamが無難です)名前を付けて保存する設定を入れるだけです。
あとは単純にセッションを引き継いできて同じ内容を出力させるようにしているだけです。

続いて当日分のログの取り込みですが、基本的に通常のログの取り込みと同じです。
サイト画面から実行できるようにする為にHTMLファイルのヘッダー部分で指定している
pick.phpというファイルを作ります。

pick.php
<?php include(“header.html”); ?>

<p>当日のSYSLOG取得はこちら</p>
<button type=button onclick=”window.open(‘today.php’,’_blank’);”>cisco</button>

<?php include(“footer.html”); ?>

とりあえずボタンを作ってphpを動かすようにしてみました。
実際取り込みをするのはシェルなのでtoday.phpではシェルを実行するようにしています。

<?php

$sys =’/bin/sh /usr/local/slog/today.sh’;
$output = array();
$ret = null;

exec($sys,$output,$ret);

print_r(“SYSLOGの取り込みが完了しました。”);

?>
<br>
<button type=button onclick=”window.close();”>閉じる</button>

execにて取り込み用のスクリプトを動かしています。
で実際のスクリプトは下記のように作りました。

#!/bin/sh
#
# syslog pick up
#
#
#
#############################################################
## set LANG
export LANG=ja

## last day infomation
DATE=`date –date ‘1 days ago’ +%Y`
DATEDAY=`date –date ‘1 days ago’ +%Y%m%d`
TODAY=`date +%Y%m%d`

## log directry
DIR=/usr/local/slog/logs/

## syslog today get
expect -c ”
set timeout 60
spawn scp user@192.168.1.1:/var/log/syslog/syslog.0 ${DIR}${DATE}_syslog
expect {
\”Are you sure you want to continue connecting (yes/no)?\” {
send \”yes\n\”
expect \”パスワード\”
send \”password\n\”
} \”パスワード\” {
send \”password\n\”
}
}

expect {
\”100%\” {exit}
}

## reset LANG
LANG=en_US.UTF-8

## today syslog
awk -v YEAR=$DATE ‘{printf(“%d%s%02d|%s|%s\n”,YEAR,$1,$2,$3,$4)}’ ${DIR}${TODAY}_syslog > ${DIR}${TODAY}_syslog.tmp1

awk ‘{for(i=5;i<NF;i++){printf(“%s “,$i)}print $NF}’ ${DIR}${TODAY}_syslog > ${DIR}${TODAY}_syslog.tmp2

/usr/bin/perl -pi -e ‘s/Jan/01/g;s/Feb/02/g;s/Mar/03/g;s/Apr/04/g;s/May/05/g;s/Jun/06/g;s/Jul/07/g;s/Aug/08/g;s/Sep/09/g;s/Oct/10/g;s/Nov/11/g;s/Dec/12/g’ ${DIR}${TODAY}_syslog.tmp1

CNT1=`cat ${DIR}${TODAY}_syslog.tmp1 | wc -l`
CNT2=`cat ${DIR}${TODAY}_syslog.tmp2 | wc -l`

if [ $CNT1 != $CNT2 ];then
echo “syslog count unmatch !!” >> ${DIR}slog.log
exit
else
paste -d “|” ${DIR}${TODAY}_syslog.tmp1 ${DIR}${TODAY}_syslog.tmp2 > ${DIR}today_syslog.txt
fi

## last check
if [ -e ${DIR}today_syslog_dif.txt ];then
rm -f ${DIR}today_syslog_dif.txt
fi
diff ${DIR}syslog_check.txt ${DIR}today_syslog.txt | grep “^>” | sed ‘s/^> //g’ > ${DIR}today_syslog_dif.txt

## mysql inport
mysql -u root -psystem syslogdb -e “load data local infile \”${DIR}today_syslog_dif.txt\” into table syslogtable fields terminated by ‘|’ lines terminated by ‘\n’;”

## next checkfile
cat ${DIR}today_syslog.txt > ${DIR}syslog_check.txt

## tmp log delete ##
rm -f ${TODAY}_syslog.tmp1
rm -f ${TODAY}_syslog.tmp2

ログをSYSLOGサーバから取得するのとMYSQLへ投入するのも全てまとめてみました。
これで当日のログの取得ができます。

これまでのものでひとまずはSYSLOG検索くんは要件を満たした形で動くようになっているはずです。

次回は最終回、まとめになります。

SYSLOG検索くん 第6回

今回はPHPでMySQLからの検索して結果を表示する画面を作成します。
ひとまず説明は後でファイルを作成します。
ファイル名は「syslog.php」になります。

syslog.php
<?php
/* セッション作成 */
session_start();

/* 年月日判定 */
if(isset($_POST[‘send’])) {
$years = $_POST[‘years’];
$months = $_POST[‘months’];
$days = $_POST[‘days’];
$yeare = $_POST[‘yeare’];
$monthe = $_POST[‘monthe’];
$daye = $_POST[‘daye’];
} else {
$years = date(“Y”,strtotime(“-1 day”));
$months = date(“m”,strtotime(“-1 day”));
$days = date(“d”,strtotime(“-1 day”));
$yeare = date(“Y”);
$monthe = date(“m”);
$daye = date(“d”);
}

/* ページ表示判定 */
if(isset($_GET[‘page’]) == false){
$page = 0;
$node = $_POST[‘node’];
$moji = $_POST[‘moji’];
} else {
/* セッションからの展開 */
$page = $_GET[‘page’];
$node = $_SESSION[‘node’];
$moji = $_SESSION[‘moji’];
$years = $_SESSION[‘years’];
$months = $_SESSION[‘months’];
$days = $_SESSION[‘days’];
$yeare = $_SESSION[‘yeare’];
$monthe = $_SESSION[‘monthe’];
$daye = $_SESSION[‘daye’];
}

/* 維持セッション登録 */
$_SESSION[‘node’] = $node;
$_SESSION[‘moji’] = $moji;
$_SESSION[‘years’] = $years;
$_SESSION[‘months’] = $months;
$_SESSION[‘days’] = $days;
$_SESSION[‘yeare’] = $yeare;
$_SESSION[‘monthe’] = $monthe;
$_SESSION[‘daye’] = $daye;

/* 固定値 */
$page_rows = 100;
$last_rows = $page + $page_rows -1;

/* セレクトオプションのループ設定 */
function optionLoop($start, $end, $value = null){

for($i = $start; $i <= $end; $i++){
if(isset($value) && $value == $i){
echo “<option value=\”{$i}\” selected=\”selected\”>{$i}</option>”;
}else{
echo “<option value=\”{$i}\”>{$i}</option>”;
}
}
}

?>
<?php include(“header.html”); ?>
<h2>SYSLOG抽出</h2>
<div style=”float:left;” id=”nav”>
<form name=”node” action=”cisco.php” method=”post”>
<b>抽出期間</b><br>

<select name=”years”>
<?php optionLoop(‘2012’, date(“Y”), $years);?>
</select> 年 

<select name=”months”>
<?php optionLoop(‘1′, ’12’, $months);?>
</select> 月 

<select name=”days”>
<?php optionLoop(‘1′, ’31’, $days);?>
</select> 日 
~ 

<select name=”yeare”>
<?php optionLoop(‘2012’, date(“Y”), $yeare);?>
</select> 年 
<select name=”monthe”>
<?php optionLoop(‘1′, ’12’, $monthe);?>
</select> 月 
<select name=”daye”>
<?php optionLoop(‘1′, ’31’, $daye);?>
</select> 日 
<br>
<b>ノード名</b>
<input style=”background-color:#CECFCE;” type=”text” name=”node” id=”node” value=”<?php print(htmlspecialchars($_SESSION[‘node’], ENT_QUOTES)); ?>” > 
<b>文字列</b>
<input style=”background-color:#CECFCE;” type=”text” name=”moji” id=”moji” value=”<?php print(htmlspecialchars($_SESSION[‘moji’], ENT_QUOTES)); ?>” > <input type=”submit” name=”send” value=”検索”><br>
</form>
</div>
<div id=”contents”>
<?php
/* ログイン */
$link = mysql_connect(‘localhost’, ‘admin’, ‘password’);
if (!$link) {
die(‘接続失敗です。’.mysql_error());
}

/* データベース選択 */
$db_selected = mysql_select_db(‘syslogdb’, $link);
if (!$db_selected){
die(‘データベース選択失敗です。’.mysql_error());
}

mysql_set_charset(‘utf8’);

/*テーブルヘッダを出力する。 */
print( “<table>” );
print( “<tr>” );
print( “<th>年月日</th>” );
print( “<th>時間</th>” );
print( “<th>ノード名</th>” );
print( “<th>ログ情報</th>” );
print( “</tr>” );

/* データ検索条件 */

/* 検索用2桁登録 */
$months = sprintf(“%02d”,$months);
$days = sprintf(“%02d”,$days);
$monthe = sprintf(“%02d”,$monthe);
$daye = sprintf(“%02d”,$daye);

/* エラー判定 */
if(isset($_POST[‘send’]) == false && isset($_GET[‘page’]) == false){
print(“</table>”);
} else if ($years > $yeare){
print(“</table>”);
echo 抽出年に誤りがあります。;
echo “$years$months$days,$yeare$monthe$daye”;
} else if ($years >= $yeare && $months > $monthe){
print(“</table>”);
echo 抽出月に誤りがあります。;
echo “$years$months$days,$yeare$monthe$daye”;
} else if ($years >= $yeare && $months >= $monthe && $days > $daye){
print(“</table>”);
echo 抽出日に誤りがあります。;
echo “$years$months$days,$yeare$monthe$daye”;
} else {

/* 該当テーブルの行数を取得 */
$select_all = “select * from syslogtable where date between ‘$years$months$days’ and ‘$yeare$monthe$daye’ and node like ‘%$node%’ and log like ‘%$moji%'”;
$result_all = mysql_query($select_all);
$all_rows = mysql_num_rows($result_all);
/* SQL実行 */
$select = “select * from syslogtable where date between ‘$years$months$days’ and ‘$yeare$monthe$daye’ and node like ‘%$node%’ and log like ‘%$moji%’ limit $page,$page_rows”;
$result = mysql_query($select);
if (!$result) {
die(‘1クエリーが失敗しました。’.mysql_error());
}

while ($row = mysql_fetch_assoc($result)){
print(“<tr>”);
print(“<td>”.$row[‘date’].”</td>”);
print(“<td>”.$row[‘time’].”</td>”);
print(“<td>”.$row[‘node’].”</td>”);
print(“<td>”.$row[‘log’].”</td>”);
print(‘</tr>’);
}
print(“</table>”);

//ページ表示
if ($all_rows < 100) {
print(“1ページ中1ページ目を表示<br>”);
} else {
print(ceil($all_rows/100).”ページ中”.ceil($page/100 + 1).”ページ目を表示<br>”);
}

//前の100件
if ($page > 0) {
print(“<a href = cisco.php?page=”.($page – $page_rows).”>&lt 前の100件</a>     ”);
}

//次の100件
if ( $last_rows < ($all_rows-1)) {
print (“<a href = cisco.php?page=”.($page + $page_rows).”>次の100件 &gt</a>”);
}
print (“<br><a href = csv.php?csv=syslog>csv出力する</a>”);
}

?>
</div>
<!– 回り込み解除 –>
<div style=”clear:both;”></div>

<?php include(“footer.html”); ?>

ざっと全部書きましたが機能要件を満たす形で作成しています。
要件から追加した機能としては100件ずつ表示させるようにしています。
あんまりいっぺんに表示されても大変ですから・・・
当然100件以上のログが見れないのは困りますから次の100件へのリンクと
戻るリンクを作成しています。
年月日のプルダウンは普通に数字を入れてもいいのですがコードが長くなるのでループ設定をしています。
あとPHPの部分とHTMLの部分でコメント判定が変わってくるので注意して下さい。
PHP → /* 中が全部コメント */
    // この行はコメント

HTML → <!– 中が全部コメント –>

また抽出の為にcsv.phpというファイルにて出力させるようにしています。
csv.phpについては次回説明します。

今回はPHPでの集計部分をやりました。次回は当日ログの取り込み部分です。

SYSLOG検索くん 第5回

今まではサーバの設定をしていましたが、今回はWEBインターフェースの作成になります。
外部UI部分はは自分で作らなくてもHTMLのテンプレートは無料で結構配布されているので
それを使ったほうが時間節約にもなるのでそちらの方がいいかもしれません。

ひとまず今回は私は作った方法について紹介します。
まずは簡単にindex.htmlを1枚作成します。

index.html
<!DOCTYPE html>
<html lang=”ja”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<meta http-equiv=”Content-Style-Type” content=”text/css” />
<meta http-equiv=”Content-Script-Type” content=”text/javascript” />
<link rel=”stylesheet” href=”css/syslog.css” type=”text/css” />
<title>SYSLOG検索くん</title>
</head>
<body>
<div id=”top”>
<div id=”header”>
<h1><a href=”index.php”>SYSLOG検索くん</a></h1>
<p>直近のsyslogを調べるサイト</p>
</div><!– /#header–>
<div id=”menu”>
<ul>
<li><a href=”index.php”>HOME</a></li>
<li><a href=”syslog.php”>SYSLOG</a></li>
<li><a href=”pick.php”>本日分の読み込み</a></li>
<li><a href=”help.php”>help</a></li>
</ul>
</div><!– /#menu–>
<div id=”contents”>
<h2>制作者より</h2>
<p>
SYSLOGサーバに送られてくるログを簡単にpickupできるようにデータベースに取り込んでいます。
</p>
<p>
毎日1:00に前日のログを取り込みます。
</p>
<p>
当日のログが必要な際は本日分の読み込みからログを取得して下さい。(現在未実装)
</p>

<ul>
<b><更新履歴></b>
<li></li>
<li>2013/7/22 SYSLOG検索くん β版公開</li>
<li>2013/7/18 SYSLOG検索くん 製作スタート</li>
</ul>
</div><!– /#contents–>
<div id=”pageTop”>
<a href=”#top”>ページのトップへ戻る</a>
</div><!– /#pageTop–>
<div id=”footer”>
<div class=”copyright”>© 2013 nekofamily All Rights Reserved.</div>
</div><!– /#footer–>
</div><!– /#top–>
</body>
</html>

基本のindexページですが、単純なHTML情報のみです。構成としてはHOMEとSYSLOG(実際にログ表示する画面)、
今日分のログを取り込む画面、HELP画面と4つあります。
すべてのページをそれぞれ作るのですが同じ内容の部分(ヘッダーとフッター)は同じなので切り出してしまいます。
上記のページをheader.html、footer.html、index.phpの3部に分けます。
header.html
<!DOCTYPE html>
<html lang=”ja”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<meta http-equiv=”Content-Style-Type” content=”text/css” />
<meta http-equiv=”Content-Script-Type” content=”text/javascript” />
<link rel=”stylesheet” href=”css/syslog.css” type=”text/css” />
<title>SYSLOG検索くん</title>
</head>
<body>
<div id=”top”>
<div id=”header”>
<h1><a href=”index.php”>SYSLOG検索くん</a></h1>
<p>直近のsyslogを調べるサイト</p>
</div><!– /#header–>
<div id=”menu”>
<ul>
<li><a href=”index.php”>HOME</a></li>
<li><a href=”syslog.php”>SYSLOG</a></li>
<li><a href=”pick.php”>本日分の読み込み</a></li>
<li><a href=”help.php”>help</a></li>
</ul>
</div><!– /#menu–>

footer.html
<div id=”pageTop”>
<a href=”#top”>ページのトップへ戻る</a>
</div><!– /#pageTop–>
<div id=”footer”>
<div class=”copyright”>© 2013 nekofamily All Rights Reserved.</div>
</div><!– /#footer–>
</div><!– /#top–>
</body>
</html>

index.php
<?php include(“header.html”); ?>

<div id=”contents”>
<h2>制作者より</h2>
<p>
SYSLOGサーバに送られてくるログを簡単にpickupできるようにデータベースに取り込んでいます。
</p>
<p>
毎日1:00に前日のログを取り込みます。
</p>
<p>
当日のログが必要な際は本日分の読み込みからログを取得して下さい。(現在未実装)
</p>

<ul>
<b><更新履歴></b>
<li></li>
<li>2013/7/22 SYSLOG検索くん β版公開</li>
<li>2013/7/18 SYSLOG検索くん 製作スタート</li>
</ul>
</div><!– /#contents–>

<?php include(“footer.html”); ?>

3分割で注意することはindex.phpの部分です。
phpのincludeで頭にheader.htmlを呼び出して、最後にfooter.htmlを呼び出しています。
この2つを分割するだけでもHTMLの更新作業などが格段に楽になります。

さて、まだこの状態では真っ白な画面に文字が並んでいるだけの状態です。
CSSで画面を装飾していきます。
header.htmlでcss/syslog.cssとcssの場所を指定しています。
指定の場所に指定のファイル名で作成します。
syslog.css

@charset “UTF-8”;

/* main */
html {
overflow-y:scroll;
}

body {
margin:0;
padding:0;
line-height: 160%;
letter-spacing:1px;
font-family: Arial, ‘MS Pゴシック’, sans-serif;
font-size: 14px;
color:#333;
}

h1,h2,h3,h4,h5,h6 {
margin:0;
padding:0;
}

a {
color:#68903C;
text-decoration:none;
}

a:hover {
color:#92C45B;
}

ul {
margin:0 0 1em 0;
padding:0;
}

li {
margin:0 0 0 40px;
padding:0;
}

/* div main */
#top {
width:800px;
margin:20px auto;
padding:0 20px;
border:1px solid #CECFCE;
background:#fff;
}

#header {
width:800px;
position:relative;
}

#navi {
position:absolute;
top:20px;
right:0;
}

#menu {
float:left;
width:800px;
margin:10px 0;
background:#333;
}

#contents {
clear:both;
float:none;
}

#pageTop {
clear:both;
}

#footer {
width:800px;
clear:both;
padding:10px 0;
}

/* header custom */
#header h1 {
padding:20px 0;
font-weight:bold;
font-size:28px;
}

#header h1 a {
color:#333;
}

#header h1 a:hover {
color:#92C45B;
}
#header p {
margin:0;
padding:0 0 5px 0;
border-bottom:1px solid #CECFCE;
}

/* navi custom */
#navi ul {
list-style:none;
}

#navi li {
float:left;
margin:0 0 0 22px;
padding:0 0 0 20px;
font-size:11px;
}

#navi li a {
border-bottom:1px solid #CECFCE;
}

/* menu custom */
#menu ul {
list-style:none;
margin:0;
padding:0;
}

#menu li {
float:left;
margin:0;
padding:0;
}

#menu li a {
display:block;
padding:8px 20px;
color:#fff;
}

#menu li a:hover {
color:#fff;
background-color:#088A08;
border:none;
}

/* contents costom */
#contents h2 {
margin-bottom:10px;
padding:10px 0;
font-weight:bold;
font-size:16px;
border-bottom:2px solid #ddd;
}

#contents h3 {
margin-bottom:2px;
padding:2px 0 2px 10px;
font-weight:bold;
font-size:15px;
line-height:1.2;
border-left:5px solid #333;
}

#contents h4 {
margin-bottom:2px;
font-weight:bold;
font-size:14px;
border-bottom:2px solid #666;
}

#contents h5 {
margin-bottom:2px;
padding:2px 5px;
font-weight:bold;
font-size:13px;
background:#ececec;
}

#contents h6 {
font-weight:bold;
font-size:13px;
}

#contents table {
width:100%;
border-collapse: collapse;
}

#contents table th {
padding:5px;
font-size:12px;
text-align:left;
border:1px solid #ddd;
background:#333;
color:#fff;
}

#contents table td {
padding:5px;
font-size:12px;
text-align:left;
border:1px solid #ddd;
background:#cfcfcf;
}

/* pagetop */
#pageTop {
padding:10px 0;
text-align:right;
}

#pageTop a {
padding:0 0 0 12px;
}

/* copyright */
.copyright {
text-align:center;
font-size:11px;
font-style:normal;
padding:20px 0;
border-top:1px solid #CECFCE;
}

結構ざっくりした感じで作っているので細かいところは都度追加していく感じで・・・
ここは好みがでてくるところだと思うので好きなように作るといいと思います。

次回はPHPでの集計画面についてです。

SYSLOG検索くん 第4回

前回ログを取得しましたがsyslogの設定や取得している機器で変わってくるので一概にこれとは言えませんが、
今回の私が対象とするログの構成は下記の通りです。
月  日 時間   syslogを送った機器 送信回数 log内容
Jul 20 09:00:00 hogeserver 9999: 実施のsyslog情報

送信回数まではsyslogの設定で固定なのでここは変わる事がない事がわかっています。
ただ、送信回数は要らないので今回は月日と時間と機器名とlogという4カラムに分けたいと思います。

ログを加工するスクリプトを作成します。
※作業場所は常にホームディレクトリ(/usr/local/slog)です。

# vi split.sh
#!/bin/sh
LANG=en_US.UTF-8

## last day infomation
DATE=`date –date ‘1 days ago’ +%Y`
DATEDAY=`date –date ‘1 days ago’ +%Y%m%d`
TODAY=`date +%Y%m%d`
DELDATE=`date –date ‘2 months ago’ +%Y%m%d`
## log directry
DIR=/usr/local/slog/logs/

## syslog custom
awk -v YEAR=$DATE ‘{printf(“%d%s%02d|%s|%s\n”,YEAR,$1,$2,$3,$4)}’ ${DIR}${DATEDAY}_syslog > ${DIR}${DATEDAY}_syslog.tmp1

awk ‘{for(i=5;i ${DIR}${DATEDAY}_syslog.tmp2

/usr/bin/perl -pi -e ‘s/Jan/01/g;s/Feb/02/g;s/Mar/03/g;s/Apr/04/g;s/May/05/g;s/Jun/06/g;s/Jul/07/g;s/Aug/08/g;s/Sep/09/g;s/Oct/10/g;s/Nov/11/g;s/Dec/12/g’ ${DIR}${DATEDAY}_syslog.tmp1

CNT1=`cat ${DIR}${DATEDAY}_syslog.tmp1 | wc -l`
CNT2=`cat ${DIR}${DATEDAY}_syslog.tmp2 | wc -l`

if [ $CNT1 != $CNT2 ];then
echo “syslog count unmatch !!” >> ${DIR}slog.log
exit
else
paste -d “|” ${DIR}${DATEDAY}_syslog.tmp1 ${DIR}${DATEDAY}_syslog.tmp2 > ${DIR}${DATEDAY}_syslog.txt
fi

簡単に内容を説明すると
最初のLANG設定は後にsyslogの抽出との連携させる為に入れています。
年がログからでは分からなかったのでawkでYEARに昨日の年を取得してカラムのピックアップ時に追加しています。
また、mysqlへの取り込みでスペース区切りや,区切りではログに含まれて予期せぬ場所で切れてしまうのでログに
含まれていない「|」で区切るようにしました。
そして年月日を数字化して1つのカラムにしています。printfの部分でカラム分けをしています。
あとはperlで月の英語部分を数字に置き換えています。
tmp1で1~3カラムを作ってtmp2で4カラム部分を作っています。
最後にpasteしてまとめています。

集計途中のファイルができるのでスクリプトの最後に
rm -f *syslog.tmp1
rm -f *syslog.tmp2
で削除してもいいですし、削除用スクリプトを作ってもいいと思います。

次にmysqlのテーブル作成です。
成型したカラムにある形のテーブルを作っていきます。
データベースと利用ユーザーは2回目の際に作ったものを利用します。

# mysql -u admin -ppassword ←-pだけで次にパスワード入力にしてもいいと思います。
mysql> use syslogdb; ←データベースに移動します。
mysql> create table syslogtable(date int(10),time varchar(10),node varchar(50),log varbinary(1000)); ←カラムの値は想定される範囲で決めて下さい。
logのカラムをバイナリにしているのは文字化けしたログがある為にバイナリで取得するようにしています。
mysql> show tables;  確認
+——————–+
| Tables_in_syslogdb |
+——————–+
| syslogtable |
+——————–+
1 row in set (0.00 sec)

mysql> desc syslogtable;  確認
+——-+—————–+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+——-+—————–+——+—–+———+——-+
| date | int(10) | YES | | NULL | |
| time | varchar(10) | YES | | NULL | |
| node | varchar(50) | YES | | NULL | |
| log | varbinary(1000) | YES | | NULL | |
+——-+—————–+——+—–+———+——-+
4 rows in set (0.01 sec)

取り込めるかどうか確認してみます。
mysql> load data local infile “/usr/local/slog/logs/20130719_syslog.txt” into table syslogtable fields terminated by ‘|’ lines terminated by ‘\n’;
Query OK, 18558 rows affected, 65535 warnings (0.12 sec)
Records: 18558 Deleted: 0 Skipped: 0 Warnings: 55674

mysql> select * from syslogtable; ←少なければtable中身を全部表示させてみます。多ければwhere等で制限して下さい。

問題ない事が確認できたらデータは一旦消します。
mysql> delete from syslogtable;
Query OK, 18558 rows affected (0.00 sec)

ひとまずログを取り込める所まで来ましたので次はインターフェース部分を作っていきます。

次回はサイトの外部UIを作成です。

SYSLOG検索くん 第3回

初回の基本設計部分でSYSLOGサーバからlogファイルをscpでコピーする形にすると
していますが、syslog検索くんのホームディレクトリを作成します。

ホームディレクトリ
# mkdir /usr/local/slog

続いてログを保管するディレクトリを作成します。
# mkdir /usr/local/slog/logs

ちなみに同じ階層にあるのでいっぺんに作る場合は-pオプションを付ければ1回でできます。
# mkdir -p /usr/local/slog/logs

ホームディレクトリにはログを集計するスクリプトを配置
その下のlogsには集計用のログを保存する事にします。

次にHTMLファイルを配置するディレクトリですが、専用サーバであればapacheのドキュメントルートに配置して
問題ありませんが、今回は/var/www/syslogというディレクトリを作成しそこに配置したいと思います。
/etc/httpd/conf.d/にAliasの記述をします。

# vi /etc/httpd/conf.d/syslog.conf

Alias /syslog /var/www/syslog

<Directory “/var/www/syslog”>
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>

設定後はapacheを再起動して下さい。
きちんとAliasが有効になっているかinfo.phpファイルを移動させて確認します。
# mv /var/www/html/info.php /var/www/syslog/

移動後URL確認を実施します。
http://nekoneko.com/syslog/info.php  ←php情報が見れる事を確認
http://nekoneko.com/info.php  ←Not Foundになるはずです

次に実際にSYSLOGサーバからログを取得するスクリプトを作ります。
接続方法はexpectを使用します。
まずはyumでインストールします。

# yum install expect

================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
expect i386 5.43.0-8.el5 base 158 k

次に実際にscpできるかスクリプトを書きます。仮にシェル名はsyslogpick.shとします。
# vi syslogpick.sh
#!/bin/sh
## set LANG
export LANG=ja  ←SYSLOGサーバの環境に合わせています。SYSLOGサーバのLANGにして下さい

## last day
DATE=`date –date ‘1 days ago’ +%Y%m%d`  ←前日の日付を取得しています

# log directry
DIR=/usr/local/slog/logs/  ←ログを保存するディレクトリを指定しています

echo ${DATE} syslog inport start >> ${DIR}slog.log  ←スクリプトの始まりをロギングしています

## syslog get  ↓実際の処理になります
expect -c ”
set timeout 60
spawn scp user@192.168.1.1:/var/log/syslog/syslog.0 ${DIR}${DATE}_syslog
expect {
\”Are you sure you want to continue connecting (yes/no)?\” {
send \”yes\n\”
expect \”パスワード\”
send \”password\n\”
} \”パスワード\” {
send \”password\n\”
}
}

expect {
\”100%\” {exit}
}

echo ${DATE} syslog inport sucsess !! >> ${DIR}slog.log
echo =============================== >> ${DIR}slog.log

今回は複数の命令で併せて使用する形にしています。
実行部分を「”」で囲みます。「”」内で「”」を使う場合は「\」エスケープ文字を付けます。
実行部分を簡単に説明するとset timeoutでタイムアウトの時間(秒)を設定しています。
spawnは実際に実行するコマンドです。
その後表示された文字列の際に実行するコマンドをsendになります。
上記は初めて接続した場合と、2回目以降の場合を書いています。
最後に100%と表示されたらexitで抜けています。

実際に起動してみます。
# sh syslogpick.sh
spawn scp user@192.168.1.1:/var/log/syslog/syslog.0 /usr/local/slog/logs/20130719_syslog
The authenticity of host ‘192.168.1.1 (192.168.1.1)’ can’t be established.
RSA key fingerprint is 9b:c7:72:5d:bd:bc:f9:df:10:62:9a:42:d4:37:ba:65.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘192.168.1.1’ (RSA) to the list of known hosts.
・ム・ケ・・シ・ノ:
syslog.0 100% 3717KB 3.6MB/s 00:00

確認
# ls -al /usr/local/slog/logs/
drwxr-xr-x 2 root root 4096 Jul 20 13:58 .
drwxr-xr-x 3 root root 4096 Jul 20 13:58 ..
-rw-r–r– 1 root root 3805184 Jul 20 13:58 20130719_syslog
-rw-r–r– 1 root root 95 Jul 20 13:58 slog.log

# cat /usr/local/slog/logs/slog.log
20130719 syslog inport start
20130719 syslog inport sucsess !!
===============================

SYSLOGサーバがunixでlinuxとは文字コードが違うので表示上文字化けしていますが問題なくログを取得できます。

ログの取得方法は以上になります。

次回は取得ログを成型とmysqlのテーブル作成をします。

SYSLOG検索くん 第2回

今回システムを動かすのに必要なミドルウェアは下記の3点です。
apache、MySQL、PHP
よくいうLAMP環境というやつです。

細かいチューニングは後ほど行うとしてまずはyumでサクッとインストールしてしまいます。

一応rpmでインストールされていないか確認する
※コマンド実行部分は青色にしています

# rpm -qa | egrep ‘php|mysql|http’
system-config-httpd-1.3.3.3-1.el5
httpd-2.2.3-31.el5.centos

apacheは既にインストール済みで他は入っていない状態です。

必要なrpmのインストールを実施
mysqlは5.0、phpは5.3にしています。

# yum install mysql mysql-server php53 php53-mbstring php53-mysql

================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
mysql i386 5.0.95-5.el5_9 updates 4.9 M
mysql-server i386 5.0.95-5.el5_9 updates 9.8 M
php53 i386 5.3.3-13.el5_9.1 updates 1.3 M
php53-mbstring i386 5.3.3-13.el5_9.1 updates 1.2 M
php53-mysql i386 5.3.3-13.el5_9.1 updates 88 k
Installing for dependencies:
gmp i386 4.1.4-10.el5 base 664 k
perl-DBD-MySQL i386 3.0007-2.el5 base 148 k
perl-DBI i386 1.52-2.el5 base 600 k
php53-cli i386 5.3.3-13.el5_9.1 updates 2.5 M
php53-common i386 5.3.3-13.el5_9.1 updates 605 k
php53-pdo i386 5.3.3-13.el5_9.1 updates 67 k

インストールが終わると下記のパッケージがインストールされた事を確認できます。

# rpm -qa | egrep ‘php|mysql|http’
system-config-httpd-1.3.3.3-1.el5
php53-common-5.3.3-13.el5_9.1
php53-5.3.3-13.el5_9.1
httpd-2.2.3-31.el5.centos
php53-cli-5.3.3-13.el5_9.1
mysql-server-5.0.95-5.el5_9
php53-pdo-5.3.3-13.el5_9.1
php53-mbstring-5.3.3-13.el5_9.1
mysql-5.0.95-5.el5_9
php53-mysql-5.3.3-13.el5_9.1

既にインストールされていましたがまずはapacheでphpを使えるようにします。
httpd.conf(デフォルト/etc/httpd/conf/httpd.conf)を編集します。

# vi /etc/httpd/conf/httpd.conf

#ServerTokens OS  ←Prodで情報を最小限にしていますが、逆に詳しい情報を表示させたい場合は
ServerTokens Prod  Fullにして下さい。あまりお勧めはできませんが。。。

#ServerAdmin root@localhost       ←管理者メールアカウントにして下さい。
ServerAdmin webadmin@nekoneko.com

#ServerName www.example.com:80
ServerName nekoneko.com:80    ←サーバのURLにして下さい。

DocumentRoot “/var/www/html”  ←ここは変更ではないですが、ドキュメントルートの場所の確認になります。
<Directory “/var/www/html”>
#
# Possible values for the Options directive are “None”, “All”,
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that “MultiViews” must be named *explicitly* — “Options All”
# doesn’t give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.2/mod/core.html#options
# for more information.
#
# Options Indexes FollowSymLinks  ←Indexesはindexファイルが無くてもIndex of/という画面が表示されます
Options ExecCGI FollowSymLinks    403エラーにする場合は外します

#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be “All”, “None”, or any combination of the keywords:
# Options FileInfo AuthConfig Limit
#
# AllowOverride None
AllowOverride All

#
# Controls who can get stuff from this server.
#
Order allow,deny
Allow from all

 

DirectoryIndex index.html index.html.var index.php  ←index.phpを追加して下さい。

ひとまず使えるようにするという所では以上で終了です。

私は既にapacheはインストールされていたので起動していますが、新規でインストールした場合は
起動でOKです。常に使うことになるのでchkconfigもonにすることも忘れずに
# /etc/init.d/httpd restart 起動してない場合はstartでOK
# chkconfig httpd on

インストール後にphpの確認をする為にapacheのドキュメントルート(デフォルトは/var/www/html)に
info.phpファイルを作成して確認します。
info.php中身
<!–?php phpinfo(); phpinfo(INFO_MODUKES); ?–>

確認の際にiptablesの設定でHTTP通信を許可していないと思いますので許可ポリシーを入れます。
コマンドでもできますが私は直接ファイル(/etc/sysconfig/iptables)を編集しています。

下記の文を追加 ※最後にREJECTポリシーがあるのでそれより上に必ず書いて下さい。

-A RH-Firewall-1-INPUT -p tcp -m tcp –dport 80 -j ACCEPT

記述後に設定を有効にするためにiptablesを再起動
# /etc/init.d/iptables restart

php情報を確認する為にサーバにアクセスします。
http://nekoneko.com/info.php

PHP情報が表示されます。

続いてmysqlにユーザーとデータベースを作成します。
mysqlユーザーを作成します。
起動していなければ起動させて下さい。
# /etc/init.d/mysqld start

初期設定時はrootがノンパスになっているのでパスワード設定して下さい。
# mysql -u root

mysql > SET PASSWORD FOR root@localhost=PASSWORD(‘password’); ←(”)内がパスワードです。
一度ログアウトしてパスワードを確認します。
mysql > quit
# mysql -u root -ppassword ←-pだけで次にパスワード入力にしてもいいと思います。
mysql >

本題のsyslog検索くん用のデータベースを作成します。(DB名は任意でつけて下さい)
mysql > create database syslogdb;

続いてデータベースを操作するユーザーを作成します。(こちらも任意でつけて下さい)
mysql > grant all on syslogdb.* to ‘admin’@’localhost’ identified by ‘password’;

mysql > quit

ひとまずデータベースの準備は完了です。
mysqlもchkconfigをonにしていた方が便利です。
# chkconfig mysqld on

ミドルウェアの準備は以上になります。

次回はディレクトリ構成とログの抽出について書きます。

SYSLOG検索くん 第1回

unixのSYSLOGサーバが1台あります。
直接機器の設定を変更することはできないのですが、
ログの調査等が必要な場合があり、それを技術者以外の人に行って
もらうこともあるのでより簡単に調査できるようなシステムを作ります。

ログもバックアップを取っているわけではないので誤って消してしまう
可能性もあるのでより安全に扱えるように別の機器でログを取得する方法
にしました。

SYSLOGサーバの状況
・毎日0:00:00にログがローテートされる(1世代前はsyslog.0となる)
・1週間以上前のログはgzでアーカイブされる
・ログの保存期間は1年間
・外部からの接続はSSHのみ可能

上記の内容を考慮して取得する方法を検討しました。

SYSLOG検索くん基本設計
・scpを使ってログファイルをSYSLOGサーバからコピーする
・外部からの接続方法はexpectを使用
・SYSLOGサーバのローテート後1:00:00に前日のログを取り込む
・当日のログについてはGUIに手動実行できるように実装
・OSはlinux(CentOS5.4)を使用 ※CentOS6.3でも動作検証する
・DBはmysqlを使用
・GUI画面はphpにて作成

機能要件
・GUI上で抽出条件にマッチしたログを表示させる
・表示したログをCSVで出力させる

検索BOXは2個所入力可能にする
1.ノード名部分で検索
2.インフォメーション部分で検索
入力なしの場合は指定なしで出力

ワイルドカード検索チェックボックスを設定
キーワードの文字が含まれる場合に使える

例)ノード:NODE ワイルドカード
インフォ:指定なし
ノードにNODEが含まれているものを抽出

・抽出期間はプルダウン方式で選択できるようにする

ひとまず実装する内容としては上記のような感じです。

次回はミドルウェアのインストールと設定について書きます。