Browse Source

Added log middleware

pull/545/head
Weslei Juan Novaes Pereira 6 years ago
parent
commit
e6a78919c2
  1. 6
      .idea/misc.xml
  2. 8
      .idea/modules.xml
  3. 9
      .idea/mux.iml
  4. 6
      .idea/vcs.xml
  5. 67
      .idea/workspace.xml
  6. 2
      go.mod
  7. 10
      go.sum
  8. 154
      logger.go
  9. 58
      logger_test.go

6
.idea/misc.xml

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mux.iml" filepath="$PROJECT_DIR$/.idea/mux.iml" />
</modules>
</component>
</project>

9
.idea/mux.iml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

67
.idea/workspace.xml

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="b10d9bd6-ec23-43f3-bef7-13a524307117" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Go File" />
</list>
</option>
</component>
<component name="GOROOT" path="C:\Go" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GoLibraries">
<option name="indexEntireGoPath" value="false" />
</component>
<component name="ProjectId" id="1WLRzIIIT7D3VUPCOTTsApByClD" />
<component name="PropertiesComponent">
<property name="DefaultGoTemplateProperty" value="Go File" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="go.import.settings.migrated" value="true" />
<property name="go.sdk.automatically.set" value="true" />
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="preferences.lookFeel" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VgoProject">
<integration-enabled>true</integration-enabled>
<proxy>direct</proxy>
</component>
</project>

2
go.mod

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
module github.com/gorilla/mux
go 1.12
require github.com/stretchr/testify v1.4.0

10
go.sum

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

154
logger.go

@ -0,0 +1,154 @@ @@ -0,0 +1,154 @@
package mux
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
const (
green = "\033[97;42m"
white = "\033[90;47m"
yellow = "\033[90;43m"
red = "\033[97;41m"
blue = "\033[97;44m"
magenta = "\033[97;45m"
cyan = "\033[97;46m"
reset = "\033[0m"
)
type LogConfig struct {
Output io.Writer
}
type LogFormatterParams struct {
Request *http.Request
// TimeStamp shows the time after the server returns a response.
TimeStamp time.Time
// StatusCode is HTTP response code.
StatusCode int
// Latency is how much time the server cost to process a certain request.
Latency time.Duration
// ClientIP equals Context's ClientIP method.
ClientIP string
// Method is the HTTP method given to the request.
Method string
// Path is a path the client requests.
Path string
}
type statusWriter struct {
http.ResponseWriter
status int
}
func (w *statusWriter) WriteHeader(s int) {
w.status = s
w.ResponseWriter.WriteHeader(s)
}
func (p *LogFormatterParams) StatusCodeColor() string {
code := p.StatusCode
switch {
case code >= http.StatusOK && code < http.StatusMultipleChoices:
return green
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
return white
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
return yellow
default:
return red
}
}
func (p *LogFormatterParams) MethodColor() string {
method := p.Method
switch method {
case http.MethodGet:
return blue
case http.MethodPost:
return cyan
case http.MethodPut:
return yellow
case http.MethodDelete:
return red
case http.MethodPatch:
return green
case http.MethodHead:
return magenta
case http.MethodOptions:
return white
default:
return reset
}
}
func (p *LogFormatterParams) ResetColor() string {
return reset
}
func Logger(next http.Handler) http.Handler {
return LoggerWithConfig(LogConfig{})(next)
}
func LoggerWithConfig(c LogConfig) MiddlewareFunc {
return func (next http.Handler) http.Handler {
out := c.Output
if out == nil {
out = os.Stdout
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
path := r.URL.Path
raw := r.URL.RawQuery
sw := statusWriter{
ResponseWriter: w,
status: 0,
}
next.ServeHTTP(&sw, r)
if raw != "" {
path = fmt.Sprintf("%s?%s", path, raw)
}
stop := time.Now()
p := LogFormatterParams{
Request: r,
TimeStamp: stop,
Latency: stop.Sub(start),
ClientIP: "",
Method: r.Method,
StatusCode: sw.status,
Path: path,
}
fmt.Fprintf(out, formatter(p))
})
}
}
func formatter(p LogFormatterParams) string {
statusColor := p.StatusCodeColor()
methodColor := p.MethodColor()
resetColor := p.ResetColor()
if p.Latency > time.Minute {
p.Latency = p.Latency - p.Latency%time.Second
}
return fmt.Sprintf("[MUX] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n",
p.TimeStamp.Format("2006/01/02 - 15:04:05"),
statusColor, p.StatusCode, resetColor,
p.Latency,
p.ClientIP,
methodColor, p.Method, resetColor,
p.Path,
)
}

58
logger_test.go

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
package mux
import (
"bytes"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func testHandler(status int) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
}
}
func TestLogger(t *testing.T) {
buffer := new(bytes.Buffer)
r := NewRouter()
r.Use(LoggerWithConfig(LogConfig{Output:buffer}))
r.HandleFunc("/example", testHandler(http.StatusOK)).
Methods("GET", "POST", "PUT", "DELETE", "OPTIONS")
rw := NewRecorder()
req := newRequest("GET", "/example")
r.ServeHTTP(rw, req)
assert.Contains(t, buffer.String(), "200")
assert.Contains(t, buffer.String(), "GET")
assert.Contains(t, buffer.String(), "/example")
buffer.Reset()
req = newRequest("POST", "/example")
r.ServeHTTP(rw, req)
assert.Contains(t, buffer.String(), "200")
assert.Contains(t, buffer.String(), "POST")
assert.Contains(t, buffer.String(), "/example")
buffer.Reset()
req = newRequest("PUT", "/example")
r.ServeHTTP(rw, req)
assert.Contains(t, buffer.String(), "200")
assert.Contains(t, buffer.String(), "PUT")
assert.Contains(t, buffer.String(), "/example")
buffer.Reset()
req = newRequest("DELETE", "/example")
r.ServeHTTP(rw, req)
assert.Contains(t, buffer.String(), "200")
assert.Contains(t, buffer.String(), "DELETE")
assert.Contains(t, buffer.String(), "/example")
buffer.Reset()
req = newRequest("OPTIONS", "/example")
r.ServeHTTP(rw, req)
assert.Contains(t, buffer.String(), "200")
assert.Contains(t, buffer.String(), "OPTIONS")
assert.Contains(t, buffer.String(), "/example")
}
Loading…
Cancel
Save