podman

Форк
0
270 строк · 6.6 Кб
1
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
2
// Use of this source code is governed by a MIT style
3
// license that can be found in the LICENSE file.
4

5
package gin
6

7
import (
8
	"fmt"
9
	"io"
10
	"net/http"
11
	"os"
12
	"time"
13

14
	"github.com/mattn/go-isatty"
15
)
16

17
type consoleColorModeValue int
18

19
const (
20
	autoColor consoleColorModeValue = iota
21
	disableColor
22
	forceColor
23
)
24

25
const (
26
	green   = "\033[97;42m"
27
	white   = "\033[90;47m"
28
	yellow  = "\033[90;43m"
29
	red     = "\033[97;41m"
30
	blue    = "\033[97;44m"
31
	magenta = "\033[97;45m"
32
	cyan    = "\033[97;46m"
33
	reset   = "\033[0m"
34
)
35

36
var consoleColorMode = autoColor
37

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

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

47
	// SkipPaths is an url path array which logs are not written.
48
	// Optional.
49
	SkipPaths []string
50
}
51

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

55
// LogFormatterParams is the structure any formatter will be handed when time to log comes
56
type LogFormatterParams struct {
57
	Request *http.Request
58

59
	// TimeStamp shows the time after the server returns a response.
60
	TimeStamp time.Time
61
	// StatusCode is HTTP response code.
62
	StatusCode int
63
	// Latency is how much time the server cost to process a certain request.
64
	Latency time.Duration
65
	// ClientIP equals Context's ClientIP method.
66
	ClientIP string
67
	// Method is the HTTP method given to the request.
68
	Method string
69
	// Path is a path the client requests.
70
	Path string
71
	// ErrorMessage is set if error has occurred in processing the request.
72
	ErrorMessage string
73
	// isTerm shows whether gin's output descriptor refers to a terminal.
74
	isTerm bool
75
	// BodySize is the size of the Response Body
76
	BodySize int
77
	// Keys are the keys set on the request's context.
78
	Keys map[string]any
79
}
80

81
// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
82
func (p *LogFormatterParams) StatusCodeColor() string {
83
	code := p.StatusCode
84

85
	switch {
86
	case code >= http.StatusOK && code < http.StatusMultipleChoices:
87
		return green
88
	case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
89
		return white
90
	case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
91
		return yellow
92
	default:
93
		return red
94
	}
95
}
96

97
// MethodColor is the ANSI color for appropriately logging http method to a terminal.
98
func (p *LogFormatterParams) MethodColor() string {
99
	method := p.Method
100

101
	switch method {
102
	case http.MethodGet:
103
		return blue
104
	case http.MethodPost:
105
		return cyan
106
	case http.MethodPut:
107
		return yellow
108
	case http.MethodDelete:
109
		return red
110
	case http.MethodPatch:
111
		return green
112
	case http.MethodHead:
113
		return magenta
114
	case http.MethodOptions:
115
		return white
116
	default:
117
		return reset
118
	}
119
}
120

121
// ResetColor resets all escape attributes.
122
func (p *LogFormatterParams) ResetColor() string {
123
	return reset
124
}
125

126
// IsOutputColor indicates whether can colors be outputted to the log.
127
func (p *LogFormatterParams) IsOutputColor() bool {
128
	return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm)
129
}
130

131
// defaultLogFormatter is the default log format function Logger middleware uses.
132
var defaultLogFormatter = func(param LogFormatterParams) string {
133
	var statusColor, methodColor, resetColor string
134
	if param.IsOutputColor() {
135
		statusColor = param.StatusCodeColor()
136
		methodColor = param.MethodColor()
137
		resetColor = param.ResetColor()
138
	}
139

140
	if param.Latency > time.Minute {
141
		param.Latency = param.Latency.Truncate(time.Second)
142
	}
143
	return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
144
		param.TimeStamp.Format("2006/01/02 - 15:04:05"),
145
		statusColor, param.StatusCode, resetColor,
146
		param.Latency,
147
		param.ClientIP,
148
		methodColor, param.Method, resetColor,
149
		param.Path,
150
		param.ErrorMessage,
151
	)
152
}
153

154
// DisableConsoleColor disables color output in the console.
155
func DisableConsoleColor() {
156
	consoleColorMode = disableColor
157
}
158

159
// ForceConsoleColor force color output in the console.
160
func ForceConsoleColor() {
161
	consoleColorMode = forceColor
162
}
163

164
// ErrorLogger returns a HandlerFunc for any error type.
165
func ErrorLogger() HandlerFunc {
166
	return ErrorLoggerT(ErrorTypeAny)
167
}
168

169
// ErrorLoggerT returns a HandlerFunc for a given error type.
170
func ErrorLoggerT(typ ErrorType) HandlerFunc {
171
	return func(c *Context) {
172
		c.Next()
173
		errors := c.Errors.ByType(typ)
174
		if len(errors) > 0 {
175
			c.JSON(-1, errors)
176
		}
177
	}
178
}
179

180
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
181
// By default, gin.DefaultWriter = os.Stdout.
182
func Logger() HandlerFunc {
183
	return LoggerWithConfig(LoggerConfig{})
184
}
185

186
// LoggerWithFormatter instance a Logger middleware with the specified log format function.
187
func LoggerWithFormatter(f LogFormatter) HandlerFunc {
188
	return LoggerWithConfig(LoggerConfig{
189
		Formatter: f,
190
	})
191
}
192

193
// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
194
// Example: os.Stdout, a file opened in write mode, a socket...
195
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
196
	return LoggerWithConfig(LoggerConfig{
197
		Output:    out,
198
		SkipPaths: notlogged,
199
	})
200
}
201

202
// LoggerWithConfig instance a Logger middleware with config.
203
func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
204
	formatter := conf.Formatter
205
	if formatter == nil {
206
		formatter = defaultLogFormatter
207
	}
208

209
	out := conf.Output
210
	if out == nil {
211
		out = DefaultWriter
212
	}
213

214
	notlogged := conf.SkipPaths
215

216
	isTerm := true
217

218
	if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
219
		(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
220
		isTerm = false
221
	}
222

223
	var skip map[string]struct{}
224

225
	if length := len(notlogged); length > 0 {
226
		skip = make(map[string]struct{}, length)
227

228
		for _, path := range notlogged {
229
			skip[path] = struct{}{}
230
		}
231
	}
232

233
	return func(c *Context) {
234
		// Start timer
235
		start := time.Now()
236
		path := c.Request.URL.Path
237
		raw := c.Request.URL.RawQuery
238

239
		// Process request
240
		c.Next()
241

242
		// Log only when path is not being skipped
243
		if _, ok := skip[path]; !ok {
244
			param := LogFormatterParams{
245
				Request: c.Request,
246
				isTerm:  isTerm,
247
				Keys:    c.Keys,
248
			}
249

250
			// Stop timer
251
			param.TimeStamp = time.Now()
252
			param.Latency = param.TimeStamp.Sub(start)
253

254
			param.ClientIP = c.ClientIP()
255
			param.Method = c.Request.Method
256
			param.StatusCode = c.Writer.Status()
257
			param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
258

259
			param.BodySize = c.Writer.Size()
260

261
			if raw != "" {
262
				path = path + "?" + raw
263
			}
264

265
			param.Path = path
266

267
			fmt.Fprint(out, formatter(param))
268
		}
269
	}
270
}
271

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.