func ExampleNewHandler() { c := xhandler.Chain{} // Install the metric handler with dogstatsd backend client and some env tags flushInterval := 5 * time.Second tags := []string{"role:my-service"} statsdWriter, err := net.Dial("udp", "127.0.0.1:8126") if err != nil { log.Fatal(err) } c.UseC(xstats.NewHandler(dogstatsd.New(statsdWriter, flushInterval), tags)) // Here is your handler h := c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Get the xstats request's instance from the context. You can safely assume it will // be always there, if the handler is removed, xstats.FromContext will return a nop // instance. m := xstats.FromContext(ctx) // Count something m.Count("requests", 1, "route:index") })) http.Handle("/", h) if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } }
// Check get the riskScore and aggregate characteristics. func (f *Forensiq) Check(ctx context.Context, creq CheckRequest) (CheckResponse, error) { var ( uri *url.URL cresp CheckResponse err error log = xlog.FromContext(ctx) sts = xstats.FromContext(ctx) ) var req *http.Request { uri, err = url.Parse(f.Host) if err != nil { log.Errorf("error parsing the URL: %s%v", err, xlog.F{"host": f.Host}) return CheckResponse{}, err } uri.Path = "/check" v := creq.toValues() v.Set("ck", f.ClientKey) v.Set("output", "JSON") uri.RawQuery = v.Encode() req, err = http.NewRequest("GET", uri.String(), nil) if err != nil { return CheckResponse{}, err } req.Header.Set("Content-Type", "application/json") } { begin := time.Now() resp, err := ctxhttp.Do(ctx, f.httpClient, req) if err != nil { return CheckResponse{}, err } defer resp.Body.Close() sts.Timing("forensiq.request_time", time.Since(begin), "request:check", "status:"+responseStatus(ctx, resp.StatusCode), "status_code:"+strconv.Itoa(resp.StatusCode), ) if resp.StatusCode == http.StatusForbidden { log.Errorf("client key is invalid%v", xlog.F{"client_key": f.ClientKey}) return CheckResponse{}, ErrInvalidClientKey } if err := json.NewDecoder(resp.Body).Decode(&cresp); err != nil { return CheckResponse{}, err } } return cresp, nil }
// WithAccessLog is a middleware that logs all access requests performed on the // sub handler using github.com/corestoreio/csfw/net/ctxlog and // github.com/rs/xstats stored in context. func WithAccessLog() ctxhttp.Middleware { return func(h ctxhttp.HandlerFunc) ctxhttp.HandlerFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { // Time request reqStart := time.Now() // Sniff the status and content size for logging lw := mutil.WrapWriter(w) err := h.ServeHTTPContext(ctx, lw, r) // Compute request duration reqDur := time.Since(reqStart) // Get request status status := ResponseStatus(ctx, lw.Status()) // Log request stats sts := xstats.FromContext(ctx) tags := []string{ "status:" + status, "status_code:" + strconv.Itoa(lw.Status()), } sts.Timing("request_time", reqDur, tags...) sts.Histogram("request_size", float64(lw.BytesWritten()), tags...) ctxlog.FromContext(ctx).Info("request", "error", util.Errors(err), "method", r.Method, "uri", r.URL.String(), "type", "access", "status", status, "status_code", lw.Status(), "duration", reqDur.Seconds(), "size", lw.BytesWritten(), "remote_addr", httputil.GetRemoteAddr(r).String(), "user_agent", r.Header.Get("User-Agent"), "referer", r.Header.Get("Referer"), ) return err } } }
// NewHandler returns a handler that log access information about each request performed // on the provided sub-handlers. Uses context's github.com/rs/xlog and // github.com/rs/xstats if present for logging. func NewHandler() func(next xhandler.HandlerC) xhandler.HandlerC { return func(next xhandler.HandlerC) xhandler.HandlerC { return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Time request reqStart := time.Now() // Sniff the status and content size for logging lw := mutil.WrapWriter(w) // Call the next handler next.ServeHTTPC(ctx, lw, r) // Conpute request duration reqDur := time.Since(reqStart) // Get request status status := responseStatus(ctx, lw.Status()) // Log request stats sts := xstats.FromContext(ctx) tags := []string{ "status:" + status, "status_code:" + strconv.Itoa(lw.Status()), } sts.Timing("request_time", reqDur, tags...) sts.Histogram("request_size", float64(lw.BytesWritten()), tags...) // Log access info log := xlog.FromContext(ctx) log.Infof("%s %s %03d", r.Method, ellipsize(r.URL.String(), 100), lw.Status(), xlog.F{ "method": r.Method, "uri": r.URL.String(), "type": "access", "status": status, "status_code": lw.Status(), "duration": reqDur.Seconds(), "size": lw.BytesWritten(), }) }) } }
// Ready returns true if the API is ready func (f *Forensiq) Ready(ctx context.Context) (bool, error) { var ( uri *url.URL b []byte err error sts = xstats.FromContext(ctx) ) { uri, err = url.Parse(f.Host) if err != nil { return false, err } uri.Path = "/ready" } { begin := time.Now() resp, err := ctxhttp.Get(ctx, f.httpClient, uri.String()) if err != nil { return false, err } defer resp.Body.Close() sts.Timing("forensiq.request_time", time.Since(begin), "request:ready", "status:"+responseStatus(ctx, resp.StatusCode), "status_code:"+strconv.Itoa(resp.StatusCode), ) b, err = ioutil.ReadAll(resp.Body) if err != nil { return false, err } } return string(b) == "1", nil }