やりたいこと
Goで立てた簡易webサーバーにアクセスした時に標準出力でLogを表示させるようにします。
webサーバーを立てる
/src/todo main.gp handler/main.gp
main.go
package main import ( "fmt" "net/http" "todos/handler" ) var addr = ":3000" func main() { router := http.NewServeMux() router.HandleFunc("/", handler.Index) fmt.Printf("[START] server. port: %s\n", addr) if err := http.ListenAndServe(addr, router); err != nil { panic(fmt.Errorf("[FAILED] start sever. err: %v", err)) } }
handler/main.go
package handler import "net/http" func Index(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello")) }
ただし、このWeb Serverを起動(go run main.go
)して、 http://localhost:3000 にアクセスしてもターミナル上で標準出力でありがちなリクエストログはされません。
go run main.go [START] server. port: :3000 # ここに標準出力でリクエストをログを表示させたい。
ログを表示させる
ログを表示させるには、Log用のhandlerを用意して、Listenする時にそのログを出力するhandlerを通るように登録します。。 cf. Google グループ - Http Server and logging?
handler/log.go
package handler import ( "fmt" "net/http" ) func Log(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rAddr := r.RemoteAddr method := r.Method path := r.URL.Path fmt.Printf("Remote: %s [%s] %s", rAddr, method, path) h.ServeHTTP(w, r) }) }
main.goを以下の用に修正します。
if err := http.ListenAndServe(addr, handler.Log(router)); err != nil { panic(fmt.Errorf("[FAILED] start sever. err: %v", err)) }
ポイントはLogのhandlerの登録の仕方です。
Log出力用のhandlerを登録する場合は http.ListenAndServe(addr, hanlder)
のhandlerの引数にrouterを単にrouterを追加すればいいのですが、以下のように middleware的な handlerの登録の記法が使えます。
func SomeMethod(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) }
return
で返す http.HandlerFunc
method内部でリクエスト毎に行いことをつらつら書いていけばなんでもできます。
まとめ
FWとか使っていると、この辺いつもFWが吸収してくれててブラックボックス化されてたんだなと痛感しました。
そういったところ、FW側でどう動いているのかわからずに使っていることが多かったので、どんな言語でも簡易的でいいので一旦web server作ってみるというのは学習としてはいい「車輪の再発明」だと思いました。