caddy/modules/logging/journaldencoder_test.go
Zen Dodd 0c7c91a447
Some checks failed
Tests / test (s390x on IBM Z) (push) Has been skipped
Tests / goreleaser-check (push) Has been skipped
Cross-Build / build (~1.26.0, 1.26, aix) (push) Failing after 4s
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Failing after 3s
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Failing after 3s
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Failing after 3s
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Failing after 2s
Cross-Build / build (~1.26.0, 1.26, linux) (push) Failing after 3s
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Failing after 2s
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Failing after 1s
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Failing after 3s
Cross-Build / build (~1.26.0, 1.26, windows) (push) Failing after 1s
Lint / lint (ubuntu-latest, linux) (push) Failing after 4s
Lint / govulncheck (push) Failing after 9s
Lint / dependency-review (push) Failing after 10s
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Failing after 3s
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Failing after 2m6s
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Lint / lint (macos-14, mac) (push) Has been cancelled
Lint / lint (windows-latest, windows) (push) Has been cancelled
logging: preserve ts for journald-wrapped JSON logs (#7644)
2026-04-13 17:33:02 -06:00

156 lines
3.7 KiB
Go

package logging
import (
"context"
"encoding/json"
"strings"
"testing"
"time"
"github.com/caddyserver/caddy/v2"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
)
func TestJournaldPriorityPrefix(t *testing.T) {
tests := []struct {
level zapcore.Level
want string
}{
{level: zapcore.InvalidLevel, want: "<6>"},
{level: zapcore.DebugLevel, want: "<7>"},
{level: zapcore.InfoLevel, want: "<6>"},
{level: zapcore.WarnLevel, want: "<4>"},
{level: zapcore.ErrorLevel, want: "<3>"},
{level: zapcore.DPanicLevel, want: "<2>"},
{level: zapcore.PanicLevel, want: "<2>"},
{level: zapcore.FatalLevel, want: "<2>"},
}
for _, tt := range tests {
t.Run(tt.level.String(), func(t *testing.T) {
if got := journaldPriorityPrefix(tt.level); got != tt.want {
t.Fatalf("got %s, want %s", got, tt.want)
}
})
}
}
func TestJournaldEncoderEncodeEntry(t *testing.T) {
tests := []struct {
name string
level zapcore.Level
want string
}{
{name: "debug", level: zapcore.DebugLevel, want: "<7>wrapped\n"},
{name: "info", level: zapcore.InfoLevel, want: "<6>wrapped\n"},
{name: "warn", level: zapcore.WarnLevel, want: "<4>wrapped\n"},
{name: "error", level: zapcore.ErrorLevel, want: "<3>wrapped\n"},
{name: "panic", level: zapcore.PanicLevel, want: "<2>wrapped\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
enc := JournaldEncoder{Encoder: staticEncoder{output: "wrapped\n"}}
buf, err := enc.EncodeEntry(zapcore.Entry{Level: tt.level}, nil)
if err != nil {
t.Fatalf("EncodeEntry() error = %v", err)
}
defer buf.Free()
if got := buf.String(); got != tt.want {
t.Fatalf("got %q, want %q", got, tt.want)
}
})
}
}
func TestJournaldEncoderUnmarshalCaddyfile(t *testing.T) {
d := caddyfile.NewTestDispenser(`
journald {
wrap console
}
`)
var enc JournaldEncoder
if err := enc.UnmarshalCaddyfile(d); err != nil {
t.Fatalf("UnmarshalCaddyfile() error = %v", err)
}
var got map[string]any
if err := json.Unmarshal(enc.WrappedRaw, &got); err != nil {
t.Fatalf("unmarshal wrapped encoder: %v", err)
}
if got["format"] != "console" {
t.Fatalf("wrapped format = %v, want console", got["format"])
}
}
func TestJournaldEncoderPreservesJSONTimestamp(t *testing.T) {
enc := &JournaldEncoder{
Encoder: &JSONEncoder{},
}
if err := enc.Provision(caddy.Context{Context: context.Background()}); err != nil {
t.Fatalf("Provision() error = %v", err)
}
buf, err := enc.EncodeEntry(zapcore.Entry{
Level: zapcore.InfoLevel,
Time: fixedEntryTime(),
Message: "hello",
}, nil)
if err != nil {
t.Fatalf("EncodeEntry() error = %v", err)
}
defer buf.Free()
got := buf.String()
if !strings.Contains(got, `"ts"`) {
t.Fatalf("got JSON output without ts field: %q", got)
}
}
func TestJournaldEncoderSuppressesConsoleTimestamp(t *testing.T) {
enc := &JournaldEncoder{
Encoder: &ConsoleEncoder{},
}
if err := enc.Provision(caddy.Context{Context: context.Background()}); err != nil {
t.Fatalf("Provision() error = %v", err)
}
buf, err := enc.EncodeEntry(zapcore.Entry{
Level: zapcore.InfoLevel,
Time: fixedEntryTime(),
Message: "hello",
}, nil)
if err != nil {
t.Fatalf("EncodeEntry() error = %v", err)
}
defer buf.Free()
got := buf.String()
if strings.Contains(got, "2001/02/03") {
t.Fatalf("got console output with timestamp: %q", got)
}
}
type staticEncoder struct {
nopEncoder
output string
}
func (se staticEncoder) Clone() zapcore.Encoder { return se }
func (se staticEncoder) EncodeEntry(zapcore.Entry, []zapcore.Field) (*buffer.Buffer, error) {
buf := bufferpool.Get()
buf.AppendString(se.output)
return buf, nil
}
func fixedEntryTime() (ts time.Time) {
return time.Date(2001, 2, 3, 4, 5, 6, 0, time.UTC)
}