# 12.1 アプリケーションログ　
我々は開発しているWebアプリケーションプログラムにプログラム全体の実行過程において発生する様々なイベントを一つ一つ記録できるようにしたいと望んでいます。Go言語では簡易のlogパッケージを提供しています。このパッケージを使用することで簡単にログを記録する機能を実装することができます。これらのログはどれもfmtパッケージの出力とpanicといった関数を組み合わせることで普段の出力、エラーの発生といった処理を行なっています。Goの標準パッケージは現在簡単な機能のみを含んでいます。もし我々のアプリケーションログをファイルに保存し、ログと組み合わせてより複雑な機能（JavaまたはC++の開発経験のある読者はlog4jとlog4cppといったログツールを使ったことがあると思います）を実装したい場合、サードパーティが開発したログシステムを使用することができます。`https://github.com/cihub/seelog`。これは非常に強力なログ機能を実現しています。以降ではこのログシステムを使ってどのように我々のアプリケーションにログ機能を実装するかご紹介します。

## seelogのご紹介
seelogはGo言語で実装されたログシステムのひとつです。これは複雑なログの割り当て、フィルタリングとフォーマッティングを実現する簡単な関数を提供します。主に以下の特徴があります：

- XMLの動的な変更、プログラムを再コンパイルすることなく動的にデータを変更することができます。
- ホットアップデート。動的に再起動する必要なく設定を変更することができます。
- マルチ出力ストリームのサポート。同時にログを複数のストリームに出力することができます。たとえばファイルストリーム、ネットワークストリーム等
- 異なるログの出力のサポート

	- コマンドライン出力
	- ファイル出力　
	- キャッシュ出力
	- log rotateのサポート
	- SMTPメール

上では特徴のいくつかを列挙しただけです。seelogは非常に強力なログ処理システムです。詳細はオフィシャルのwikiをご参照ください。以降ではどのようにしてプロジェクトにおいてこれを利用するのか簡単にご紹介します：

まずseelogをインストールします

	go get -u github.com/cihub/seelog
	
次に簡単な例を見てみます：

	package main

	import log "github.com/cihub/seelog"

	func main() {
	    defer log.Flush()
	    log.Info("Hello from Seelog!")
	}

コンパイルして実行すると`Hello from seelog`という出力がでます。seelogログシステムのインストールに成功して、正常に実行されています。

## seelogに基づいたカスタム定義のログ処理
seelogはカスタムなログ処理の定義をサポートしています。以下はカスタムに定義されたログ処理パッケージの一部の内容にもとづいています：

	package logs
	
	import (
		"errors"
		"fmt"
		seelog "github.com/cihub/seelog"
		"io"
	)
	
	var Logger seelog.LoggerInterface
	
	func loadAppConfig() {
		appConfig := `
	<seelog minlevel="warn">
	    <outputs formatid="common">
	        <rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/>
			<filter levels="critical">
	            <file path="/data/logs/critical.log" formatid="critical"/>
	            <smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
	                <recipient address="xiemengjun@gmail.com"/>
	            </smtp>
	        </filter>
	    </outputs>
	    <formats>
	        <format id="common" format="%Date/%Time [%LEV] %Msg%n" />
		    <format id="critical" format="%File %FullPath %Func %Msg%n" />
		    <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
	    </formats>
	</seelog>
	`
		logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig))
		if err != nil {
			fmt.Println(err)
			return
		}
		UseLogger(logger)
	}
	
	func init() {
		DisableLog()
		loadAppConfig()
	}
	
	// DisableLog disables all library log output
	func DisableLog() {
		Logger = seelog.Disabled
	}
	
	// UseLogger uses a specified seelog.LoggerInterface to output library log.
	// Use this func if you are using Seelog logging system in your app.
	func UseLogger(newLogger seelog.LoggerInterface) {
		Logger = newLogger
	}

上は主に３つの関数を実装しています、

- `DisableLog`
	
	グローバル変数Loggerをseelogを使用しない状態に初期化します。主にLoggerが複数回初期化されないよう防止するためです。
