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)
	}
}
示例#2
0
// 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
}
示例#3
0
// 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
		}
	}
}
示例#4
0
// 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(),
			})
		})
	}
}
示例#5
0
// 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
}