1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-05 19:27:05 +00:00

accesslog: add IP in builtin fields, change the format a bit. Default func: remove compression middleware, force-set debug log level, replace the old request logger with the accesslog one, use request id middlewareand keep recovery

This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-09-11 09:38:55 +03:00
parent 0f5ec75d54
commit e63d1041d2
10 changed files with 95 additions and 46 deletions

View File

@@ -10,7 +10,6 @@ import (
"sync"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/memstore"
)
@@ -27,7 +26,7 @@ const (
// GetFields returns the accesslog fields for this request.
// Returns a store which the caller can use to
// set/get/remove custom log fields. Use its `Set` method.
func GetFields(ctx iris.Context) (fields *Fields) {
func GetFields(ctx *context.Context) (fields *Fields) {
if v := ctx.Values().Get(fieldsContextKey); v != nil {
fields = v.(*Fields)
} else {
@@ -40,18 +39,18 @@ func GetFields(ctx iris.Context) (fields *Fields) {
// Skip called when a specific route should be skipped from the logging process.
// It's an easy to use alternative for iris.NewConditionalHandler.
func Skip(ctx iris.Context) {
func Skip(ctx *context.Context) {
ctx.Values().Set(skipLogContextKey, struct{}{})
}
// SkipHandler same as `Skip` but it can be used
// as a middleware, it executes ctx.Next().
func SkipHandler(ctx iris.Context) {
func SkipHandler(ctx *context.Context) {
Skip(ctx)
ctx.Next()
}
func shouldSkip(ctx iris.Context) bool {
func shouldSkip(ctx *context.Context) bool {
return ctx.Values().Get(skipLogContextKey) != nil
}
@@ -134,9 +133,11 @@ type AccessLog struct {
// Defaults to false.
Async bool
// The time format for current time on log print.
// Defaults to the Iris Application's TimeFormat.
// Defaults to ""2006-01-02 15:04:05" on `New` function.
// Set it to empty to inherit the Iris Application's TimeFormat.
TimeFormat string
// IP displays the remote address.
IP bool
// The actual number of bytes received and sent on the network (headers + body).
// It is kind of "slow" operation as it uses the httputil to dumb request
// and response to get the total amount of bytes (headers + body).
@@ -197,10 +198,15 @@ const (
// Register by its `Handler` method.
// See `File` package-level function too.
//
// Example: https://github.com/kataras/iris/tree/master/_examples/logging/request-logger/accesslog
// Examples:
// https://github.com/kataras/iris/tree/master/_examples/logging/request-logger/accesslog
// https://github.com/kataras/iris/tree/master/_examples/logging/request-logger/accesslog-template
// https://github.com/kataras/iris/tree/master/_examples/logging/request-logger/accesslog-broker
func New(w io.Writer) *AccessLog {
ac := &AccessLog{
Clock: clockFunc(time.Now),
TimeFormat: "2006-01-02 15:04:05",
IP: true,
BytesReceived: true,
BytesSent: true,
BodyMinify: true,
@@ -527,6 +533,11 @@ func (ac *AccessLog) after(ctx *context.Context, lat time.Duration, method, path
timeFormat = ctx.Application().ConfigurationReadOnly().GetTimeFormat()
}
ip := ""
if ac.IP {
ip = ctx.RemoteAddr()
}
if err := ac.Print(ctx,
// latency between begin and finish of the handlers chain.
lat,
@@ -535,6 +546,8 @@ func (ac *AccessLog) after(ctx *context.Context, lat time.Duration, method, path
ctx.GetStatusCode(),
// original request's method and path.
method, path,
// remote ip.
ip,
requestBody, responseBody,
bytesReceived, bytesSent,
ctx.Params(), ctx.URLParamsSorted(), *fields,
@@ -545,7 +558,7 @@ func (ac *AccessLog) after(ctx *context.Context, lat time.Duration, method, path
// Print writes a log manually.
// The `Handler` method calls it.
func (ac *AccessLog) Print(ctx *context.Context, latency time.Duration, timeFormat string, code int, method, path, reqBody, respBody string, bytesReceived, bytesSent int, params *context.RequestParams, query []memstore.StringEntry, fields []memstore.Entry) (err error) {
func (ac *AccessLog) Print(ctx *context.Context, latency time.Duration, timeFormat string, code int, method, path, ip, reqBody, respBody string, bytesReceived, bytesSent int, params *context.RequestParams, query []memstore.StringEntry, fields []memstore.Entry) (err error) {
now := ac.Clock.Now()
if hasFormatter, hasBroker := ac.formatter != nil, ac.broker != nil; hasFormatter || hasBroker {
@@ -555,9 +568,10 @@ func (ac *AccessLog) Print(ctx *context.Context, latency time.Duration, timeForm
log.TimeFormat = timeFormat
log.Timestamp = now.UnixNano() / 1000000
log.Latency = latency
log.Code = code
log.Method = method
log.Path = path
log.Code = code
log.IP = ip
log.Query = query
log.PathParams = params.Store
log.Fields = fields
@@ -593,13 +607,14 @@ func (ac *AccessLog) Print(ctx *context.Context, latency time.Duration, timeForm
// the number of separators are the same, in order to be easier
// for 3rd-party programs to read the result log file.
_, err = fmt.Fprintf(ac, "%s|%s|%s|%s|%s|%d|%s|%s|%s|%s|\n",
_, err = fmt.Fprintf(ac, "%s|%s|%d|%s|%s|%s|%s|%s|%s|%s|%s|\n",
now.Format(timeFormat),
latency,
code,
method,
path,
ip,
requestValues,
code,
formatBytes(bytesReceived),
formatBytes(bytesSent),
reqBody,

View File

@@ -35,7 +35,7 @@ func TestAccessLogPrint_Simple(t *testing.T) {
for i := 0; i < goroutinesN; i++ {
wg.Add(1)
expected += "0001-01-01 00:00:00|1s|GET|/path_value?url_query=url_query_value|path_param=path_param_value url_query=url_query_value custom=custom_value|200|||Incoming|Outcoming|\n"
expected += "0001-01-01 00:00:00|1s|200|GET|/path_value?url_query=url_query_value|::1|path_param=path_param_value url_query=url_query_value custom=custom_value|||Incoming|Outcoming|\n"
go func() {
defer wg.Done()
@@ -47,6 +47,7 @@ func TestAccessLogPrint_Simple(t *testing.T) {
200,
"GET",
"/path_value?url_query=url_query_value",
"::1",
"Incoming",
"Outcoming",
0,
@@ -73,7 +74,6 @@ func TestAccessLogPrint_Simple(t *testing.T) {
func TestAccessLogBroker(t *testing.T) {
w := new(bytes.Buffer)
ac := New(w)
ac.TimeFormat = "2006-01-02 15:04:05"
ac.Clock = TClock(time.Time{})
broker := ac.Broker()
@@ -123,6 +123,7 @@ func TestAccessLogBroker(t *testing.T) {
"",
"",
"",
"",
0,
0,
&context.RequestParams{},
@@ -161,7 +162,6 @@ func (*noOpFormatter) Format(*Log) (bool, error) {
func BenchmarkAccessLogAfter(b *testing.B) {
ac := New(ioutil.Discard)
ac.Clock = TClock(time.Time{})
ac.TimeFormat = "2006-01-02 15:04:05"
ac.BytesReceived = false
ac.BytesSent = false
ac.BodyMinify = false
@@ -169,6 +169,7 @@ func BenchmarkAccessLogAfter(b *testing.B) {
ac.ResponseBody = false
ac.KeepMultiLineError = true
ac.Async = false
ac.IP = false
ac.SetFormatter(new(noOpFormatter)) // just to create the log structure.)
ctx := new(context.Context)

View File

@@ -28,11 +28,13 @@ type Log struct {
// Request-Response latency.
Latency time.Duration `json:"latency"`
// The response status code.
Code int `json:"code"`
// Init request's Method and Path.
Method string `json:"method"`
Path string `json:"path"`
// The response status code.
Code int `json:"code"`
// The Remote Address.
IP string `json:"ip,omitempty"`
// Sorted URL Query arguments.
Query []memstore.StringEntry `json:"query,omitempty"`
// Dynamic path parameters.
@@ -223,7 +225,7 @@ func (f *Template) SetOutput(dest io.Writer) {
f.dest = dest
}
const defaultTmplText = "{{.Now.Format .TimeFormat}}|{{.Latency}}|{{.Method}}|{{.Path}}|{{.RequestValuesLine}}|{{.Code}}|{{.BytesReceivedLine}}|{{.BytesSentLine}}|{{.Request}}|{{.Response}}|\n"
const defaultTmplText = "{{.Now.Format .TimeFormat}}|{{.Latency}}|{{.Code}}|{{.Method}}|{{.Path}}|{{.IP}}|{{.RequestValuesLine}}|{{.BytesReceivedLine}}|{{.BytesSentLine}}|{{.Request}}|{{.Response}}|\n"
// Format prints the logs in text/template format.
func (f *Template) Format(log *Log) (bool, error) {