github.com/wlattner/mlserver@v0.0.0-20141113171038-895f261d2bfd/http_util.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"net"
     6  	"net/http"
     7  	"time"
     8  
     9  	"github.com/coreos/go-log/log"
    10  )
    11  
    12  func writeJSONOK(w http.ResponseWriter, v interface{}) {
    13  	writeJSON(w, v, http.StatusOK)
    14  }
    15  
    16  func writeJSON(w http.ResponseWriter, v interface{}, status int) {
    17  
    18  	w.Header().Set("Content-Type", "application/json")
    19  	w.WriteHeader(status)
    20  	err := json.NewEncoder(w).Encode(v)
    21  	if err != nil {
    22  		http.Error(w, err.Error(), http.StatusInternalServerError)
    23  	}
    24  }
    25  
    26  func notAllowed(w http.ResponseWriter) {
    27  	http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
    28  }
    29  
    30  //-----------------------------------------------------------------------------
    31  // HTTP Request Logging
    32  //-----------------------------------------------------------------------------
    33  // mostly copied from github.com/wlattner/logger
    34  
    35  // requestLogger wraps an http.Handler, logging all requests
    36  func requestLogger(fn http.Handler) http.Handler {
    37  	return logger{fn}
    38  }
    39  
    40  type logger struct {
    41  	h http.Handler
    42  }
    43  
    44  func (l logger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    45  	start := time.Now()
    46  	resp := &responseLogger{w: w}
    47  	l.h.ServeHTTP(resp, r)
    48  	go printLog(r, resp.status, resp.size, time.Since(start))
    49  }
    50  
    51  // responseLogger allows us to trap the response size and status code
    52  type responseLogger struct {
    53  	w      http.ResponseWriter
    54  	status int
    55  	size   int
    56  }
    57  
    58  func (l *responseLogger) Header() http.Header {
    59  	return l.w.Header()
    60  }
    61  
    62  // wrap ResponseWriter.Write to capture response size
    63  func (l *responseLogger) Write(b []byte) (int, error) {
    64  	if l.status == 0 {
    65  		l.status = http.StatusOK
    66  	}
    67  	size, err := l.w.Write(b)
    68  	l.size += size
    69  	return size, err
    70  }
    71  
    72  // wrap ResponseWriter.WriteHeader to capture http status code
    73  func (l *responseLogger) WriteHeader(s int) {
    74  	l.w.WriteHeader(s)
    75  	l.status = s
    76  }
    77  
    78  func printLog(req *http.Request, status int, size int, d time.Duration) {
    79  	host, _, _ := net.SplitHostPort(req.RemoteAddr)
    80  	requestTime := float64(d.Nanoseconds()) / 1e6
    81  	// ip method path status size time
    82  	// 0.0.0.0 GET /api/users 200 312 34
    83  	log.Infof("%s %s %s %d %d %.2f",
    84  		host,
    85  		req.Method,
    86  		req.URL.RequestURI(),
    87  		status,
    88  		size,
    89  		requestTime,
    90  	)
    91  }