Repository: caddyserver/caddy
File: modules/caddyhttp/server.go (Go)

Code before:
	loggableReq := zap.Object("request", LoggableHTTPRequest{
		Request:              r,
		ShouldLogCredentials: shouldLogCredentials,
	})
	errLog := s.errorLogger.With(loggableReq)

	var duration time.Duration

	if s.shouldLogRequest(r) {
		wrec := NewResponseRecorder(w, nil, nil)
		w = wrec

		// wrap the request body in a LengthReader
		// so we can track the number of bytes read from it
		var bodyReader *lengthReader
		if r.Body != nil {
			bodyReader = &lengthReader{Source: r.Body}
			r.Body = bodyReader
		}

		// capture the original version of the request
		accLog := s.accessLogger.With(loggableReq)

		defer func() {
			// this request may be flagged as omitted from the logs
			if skipLog, ok := GetVar(r.Context(), SkipLogVar).(bool); ok && skipLog {
				return
			}

			repl.Set("http.response.status", wrec.Status()) // will be 0 if no response is written by us (Go will write 200 to client)
			repl.Set("http.response.size", wrec.Size())
			repl.Set("http.response.duration", duration)
			repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)

			logger := accLog
			if s.Logs != nil {
				logger = s.Logs.wrapLogger(logger, r.Host)
			}

			log := logger.Info
			if wrec.Status() >= 400 {
				log = logger.Error
			}

			userID, _ := repl.GetString("http.auth.user.id")

			reqBodyLength := 0
			if bodyReader != nil {
				reqBodyLength = bodyReader.Length
			}


Review comment (suggestion):
Might be a long shot, but does this have to be a pointer? Just wondering if we can avoid an allocation.

Code after:
		return
	}

	repl := caddy.NewReplacer()
	r = PrepareRequest(r, repl, w, s)

	// encode the request for logging purposes before
	// it enters any handler chain; this is necessary
	// to capture the original request in case it gets
	// modified during handling
	shouldLogCredentials := s.Logs != nil && s.Logs.ShouldLogCredentials
	loggableReq := zap.Object("request", LoggableHTTPRequest{
		Request:              r,
		ShouldLogCredentials: shouldLogCredentials,
	})
	errLog := s.errorLogger.With(loggableReq)

	var duration time.Duration

	if s.shouldLogRequest(r) {
		wrec := NewResponseRecorder(w, nil, nil)
		w = wrec

		// wrap the request body in a LengthReader
		// so we can track the number of bytes read from it
		var bodyReader *lengthReader
		if r.Body != nil {
			bodyReader = &lengthReader{Source: r.Body}
			r.Body = bodyReader
		}

		// capture the original version of the request
		accLog := s.accessLogger.With(loggableReq)

		defer func() {
			// this request may be flagged as omitted from the logs
			if skipLog, ok := GetVar(r.Context(), SkipLogVar).(bool); ok && skipLog {
				return
			}

			repl.Set("http.response.status", wrec.Status()) // will be 0 if no response is written by us (Go will write 200 to client)
			repl.Set("http.response.size", wrec.Size())
			repl.Set("http.response.duration", duration)
			repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)

			logger := accLog
			if s.Logs != nil {
				logger = s.Logs.wrapLogger(logger, r.Host)
			}

			log := logger.Info