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