mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-08-02 00:15:21 +02:00
This feature is intended to help reduce noisy logs generated by routine Kubernetes probes and Prometheus scraping. While logs are essential, these specific requests (e.g., to /metrics and /api/healthz) generally don't provide useful information and tend to clutter the output. The goal is to introduce functionality that effectively acts as the inverse of the existing EXPRESSION mode—allowing logging to be excluded based on a condition, rather than included. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8212 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: zokki <zokki.softwareschmiede@gmail.com> Co-committed-by: zokki <zokki.softwareschmiede@gmail.com>
161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package log
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type dummyWriter struct {
|
|
*EventWriterBaseImpl
|
|
|
|
delay time.Duration
|
|
|
|
mu sync.Mutex
|
|
logs []string
|
|
}
|
|
|
|
func (d *dummyWriter) Write(p []byte) (n int, err error) {
|
|
if d.delay > 0 {
|
|
time.Sleep(d.delay)
|
|
}
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.logs = append(d.logs, string(p))
|
|
return len(p), nil
|
|
}
|
|
|
|
func (d *dummyWriter) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (d *dummyWriter) GetLogs() []string {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
logs := make([]string, len(d.logs))
|
|
copy(logs, d.logs)
|
|
return logs
|
|
}
|
|
|
|
func newDummyWriter(name string, level Level, delay time.Duration) *dummyWriter {
|
|
w := &dummyWriter{
|
|
EventWriterBaseImpl: NewEventWriterBase(name, "dummy", WriterMode{Level: level, Flags: FlagsFromBits(0)}),
|
|
}
|
|
w.delay = delay
|
|
w.Base().OutputWriteCloser = w
|
|
return w
|
|
}
|
|
|
|
func TestLogger(t *testing.T) {
|
|
logger := NewLoggerWithWriters(t.Context(), "test")
|
|
|
|
dump := logger.DumpWriters()
|
|
assert.Empty(t, dump)
|
|
assert.Equal(t, NONE, logger.GetLevel())
|
|
assert.False(t, logger.IsEnabled())
|
|
|
|
w1 := newDummyWriter("dummy-1", DEBUG, 0)
|
|
logger.AddWriters(w1)
|
|
assert.Equal(t, DEBUG, logger.GetLevel())
|
|
|
|
w2 := newDummyWriter("dummy-2", WARN, 200*time.Millisecond)
|
|
logger.AddWriters(w2)
|
|
assert.Equal(t, DEBUG, logger.GetLevel())
|
|
|
|
dump = logger.DumpWriters()
|
|
assert.Len(t, dump, 2)
|
|
|
|
logger.Trace("trace-level") // this level is not logged
|
|
logger.Debug("debug-level")
|
|
logger.Error("error-level")
|
|
|
|
// w2 is slow, so only w1 has logs
|
|
time.Sleep(100 * time.Millisecond)
|
|
assert.Equal(t, []string{"debug-level\n", "error-level\n"}, w1.GetLogs())
|
|
assert.Equal(t, []string{}, w2.GetLogs())
|
|
|
|
logger.Close()
|
|
|
|
// after Close, all logs are flushed
|
|
assert.Equal(t, []string{"debug-level\n", "error-level\n"}, w1.GetLogs())
|
|
assert.Equal(t, []string{"error-level\n"}, w2.GetLogs())
|
|
}
|
|
|
|
func TestLoggerPause(t *testing.T) {
|
|
logger := NewLoggerWithWriters(t.Context(), "test")
|
|
|
|
w1 := newDummyWriter("dummy-1", DEBUG, 0)
|
|
logger.AddWriters(w1)
|
|
|
|
GetManager().PauseAll()
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
logger.Info("info-level")
|
|
time.Sleep(100 * time.Millisecond)
|
|
assert.Equal(t, []string{}, w1.GetLogs())
|
|
|
|
GetManager().ResumeAll()
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
assert.Equal(t, []string{"info-level\n"}, w1.GetLogs())
|
|
|
|
logger.Close()
|
|
}
|
|
|
|
type testLogString struct {
|
|
Field string
|
|
}
|
|
|
|
func (t testLogString) LogString() string {
|
|
return "log-string"
|
|
}
|
|
|
|
func TestLoggerLogString(t *testing.T) {
|
|
logger := NewLoggerWithWriters(t.Context(), "test")
|
|
|
|
w1 := newDummyWriter("dummy-1", DEBUG, 0)
|
|
w1.Mode.Colorize = true
|
|
logger.AddWriters(w1)
|
|
|
|
logger.Info("%s %s %#v %v", testLogString{}, &testLogString{}, testLogString{Field: "detail"}, NewColoredValue(testLogString{}, FgRed))
|
|
logger.Close()
|
|
|
|
assert.Equal(t, []string{"log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n"}, w1.GetLogs())
|
|
}
|
|
|
|
func TestLoggerExpressionFilter(t *testing.T) {
|
|
logger := NewLoggerWithWriters(t.Context(), "test")
|
|
|
|
w1 := newDummyWriter("dummy-1", DEBUG, 0)
|
|
w1.Mode.Expression = "foo.*"
|
|
logger.AddWriters(w1)
|
|
|
|
logger.Info("foo")
|
|
logger.Info("bar")
|
|
logger.Info("foo bar")
|
|
logger.SendLogEvent(&Event{Level: INFO, Filename: "foo.go", MsgSimpleText: "by filename"})
|
|
logger.Close()
|
|
|
|
assert.Equal(t, []string{"foo\n", "foo bar\n", "by filename\n"}, w1.GetLogs())
|
|
}
|
|
|
|
func TestLoggerExclusionFilter(t *testing.T) {
|
|
logger := NewLoggerWithWriters(t.Context(), "test")
|
|
|
|
w1 := newDummyWriter("dummy-1", DEBUG, 0)
|
|
w1.Mode.Exclusion = "foo.*"
|
|
logger.AddWriters(w1)
|
|
|
|
logger.Info("foo")
|
|
logger.Info("bar")
|
|
logger.Info("foo bar")
|
|
logger.SendLogEvent(&Event{Level: INFO, Filename: "foo.go", MsgSimpleText: "by filename"})
|
|
logger.Close()
|
|
|
|
assert.Equal(t, []string{"bar\n"}, w1.GetLogs())
|
|
}
|