LoginSignup
1
1

More than 5 years have passed since last update.

net/httpの統計を取る

Last updated at Posted at 2014-06-21

ぱっと調べた所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)
}

もっといい方法あったらだれか教えて!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1