// 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() Middleware { return func(h Handler) Handler { return HandlerFunc(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", utils.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", httputils.GetRemoteAddr(r).String(), "user_agent", r.Header.Get("User-Agent"), "referer", r.Header.Get("Referer"), ) return err }) } }
// newContextCountryByIP searches the country for an IP address and puts the country // into a new context. func (s *Service) newContextCountryByIP(ctx context.Context, r *http.Request) (context.Context, *IPCountry, error) { remoteAddr := httputils.GetRemoteAddr(r) if remoteAddr == nil { if PkgLog.IsDebug() { PkgLog.Debug("geoip.WithCountryByIP.GetRemoteAddr", "err", ErrCannotGetRemoteAddr, "req", r) } return ctx, nil, ErrCannotGetRemoteAddr } c, err := s.GetCountryByIP(remoteAddr) if err != nil { if PkgLog.IsDebug() { PkgLog.Debug("geoip.WithCountryByIP.GetCountryByIP", "err", err, "remoteAddr", remoteAddr, "req", r) } return ctx, nil, errgo.Mask(err) } c.IP = remoteAddr return NewContextCountry(ctx, c), c, nil }
func TestGetRemoteAddr(t *testing.T) { tests := []struct { r *http.Request wantIP net.IP }{ {func() *http.Request { r, err := http.NewRequest("GET", "http://gopher.go", nil) assert.NoError(t, err) r.Header.Set("X-Real-IP", "123.123.123.123") return r }(), net.ParseIP("123.123.123.123")}, {func() *http.Request { r, err := http.NewRequest("GET", "http://gopher.go", nil) assert.NoError(t, err) r.Header.Set("X-Forwarded-For", "200.100.50.3") return r }(), net.ParseIP("200.100.50.3")}, {func() *http.Request { r, err := http.NewRequest("GET", "http://gopher.go", nil) assert.NoError(t, err) r.RemoteAddr = "100.200.50.3" return r }(), net.ParseIP("100.200.50.3")}, {func() *http.Request { r, err := http.NewRequest("GET", "http://gopher.go", nil) assert.NoError(t, err) r.RemoteAddr = "100.200.a.3" return r }(), nil}, } for i, test := range tests { haveIP := httputils.GetRemoteAddr(test.r) assert.Exactly(t, test.wantIP, haveIP, "Index: %d", i) } }