GAEのスタンダード環境でGo言語を使ってログを出力する方法

Google Cloud Platform が提供しているサービスの1つ、Google App Engine (GAE) のスタンダード環境では、Go言語標準の『log.Print』といった方法を使ってログの表示が出来ません。

しかし、スタンダード環境用に用意されているライブラリを使うことで、標準のものよりも遥かにグラフィカルで見やすいログを見ることが出来ます。

今回はその機能の利用方法と対応する Go言語コードをご紹介していきます。

コンテンツの転載は固くお断りいたします。

Go言語コード

以下のコードでは『/warning』や『/error』といったアドレスにアクセスすると、それぞれ、警告用のログ、エラー用のログを出力します。GAE でのウェブサーバーの作り方は『GAEで初めてのGo言語製ウェブサーバーの作り方』を御覧ください。


package test

import (
	"net/http"
	"strconv"

	"google.golang.org/appengine"
	"google.golang.org/appengine/log"
)

func handler(w http.ResponseWriter, r *http.Request) {

}

// 通常ログ
func handlerInfo(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	log.Infof(ctx, "Info!!")
}

// エラーログ
func handlerError(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

    // r.Host を数値に変換しようとするが失敗する
	if _, err := strconv.Atoi(r.Host); err != nil {
		log.Errorf(ctx, "Error: %v", err)
	}
}

// 警告ログ
func handlerWarning(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	log.Warningf(ctx, "Warning!!")
}

// デバッグログ
func handlerDebug(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	log.Debugf(ctx, "Debug!!")
}

func init() {
    // ハンドラーの登録
	http.HandleFunc("/", handler)
	http.HandleFunc("/info", handlerInfo)
	http.HandleFunc("/error", handlerError)
	http.HandleFunc("/warning", handlerWarning)
	http.HandleFunc("/debug", handlerDebug)
}

ログの確認方法

ログは App Engine のコンソール画面から確認することが出来ます。まず、下の画像のように左側にあるメニューから『サービス』か『バージョン』のどちらかをクリックします。今回はバージョンをクリックしています。

すると、デプロイされた一覧が表示されます。その中から先程のプログラムのものを選び、下の画像のオレンジ色の線で囲った『ツール』をクリックして『ログ』を選択します。

一目でログの種類を確認出来る

上の写真はログ画面で、過去1時間分のログが表示されています。既にいくつかログがあるのは、上のプログラムに対応するアドレスにアクセスしたからです。

ログは下にいくほど新しいもので、上にいくほど古いものになっており、より最新のもの、より古いものは読み込みボタンを押すことで実行できます。

後ほど改めて解説しますが、GAE のスタンダード環境のログは、アドレスにアクセスがある度に自動的にログとして記録されます。上のコードで『log.Info』などを使って出力すると、自動的に記録されたログの中に更にログとして記録されるようになります。

上の写真の左側に、水色や赤色のアイコンが表示されているログがありますが、色付きのアイコンが表示されているのは、その中に『log.Info』などで出力されたログが含まれていることを表しています。

フィルターも自由自在

それぞれのログの『GET』や『200』といったメソッドやレスポンスコードをクリックすることで、同じメソッド、レスポンスコードのログのみを表示するといったことも可能です。

ログの詳細は開くことで確認出来る

アクセスされて自動的に記録されたログは開くことで詳細を確認出来ます。アクセス元の IPアドレスやブラウザ情報などが具体的に書かれています。

上の写真では『log.Info』関数を使って出力されたログが表示されています。App Engine の logパッケージを使ってログを出力すると、自動的に記録されたログの中で表示されます。

エラー内容もしっかりと確認出来る

今回のコードでは『/error』というアドレスにアクセスすると、r.Host を数値に変換しようとします。しかし、r.Host は主にIPアドレスなので正常に数値には変換できません。

なので、変換に失敗したというエラーメッセージが表示されます。

コードの解説

ではコードの解説をしています。

GAE スタンダード環境専用のパッケージを用意する

GAE のスタンダード環境では、専用のパッケージを使って GCP の様々なサービスを利用することが出来ます。なので、以下のコマンドを使ってローカル環境にインストールしておきましょう。


go get google.golang.org/appengine

開発環境によっては、コードを書いている際に自動的に Go言語標準の『log』パッケージがインポートされるかもしれませんが、そちらの記述は削除しておき、『google.golang.org/appengine/log』に書き換えます。import部分は以下のようになります。


import (
	"net/http"
	"strconv"

    //"log"  これはいらない

	"google.golang.org/appengine"
	"google.golang.org/appengine/log"  //これが必要
)

専用のコンテキストを用意する

GAE で Datastore や Cloud Storage 、そしてログサービスを利用する時には、App Engine 専用のコンテキストを用意して引数として渡す必要があります。

用意する方法は難しくなく、ハンドラー関数内に1行追加するだけです。引数として渡している『r』はハンドラー関数の引数である『*http.Request』です。


func handler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
}

ログを出力する

ログの表示はとても簡単です。以下の例だと通常のログを表示しており、App Engine の『log』パッケージの『Infof』関数を使い、引数は最初に先程のコンテキスト、次に表示させたい文字列を渡します。


log.Infof(ctx, "Info!!")

ログに使用する関数を使い分けることで、エラーログ、警告ログ、デバッグログを表示させられます。引数はどれも同じパターンです。


log.Infof(ctx, "Info!!")  // 通常ログ
log.Errorf(ctx, "Error: %v", err)  // エラー内容も含めて出力
log.Warningf(ctx, "Warning!!")  // 警告ログ
log.Debugf(ctx, "Debug!!")  // デバッグログ

これらのログは出力形式をフォーマット可能なので、使い方は『fmt.Printf』や『log.Printf』とよく似ています。違いはコンテキストを渡すかどうかです。

さいごに

記事の最初でも書きましたが、App Engine ではグラフィカルで見やすく、優秀なフィルター機能も備えたログシステムがあるので、みなさんもどんどん App Engine を活用してみて下さい。