Skip to content

Commit

Permalink
adding option for writing in buf and resolving errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Madhur committed Dec 5, 2024
1 parent 366bc6e commit b5d0a06
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 26 deletions.
6 changes: 3 additions & 3 deletions cmd/proxy/actions/basicauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ func TestBasicAuth(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, tc.path, nil)
r.SetBasicAuth(tc.user, tc.pass)
lggr := log.New("none", slog.LevelDebug, "")
buf := &bytes.Buffer{}
lggr.Out = buf
ctx := log.SetEntryInContext(context.Background(), lggr)
lggr := log.New("none", slog.LevelDebug, "", buf)
entry := lggr.WithFields(map[string]any{})
ctx := log.SetEntryInContext(context.Background(), entry)
r = r.WithContext(ctx)
handler.ServeHTTP(w, r)
resp := w.Result()
Expand Down
8 changes: 4 additions & 4 deletions cmd/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ func main() {
stdlog.Fatalf("Could not parse log level %q: %v", conf.LogLevel, err)
}

logger := athenslog.New(conf.CloudRuntime, logLvl, conf.LogFormat)
logger := athenslog.New(conf.CloudRuntime, logLvl, conf.LogFormat, os.Stdout)

// Turn standard logger output into slog Errors.
logrusErrorWriter := logger.WriterLevel(slog.LevelError)
slogErrorWriter := logger.WriterLevel(slog.LevelError)
defer func() {
if err := logrusErrorWriter.Close(); err != nil {
if err := slogErrorWriter.Close(); err != nil {
logger.WithError(err).Warn("Could not close logrus writer pipe")
}
}()
stdlog.SetOutput(logrusErrorWriter)
stdlog.SetOutput(slogErrorWriter)
stdlog.SetFlags(stdlog.Flags() &^ (stdlog.Ldate | stdlog.Ltime))

handler, err := actions.App(logger, conf)
Expand Down
38 changes: 37 additions & 1 deletion pkg/log/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,64 @@ import (
// an Entry copy which ensures no
// Fields are being overwritten.
type Entry interface {
// Keep the existing interface methods unchanged
// Debugf logs a debug message with formatting
Debugf(string, ...interface{})

Check failure on line 21 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Debugf must have named param for type string (inamedparam)

// Infof logs an info message with formatting
Infof(string, ...interface{})

Check failure on line 24 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Infof must have named param for type string (inamedparam)

// Warnf logs a warning message with formatting
Warnf(string, ...interface{})

Check failure on line 27 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Warnf must have named param for type string (inamedparam)

// Errorf logs an error message with formatting
Errorf(string, ...interface{})

Check failure on line 30 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Errorf must have named param for type string (inamedparam)

// Fatalf logs a fatal message with formatting and terminates the program
Fatalf(string, ...interface{})

Check failure on line 33 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Fatalf must have named param for type string (inamedparam)

// Panicf logs a panic message with formatting and panics
Panicf(string, ...interface{})

Check failure on line 36 in pkg/log/entry.go

View workflow job for this annotation

GitHub Actions / lint

interface method Panicf must have named param for type string (inamedparam)

// Printf logs a message with formatting at default level
Printf(string, ...interface{})

// Debug logs a debug message
Debug(...interface{})

// Info logs an info message
Info(...interface{})

// Warn logs a warning message
Warn(...interface{})

// Error logs an error message
Error(...interface{})

// Fatal logs a fatal message and terminates the program
Fatal(...interface{})

// Panic logs a panic message and panics
Panic(...interface{})

// Print logs a message at default level
Print(...interface{})

// WithFields returns a new Entry with the provided fields added
WithFields(fields map[string]any) Entry

// WithField returns a new Entry with a single field added
WithField(key string, value any) Entry

// WithError returns a new Entry with the error added to the fields
WithError(err error) Entry

// WithContext returns a new Entry with the context added to the fields
WithContext(ctx context.Context) Entry

// SystemErr handles system errors with appropriate logging levels
SystemErr(err error)

// WriterLevel returns an io.PipeWriter for the specified logging level
WriterLevel(level slog.Level) *io.PipeWriter
}

Expand Down
9 changes: 5 additions & 4 deletions pkg/log/format.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package log

import (
"io"
"log/slog"
"os"
"sort"
Expand All @@ -9,8 +10,8 @@ import (
"github.com/fatih/color"
)

func getGCPFormatter(level slog.Level) *slog.Logger {
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
func getGCPFormatter(level slog.Level, w io.Writer) *slog.Logger {
return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{
Level: level,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
switch a.Key {
Expand Down Expand Up @@ -78,9 +79,9 @@ func sortFields(data map[string]any) []string {
return keys
}

func parseFormat(format string, level slog.Level) *slog.Logger {
func parseFormat(format string, level slog.Level, w io.Writer) *slog.Logger {
if format == "json" {
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
return slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions{Level: level}))
}

return getDevFormatter(level)
Expand Down
18 changes: 13 additions & 5 deletions pkg/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"log/slog"
"os"
Expand All @@ -21,13 +22,16 @@ type Logger struct {
// environment and the cloud platform it is
// running on. TODO: take cloud arg and env
// to construct the correct JSON formatter.
func New(cloudProvider string, level slog.Level, format string) *Logger {
l := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
func New(cloudProvider string, level slog.Level, format string, w io.Writer) *Logger {
var l *slog.Logger
switch cloudProvider {
case "GCP":
l = getGCPFormatter(level)
l = getGCPFormatter(level, w)
default:
l = parseFormat(format, level)
l = parseFormat(format, level, w)
}
if l == nil {
l = slog.New(slog.NewTextHandler(w, &slog.HandlerOptions{Level: level}))
}
slog.SetDefault(l)
return &Logger{Logger: l}
Expand Down Expand Up @@ -69,7 +73,6 @@ func (l *Logger) WithContext(ctx context.Context) Entry {
return l.WithFields(keys)
}

// Define WriterLevel
func (l *Logger) WriterLevel(level slog.Level) *io.PipeWriter {
pipeReader, pipeWriter := io.Pipe()
go func() {
Expand All @@ -82,6 +85,11 @@ func (l *Logger) WriterLevel(level slog.Level) *io.PipeWriter {
return pipeWriter
}

func (l *Logger) Fatal(args ...any) {
l.Logger.Error(fmt.Sprint(args...))
os.Exit(1)
}

// NoOpLogger provides a Logger that does nothing.
func NoOpLogger() *Logger {
return &Logger{
Expand Down
14 changes: 6 additions & 8 deletions pkg/log/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package log
import (
"bytes"
"fmt"
"log/slog"
"strings"
"testing"
"time"
"log/slog"


"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -87,7 +87,7 @@ var testCases = []input{
format: "plain",
cloudProvider: "none",
level: slog.LevelDebug,
fields: map[string]any{"xyz": "abc", "abc": "xyz"},
fields: map[string]any{"xyz": "abc", "abc": "xyz"},
logFunc: func(e Entry) time.Time {
t := time.Now()
e.Warnf("warn message")
Expand All @@ -112,7 +112,7 @@ var testCases = []input{
format: "json",
cloudProvider: "none",
level: slog.LevelDebug,
fields: map[string]any{"xyz": "abc", "abc": "xyz"},
fields: map[string]any{"xyz": "abc", "abc": "xyz"},
logFunc: func(e Entry) time.Time {
t := time.Now()
e.Warnf("warn message")
Expand All @@ -125,9 +125,8 @@ var testCases = []input{
func TestCloudLogger(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
lggr := New(tc.cloudProvider, tc.level, tc.format)
var buf bytes.Buffer
lggr.Out = &buf
buf := &bytes.Buffer{}
lggr := New(tc.cloudProvider, tc.level, tc.format, buf)
e := lggr.WithFields(tc.fields)
entryTime := tc.logFunc(e)
out := buf.String()
Expand All @@ -144,7 +143,6 @@ func TestCloudLogger(t *testing.T) {
})
}
}

func TestNoOpLogger(t *testing.T) {
l := NoOpLogger()
require.NotPanics(t, func() { l.Info("test") })
Expand Down
2 changes: 1 addition & 1 deletion pkg/middleware/log_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestLogContext(t *testing.T) {
r.HandleFunc("/test", h)

buf := &bytes.Buffer{}
lggr := log.New("", slog.LevelDebug, "")
lggr := log.New("", slog.LevelDebug, "", buf)
opts := slog.HandlerOptions{Level: slog.LevelDebug}
handler := slog.NewJSONHandler(buf, &opts)
lggr.Logger = slog.New(handler)
Expand Down

0 comments on commit b5d0a06

Please sign in to comment.