Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ require (
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.2
github.com/rs/xid v1.6.0
github.com/sirupsen/logrus v1.9.3
github.com/slackhq/nebula v1.9.7
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
github.com/smallstep/cli-utils v0.12.2
Expand Down
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
50 changes: 41 additions & 9 deletions logging/clf.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,47 @@ package logging

import (
"bytes"
"context"
"fmt"
"io"
"log/slog"
"strconv"
"time"

"github.com/sirupsen/logrus"
)

var clfFields = [...]string{
"request-id", "remote-address", "name", "user-id", "time", "duration", "method", "path", "protocol", "status", "size",
}

// CommonLogFormat implements the logrus.Formatter interface it writes logrus
// CommonLogFormat implements the slog.Handler interface it writes slog
// entries using a CLF format prepended by the request-id.
type CommonLogFormat struct{}
type CommonLogFormat struct {
output io.Writer
}

// Enabled implements the slog.Handler interface.
func (f *CommonLogFormat) Enabled(ctx context.Context, level slog.Level) bool {
return true
}

// Format implements the logrus.Formatter interface. It returns the given
// logrus entry as a CLF line with the following format:
// Handle implements the slog.Handler interface. It returns the given
// slog record as a CLF line with the following format:
//
// <request-id> <remote-address> <name> <user-id> <time> <duration> "<method> <path> <protocol>" <status> <size>
//
// If a field is not known, the hyphen symbol (-) will be used.
func (f *CommonLogFormat) Format(entry *logrus.Entry) ([]byte, error) {
func (f *CommonLogFormat) Handle(ctx context.Context, record slog.Record) error {
data := make([]string, len(clfFields))

// Extract fields from the record
fields := make(map[string]interface{})
record.Attrs(func(attr slog.Attr) bool {
fields[attr.Key] = attr.Value.Any()
return true
})

for i, name := range clfFields {
if v, ok := entry.Data[name]; ok {
if v, ok := fields[name]; ok {
switch v := v.(type) {
case error:
data[i] = v.Error()
Expand Down Expand Up @@ -75,5 +91,21 @@ func (f *CommonLogFormat) Format(entry *logrus.Entry) ([]byte, error) {
buf.WriteByte(' ')
buf.WriteString(data[10])
buf.WriteByte('\n')
return buf.Bytes(), nil

_, err := f.output.Write(buf.Bytes())
return err
}

// WithAttrs implements the slog.Handler interface.
func (f *CommonLogFormat) WithAttrs(attrs []slog.Attr) slog.Handler {
// For simplicity, return the same handler since CLF format
// doesn't support additional attributes
return f
}

// WithGroup implements the slog.Handler interface.
func (f *CommonLogFormat) WithGroup(name string) slog.Handler {
// For simplicity, return the same handler since CLF format
// doesn't support groups
return f
}
46 changes: 23 additions & 23 deletions logging/handler.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package logging

import (
"log/slog"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"

"github.com/sirupsen/logrus"

"github.com/smallstep/certificates/internal/userid"
"github.com/smallstep/certificates/middleware/requestid"
)
Expand All @@ -25,7 +24,7 @@ var (
// LoggerHandler creates a logger handler
type LoggerHandler struct {
name string
logger *logrus.Logger
logger *slog.Logger
options options
next http.Handler
}
Expand Down Expand Up @@ -104,38 +103,39 @@ func (l *LoggerHandler) writeEntry(w ResponseLogger, r *http.Request, t time.Tim

status := w.StatusCode()

fields := logrus.Fields{
"request-id": requestID,
"remote-address": addr,
"name": l.name,
"user-id": userID,
"time": t.Format(time.RFC3339),
"duration-ns": d.Nanoseconds(),
"duration": d.String(),
"method": r.Method,
"path": uri,
"protocol": r.Proto,
"status": status,
"size": w.Size(),
"referer": sanitizeLogEntry(r.Referer()),
"user-agent": sanitizeLogEntry(r.UserAgent()),
attrs := []slog.Attr{
slog.String("request-id", requestID),
slog.String("remote-address", addr),
slog.String("name", l.name),
slog.String("user-id", userID),
slog.String("time", t.Format(time.RFC3339)),
slog.Int64("duration-ns", d.Nanoseconds()),
slog.String("duration", d.String()),
slog.String("method", r.Method),
slog.String("path", uri),
slog.String("protocol", r.Proto),
slog.Int("status", status),
slog.Int("size", w.Size()),
slog.String("referer", sanitizeLogEntry(r.Referer())),
slog.String("user-agent", sanitizeLogEntry(r.UserAgent())),
}

// Add additional fields from ResponseLogger
for k, v := range w.Fields() {
fields[k] = v
attrs = append(attrs, slog.Any(k, v))
}

switch {
case status < http.StatusBadRequest:
if l.options.onlyTraceHealthEndpoint && uri == "/health" {
l.logger.WithFields(fields).Trace()
l.logger.LogAttrs(r.Context(), slog.LevelDebug-1, "", attrs...) // Use Debug-1 as trace level
} else {
l.logger.WithFields(fields).Info()
l.logger.LogAttrs(r.Context(), slog.LevelInfo, "", attrs...)
}
case status < http.StatusInternalServerError:
l.logger.WithFields(fields).Warn()
l.logger.LogAttrs(r.Context(), slog.LevelWarn, "", attrs...)
default:
l.logger.WithFields(fields).Error()
l.logger.LogAttrs(r.Context(), slog.LevelError, "", attrs...)
}
}

Expand Down
Loading