Commit f38e87cf4cc29108b558d5a97a1fef09e203c337

Authored by Marko Tikvić
1 parent 8a070abe23
Exists in master

status recorder

Showing 2 changed files with 35 additions and 15 deletions   Show diff stats
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 }