code.gitea.io/gitea@v1.19.3/modules/web/routing/logger.go (about) 1 // Copyright 2021 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package routing 5 6 import ( 7 "net/http" 8 "time" 9 10 "code.gitea.io/gitea/modules/context" 11 "code.gitea.io/gitea/modules/log" 12 ) 13 14 // NewLoggerHandler is a handler that will log routing to the router log taking account of 15 // routing information 16 func NewLoggerHandler() func(next http.Handler) http.Handler { 17 manager := requestRecordsManager{ 18 requestRecords: map[uint64]*requestRecord{}, 19 } 20 manager.startSlowQueryDetector(3 * time.Second) 21 22 logger := log.GetLogger("router") 23 manager.print = logPrinter(logger) 24 return manager.handler 25 } 26 27 var ( 28 startMessage = log.NewColoredValueBytes("started ", log.DEBUG.Color()) 29 slowMessage = log.NewColoredValueBytes("slow ", log.WARN.Color()) 30 pollingMessage = log.NewColoredValueBytes("polling ", log.INFO.Color()) 31 failedMessage = log.NewColoredValueBytes("failed ", log.WARN.Color()) 32 completedMessage = log.NewColoredValueBytes("completed", log.INFO.Color()) 33 unknownHandlerMessage = log.NewColoredValueBytes("completed", log.ERROR.Color()) 34 ) 35 36 func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { 37 return func(trigger Event, record *requestRecord) { 38 if trigger == StartEvent { 39 if !logger.IsTrace() { 40 // for performance, if the "started" message shouldn't be logged, we just return as early as possible 41 // developers can set the router log level to TRACE to get the "started" request messages. 42 return 43 } 44 // when a request starts, we have no information about the handler function information, we only have the request path 45 req := record.request 46 logger.Trace("router: %s %v %s for %s", startMessage, log.ColoredMethod(req.Method), req.RequestURI, req.RemoteAddr) 47 return 48 } 49 50 req := record.request 51 52 // Get data from the record 53 record.lock.Lock() 54 handlerFuncInfo := record.funcInfo.String() 55 isLongPolling := record.isLongPolling 56 isUnknownHandler := record.funcInfo == nil 57 panicErr := record.panicError 58 record.lock.Unlock() 59 60 if trigger == StillExecutingEvent { 61 message := slowMessage 62 level := log.WARN 63 if isLongPolling { 64 level = log.INFO 65 message = pollingMessage 66 } 67 _ = logger.Log(0, level, "router: %s %v %s for %s, elapsed %v @ %s", 68 message, 69 log.ColoredMethod(req.Method), req.RequestURI, req.RemoteAddr, 70 log.ColoredTime(time.Since(record.startTime)), 71 handlerFuncInfo, 72 ) 73 return 74 } 75 76 if panicErr != nil { 77 _ = logger.Log(0, log.WARN, "router: %s %v %s for %s, panic in %v @ %s, err=%v", 78 failedMessage, 79 log.ColoredMethod(req.Method), req.RequestURI, req.RemoteAddr, 80 log.ColoredTime(time.Since(record.startTime)), 81 handlerFuncInfo, 82 panicErr, 83 ) 84 return 85 } 86 87 var status int 88 if v, ok := record.responseWriter.(context.ResponseWriter); ok { 89 status = v.Status() 90 } 91 level := log.INFO 92 message := completedMessage 93 if isUnknownHandler { 94 level = log.ERROR 95 message = unknownHandlerMessage 96 } 97 98 _ = logger.Log(0, level, "router: %s %v %s for %s, %v %v in %v @ %s", 99 message, 100 log.ColoredMethod(req.Method), req.RequestURI, req.RemoteAddr, 101 log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(status)), log.ColoredTime(time.Since(record.startTime)), 102 handlerFuncInfo, 103 ) 104 } 105 }