summaryrefslogtreecommitdiffstats
path: root/pkg/v1/remote/transport/logger.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/v1/remote/transport/logger.go')
-rw-r--r--pkg/v1/remote/transport/logger.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/pkg/v1/remote/transport/logger.go b/pkg/v1/remote/transport/logger.go
new file mode 100644
index 0000000..c341f84
--- /dev/null
+++ b/pkg/v1/remote/transport/logger.go
@@ -0,0 +1,91 @@
+// Copyright 2020 Google LLC All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package transport
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httputil"
+ "time"
+
+ "github.com/google/go-containerregistry/internal/redact"
+ "github.com/google/go-containerregistry/pkg/logs"
+)
+
+type logTransport struct {
+ inner http.RoundTripper
+}
+
+// NewLogger returns a transport that logs requests and responses to
+// github.com/google/go-containerregistry/pkg/logs.Debug.
+func NewLogger(inner http.RoundTripper) http.RoundTripper {
+ return &logTransport{inner}
+}
+
+func (t *logTransport) RoundTrip(in *http.Request) (out *http.Response, err error) {
+ // Inspired by: github.com/motemen/go-loghttp
+
+ // We redact token responses and binary blobs in response/request.
+ omitBody, reason := redact.FromContext(in.Context())
+ if omitBody {
+ logs.Debug.Printf("--> %s %s [body redacted: %s]", in.Method, in.URL, reason)
+ } else {
+ logs.Debug.Printf("--> %s %s", in.Method, in.URL)
+ }
+
+ // Save these headers so we can redact Authorization.
+ savedHeaders := in.Header.Clone()
+ if in.Header != nil && in.Header.Get("authorization") != "" {
+ in.Header.Set("authorization", "<redacted>")
+ }
+
+ b, err := httputil.DumpRequestOut(in, !omitBody)
+ if err == nil {
+ logs.Debug.Println(string(b))
+ } else {
+ logs.Debug.Printf("Failed to dump request %s %s: %v", in.Method, in.URL, err)
+ }
+
+ // Restore the non-redacted headers.
+ in.Header = savedHeaders
+
+ start := time.Now()
+ out, err = t.inner.RoundTrip(in)
+ duration := time.Since(start)
+ if err != nil {
+ logs.Debug.Printf("<-- %v %s %s (%s)", err, in.Method, in.URL, duration)
+ }
+ if out != nil {
+ msg := fmt.Sprintf("<-- %d", out.StatusCode)
+ if out.Request != nil {
+ msg = fmt.Sprintf("%s %s", msg, out.Request.URL)
+ }
+ msg = fmt.Sprintf("%s (%s)", msg, duration)
+
+ if omitBody {
+ msg = fmt.Sprintf("%s [body redacted: %s]", msg, reason)
+ }
+
+ logs.Debug.Print(msg)
+
+ b, err := httputil.DumpResponse(out, !omitBody)
+ if err == nil {
+ logs.Debug.Println(string(b))
+ } else {
+ logs.Debug.Printf("Failed to dump response %s %s: %v", in.Method, in.URL, err)
+ }
+ }
+ return
+}