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  }