- `loadAppConfig`

	設定ファイルが初期化したseelogの設定情報にもとづいて、設定ファイルを文字列を通して読み取り設定します。当然XMLファイルを読み取ってもかまいません。中の設定の説明は以下の通り：
	
	- seelog 
	
		minlevelパラメータはオプションです。もし設定されていれば、このレベルと同じかそれ以上のログが記録されます。maxlevelと同じです。
	- outputs
		
		データの出力先です。ここでは２つのデータにわけます。ひとつはlog rotateファイルに記録され、もうひとつはfilterを設定します。もしエラーレベルがcriticalであれば、エラーメールを送信します。
		
	- formats
	
		各種ログフォーマットを定義します
	
- `UseLogger`

	現在のロガーを対応するログ処理に設定します
	
上ではカスタムにログ処理パッケージを定義しています。以下は使用例です：

	package main
	
	import (
		"net/http"
		"project/logs"
		"project/configs"
		"project/routes"
	)
	
	func main() {
		addr, _ := configs.MainConfig.String("server", "addr")
		logs.Logger.Info("Start server at:%v", addr)
		err := http.ListenAndServe(addr, routes.NewMux())
		logs.Logger.Critical("Server err:%v", err)
	}

## エラーの発生によりメールを送信
上の例ではどのようにメールの送信を設定するか説明しています。以下のようなsmtp設定によってメールを送信します：

	<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
		<recipient address="xiemengjun@gmail.com"/>
	</smtp>

メールのフォーマットはcriticalemail設定とその他のSMTPサーバの設定によって設定されます。recipient設定でメールの送信先を設定します。もし複数のユーザがいる場合はもう一行追加することができます。

このコードが正しく動作するかテストする場合、コードに以下のような偽の情報を追加することが可能です。しかし後に削除することを忘れないようにしてください、さもなければ、実運用で沢山のスパムメールを受け取ることになります。

	logs.Logger.Critical("test Critical message")

現在、我々のアプリケーションが実運用でCriticalな情報を一つ記録すると、あなたのメールボックスにEmailが届きます。このように一旦実運用されたシステムに問題が発生するとすぐにメールの受信ができ、その時に処理を実行することができます。
## アプリケーションログの使用
アプリケーションログに対しては人によってアプリケーションのバックグラウンドが異なる可能性があります。一部の人はアプリケーションログを使ってデータ分析を行うかもしれませんし、ある人はアプリケーションログを使って性能を分析するかもしれません。またある人はユーザの行動分析を行うかもしれませんし、アプリケーションに問題が発生した際問題を見つけやすくするために、純粋に記録を行いたいだけの場合もあります。

一つ例を挙げましょう。ユーザがシステムにログインしようとする操作を追跡したいとします。ここでは成功と失敗の試みがすべて記録されています。成功のログは"Info"ログレベルが使用され、失敗には"warn"レベルが使用されます。もしすべてのログイン失敗記録を探したい場合、linuxのgrepといったコマンドツールを使って以下のようにすることができます：

	# cat /data/logs/roll.log | grep "failed login"
	2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password

このような方法によって簡単に対応する情報を探し出すことができます。これにはアプリケーションログに対して統計と分析を行えるという利点があります。また、ログのサイズを考慮する必要もあります。高トラフィックのWebアプリケーションにとって、ログの増加は恐るべきものです。そのため、seelogの設定ファイルでlogrotateを設定することで、ログファイルが絶え間なく増大し我々のディスクスペースが足りなくなるといった問題を引き起こさないよう保証することができます。

## 概要
上のseelogシステムとこれに基づいてどのようにログシステムを定義するかを学ぶことによって、非常に気軽に強力で適切な機能を持つログシステムを作成できることができました。ログシステムはデータ分析に信用できるデータソースを提供します。例えばログの分析を通して、システムをより一歩改善することができますし、アプリケーションに問題が発生した時に問題の位置を特定しやすくなります。また、seelogはログのレベル分け機能もサポートしています。minlevelの設定によって簡単にテストや配布版の出力情報のレベルを設定することができます。

## links
   * [目次](<preface.md>)
   * 前へ: [デプロイとメンテナンス](<12.0.md>)
   * 次へ: [ウェブサイトのエラー処理](<12.2.md>)
