mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Parse external request id from request headers, and print it in access log (#22906)
Close: #22890. --- ### Configure in .ini file: ```ini [log] REQUEST_ID_HEADERS = X-Request-ID, X-Trace-Id ``` ### Params in Request Header ``` X-Trace-ID: trace-id-1q2w3e4r ```  ### Log output: 
This commit is contained in:
		| @@ -6,7 +6,9 @@ package context | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
| 	"time" | ||||
|  | ||||
| @@ -20,13 +22,39 @@ type routerLoggerOptions struct { | ||||
| 	Start          *time.Time | ||||
| 	ResponseWriter http.ResponseWriter | ||||
| 	Ctx            map[string]interface{} | ||||
| 	RequestID      *string | ||||
| } | ||||
|  | ||||
| var signedUserNameStringPointerKey interface{} = "signedUserNameStringPointerKey" | ||||
|  | ||||
| const keyOfRequestIDInTemplate = ".RequestID" | ||||
|  | ||||
| // According to: | ||||
| // TraceId: A valid trace identifier is a 16-byte array with at least one non-zero byte | ||||
| // MD5 output is 16 or 32 bytes: md5-bytes is 16, md5-hex is 32 | ||||
| // SHA1: similar, SHA1-bytes is 20, SHA1-hex is 40. | ||||
| // UUID is 128-bit, 32 hex chars, 36 ASCII chars with 4 dashes | ||||
| // So, we accept a Request ID with a maximum character length of 40 | ||||
| const maxRequestIDByteLength = 40 | ||||
|  | ||||
| func parseRequestIDFromRequestHeader(req *http.Request) string { | ||||
| 	requestID := "-" | ||||
| 	for _, key := range setting.Log.RequestIDHeaders { | ||||
| 		if req.Header.Get(key) != "" { | ||||
| 			requestID = req.Header.Get(key) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if len(requestID) > maxRequestIDByteLength { | ||||
| 		requestID = fmt.Sprintf("%s...", requestID[:maxRequestIDByteLength]) | ||||
| 	} | ||||
| 	return requestID | ||||
| } | ||||
|  | ||||
| // AccessLogger returns a middleware to log access logger | ||||
| func AccessLogger() func(http.Handler) http.Handler { | ||||
| 	logger := log.GetLogger("access") | ||||
| 	needRequestID := len(setting.Log.RequestIDHeaders) > 0 && strings.Contains(setting.Log.AccessLogTemplate, keyOfRequestIDInTemplate) | ||||
| 	logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate) | ||||
| 	return func(next http.Handler) http.Handler { | ||||
| 		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | ||||
| @@ -34,6 +62,11 @@ func AccessLogger() func(http.Handler) http.Handler { | ||||
| 			identity := "-" | ||||
| 			r := req.WithContext(context.WithValue(req.Context(), signedUserNameStringPointerKey, &identity)) | ||||
|  | ||||
| 			var requestID string | ||||
| 			if needRequestID { | ||||
| 				requestID = parseRequestIDFromRequestHeader(req) | ||||
| 			} | ||||
|  | ||||
| 			next.ServeHTTP(w, r) | ||||
| 			rw := w.(ResponseWriter) | ||||
|  | ||||
| @@ -47,6 +80,7 @@ func AccessLogger() func(http.Handler) http.Handler { | ||||
| 					"RemoteAddr": req.RemoteAddr, | ||||
| 					"Req":        req, | ||||
| 				}, | ||||
| 				RequestID: &requestID, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				log.Error("Could not set up chi access logger: %v", err.Error()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user