Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-08-22 20:04:56 -04:00
pkg-proxy/internal/httpclient/access_log.go
Andrew Nesbitt e4fbf3f277
Add JSONL access logging (#269)
* Add JSONL access logging

* Initialize access log before server dependencies
2026-08-16 18:07:39 +01:00

74 lines
1.7 KiB
Go

package httpclient
import (
"log/slog"
"net/http"
"net/url"
"strings"
"time"
"github.com/git-pkgs/proxy/internal/accesslog"
)
type accessLogTransport struct {
base http.RoundTripper
accessLog *accesslog.Logger
logger *slog.Logger
}
// NewAccessLogTransport records each upstream HTTP exchange around base.
func NewAccessLogTransport(base http.RoundTripper, log *accesslog.Logger, logger *slog.Logger) http.RoundTripper {
if base == nil {
base = http.DefaultTransport
}
if logger == nil {
logger = slog.Default()
}
if log == nil {
return base
}
return &accessLogTransport{
base: base,
accessLog: log,
logger: logger,
}
}
func (t *accessLogTransport) RoundTrip(req *http.Request) (*http.Response, error) {
start := time.Now()
resp, err := t.base.RoundTrip(req)
entry := accesslog.Entry{
Event: accesslog.EventUpstream,
RequestID: accesslog.RequestID(req.Context()),
Method: req.Method,
URL: accesslog.URLWithoutSecrets(req.URL),
DurationMS: time.Since(start).Milliseconds(),
}
if resp != nil {
entry.StatusCode = resp.StatusCode
}
if err != nil {
entry.Error = errorWithoutSecrets(err, req.URL)
}
if writeErr := t.accessLog.Write(entry); writeErr != nil {
t.logger.Error("failed to write access log", "error", writeErr)
}
return resp, err
}
func errorWithoutSecrets(err error, requestURL *url.URL) string {
message := err.Error()
if requestURL == nil {
return message
}
cleanURL := accesslog.URLWithoutSecrets(requestURL)
for _, value := range []string{requestURL.String(), requestURL.Redacted()} {
if value != "" {
message = strings.ReplaceAll(message, value, cleanURL)
}
}
return message
}