Add LoggerWithFormatter method (#1677)
* Add LoggerWithFormatter * Add tests for LoggerWithFormatter & LoggerWithConfig * Add note for README * Add tests for DefaultLogFormatter * Add comment * Change DefaultLogFormatter to a private method
This commit is contained in:
		
							
								
								
									
										38
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								README.md
									
									
									
									
									
								
							@ -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)
 | 
					    - [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default)
 | 
				
			||||||
    - [Using middleware](#using-middleware)
 | 
					    - [Using middleware](#using-middleware)
 | 
				
			||||||
    - [How to write log file](#how-to-write-log-file)
 | 
					    - [How to write log file](#how-to-write-log-file)
 | 
				
			||||||
 | 
					    - [Custom Log Format](#custom-log-format)
 | 
				
			||||||
    - [Model binding and validation](#model-binding-and-validation)
 | 
					    - [Model binding and validation](#model-binding-and-validation)
 | 
				
			||||||
    - [Custom Validators](#custom-validators)
 | 
					    - [Custom Validators](#custom-validators)
 | 
				
			||||||
    - [Only Bind Query String](#only-bind-query-string)
 | 
					    - [Only Bind Query String](#only-bind-query-string)
 | 
				
			||||||
@ -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
 | 
					### 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).
 | 
					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).
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										116
									
								
								logger.go
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								logger.go
									
									
									
									
									
								
							@ -26,6 +26,56 @@ var (
 | 
				
			|||||||
	disableColor = false
 | 
						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.
 | 
					// DisableConsoleColor disables color output in the console.
 | 
				
			||||||
func DisableConsoleColor() {
 | 
					func DisableConsoleColor() {
 | 
				
			||||||
	disableColor = true
 | 
						disableColor = true
 | 
				
			||||||
@ -50,12 +100,39 @@ func ErrorLoggerT(typ ErrorType) HandlerFunc {
 | 
				
			|||||||
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
 | 
					// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
 | 
				
			||||||
// By default gin.DefaultWriter = os.Stdout.
 | 
					// By default gin.DefaultWriter = os.Stdout.
 | 
				
			||||||
func Logger() HandlerFunc {
 | 
					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.
 | 
					// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
 | 
				
			||||||
// Example: os.Stdout, a file opened in write mode, a socket...
 | 
					// Example: os.Stdout, a file opened in write mode, a socket...
 | 
				
			||||||
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
 | 
					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
 | 
						isTerm := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if w, ok := out.(*os.File); !ok ||
 | 
						if w, ok := out.(*os.File); !ok ||
 | 
				
			||||||
@ -85,34 +162,27 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Log only when path is not being skipped
 | 
							// Log only when path is not being skipped
 | 
				
			||||||
		if _, ok := skip[path]; !ok {
 | 
							if _, ok := skip[path]; !ok {
 | 
				
			||||||
			// Stop timer
 | 
								param := LogFormatterParams{
 | 
				
			||||||
			end := time.Now()
 | 
									Request: c.Request,
 | 
				
			||||||
			latency := end.Sub(start)
 | 
									IsTerm:  isTerm,
 | 
				
			||||||
 | 
					 | 
				
			||||||
			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
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			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 != "" {
 | 
								if raw != "" {
 | 
				
			||||||
				path = path + "?" + raw
 | 
									path = path + "?" + raw
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
 | 
								param.Path = path
 | 
				
			||||||
				end.Format("2006/01/02 - 15:04:05"),
 | 
					
 | 
				
			||||||
				statusColor, statusCode, resetColor,
 | 
								fmt.Fprintf(out, formatter(param))
 | 
				
			||||||
				latency,
 | 
					 | 
				
			||||||
				clientIP,
 | 
					 | 
				
			||||||
				methodColor, method, resetColor,
 | 
					 | 
				
			||||||
				path,
 | 
					 | 
				
			||||||
				comment,
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										194
									
								
								logger_test.go
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								logger_test.go
									
									
									
									
									
								
							@ -7,8 +7,10 @@ package gin
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -79,7 +81,179 @@ func TestLogger(t *testing.T) {
 | 
				
			|||||||
	assert.Contains(t, buffer.String(), "404")
 | 
						assert.Contains(t, buffer.String(), "404")
 | 
				
			||||||
	assert.Contains(t, buffer.String(), "GET")
 | 
						assert.Contains(t, buffer.String(), "GET")
 | 
				
			||||||
	assert.Contains(t, buffer.String(), "/notfound")
 | 
						assert.Contains(t, buffer.String(), "/notfound")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoggerWithConfig(t *testing.T) {
 | 
				
			||||||
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
 | 
						router := New()
 | 
				
			||||||
 | 
						router.Use(LoggerWithConfig(LoggerConfig{Output: buffer}))
 | 
				
			||||||
 | 
						router.GET("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.POST("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.PUT("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.DELETE("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.PATCH("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.HEAD("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						router.OPTIONS("/example", func(c *Context) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/example?a=100")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "GET")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "a=100")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// I wrote these first (extending the above) but then realized they are more
 | 
				
			||||||
 | 
						// like integration tests because they test the whole logging process rather
 | 
				
			||||||
 | 
						// than individual functions.  Im not sure where these should go.
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "POST", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "POST")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "PUT", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "PUT")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "DELETE", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "DELETE")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "PATCH", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "PATCH")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "HEAD", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "HEAD")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "OPTIONS", "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "OPTIONS")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/notfound")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "404")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "GET")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/notfound")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoggerWithFormatter(t *testing.T) {
 | 
				
			||||||
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := DefaultWriter
 | 
				
			||||||
 | 
						DefaultWriter = buffer
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							DefaultWriter = d
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						router := New()
 | 
				
			||||||
 | 
						router.Use(LoggerWithFormatter(func(param LogFormatterParams) string {
 | 
				
			||||||
 | 
							return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s\n%s",
 | 
				
			||||||
 | 
								param.TimeStamp.Format("2006/01/02 - 15:04:05"),
 | 
				
			||||||
 | 
								param.StatusCode,
 | 
				
			||||||
 | 
								param.Latency,
 | 
				
			||||||
 | 
								param.ClientIP,
 | 
				
			||||||
 | 
								param.Method,
 | 
				
			||||||
 | 
								param.Path,
 | 
				
			||||||
 | 
								param.ErrorMessage,
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						router.GET("/example", func(c *Context) {})
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/example?a=100")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// output test
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "GET")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "a=100")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoggerWithConfigFormatting(t *testing.T) {
 | 
				
			||||||
 | 
						var gotParam LogFormatterParams
 | 
				
			||||||
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						router := New()
 | 
				
			||||||
 | 
						router.Use(LoggerWithConfig(LoggerConfig{
 | 
				
			||||||
 | 
							Output: buffer,
 | 
				
			||||||
 | 
							Formatter: func(param LogFormatterParams) string {
 | 
				
			||||||
 | 
								// for assert test
 | 
				
			||||||
 | 
								gotParam = param
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s\n%s",
 | 
				
			||||||
 | 
									param.TimeStamp.Format("2006/01/02 - 15:04:05"),
 | 
				
			||||||
 | 
									param.StatusCode,
 | 
				
			||||||
 | 
									param.Latency,
 | 
				
			||||||
 | 
									param.ClientIP,
 | 
				
			||||||
 | 
									param.Method,
 | 
				
			||||||
 | 
									param.Path,
 | 
				
			||||||
 | 
									param.ErrorMessage,
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						router.GET("/example", func(c *Context) {
 | 
				
			||||||
 | 
							// set dummy ClientIP
 | 
				
			||||||
 | 
							c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/example?a=100")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// output test
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "GET")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "/example")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "a=100")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// LogFormatterParams test
 | 
				
			||||||
 | 
						assert.NotNil(t, gotParam.Request)
 | 
				
			||||||
 | 
						assert.NotEmpty(t, gotParam.TimeStamp)
 | 
				
			||||||
 | 
						assert.Equal(t, 200, gotParam.StatusCode)
 | 
				
			||||||
 | 
						assert.NotEmpty(t, gotParam.Latency)
 | 
				
			||||||
 | 
						assert.Equal(t, "20.20.20.20", gotParam.ClientIP)
 | 
				
			||||||
 | 
						assert.Equal(t, "GET", gotParam.Method)
 | 
				
			||||||
 | 
						assert.Equal(t, "/example?a=100", gotParam.Path)
 | 
				
			||||||
 | 
						assert.Empty(t, gotParam.ErrorMessage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDefaultLogFormatter(t *testing.T) {
 | 
				
			||||||
 | 
						timeStamp := time.Unix(1544173902, 0).UTC()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						termFalseParam := LogFormatterParams{
 | 
				
			||||||
 | 
							TimeStamp:    timeStamp,
 | 
				
			||||||
 | 
							StatusCode:   200,
 | 
				
			||||||
 | 
							Latency:      time.Second * 5,
 | 
				
			||||||
 | 
							ClientIP:     "20.20.20.20",
 | 
				
			||||||
 | 
							Method:       "GET",
 | 
				
			||||||
 | 
							Path:         "/",
 | 
				
			||||||
 | 
							ErrorMessage: "",
 | 
				
			||||||
 | 
							IsTerm:       false,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						termTrueParam := LogFormatterParams{
 | 
				
			||||||
 | 
							TimeStamp:    timeStamp,
 | 
				
			||||||
 | 
							StatusCode:   200,
 | 
				
			||||||
 | 
							Latency:      time.Second * 5,
 | 
				
			||||||
 | 
							ClientIP:     "20.20.20.20",
 | 
				
			||||||
 | 
							Method:       "GET",
 | 
				
			||||||
 | 
							Path:         "/",
 | 
				
			||||||
 | 
							ErrorMessage: "",
 | 
				
			||||||
 | 
							IsTerm:       true,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 | 200 |            5s |     20.20.20.20 | GET      /\n", defaultLogFormatter(termFalseParam))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m|            5s |     20.20.20.20 |\x1b[97;44m GET     \x1b[0m /\n", defaultLogFormatter(termTrueParam))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestColorForMethod(t *testing.T) {
 | 
					func TestColorForMethod(t *testing.T) {
 | 
				
			||||||
@ -127,7 +301,7 @@ func TestErrorLogger(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String())
 | 
						assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSkippingPaths(t *testing.T) {
 | 
					func TestLoggerWithWriterSkippingPaths(t *testing.T) {
 | 
				
			||||||
	buffer := new(bytes.Buffer)
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
	router := New()
 | 
						router := New()
 | 
				
			||||||
	router.Use(LoggerWithWriter(buffer, "/skipped"))
 | 
						router.Use(LoggerWithWriter(buffer, "/skipped"))
 | 
				
			||||||
@ -142,6 +316,24 @@ func TestSkippingPaths(t *testing.T) {
 | 
				
			|||||||
	assert.Contains(t, buffer.String(), "")
 | 
						assert.Contains(t, buffer.String(), "")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLoggerWithConfigSkippingPaths(t *testing.T) {
 | 
				
			||||||
 | 
						buffer := new(bytes.Buffer)
 | 
				
			||||||
 | 
						router := New()
 | 
				
			||||||
 | 
						router.Use(LoggerWithConfig(LoggerConfig{
 | 
				
			||||||
 | 
							Output:     buffer,
 | 
				
			||||||
 | 
							SkipPathes: []string{"/skipped"},
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						router.GET("/logged", func(c *Context) {})
 | 
				
			||||||
 | 
						router.GET("/skipped", func(c *Context) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/logged")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "200")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer.Reset()
 | 
				
			||||||
 | 
						performRequest(router, "GET", "/skipped")
 | 
				
			||||||
 | 
						assert.Contains(t, buffer.String(), "")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDisableConsoleColor(t *testing.T) {
 | 
					func TestDisableConsoleColor(t *testing.T) {
 | 
				
			||||||
	New()
 | 
						New()
 | 
				
			||||||
	assert.False(t, disableColor)
 | 
						assert.False(t, disableColor)
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user