Skip to content

Commit

Permalink
Add LoggerWithFormatter method (#1677)
Browse files Browse the repository at this point in the history
* Add LoggerWithFormatter

* Add tests for LoggerWithFormatter & LoggerWithConfig

* Add note for README

* Add tests for DefaultLogFormatter

* Add comment

* Change DefaultLogFormatter to a private method
  • Loading branch information
sairoutine authored and thinkerou committed Dec 12, 2018
1 parent cce4958 commit f76ccb2
Show file tree
Hide file tree
Showing 3 changed files with 324 additions and 24 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
- [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default)
- [Using middleware](#using-middleware)
- [How to write log file](#how-to-write-log-file)
- [Custom Log Format](#custom-log-format)
- [Model binding and validation](#model-binding-and-validation)
- [Custom Validators](#custom-validators)
- [Only Bind Query String](#only-bind-query-string)
Expand Down Expand Up @@ -528,6 +529,43 @@ func main() {
}
```

### Custom Log Format
```go
func main() {
router := gin.New()

// LoggerWithFormatter middleware will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {

// your custom format
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
router.Use(gin.Recovery())

router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})

router.Run(":8080")
}
```

**Sample Output**
```
::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
```

### Model binding and validation

To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz).
Expand Down
116 changes: 93 additions & 23 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,56 @@ var (
disableColor = false
)

// LoggerConfig defines the config for Logger middleware.
type LoggerConfig struct {
// Optional. Default value is gin.defaultLogFormatter
Formatter LogFormatter

// Output is a writer where logs are written.
// Optional. Default value is gin.DefaultWriter.
Output io.Writer

// SkipPathes is a url path array which logs are not written.
// Optional.
SkipPathes []string
}

// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
type LogFormatter func(params LogFormatterParams) string

// LogFormatterParams is the structure any formatter will be handed when time to log comes
type LogFormatterParams struct {
Request *http.Request
TimeStamp time.Time
StatusCode int
Latency time.Duration
ClientIP string
Method string
Path string
ErrorMessage string
IsTerm bool
}

// defaultLogFormatter is the default log format function Logger middleware uses.
var defaultLogFormatter = func(param LogFormatterParams) string {
var statusColor, methodColor, resetColor string
if param.IsTerm {
statusColor = colorForStatus(param.StatusCode)
methodColor = colorForMethod(param.Method)
resetColor = reset
}

return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
statusColor, param.StatusCode, resetColor,
param.Latency,
param.ClientIP,
methodColor, param.Method, resetColor,
param.Path,
param.ErrorMessage,
)
}

// DisableConsoleColor disables color output in the console.
func DisableConsoleColor() {
disableColor = true
Expand All @@ -50,12 +100,39 @@ func ErrorLoggerT(typ ErrorType) HandlerFunc {
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
// By default gin.DefaultWriter = os.Stdout.
func Logger() HandlerFunc {
return LoggerWithWriter(DefaultWriter)
return LoggerWithConfig(LoggerConfig{})
}

// LoggerWithFormatter instance a Logger middleware with the specified log format function.
func LoggerWithFormatter(f LogFormatter) HandlerFunc {
return LoggerWithConfig(LoggerConfig{
Formatter: f,
})
}

// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
return LoggerWithConfig(LoggerConfig{
Output: out,
SkipPathes: notlogged,
})
}

// LoggerWithConfig instance a Logger middleware with config.
func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
formatter := conf.Formatter
if formatter == nil {
formatter = defaultLogFormatter
}

out := conf.Output
if out == nil {
out = DefaultWriter
}

notlogged := conf.SkipPathes

isTerm := true

if w, ok := out.(*os.File); !ok ||
Expand Down Expand Up @@ -85,34 +162,27 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {

// Log only when path is not being skipped
if _, ok := skip[path]; !ok {
// Stop timer
end := time.Now()
latency := end.Sub(start)

clientIP := c.ClientIP()
method := c.Request.Method
statusCode := c.Writer.Status()
var statusColor, methodColor, resetColor string
if isTerm {
statusColor = colorForStatus(statusCode)
methodColor = colorForMethod(method)
resetColor = reset
param := LogFormatterParams{
Request: c.Request,
IsTerm: isTerm,
}
comment := c.Errors.ByType(ErrorTypePrivate).String()

// Stop timer
param.TimeStamp = time.Now()
param.Latency = param.TimeStamp.Sub(start)

param.ClientIP = c.ClientIP()
param.Method = c.Request.Method
param.StatusCode = c.Writer.Status()
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()

if raw != "" {
path = path + "?" + raw
}

fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
end.Format("2006/01/02 - 15:04:05"),
statusColor, statusCode, resetColor,
latency,
clientIP,
methodColor, method, resetColor,
path,
comment,
)
param.Path = path

fmt.Fprintf(out, formatter(param))
}
}
}
Expand Down
Loading

0 comments on commit f76ccb2

Please sign in to comment.