forked from corestoreio/pkg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
access_log.go
116 lines (98 loc) · 3.59 KB
/
access_log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2015-present, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package accesslog
import (
"context"
"net/http"
"strconv"
"time"
"github.com/corestoreio/log"
"github.com/corestoreio/pkg/net/mw"
"github.com/corestoreio/pkg/net/request"
"github.com/rs/xstats"
"github.com/zenazn/goji/web/mutil"
)
// Idea: github.com/rs/xaccess Copyright (c) 2015 Olivier Poitrey <rs@dailymotion.com> MIT License
// BlackholeXStat provides a type to disable the stats.
type BlackholeXStat struct{}
// AddTags implements XStats interface
func (BlackholeXStat) AddTags(tags ...string) {}
// Gauge implements XStats interface
func (BlackholeXStat) Gauge(stat string, value float64, tags ...string) {}
// Count implements XStats interface
func (BlackholeXStat) Count(stat string, count float64, tags ...string) {}
// Histogram implements XStats interface
func (BlackholeXStat) Histogram(stat string, value float64, tags ...string) {}
// Timing implements xstats interface
func (BlackholeXStat) Timing(stat string, duration time.Duration, tags ...string) {}
// WithAccessLog is a middleware that logs all access requests performed on the
// sub handler and uses github.com/rs/xstats for collecting stats. Default
// logger uses black hole engine. Log level must be set to info. Logger must be
// thread safe.
func WithAccessLog(x xstats.XStater, l ...log.Logger) mw.Middleware {
var lg log.Logger = log.BlackHole{}
if len(l) == 1 {
lg = l[0]
}
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Time request
reqStart := time.Now()
// Sniff the status and content size for logging
lw := mutil.WrapWriter(w)
h.ServeHTTP(lw, r)
// Compute request duration
reqDur := time.Since(reqStart)
// Get request status
status := ResponseStatus(r.Context(), lw.Status())
// Log request stats
tags := []string{
"status:" + status,
"status_code:" + strconv.Itoa(lw.Status()),
}
x.Timing("request_time", reqDur, tags...)
x.Histogram("request_size", float64(lw.BytesWritten()), tags...)
if lg.IsInfo() {
lg.Info("request",
log.String("proto", r.Proto),
log.String("request_uri", r.RequestURI),
log.String("method", r.Method),
log.Stringer("uri", r.URL),
log.String("type", "access"),
log.String("status", status),
log.Int("status_code", lw.Status()),
log.Duration("duration", reqDur),
log.String("requested-host", r.Host),
log.Int("size", lw.BytesWritten()),
log.Stringer("remote_addr", request.RealIP(r, request.IPForwardedTrust)),
log.String("user_agent", r.Header.Get("User-Agent")),
log.String("referer", r.Header.Get("Referer")),
)
}
})
}
}
// ResponseStatus checks the context for timeout, canceled, ok or error. Used in
// WithAccessLog().
func ResponseStatus(ctx context.Context, statusCode int) string {
if ctx.Err() != nil {
if ctx.Err() == context.DeadlineExceeded {
return "timeout"
}
return "canceled"
} else if statusCode >= 200 && statusCode < 300 {
return "ok"
}
return "error"
}