This repository has been archived by the owner on Feb 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
accesslog.go
99 lines (88 loc) · 3.42 KB
/
accesslog.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
package components
import (
"context"
"net"
"net/http"
"strconv"
"time"
"github.com/asecurityteam/runhttp"
)
type accessLog struct {
Time string `logevent:"@timestamp"`
UGCDirty []string `logevent:"ugc_dirty"`
Schema string `logevent:"schema,default=access"`
SourceIP string `logevent:"src_ip"`
ForwardedFor string `logevent:"forwarded_for"`
DestinationIP string `logevent:"dest_ip"`
Site string `logevent:"site"`
HTTPRequestContentType string `logevent:"http_request_content_type"`
HTTPMethod string `logevent:"http_method"`
HTTPReferrer string `logevent:"http_referrer"`
HTTPUserAgent string `logevent:"http_user_agent"`
URIPath string `logevent:"uri_path"`
URIQuery string `logevent:"uri_query"`
Scheme string `logevent:"scheme"`
Port int `logevent:"port"`
Bytes int `logevent:"bytes"`
BytesOut int `logevent:"bytes_out"`
BytesIn int `logevent:"bytes_in"`
Duration int `logevent:"duration"`
HTTPContentType string `logevent:"http_content_type"`
Status int `logevent:"status"`
Message string `logevent:"message,default=access"`
}
type loggingTransport struct {
Wrapped http.RoundTripper
}
// RoundTrip writes structured access logs for the request.
func (c *loggingTransport) RoundTrip(r *http.Request) (*http.Response, error) {
var srcIP, _, _ = net.SplitHostPort(r.RemoteAddr)
var dstIP, dstPortStr, _ = net.SplitHostPort(r.Context().Value(http.LocalAddrContextKey).(net.Addr).String())
var dstPort, _ = strconv.Atoi(dstPortStr)
var a = accessLog{
Time: time.Now().UTC().Format(time.RFC3339Nano),
DestinationIP: dstIP,
Port: dstPort,
SourceIP: srcIP,
Site: r.Host,
HTTPRequestContentType: r.Header.Get("Content-Type"),
HTTPMethod: r.Method,
HTTPReferrer: r.Referer(),
HTTPUserAgent: r.UserAgent(),
URIPath: r.URL.Path,
URIQuery: r.URL.Query().Encode(),
Scheme: r.URL.Scheme,
}
var start = time.Now()
var resp, e = c.Wrapped.RoundTrip(r)
a.Duration = int(time.Since(start).Nanoseconds() / 1e6)
a.Status = -1
if e == nil {
a.Status = resp.StatusCode
a.HTTPContentType = resp.Header.Get("Content-Type")
}
runhttp.LoggerFromContext(r.Context()).Info(a)
return resp, e
}
// AccessLogConfig modifies the behavior of the access logs.
type AccessLogConfig struct{}
// Name of the config root.
func (*AccessLogConfig) Name() string {
return "accesslog"
}
// AccessLogComponent is a logging plugin.
type AccessLogComponent struct{}
// AccessLog satisfies the NewComponent signature.
func AccessLog(_ context.Context, _ string, _ string, _ string) (interface{}, error) {
return &AccessLogComponent{}, nil
}
// Settings generates a config populated with defaults.
func (m *AccessLogComponent) Settings() *AccessLogConfig {
return &AccessLogConfig{}
}
// New generates the middleware.
func (*AccessLogComponent) New(ctx context.Context, conf *AccessLogConfig) (func(http.RoundTripper) http.RoundTripper, error) {
return func(next http.RoundTripper) http.RoundTripper {
return &loggingTransport{Wrapped: next}
}, nil
}