Skip to content

Commit

Permalink
feat: allow external loggers to be used with glog as default
Browse files Browse the repository at this point in the history
  • Loading branch information
janhoon committed Oct 29, 2024
1 parent 4a74dcc commit 823b46b
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 21 deletions.
21 changes: 0 additions & 21 deletions ginoauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ import (
"time"

"github.com/gin-gonic/gin"
"github.com/golang/glog"
"golang.org/x/oauth2"
)

Expand Down Expand Up @@ -102,26 +101,6 @@ func maskAccessToken(a interface{}) string {
return s
}

func logf(l func(string, ...interface{}), f string, args ...interface{}) {
for i := range args {
args[i] = maskAccessToken(args[i])
}

l(f, args...)
}

func errorf(f string, args ...interface{}) {
logf(glog.Errorf, f, args...)
}

func infof(f string, args ...interface{}) {
logf(glog.Infof, f, args...)
}

func infofv2(f string, args ...interface{}) {
logf(glog.V(2).Infof, f, args...)
}

func extractToken(r *http.Request) (*oauth2.Token, error) {
hdr := r.Header.Get("Authorization")
if hdr == "" {
Expand Down
82 changes: 82 additions & 0 deletions logging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ginoauth2

import (
"fmt"
"io"
"os"

"github.com/golang/glog"
)

// Logger is the interface used by GinOAuth2 to log messages.
type Logger interface {
Errorf(format string, args ...interface{})
Infof(format string, args ...interface{})
Debugf(format string, args ...interface{})
}

type glogLogger struct {
output io.Writer
}

// DefaultLogger is the default logger used by GinOAuth2 if no other logger is provided.
// To use a different logger, set the DefaultLogger variable to a logger of your choice.
// Replacement loggers must implement the Logger interface.
//
// Example:
//
// import "github.com/zalando/gin-oauth2"
//
// ginoauth2.DefaultLogger = &logrusLogger{} // use logrus
var DefaultLogger Logger = &glogLogger{output: os.Stderr}

func maskLogArgs(args ...interface{}) []interface{} {
for i := range args {
args[i] = maskAccessToken(args[i])
}

return args
}

// SetOutput sets the output destination for the logger
func (gl *glogLogger) setOutput(w io.Writer) {
gl.output = w
}

// Errorf is a logging function using glog.Errorf
func (gl *glogLogger) Errorf(f string, args ...interface{}) {
glog.ErrorDepth(1, fmt.Sprintf(f, args...))
if gl.output != nil {
fmt.Fprintf(gl.output, f+"\n", args...)
}
}

// Infof is a logging function using glog.Infof
func (gl *glogLogger) Infof(f string, args ...interface{}) {
glog.InfoDepth(1, fmt.Sprintf(f, args...))
if gl.output != nil {
fmt.Fprintf(gl.output, f+"\n", args...)
}
}

// Debugf is a verbose logging function using glog.V(2)
func (gl *glogLogger) Debugf(f string, args ...interface{}) {
if glog.V(2) {
glog.InfoDepth(1, fmt.Sprintf(f, args...))
}
if gl.output != nil {
fmt.Fprintf(gl.output, f+"\n", args...)
}
}

func errorf(f string, args ...interface{}) {
DefaultLogger.Errorf(f, maskLogArgs(args...)...)
}

func infof(f string, args ...interface{}) {
DefaultLogger.Infof(f, maskLogArgs(args...)...)
}

func infofv2(f string, args ...interface{}) {
DefaultLogger.Debugf(f, maskLogArgs(args...)...)
}
45 changes: 45 additions & 0 deletions logging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ginoauth2

import (
"bytes"
"fmt"
"strings"
"testing"
)

type mockLogger struct{ buffer bytes.Buffer }

func (m *mockLogger) Errorf(format string, args ...interface{}) {
m.buffer.WriteString(fmt.Sprintf("ERROR: "+format, args...))
}
func (m *mockLogger) Infof(format string, args ...interface{}) {
m.buffer.WriteString(fmt.Sprintf("INFO: "+format, args...))
}
func (m *mockLogger) Debugf(format string, args ...interface{}) {
m.buffer.WriteString(fmt.Sprintf("DEBUG: "+format, args...))
}

func TestLogWithMaskedAccessToken(t *testing.T) {
mockLog := &mockLogger{}
DefaultLogger = mockLog
tests := []struct{ name, input, expected string }{
{"With access token", "&access_token=abcdefghijklmnop&", "INFO: <MASK>&"},
{"Without access token", "no_token_here", "INFO: no_token_here"},
{"Empty string", "", "INFO: "},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockLog.buffer.Reset()

infof("%s", tt.input)

logOutput := mockLog.buffer.String()
if logOutput != tt.expected {
t.Errorf("Expected log to contain %q, got %q", tt.expected, logOutput)
}
if strings.Contains(logOutput, "abcdefghijklmnop") {
t.Errorf("Log should not contain the original token")
}
})
}
}

0 comments on commit 823b46b

Please sign in to comment.