Copyright 2019 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package middleware

import (
	
	
	
	
	
	

	
	
)
Logger is the interface used to write request logs to GCP.
type Logger interface {
	Log(logging.Entry)
}
LocalLogger is a logger that can be used when running locally (i.e.: not on GCP)
type LocalLogger struct{}
Log implements the Logger interface via our internal log package.
func ( LocalLogger) ( logging.Entry) {
	var  strings.Builder
	if .HTTPRequest != nil {
		.WriteString(strconv.Itoa(.HTTPRequest.Status) + " ")
		if .HTTPRequest.Request != nil {
			.WriteString(.HTTPRequest.Request.URL.Path + " ")
		}
	}
	.WriteString(fmt.Sprint(.Payload))
	log.Info(context.Background(), .String())
}
RequestLog returns a middleware that logs each incoming requests using the given logger. This logger replaces the built-in appengine request logger, which logged PII when behind IAP, in such a way that was impossible to turn off. Logs may be viewed in Pantheon by selecting the log source corresponding to the AppEngine service name (e.g. 'dev-worker').
func ( Logger) Middleware {
	return func( http.Handler) http.Handler {
		return &handler{delegate: , logger: }
	}
}

type handler struct {
	delegate http.Handler
	logger   Logger
}

func ( *handler) ( http.ResponseWriter,  *http.Request) {
	 := time.Now()
	 := .Header.Get("X-Cloud-Trace-Context")
	 := logging.Info
	if .Method == http.MethodGet && .URL.Path == "/healthz" {
		 = logging.Debug
	}
	.logger.Log(logging.Entry{
		HTTPRequest: &logging.HTTPRequest{Request: },
		Payload: map[string]string{
			"requestType": "request start",
		},
		Severity: ,
		Trace:    ,
	})
	 := &responseWriter{ResponseWriter: }
	.delegate.ServeHTTP(, .WithContext(log.NewContextWithTraceID(.Context(), )))
	 := 
load shedding is a warning, not an error
		 = logging.Warning
	} else if .status >= 500 {
		 = logging.Error
	}
	.logger.Log(logging.Entry{
		HTTPRequest: &logging.HTTPRequest{
			Request: ,
			Status:  translateStatus(.status),
			Latency: time.Since(),
		},
		Payload: map[string]interface{}{
			"requestType": "request end",
			"isRobot":     isRobot(.Header.Get("User-Agent")),
		},
		Severity: ,
		Trace:    ,
	})
}

var browserAgentPrefixes = []string{
	"MobileSafari/",
	"Mozilla/",
	"Opera/",
	"Safari/",
}

func ( string) bool {
	if strings.Contains(strings.ToLower(), "bot/") || strings.Contains(, "robot") {
		return true
	}
	for ,  := range browserAgentPrefixes {
		if strings.HasPrefix(, ) {
			return false
		}
	}
	return true
}

type responseWriter struct {
	http.ResponseWriter

	status int
}

func ( *responseWriter) ( int) {
	.status = 
	.ResponseWriter.WriteHeader()
}

func ( int) int {
	if  == 0 {
		return http.StatusOK
	}
	return