github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/log/request.go (about) 1 /* 2 * Copyright 2020 The Compass Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package log 18 19 import ( 20 "net/http" 21 "strings" 22 "time" 23 24 "github.com/kyma-incubator/compass/components/director/pkg/correlation" 25 26 "github.com/sirupsen/logrus" 27 ) 28 29 // RequestLogger returns middleware that setups request scoped logging. 30 // URL paths starting with pathsToLogOnDebug will be logged on debug instead of info. 31 func RequestLogger(pathsToLogOnDebug ...string) func(next http.Handler) http.Handler { 32 return func(next http.Handler) http.Handler { 33 return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 34 ctx := r.Context() 35 entry := LoggerWithCorrelationID(r) 36 37 ctx = ContextWithLogger(ctx, entry) 38 ctx = ContextWithMdc(ctx) 39 r = r.WithContext(ctx) 40 41 start := time.Now() 42 43 remoteAddr := r.RemoteAddr 44 if realIP := r.Header.Get("X-Real-IP"); realIP != "" { 45 remoteAddr = realIP 46 } 47 48 logOnDebug := shouldLogOnDebug(r.URL.Path, pathsToLogOnDebug) 49 50 beforeLogger := entry.WithFields(logrus.Fields{ 51 "request": r.RequestURI, 52 "method": r.Method, 53 "remote": remoteAddr, 54 }) 55 beforeLogFunc := beforeLogger.Info 56 if logOnDebug { 57 beforeLogFunc = beforeLogger.Debug 58 } 59 beforeLogFunc("Started handling request...") 60 61 lrw := newLoggingResponseWriter(rw) 62 next.ServeHTTP(lrw, r) 63 64 duration := time.Since(start) 65 66 afterLogger := entry.WithFields(logrus.Fields{ 67 "status_code": lrw.statusCode, 68 "took": duration, 69 }) 70 71 if mdc := MdcFromContext(ctx); nil != mdc { 72 afterLogger = mdc.appendFields(afterLogger) 73 } 74 75 afterLogFunc := afterLogger.Info 76 if logOnDebug { 77 afterLogFunc = afterLogger.Debug 78 } 79 afterLogFunc("Finished handling request...") 80 }) 81 } 82 } 83 84 func shouldLogOnDebug(requestPath string, pathsToLogOnDebug []string) bool { 85 for _, path := range pathsToLogOnDebug { 86 if strings.HasPrefix(requestPath, path) { 87 return true 88 } 89 } 90 return false 91 } 92 93 // LoggerWithCorrelationID missing godoc 94 func LoggerWithCorrelationID(r *http.Request) *logrus.Entry { 95 ctx := r.Context() 96 entry := C(ctx) 97 if correlationID := correlation.CorrelationIDForRequest(r); correlationID != "" { 98 entry = entry.WithField(FieldRequestID, correlationID) 99 } 100 101 return entry 102 }