mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2026-10-17 20:17:03 +02:00
Allow Logging to stdout with separate Error Log Channel (#718)
* Add dedicated error logging writer * Document new errors to stdout flag * Update changelog * Thread-safe the log buffer * Address feedback * Remove duplication by adding log level * Clean up error formatting * Apply suggestions from code review Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
This commit is contained in:
co-authored by
Joel Speed
parent
33e04cc52f
commit
d69fd6af22
+87
-22
@@ -1,6 +1,7 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -15,6 +16,9 @@ import (
|
||||
// AuthStatus defines the different types of auth logging that occur
|
||||
type AuthStatus string
|
||||
|
||||
// Level indicates the log level for log messages
|
||||
type Level int
|
||||
|
||||
const (
|
||||
// DefaultStandardLoggingFormat defines the default standard log format
|
||||
DefaultStandardLoggingFormat = "[{{.Timestamp}}] [{{.File}}] {{.Message}}"
|
||||
@@ -38,6 +42,11 @@ const (
|
||||
LUTC
|
||||
// LstdFlags flag for initial values for the logger
|
||||
LstdFlags = Lshortfile
|
||||
|
||||
// DEFAULT is the default log level (effectively INFO)
|
||||
DEFAULT Level = iota
|
||||
// ERROR is for error-level logging
|
||||
ERROR
|
||||
)
|
||||
|
||||
// These are the containers for all values that are available as variables in the logging formats.
|
||||
@@ -87,6 +96,7 @@ type Logger struct {
|
||||
mu sync.Mutex
|
||||
flag int
|
||||
writer io.Writer
|
||||
errWriter io.Writer
|
||||
stdEnabled bool
|
||||
authEnabled bool
|
||||
reqEnabled bool
|
||||
@@ -100,7 +110,8 @@ type Logger struct {
|
||||
// New creates a new Standarderr Logger.
|
||||
func New(flag int) *Logger {
|
||||
return &Logger{
|
||||
writer: os.Stderr,
|
||||
writer: os.Stdout,
|
||||
errWriter: os.Stderr,
|
||||
flag: flag,
|
||||
stdEnabled: true,
|
||||
authEnabled: true,
|
||||
@@ -115,13 +126,7 @@ func New(flag int) *Logger {
|
||||
|
||||
var std = New(LstdFlags)
|
||||
|
||||
// Output a standard log template with a simple message.
|
||||
// Write a final newline at the end of every message.
|
||||
func (l *Logger) Output(calldepth int, message string) {
|
||||
if !l.stdEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
func (l *Logger) formatLogMessage(calldepth int, message string) []byte {
|
||||
now := time.Now()
|
||||
file := "???:0"
|
||||
|
||||
@@ -129,10 +134,8 @@ func (l *Logger) Output(calldepth int, message string) {
|
||||
file = l.GetFileLineString(calldepth + 1)
|
||||
}
|
||||
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
err := l.stdLogTemplate.Execute(l.writer, stdLogMessageData{
|
||||
var logBuff = new(bytes.Buffer)
|
||||
err := l.stdLogTemplate.Execute(logBuff, stdLogMessageData{
|
||||
Timestamp: FormatTimestamp(now),
|
||||
File: file,
|
||||
Message: message,
|
||||
@@ -145,6 +148,26 @@ func (l *Logger) Output(calldepth int, message string) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logBuff.Write([]byte("\n"))
|
||||
|
||||
return logBuff.Bytes()
|
||||
}
|
||||
|
||||
// Output a standard log template with a simple message to default output channel.
|
||||
// Write a final newline at the end of every message.
|
||||
func (l *Logger) Output(lvl Level, calldepth int, message string) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if !l.stdEnabled {
|
||||
return
|
||||
}
|
||||
msg := l.formatLogMessage(calldepth, message)
|
||||
switch lvl {
|
||||
case ERROR:
|
||||
l.errWriter.Write(msg)
|
||||
default:
|
||||
l.writer.Write(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintAuthf writes auth info to the logger. Requires an http.Request to
|
||||
@@ -302,6 +325,17 @@ func (l *Logger) SetStandardEnabled(e bool) {
|
||||
l.stdEnabled = e
|
||||
}
|
||||
|
||||
// SetErrToInfo enables or disables error logging to error writer instead of the default.
|
||||
func (l *Logger) SetErrToInfo(e bool) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if e {
|
||||
l.errWriter = l.writer
|
||||
} else {
|
||||
l.errWriter = os.Stderr
|
||||
}
|
||||
}
|
||||
|
||||
// SetAuthEnabled enables or disables auth logging.
|
||||
func (l *Logger) SetAuthEnabled(e bool) {
|
||||
l.mu.Lock()
|
||||
@@ -371,19 +405,32 @@ func SetFlags(flag int) {
|
||||
std.SetFlags(flag)
|
||||
}
|
||||
|
||||
// SetOutput sets the output destination for the standard logger.
|
||||
// SetOutput sets the output destination for the standard logger's default channel.
|
||||
func SetOutput(w io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.writer = w
|
||||
}
|
||||
|
||||
// SetErrOutput sets the output destination for the standard logger's error channel.
|
||||
func SetErrOutput(w io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.errWriter = w
|
||||
}
|
||||
|
||||
// SetStandardEnabled enables or disables standard logging for the
|
||||
// standard logger.
|
||||
func SetStandardEnabled(e bool) {
|
||||
std.SetStandardEnabled(e)
|
||||
}
|
||||
|
||||
// SetErrToInfo enables or disables error logging to output writer instead of
|
||||
// error writer.
|
||||
func SetErrToInfo(e bool) {
|
||||
std.SetErrToInfo(e)
|
||||
}
|
||||
|
||||
// SetAuthEnabled enables or disables auth logging for the standard
|
||||
// logger.
|
||||
func SetAuthEnabled(e bool) {
|
||||
@@ -428,57 +475,75 @@ func SetReqTemplate(t string) {
|
||||
// Print calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func Print(v ...interface{}) {
|
||||
std.Output(2, fmt.Sprint(v...))
|
||||
std.Output(DEFAULT, 2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Printf calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
std.Output(2, fmt.Sprintf(format, v...))
|
||||
std.Output(DEFAULT, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Println calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Println.
|
||||
func Println(v ...interface{}) {
|
||||
std.Output(2, fmt.Sprintln(v...))
|
||||
std.Output(DEFAULT, 2, fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Error calls OutputErr to print to the standard logger's error channel.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func Error(v ...interface{}) {
|
||||
std.Output(ERROR, 2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Errorf calls OutputErr to print to the standard logger's error channel.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
std.Output(ERROR, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Errorln calls OutputErr to print to the standard logger's error channel.
|
||||
// Arguments are handled in the manner of fmt.Println.
|
||||
func Errorln(v ...interface{}) {
|
||||
std.Output(ERROR, 2, fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Fatal is equivalent to Print() followed by a call to os.Exit(1).
|
||||
func Fatal(v ...interface{}) {
|
||||
std.Output(2, fmt.Sprint(v...))
|
||||
std.Output(ERROR, 2, fmt.Sprint(v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf is equivalent to Printf() followed by a call to os.Exit(1).
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
std.Output(2, fmt.Sprintf(format, v...))
|
||||
std.Output(ERROR, 2, fmt.Sprintf(format, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
|
||||
func Fatalln(v ...interface{}) {
|
||||
std.Output(2, fmt.Sprintln(v...))
|
||||
std.Output(ERROR, 2, fmt.Sprintln(v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Panic is equivalent to Print() followed by a call to panic().
|
||||
func Panic(v ...interface{}) {
|
||||
s := fmt.Sprint(v...)
|
||||
std.Output(2, s)
|
||||
std.Output(ERROR, 2, s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Panicf is equivalent to Printf() followed by a call to panic().
|
||||
func Panicf(format string, v ...interface{}) {
|
||||
s := fmt.Sprintf(format, v...)
|
||||
std.Output(2, s)
|
||||
std.Output(ERROR, 2, s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Panicln is equivalent to Println() followed by a call to panic().
|
||||
func Panicln(v ...interface{}) {
|
||||
s := fmt.Sprintln(v...)
|
||||
std.Output(2, s)
|
||||
std.Output(ERROR, 2, s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user