aboutsummaryrefslogtreecommitdiffstats
path: root/modules/log
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2019-04-07 01:25:14 +0100
committerLauris BH <lauris@nix.lv>2019-04-07 03:25:14 +0300
commit5422f23ed8174661b6e658250e4007b7fdf0d603 (patch)
tree87d975854be55c51e0a51c49cf93c33e310d30da /modules/log
parent7ed65a98e80a341885b8cddce971012b7fcdae4e (diff)
downloadgitea-5422f23ed8174661b6e658250e4007b7fdf0d603.tar.gz
gitea-5422f23ed8174661b6e658250e4007b7fdf0d603.zip
Quieter Integration Tests (#6513)
* Rename BaseLogger to WriterLogger to help the creation of other providers * Don't export ColorBytes and ResetBytes from ColoredValues * Make integration tests only print logs if they fail * check can color before coloring * I always forget about MSSQL * Oh and use LEVEL in sqlite.ini * Make the test logger log at info - as it means you see the router * Remove empty expected changes * Make the migrations quieter too * Don't display SQL on error - it can be looked at in the file logs if necessary * Fix skip when using onGiteaRun
Diffstat (limited to 'modules/log')
-rw-r--r--modules/log/base.go328
-rw-r--r--modules/log/colors.go40
-rw-r--r--modules/log/conn.go4
-rw-r--r--modules/log/console.go8
-rw-r--r--modules/log/file.go4
-rw-r--r--modules/log/file_test.go2
-rw-r--r--modules/log/flags.go64
-rw-r--r--modules/log/smtp.go4
-rw-r--r--modules/log/writer.go273
-rw-r--r--modules/log/writer_test.go (renamed from modules/log/base_test.go)12
10 files changed, 383 insertions, 356 deletions
diff --git a/modules/log/base.go b/modules/log/base.go
deleted file mode 100644
index 5577737e04..0000000000
--- a/modules/log/base.go
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package log
-
-import (
- "bytes"
- "fmt"
- "io"
- "regexp"
- "strings"
- "sync"
-)
-
-// These flags define which text to prefix to each log entry generated
-// by the Logger. Bits are or'ed together to control what's printed.
-// There is no control over the order they appear (the order listed
-// here) or the format they present (as described in the comments).
-// The prefix is followed by a colon only if more than time is stated
-// is specified. For example, flags Ldate | Ltime
-// produce, 2009/01/23 01:23:23 message.
-// The standard is:
-// 2009/01/23 01:23:23 ...a/b/c/d.go:23:runtime.Caller() [I]: message
-const (
- Ldate = 1 << iota // the date in the local time zone: 2009/01/23
- Ltime // the time in the local time zone: 01:23:23
- Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
- Llongfile // full file name and line number: /a/b/c/d.go:23
- Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
- Lfuncname // function name of the caller: runtime.Caller()
- Lshortfuncname // last part of the function name
- LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
- Llevelinitial // Initial character of the provided level in brackets eg. [I] for info
- Llevel // Provided level in brackets [INFO]
-
- // Last 20 characters of the filename
- Lmedfile = Lshortfile | Llongfile
-
- // LstdFlags is the initial value for the standard logger
- LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial
-)
-
-var flagFromString = map[string]int{
- "none": 0,
- "date": Ldate,
- "time": Ltime,
- "microseconds": Lmicroseconds,
- "longfile": Llongfile,
- "shortfile": Lshortfile,
- "funcname": Lfuncname,
- "shortfuncname": Lshortfuncname,
- "utc": LUTC,
- "levelinitial": Llevelinitial,
- "level": Llevel,
- "medfile": Lmedfile,
- "stdflags": LstdFlags,
-}
-
-// FlagsFromString takes a comma separated list of flags and returns
-// the flags for this string
-func FlagsFromString(from string) int {
- flags := 0
- for _, flag := range strings.Split(strings.ToLower(from), ",") {
- f, ok := flagFromString[strings.TrimSpace(flag)]
- if ok {
- flags = flags | f
- }
- }
- return flags
-}
-
-type byteArrayWriter []byte
-
-func (b *byteArrayWriter) Write(p []byte) (int, error) {
- *b = append(*b, p...)
- return len(p), nil
-}
-
-// BaseLogger represent a basic logger for Gitea
-type BaseLogger struct {
- out io.WriteCloser
- mu sync.Mutex
-
- Level Level `json:"level"`
- StacktraceLevel Level `json:"stacktraceLevel"`
- Flags int `json:"flags"`
- Prefix string `json:"prefix"`
- Colorize bool `json:"colorize"`
- Expression string `json:"expression"`
- regexp *regexp.Regexp
-}
-
-func (b *BaseLogger) createLogger(out io.WriteCloser, level ...Level) {
- b.mu.Lock()
- defer b.mu.Unlock()
- b.out = out
- switch b.Flags {
- case 0:
- b.Flags = LstdFlags
- case -1:
- b.Flags = 0
- }
- if len(level) > 0 {
- b.Level = level[0]
- }
- b.createExpression()
-}
-
-func (b *BaseLogger) createExpression() {
- if len(b.Expression) > 0 {
- var err error
- b.regexp, err = regexp.Compile(b.Expression)
- if err != nil {
- b.regexp = nil
- }
- }
-}
-
-// GetLevel returns the logging level for this logger
-func (b *BaseLogger) GetLevel() Level {
- return b.Level
-}
-
-// GetStacktraceLevel returns the stacktrace logging level for this logger
-func (b *BaseLogger) GetStacktraceLevel() Level {
- return b.StacktraceLevel
-}
-
-// Copy of cheap integer to fixed-width decimal to ascii from logger.
-func itoa(buf *[]byte, i int, wid int) {
- var b [20]byte
- bp := len(b) - 1
- for i >= 10 || wid > 1 {
- wid--
- q := i / 10
- b[bp] = byte('0' + i - q*10)
- bp--
- i = q
- }
- // i < 10
- b[bp] = byte('0' + i)
- *buf = append(*buf, b[bp:]...)
-}
-
-func (b *BaseLogger) createMsg(buf *[]byte, event *Event) {
- *buf = append(*buf, b.Prefix...)
- t := event.time
- if b.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
- if b.Colorize {
- *buf = append(*buf, fgCyanBytes...)
- }
- if b.Flags&LUTC != 0 {
- t = t.UTC()
- }
- if b.Flags&Ldate != 0 {
- year, month, day := t.Date()
- itoa(buf, year, 4)
- *buf = append(*buf, '/')
- itoa(buf, int(month), 2)
- *buf = append(*buf, '/')
- itoa(buf, day, 2)
- *buf = append(*buf, ' ')
- }
- if b.Flags&(Ltime|Lmicroseconds) != 0 {
- hour, min, sec := t.Clock()
- itoa(buf, hour, 2)
- *buf = append(*buf, ':')
- itoa(buf, min, 2)
- *buf = append(*buf, ':')
- itoa(buf, sec, 2)
- if b.Flags&Lmicroseconds != 0 {
- *buf = append(*buf, '.')
- itoa(buf, t.Nanosecond()/1e3, 6)
- }
- *buf = append(*buf, ' ')
- }
- if b.Colorize {
- *buf = append(*buf, resetBytes...)
- }
-
- }
- if b.Flags&(Lshortfile|Llongfile) != 0 {
- if b.Colorize {
- *buf = append(*buf, fgGreenBytes...)
- }
- file := event.filename
- if b.Flags&Lmedfile == Lmedfile {
- startIndex := len(file) - 20
- if startIndex > 0 {
- file = "..." + file[startIndex:]
- }
- } else if b.Flags&Lshortfile != 0 {
- startIndex := strings.LastIndexByte(file, '/')
- if startIndex > 0 && startIndex < len(file) {
- file = file[startIndex+1:]
- }
- }
- *buf = append(*buf, file...)
- *buf = append(*buf, ':')
- itoa(buf, event.line, -1)
- if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
- *buf = append(*buf, ':')
- } else {
- if b.Colorize {
- *buf = append(*buf, resetBytes...)
- }
- *buf = append(*buf, ' ')
- }
- }
- if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
- if b.Colorize {
- *buf = append(*buf, fgGreenBytes...)
- }
- funcname := event.caller
- if b.Flags&Lshortfuncname != 0 {
- lastIndex := strings.LastIndexByte(funcname, '.')
- if lastIndex > 0 && len(funcname) > lastIndex+1 {
- funcname = funcname[lastIndex+1:]
- }
- }
- *buf = append(*buf, funcname...)
- if b.Colorize {
- *buf = append(*buf, resetBytes...)
- }
- *buf = append(*buf, ' ')
-
- }
- if b.Flags&(Llevel|Llevelinitial) != 0 {
- level := strings.ToUpper(event.level.String())
- if b.Colorize {
- *buf = append(*buf, levelToColor[event.level]...)
- }
- *buf = append(*buf, '[')
- if b.Flags&Llevelinitial != 0 {
- *buf = append(*buf, level[0])
- } else {
- *buf = append(*buf, level...)
- }
- *buf = append(*buf, ']')
- if b.Colorize {
- *buf = append(*buf, resetBytes...)
- }
- *buf = append(*buf, ' ')
- }
-
- var msg = []byte(event.msg)
- if len(msg) > 0 && msg[len(msg)-1] == '\n' {
- msg = msg[:len(msg)-1]
- }
-
- pawMode := allowColor
- if !b.Colorize {
- pawMode = removeColor
- }
-
- baw := byteArrayWriter(*buf)
- (&protectedANSIWriter{
- w: &baw,
- mode: pawMode,
- }).Write([]byte(msg))
- *buf = baw
-
- if event.stacktrace != "" && b.StacktraceLevel <= event.level {
- lines := bytes.Split([]byte(event.stacktrace), []byte("\n"))
- if len(lines) > 1 {
- for _, line := range lines {
- *buf = append(*buf, "\n\t"...)
- *buf = append(*buf, line...)
- }
- }
- *buf = append(*buf, '\n')
- }
- *buf = append(*buf, '\n')
-}
-
-// LogEvent logs the event to the internal writer
-func (b *BaseLogger) LogEvent(event *Event) error {
- if b.Level > event.level {
- return nil
- }
-
- b.mu.Lock()
- defer b.mu.Unlock()
- if !b.Match(event) {
- return nil
- }
- var buf []byte
- b.createMsg(&buf, event)
- _, err := b.out.Write(buf)
- return err
-}
-
-// Match checks if the given event matches the logger's regexp expression
-func (b *BaseLogger) Match(event *Event) bool {
- if b.regexp == nil {
- return true
- }
- if b.regexp.Match([]byte(fmt.Sprintf("%s:%d:%s", event.filename, event.line, event.caller))) {
- return true
- }
- // Match on the non-colored msg - therefore strip out colors
- var msg []byte
- baw := byteArrayWriter(msg)
- (&protectedANSIWriter{
- w: &baw,
- mode: removeColor,
- }).Write([]byte(event.msg))
- msg = baw
- if b.regexp.Match(msg) {
- return true
- }
- return false
-}
-
-// Close the base logger
-func (b *BaseLogger) Close() {
- b.mu.Lock()
- defer b.mu.Unlock()
- if b.out != nil {
- b.out.Close()
- }
-}
-
-// GetName returns empty for these provider loggers
-func (b *BaseLogger) GetName() string {
- return ""
-}
diff --git a/modules/log/colors.go b/modules/log/colors.go
index fa8a664f08..ed6477d431 100644
--- a/modules/log/colors.go
+++ b/modules/log/colors.go
@@ -268,8 +268,8 @@ normalLoop:
// ColoredValue will Color the provided value
type ColoredValue struct {
- ColorBytes *[]byte
- ResetBytes *[]byte
+ colorBytes *[]byte
+ resetBytes *[]byte
Value *interface{}
}
@@ -290,14 +290,14 @@ func NewColoredValuePointer(value *interface{}, color ...ColorAttribute) *Colore
if len(color) > 0 {
bytes := ColorBytes(color...)
return &ColoredValue{
- ColorBytes: &bytes,
- ResetBytes: &resetBytes,
+ colorBytes: &bytes,
+ resetBytes: &resetBytes,
Value: value,
}
}
return &ColoredValue{
- ColorBytes: &fgBoldBytes,
- ResetBytes: &resetBytes,
+ colorBytes: &fgBoldBytes,
+ resetBytes: &resetBytes,
Value: value,
}
@@ -310,17 +310,37 @@ func NewColoredValueBytes(value interface{}, colorBytes *[]byte) *ColoredValue {
return val
}
return &ColoredValue{
- ColorBytes: colorBytes,
- ResetBytes: &resetBytes,
+ colorBytes: colorBytes,
+ resetBytes: &resetBytes,
Value: &value,
}
}
// Format will format the provided value and protect against ANSI spoofing within the value
func (cv *ColoredValue) Format(s fmt.State, c rune) {
- s.Write([]byte(*cv.ColorBytes))
+ s.Write([]byte(*cv.colorBytes))
fmt.Fprintf(&protectedANSIWriter{w: s}, fmtString(s, c), *(cv.Value))
- s.Write([]byte(*cv.ResetBytes))
+ s.Write([]byte(*cv.resetBytes))
+}
+
+// SetColorBytes will allow a user to set the colorBytes of a colored value
+func (cv *ColoredValue) SetColorBytes(colorBytes []byte) {
+ cv.colorBytes = &colorBytes
+}
+
+// SetColorBytesPointer will allow a user to set the colorBytes pointer of a colored value
+func (cv *ColoredValue) SetColorBytesPointer(colorBytes *[]byte) {
+ cv.colorBytes = colorBytes
+}
+
+// SetResetBytes will allow a user to set the resetBytes pointer of a colored value
+func (cv *ColoredValue) SetResetBytes(resetBytes []byte) {
+ cv.resetBytes = &resetBytes
+}
+
+// SetResetBytesPointer will allow a user to set the resetBytes pointer of a colored value
+func (cv *ColoredValue) SetResetBytesPointer(resetBytes *[]byte) {
+ cv.resetBytes = resetBytes
}
func fmtString(s fmt.State, c rune) string {
diff --git a/modules/log/conn.go b/modules/log/conn.go
index d48bb4b334..bd76855168 100644
--- a/modules/log/conn.go
+++ b/modules/log/conn.go
@@ -77,7 +77,7 @@ func (i *connWriter) connect() error {
// ConnLogger implements LoggerProvider.
// it writes messages in keep-live tcp connection.
type ConnLogger struct {
- BaseLogger
+ WriterLogger
ReconnectOnMsg bool `json:"reconnectOnMsg"`
Reconnect bool `json:"reconnect"`
Net string `json:"net"`
@@ -98,7 +98,7 @@ func (log *ConnLogger) Init(jsonconfig string) error {
if err != nil {
return err
}
- log.createLogger(&connWriter{
+ log.NewWriterLogger(&connWriter{
ReconnectOnMsg: log.ReconnectOnMsg,
Reconnect: log.Reconnect,
Net: log.Net,
diff --git a/modules/log/console.go b/modules/log/console.go
index cf2dfa499f..6cfca8a733 100644
--- a/modules/log/console.go
+++ b/modules/log/console.go
@@ -34,14 +34,14 @@ func (n *nopWriteCloser) Close() error {
// ConsoleLogger implements LoggerProvider and writes messages to terminal.
type ConsoleLogger struct {
- BaseLogger
+ WriterLogger
Stderr bool `json:"stderr"`
}
// NewConsoleLogger create ConsoleLogger returning as LoggerProvider.
func NewConsoleLogger() LoggerProvider {
log := &ConsoleLogger{}
- log.createLogger(&nopWriteCloser{
+ log.NewWriterLogger(&nopWriteCloser{
w: os.Stdout,
})
return log
@@ -55,11 +55,11 @@ func (log *ConsoleLogger) Init(config string) error {
return err
}
if log.Stderr {
- log.createLogger(&nopWriteCloser{
+ log.NewWriterLogger(&nopWriteCloser{
w: os.Stderr,
})
} else {
- log.createLogger(log.out)
+ log.NewWriterLogger(log.out)
}
return nil
}
diff --git a/modules/log/file.go b/modules/log/file.go
index 5c219c3910..cdda85d626 100644
--- a/modules/log/file.go
+++ b/modules/log/file.go
@@ -20,7 +20,7 @@ import (
// FileLogger implements LoggerProvider.
// It writes messages by lines limit, file size limit, or time frequency.
type FileLogger struct {
- BaseLogger
+ WriterLogger
mw *MuxWriter
// The opened file
Filename string `json:"filename"`
@@ -106,7 +106,7 @@ func (log *FileLogger) Init(config string) error {
return errors.New("config must have filename")
}
// set MuxWriter as Logger's io.Writer
- log.createLogger(log.mw)
+ log.NewWriterLogger(log.mw)
return log.StartLogger()
}
diff --git a/modules/log/file_test.go b/modules/log/file_test.go
index 9527069079..648db6f393 100644
--- a/modules/log/file_test.go
+++ b/modules/log/file_test.go
@@ -89,7 +89,6 @@ func TestFileLogger(t *testing.T) {
assert.Equal(t, expected, string(logData))
event.level = DEBUG
- expected = expected + ""
fileLogger.LogEvent(&event)
fileLogger.Flush()
logData, err = ioutil.ReadFile(filename)
@@ -97,7 +96,6 @@ func TestFileLogger(t *testing.T) {
assert.Equal(t, expected, string(logData))
event.level = TRACE
- expected = expected + ""
fileLogger.LogEvent(&event)
fileLogger.Flush()
logData, err = ioutil.ReadFile(filename)
diff --git a/modules/log/flags.go b/modules/log/flags.go
new file mode 100644
index 0000000000..928d42b965
--- /dev/null
+++ b/modules/log/flags.go
@@ -0,0 +1,64 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package log
+
+import "strings"
+
+// These flags define which text to prefix to each log entry generated
+// by the Logger. Bits are or'ed together to control what's printed.
+// There is no control over the order they appear (the order listed
+// here) or the format they present (as described in the comments).
+// The prefix is followed by a colon only if more than time is stated
+// is specified. For example, flags Ldate | Ltime
+// produce, 2009/01/23 01:23:23 message.
+// The standard is:
+// 2009/01/23 01:23:23 ...a/logger/c/d.go:23:runtime.Caller() [I]: message
+const (
+ Ldate = 1 << iota // the date in the local time zone: 2009/01/23
+ Ltime // the time in the local time zone: 01:23:23
+ Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
+ Llongfile // full file name and line number: /a/logger/c/d.go:23
+ Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
+ Lfuncname // function name of the caller: runtime.Caller()
+ Lshortfuncname // last part of the function name
+ LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
+ Llevelinitial // Initial character of the provided level in brackets eg. [I] for info
+ Llevel // Provided level in brackets [INFO]
+
+ // Last 20 characters of the filename
+ Lmedfile = Lshortfile | Llongfile
+
+ // LstdFlags is the initial value for the standard logger
+ LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial
+)
+
+var flagFromString = map[string]int{
+ "none": 0,
+ "date": Ldate,
+ "time": Ltime,
+ "microseconds": Lmicroseconds,
+ "longfile": Llongfile,
+ "shortfile": Lshortfile,
+ "funcname": Lfuncname,
+ "shortfuncname": Lshortfuncname,
+ "utc": LUTC,
+ "levelinitial": Llevelinitial,
+ "level": Llevel,
+ "medfile": Lmedfile,
+ "stdflags": LstdFlags,
+}
+
+// FlagsFromString takes a comma separated list of flags and returns
+// the flags for this string
+func FlagsFromString(from string) int {
+ flags := 0
+ for _, flag := range strings.Split(strings.ToLower(from), ",") {
+ f, ok := flagFromString[strings.TrimSpace(flag)]
+ if ok {
+ flags = flags | f
+ }
+ }
+ return flags
+}
diff --git a/modules/log/smtp.go b/modules/log/smtp.go
index 2e78d713ca..f77d716d94 100644
--- a/modules/log/smtp.go
+++ b/modules/log/smtp.go
@@ -31,7 +31,7 @@ func (s *smtpWriter) Close() error {
// SMTPLogger implements LoggerProvider and is used to send emails via given SMTP-server.
type SMTPLogger struct {
- BaseLogger
+ WriterLogger
Username string `json:"Username"`
Password string `json:"password"`
Host string `json:"host"`
@@ -63,7 +63,7 @@ func (log *SMTPLogger) Init(jsonconfig string) error {
if err != nil {
return err
}
- log.createLogger(&smtpWriter{
+ log.NewWriterLogger(&smtpWriter{
owner: log,
})
log.sendMailFn = smtp.SendMail
diff --git a/modules/log/writer.go b/modules/log/writer.go
new file mode 100644
index 0000000000..22ef0b9047
--- /dev/null
+++ b/modules/log/writer.go
@@ -0,0 +1,273 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package log
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "regexp"
+ "strings"
+ "sync"
+)
+
+type byteArrayWriter []byte
+
+func (b *byteArrayWriter) Write(p []byte) (int, error) {
+ *b = append(*b, p...)
+ return len(p), nil
+}
+
+// WriterLogger represent a basic logger for Gitea
+type WriterLogger struct {
+ out io.WriteCloser
+ mu sync.Mutex
+
+ Level Level `json:"level"`
+ StacktraceLevel Level `json:"stacktraceLevel"`
+ Flags int `json:"flags"`
+ Prefix string `json:"prefix"`
+ Colorize bool `json:"colorize"`
+ Expression string `json:"expression"`
+ regexp *regexp.Regexp
+}
+
+// NewWriterLogger creates a new WriterLogger from the provided WriteCloser.
+// Optionally the level can be changed at the same time.
+func (logger *WriterLogger) NewWriterLogger(out io.WriteCloser, level ...Level) {
+ logger.mu.Lock()
+ defer logger.mu.Unlock()
+ logger.out = out
+ switch logger.Flags {
+ case 0:
+ logger.Flags = LstdFlags
+ case -1:
+ logger.Flags = 0
+ }
+ if len(level) > 0 {
+ logger.Level = level[0]
+ }
+ logger.createExpression()
+}
+
+func (logger *WriterLogger) createExpression() {
+ if len(logger.Expression) > 0 {
+ var err error
+ logger.regexp, err = regexp.Compile(logger.Expression)
+ if err != nil {
+ logger.regexp = nil
+ }
+ }
+}
+
+// GetLevel returns the logging level for this logger
+func (logger *WriterLogger) GetLevel() Level {
+ return logger.Level
+}
+
+// GetStacktraceLevel returns the stacktrace logging level for this logger
+func (logger *WriterLogger) GetStacktraceLevel() Level {
+ return logger.StacktraceLevel
+}
+
+// Copy of cheap integer to fixed-width decimal to ascii from logger.
+func itoa(buf *[]byte, i int, wid int) {
+ var logger [20]byte
+ bp := len(logger) - 1
+ for i >= 10 || wid > 1 {
+ wid--
+ q := i / 10
+ logger[bp] = byte('0' + i - q*10)
+ bp--
+ i = q
+ }
+ // i < 10
+ logger[bp] = byte('0' + i)
+ *buf = append(*buf, logger[bp:]...)
+}
+
+func (logger *WriterLogger) createMsg(buf *[]byte, event *Event) {
+ *buf = append(*buf, logger.Prefix...)
+ t := event.time
+ if logger.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
+ if logger.Colorize {
+ *buf = append(*buf, fgCyanBytes...)
+ }
+ if logger.Flags&LUTC != 0 {
+ t = t.UTC()
+ }
+ if logger.Flags&Ldate != 0 {
+ year, month, day := t.Date()
+ itoa(buf, year, 4)
+ *buf = append(*buf, '/')
+ itoa(buf, int(month), 2)
+ *buf = append(*buf, '/')
+ itoa(buf, day, 2)
+ *buf = append(*buf, ' ')
+ }
+ if logger.Flags&(Ltime|Lmicroseconds) != 0 {
+ hour, min, sec := t.Clock()
+ itoa(buf, hour, 2)
+ *buf = append(*buf, ':')
+ itoa(buf, min, 2)
+ *buf = append(*buf, ':')
+ itoa(buf, sec, 2)
+ if logger.Flags&Lmicroseconds != 0 {
+ *buf = append(*buf, '.')
+ itoa(buf, t.Nanosecond()/1e3, 6)
+ }
+ *buf = append(*buf, ' ')
+ }
+ if logger.Colorize {
+ *buf = append(*buf, resetBytes...)
+ }
+
+ }
+ if logger.Flags&(Lshortfile|Llongfile) != 0 {
+ if logger.Colorize {
+ *buf = append(*buf, fgGreenBytes...)
+ }
+ file := event.filename
+ if logger.Flags&Lmedfile == Lmedfile {
+ startIndex := len(file) - 20
+ if startIndex > 0 {
+ file = "..." + file[startIndex:]
+ }
+ } else if logger.Flags&Lshortfile != 0 {
+ startIndex := strings.LastIndexByte(file, '/')
+ if startIndex > 0 && startIndex < len(file) {
+ file = file[startIndex+1:]
+ }
+ }
+ *buf = append(*buf, file...)
+ *buf = append(*buf, ':')
+ itoa(buf, event.line, -1)
+ if logger.Flags&(Lfuncname|Lshortfuncname) != 0 {
+ *buf = append(*buf, ':')
+ } else {
+ if logger.Colorize {
+ *buf = append(*buf, resetBytes...)
+ }
+ *buf = append(*buf, ' ')
+ }
+ }
+ if logger.Flags&(Lfuncname|Lshortfuncname) != 0 {
+ if logger.Colorize {
+ *buf = append(*buf, fgGreenBytes...)
+ }
+ funcname := event.caller
+ if logger.Flags&Lshortfuncname != 0 {
+ lastIndex := strings.LastIndexByte(funcname, '.')
+ if lastIndex > 0 && len(funcname) > lastIndex+1 {
+ funcname = funcname[lastIndex+1:]
+ }
+ }
+ *buf = append(*buf, funcname...)
+ if logger.Colorize {
+ *buf = append(*buf, resetBytes...)
+ }
+ *buf = append(*buf, ' ')
+
+ }
+ if logger.Flags&(Llevel|Llevelinitial) != 0 {
+ level := strings.ToUpper(event.level.String())
+ if logger.Colorize {
+ *buf = append(*buf, levelToColor[event.level]...)
+ }
+ *buf = append(*buf, '[')
+ if logger.Flags&Llevelinitial != 0 {
+ *buf = append(*buf, level[0])
+ } else {
+ *buf = append(*buf, level...)
+ }
+ *buf = append(*buf, ']')
+ if logger.Colorize {
+ *buf = append(*buf, resetBytes...)
+ }
+ *buf = append(*buf, ' ')
+ }
+
+ var msg = []byte(event.msg)
+ if len(msg) > 0 && msg[len(msg)-1] == '\n' {
+ msg = msg[:len(msg)-1]
+ }
+
+ pawMode := allowColor
+ if !logger.Colorize {
+ pawMode = removeColor
+ }
+
+ baw := byteArrayWriter(*buf)
+ (&protectedANSIWriter{
+ w: &baw,
+ mode: pawMode,
+ }).Write([]byte(msg))
+ *buf = baw
+
+ if event.stacktrace != "" && logger.StacktraceLevel <= event.level {
+ lines := bytes.Split([]byte(event.stacktrace), []byte("\n"))
+ if len(lines) > 1 {
+ for _, line := range lines {
+ *buf = append(*buf, "\n\t"...)
+ *buf = append(*buf, line...)
+ }
+ }
+ *buf = append(*buf, '\n')
+ }
+ *buf = append(*buf, '\n')
+}
+
+// LogEvent logs the event to the internal writer
+func (logger *WriterLogger) LogEvent(event *Event) error {
+ if logger.Level > event.level {
+ return nil
+ }
+
+ logger.mu.Lock()
+ defer logger.mu.Unlock()
+ if !logger.Match(event) {
+ return nil
+ }
+ var buf []byte
+ logger.createMsg(&buf, event)
+ _, err := logger.out.Write(buf)
+ return err
+}
+
+// Match checks if the given event matches the logger's regexp expression
+func (logger *WriterLogger) Match(event *Event) bool {
+ if logger.regexp == nil {
+ return true
+ }
+ if logger.regexp.Match([]byte(fmt.Sprintf("%s:%d:%s", event.filename, event.line, event.caller))) {
+ return true
+ }
+ // Match on the non-colored msg - therefore strip out colors
+ var msg []byte
+ baw := byteArrayWriter(msg)
+ (&protectedANSIWriter{
+ w: &baw,
+ mode: removeColor,
+ }).Write([]byte(event.msg))
+ msg = baw
+ if logger.regexp.Match(msg) {
+ return true
+ }
+ return false
+}
+
+// Close the base logger
+func (logger *WriterLogger) Close() {
+ logger.mu.Lock()
+ defer logger.mu.Unlock()
+ if logger.out != nil {
+ logger.out.Close()
+ }
+}
+
+// GetName returns empty for these provider loggers
+func (logger *WriterLogger) GetName() string {
+ return ""
+}
diff --git a/modules/log/base_test.go b/modules/log/writer_test.go
index 3686c26ce8..886dd58fb3 100644
--- a/modules/log/base_test.go
+++ b/modules/log/writer_test.go
@@ -38,7 +38,7 @@ func TestBaseLogger(t *testing.T) {
},
}
prefix := "TestPrefix "
- b := BaseLogger{
+ b := WriterLogger{
out: c,
Level: INFO,
Flags: LstdFlags | LUTC,
@@ -115,7 +115,7 @@ func TestBaseLoggerDated(t *testing.T) {
},
}
prefix := ""
- b := BaseLogger{
+ b := WriterLogger{
out: c,
Level: WARN,
Flags: Ldate | Ltime | Lmicroseconds | Lshortfile | Llevel,
@@ -195,14 +195,14 @@ func TestBaseLoggerMultiLineNoFlagsRegexp(t *testing.T) {
},
}
prefix := ""
- b := BaseLogger{
+ b := WriterLogger{
Level: DEBUG,
StacktraceLevel: ERROR,
Flags: -1,
Prefix: prefix,
Expression: "FILENAME",
}
- b.createLogger(c)
+ b.NewWriterLogger(c)
location, _ := time.LoadLocation("EST")
@@ -263,14 +263,14 @@ func TestBrokenRegexp(t *testing.T) {
},
}
- b := BaseLogger{
+ b := WriterLogger{
Level: DEBUG,
StacktraceLevel: ERROR,
Flags: -1,
Prefix: prefix,
Expression: "\\",
}
- b.createLogger(c)
+ b.NewWriterLogger(c)
assert.Empty(t, b.regexp)
b.Close()
assert.Equal(t, true, closed)