ぱっと調べた所net/httpの統計情報:例えばどのぐらい書き込んだか、読み込んだか、statusは何だったのかというのを取るようなinterfaceがnet/httpにはなかったりします。
別途monitoring用のAgentを使ってもいいのですが、networkのtrafficだけならまだしもHTTPのStatusなどを取りたいといった場合に構成が面倒になるのでサーバー自体で統計を取る仕組みをつくってしまうのが運用上楽かと思います。
アプローチ
http.ListenAndServeでは細かい指定ができないのでhttp.Serverにnet.Listenerをかぶせたものを渡してあげればごにょごにょすることができます。
HTTPのStatusに関しては特にAPIがないようなのであまりよくない手法ですがReflectionで取るのが楽なようです。
package main
import (
"fmt"
"net"
"net/http"
"reflect"
"time"
)
// trace bytes written, connection count.
type TracingListener struct {
net.Listener
}
type TracingConn struct {
net.Conn
}
func (self TracingListener) Accept() (c net.Conn, err error) {
conn, err := self.Listener.Accept()
if err != nil {
return nil, err
}
// TODO: connectionをincrementする
return TracingConn{conn}, nil
}
func (self TracingConn) Close() error {
// TODO: connectionをdecrementする
return self.Conn.Close()
}
func (self TracingConn) Read(b []byte) (int, error) {
// TODO: len(b)の大きさだけreadを増やす
return self.Conn.Read(b)
}
func (self TracingConn) Write(b []byte) (int, error) {
// TODO: len(b)の大きさだけwriteを増やす
return self.Conn.Write(b)
}
func getStatusCode(w http.ResponseWriter) uint64 {
var status int64 = 0
field := reflect.ValueOf(w).Elem().FieldByName("status")
if field.Kind() == reflect.Int {
status = field.Int()
}
return uint64(status)
}
type Handler struct {
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
//実際の処理はかぶせちゃったほうが楽かも
fmt.Fprint(w, "Hello")
end := time.Now().Sub(begin)
status := getStatusCode(w)
fmt.Printf("Status: %d, Elapsed: %f\n", status, end.Seconds())
}
func main() {
h := &Handler{}
listener, err := net.Listen("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
listener = TracingListener{listener}
srv := &http.Server{
Handler: h,
}
srv.Serve(listener)
}
もっといい方法あったらだれか教えて!