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  }