Commit f38e87cf4cc29108b558d5a97a1fef09e203c337
1 parent
8a070abe23
Exists in
master
status recorder
Showing
2 changed files
with
35 additions
and
15 deletions
Show diff stats
http.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/json" | 4 | "encoding/json" |
5 | "fmt" | 5 | "fmt" |
6 | "net/http" | 6 | "net/http" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | type ResponseWriterStatusRecorder struct { | 9 | type StatusRecorder struct { |
10 | http.ResponseWriter | 10 | writer http.ResponseWriter |
11 | status int | 11 | status int |
12 | size int | ||
12 | } | 13 | } |
13 | 14 | ||
14 | func WrapWithStatusRecorder(w http.ResponseWriter) *ResponseWriterStatusRecorder { | 15 | func NewStatusRecorder(w http.ResponseWriter) *StatusRecorder { |
15 | return &ResponseWriterStatusRecorder{w, 0} | 16 | return &StatusRecorder{ |
17 | writer: w, | ||
18 | status: 0, | ||
19 | size: 0, | ||
20 | } | ||
16 | } | 21 | } |
17 | 22 | ||
18 | func (r *ResponseWriterStatusRecorder) WriteHeader(code int) { | 23 | // http.ResponseWriter interface |
24 | func (r *StatusRecorder) WriteHeader(code int) { | ||
19 | r.status = code | 25 | r.status = code |
20 | r.ResponseWriter.WriteHeader(code) | 26 | r.writer.WriteHeader(code) |
27 | } | ||
28 | |||
29 | // http.ResponseWriter interface | ||
30 | func (r *StatusRecorder) Write(in []byte) (int, error) { | ||
31 | r.size = len(in) | ||
32 | return r.writer.Write(in) | ||
21 | } | 33 | } |
22 | 34 | ||
23 | func (r *ResponseWriterStatusRecorder) Status() int { | 35 | // http.ResponseWriter interface |
36 | func (r *StatusRecorder) Header() http.Header { | ||
37 | return r.writer.Header() | ||
38 | } | ||
39 | |||
40 | func (r *StatusRecorder) Status() int { | ||
24 | return r.status | 41 | return r.status |
25 | } | 42 | } |
26 | 43 | ||
44 | func (r *StatusRecorder) Size() int { | ||
45 | return r.size | ||
46 | } | ||
47 | |||
27 | // NotFoundHandlerFunc writes HTTP error 404 to w. | 48 | // NotFoundHandlerFunc writes HTTP error 404 to w. |
28 | func NotFoundHandlerFunc(w http.ResponseWriter, req *http.Request) { | 49 | func NotFoundHandlerFunc(w http.ResponseWriter, req *http.Request) { |
29 | SetDefaultHeaders(w) | 50 | SetDefaultHeaders(w) |
30 | if req.Method == "OPTIONS" { | 51 | if req.Method == "OPTIONS" { |
31 | return | 52 | return |
32 | } | 53 | } |
33 | NotFound(w, req, fmt.Sprintf("Resource you requested was not found: %s", req.URL.String())) | 54 | NotFound(w, req, fmt.Sprintf("Resource you requested was not found: %s", req.URL.String())) |
34 | } | 55 | } |
35 | 56 | ||
36 | // SetDefaultHeaders set's default headers for an HTTP response. | 57 | // SetDefaultHeaders set's default headers for an HTTP response. |
37 | func SetDefaultHeaders(w http.ResponseWriter) { | 58 | func SetDefaultHeaders(w http.ResponseWriter) { |
38 | w.Header().Set("Access-Control-Allow-Origin", "*") | 59 | w.Header().Set("Access-Control-Allow-Origin", "*") |
39 | w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") | 60 | w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") |
40 | w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") | 61 | w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") |
41 | w.Header().Set("Content-Type", "application/json; charset=utf-8") | 62 | w.Header().Set("Content-Type", "application/json; charset=utf-8") |
42 | } | 63 | } |
43 | 64 | ||
44 | func GetLocale(req *http.Request, dflt string) string { | 65 | func GetLocale(req *http.Request, dflt string) string { |
45 | loc := req.FormValue("locale") | 66 | loc := req.FormValue("locale") |
46 | if loc == "" { | 67 | if loc == "" { |
47 | return dflt | 68 | return dflt |
48 | } | 69 | } |
49 | return loc | 70 | return loc |
50 | } | 71 | } |
51 | 72 | ||
52 | // 2xx | 73 | // 2xx |
53 | func Success(w http.ResponseWriter, payload interface{}, code int) { | 74 | func Success(w http.ResponseWriter, payload interface{}, code int) { |
54 | w.WriteHeader(code) | 75 | w.WriteHeader(code) |
55 | if payload != nil { | 76 | if payload != nil { |
56 | json.NewEncoder(w).Encode(payload) | 77 | json.NewEncoder(w).Encode(payload) |
57 | } | 78 | } |
58 | } | 79 | } |
59 | 80 | ||
60 | // 200 | 81 | // 200 |
61 | func OK(w http.ResponseWriter, payload interface{}) { | 82 | func OK(w http.ResponseWriter, payload interface{}) { |
62 | Success(w, payload, http.StatusOK) | 83 | Success(w, payload, http.StatusOK) |
63 | } | 84 | } |
64 | 85 | ||
65 | // 201 | 86 | // 201 |
66 | func Created(w http.ResponseWriter, payload interface{}) { | 87 | func Created(w http.ResponseWriter, payload interface{}) { |
67 | Success(w, payload, http.StatusCreated) | 88 | Success(w, payload, http.StatusCreated) |
68 | } | 89 | } |
69 | 90 | ||
70 | type weberror struct { | 91 | type weberror struct { |
71 | Request string `json:"request"` | 92 | Request string `json:"request"` |
72 | Error string `json:"error"` | 93 | Error string `json:"error"` |
73 | } | 94 | } |
74 | 95 | ||
75 | // 4xx; 5xx | 96 | // 4xx; 5xx |
76 | func Error(w http.ResponseWriter, r *http.Request, code int, err string) { | 97 | func Error(w http.ResponseWriter, r *http.Request, code int, err string) { |
77 | werr := weberror{Error: err, Request: r.Method + " " + r.RequestURI} | 98 | werr := weberror{Error: err, Request: r.Method + " " + r.RequestURI} |
78 | w.WriteHeader(code) | 99 | w.WriteHeader(code) |
79 | json.NewEncoder(w).Encode(werr) | 100 | json.NewEncoder(w).Encode(werr) |
80 | } | 101 | } |
81 | 102 | ||
82 | // 400 | 103 | // 400 |
83 | func BadRequest(w http.ResponseWriter, r *http.Request, err string) { | 104 | func BadRequest(w http.ResponseWriter, r *http.Request, err string) { |
84 | Error(w, r, http.StatusBadRequest, err) | 105 | Error(w, r, http.StatusBadRequest, err) |
85 | } | 106 | } |
86 | 107 | ||
87 | // 401 | 108 | // 401 |
88 | func Unauthorized(w http.ResponseWriter, r *http.Request, err string) { | 109 | func Unauthorized(w http.ResponseWriter, r *http.Request, err string) { |
89 | Error(w, r, http.StatusUnauthorized, err) | 110 | Error(w, r, http.StatusUnauthorized, err) |
90 | } | 111 | } |
91 | 112 | ||
92 | // 403 | 113 | // 403 |
93 | func Forbidden(w http.ResponseWriter, r *http.Request, err string) { | 114 | func Forbidden(w http.ResponseWriter, r *http.Request, err string) { |
94 | Error(w, r, http.StatusForbidden, err) | 115 | Error(w, r, http.StatusForbidden, err) |
95 | } | 116 | } |
96 | 117 | ||
97 | // 404 | 118 | // 404 |
98 | func NotFound(w http.ResponseWriter, r *http.Request, err string) { | 119 | func NotFound(w http.ResponseWriter, r *http.Request, err string) { |
99 | Error(w, r, http.StatusNotFound, err) | 120 | Error(w, r, http.StatusNotFound, err) |
100 | } | 121 | } |
101 | 122 | ||
102 | // 409 | 123 | // 409 |
103 | func Conflict(w http.ResponseWriter, r *http.Request, err string) { | 124 | func Conflict(w http.ResponseWriter, r *http.Request, err string) { |
104 | Error(w, r, http.StatusConflict, err) | 125 | Error(w, r, http.StatusConflict, err) |
105 | } | 126 | } |
106 | 127 | ||
107 | // 500 | 128 | // 500 |
108 | func InternalServerError(w http.ResponseWriter, r *http.Request, err string) { | 129 | func InternalServerError(w http.ResponseWriter, r *http.Request, err string) { |
109 | Error(w, r, http.StatusInternalServerError, err) | 130 | Error(w, r, http.StatusInternalServerError, err) |
110 | } | 131 | } |
111 | 132 |
middleware_log.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "net/http" | 4 | "net/http" |
5 | "time" | 5 | "time" |
6 | 6 | ||
7 | "git.to-net.rs/marko.tikvic/gologger" | 7 | "git.to-net.rs/marko.tikvic/gologger" |
8 | ) | 8 | ) |
9 | 9 | ||
10 | var trafficLogger *gologger.Logger | 10 | var httpLogger *gologger.Logger |
11 | 11 | ||
12 | func EnableLogging(log string) (err error) { | 12 | func EnableLogging(log string) (err error) { |
13 | trafficLogger, err = gologger.New(log, gologger.MaxLogSize5MB) | 13 | httpLogger, err = gologger.New(log, gologger.MaxLogSize5MB) |
14 | return err | 14 | return err |
15 | } | 15 | } |
16 | 16 | ||
17 | func Log(h http.HandlerFunc) http.HandlerFunc { | 17 | func Log(h http.HandlerFunc) http.HandlerFunc { |
18 | return func(w http.ResponseWriter, req *http.Request) { | 18 | return func(w http.ResponseWriter, req *http.Request) { |
19 | t1 := time.Now() | 19 | t1 := time.Now() |
20 | 20 | ||
21 | claims, _ := GetTokenClaims(req) | 21 | claims, _ := GetTokenClaims(req) |
22 | in := httpLogger.LogHTTPRequest(req, claims.Username) | ||
22 | 23 | ||
23 | in := trafficLogger.RequestLog(req, claims.Username) | 24 | rec := NewStatusRecorder(w) |
24 | 25 | ||
25 | wRec := WrapWithStatusRecorder(w) | 26 | h(rec, req) |
26 | h(wRec, req) | ||
27 | 27 | ||
28 | t2 := time.Now() | 28 | t2 := time.Now() |
29 | out := httpLogger.LogHTTPResponse(rec.Status(), t2.Sub(t1), rec.Size()) | ||
29 | 30 | ||
30 | out := trafficLogger.ResponseLog(wRec.Status(), t2.Sub(t1), 0) | 31 | httpLogger.CombineHTTPLogs(in, out) |
31 | |||
32 | trafficLogger.LogHTTPTraffic(in, out) | ||
33 | } | 32 | } |