Files
weichenandCursor bed0dbf076
ci / vet-and-test (push) Successful in 4s
ci / docker-checkout-hostgateway (push) Successful in 2s
Add a structured logger and collector so runs can be traced across processes.
Sync and async sinks, redaction, and a queryable HTTP service keep concurrent logs tied to a trace id.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 13:51:16 +00:00

111 lines
2.6 KiB
Go

package conformance
import (
"sync"
"sync/atomic"
"testing"
"time"
"logging-system/logsys"
"logging-system/redact"
"logging-system/sink"
)
func TestSyncConcurrentNoLoss(t *testing.T) {
mem := &sink.Memory{}
log := logsys.New(logsys.Options{Level: logsys.LevelInfo, Sinks: []logsys.Sink{mem}})
const goroutines = 100
const per = 1000
var wg sync.WaitGroup
wg.Add(goroutines)
for g := 0; g < goroutines; g++ {
go func() {
defer wg.Done()
for i := 0; i < per; i++ {
log.Info("sync")
}
}()
}
wg.Wait()
if err := log.Sync(); err != nil {
t.Fatal(err)
}
if got := len(mem.Snapshot()); got != goroutines*per {
t.Fatalf("got %d want %d", got, goroutines*per)
}
}
func TestAsyncCloseDrains(t *testing.T) {
mem := &sink.Memory{}
async := &sink.Async{Inner: mem, Queue: 4096}
log := logsys.New(logsys.Options{Level: logsys.LevelInfo, Sinks: []logsys.Sink{async}})
const n = 500
for i := 0; i < n; i++ {
log.Info("async")
}
if err := log.Close(); err != nil {
t.Fatal(err)
}
if got := len(mem.Snapshot()); got != n {
t.Fatalf("drained %d want %d dropped %d", got, n, async.Dropped())
}
if async.Dropped() != 0 {
t.Fatalf("dropped %d", async.Dropped())
}
}
func TestRedactDoesNotLeak(t *testing.T) {
rd, err := redact.New(nil)
if err != nil {
t.Fatal(err)
}
mem := &sink.Memory{}
log := logsys.New(logsys.Options{
Level: logsys.LevelInfo,
Sinks: []logsys.Sink{mem},
Redact: rd.Apply,
})
log.Error("call", nil, "header", "Bearer abcdefghijklmnop", "key", "sk-abcdefghijklmnopqrstuvwxyz")
raw := mem.Snapshot()[0]
blob := raw.Message + raw.Fields["header"].(string) + raw.Fields["key"].(string)
for _, secret := range []string{"abcdefghijklmnop", "sk-abcdefghijklmnopqrstuvwxyz"} {
if stringsContains(blob, secret) {
t.Fatalf("leaked %s in %+v", secret, raw.Fields)
}
}
}
func TestFanoutConsistent(t *testing.T) {
a, b := &sink.Memory{}, &sink.Memory{}
log := logsys.New(logsys.Options{Level: logsys.LevelInfo, Sinks: []logsys.Sink{sink.Fanout{Sinks: []logsys.Sink{a, b}}}})
var seq atomic.Int64
var wg sync.WaitGroup
wg.Add(20)
for i := 0; i < 20; i++ {
go func() {
defer wg.Done()
for j := 0; j < 50; j++ {
log.Info("fan", "n", seq.Add(1))
}
}()
}
wg.Wait()
if len(a.Snapshot()) != 1000 || len(b.Snapshot()) != 1000 {
t.Fatalf("a=%d b=%d", len(a.Snapshot()), len(b.Snapshot()))
}
_ = time.Second
}
func stringsContains(s, sub string) bool {
return len(s) >= len(sub) && (s == sub || len(sub) > 0 && index(s, sub))
}
func index(s, sub string) bool {
for i := 0; i+len(sub) <= len(s); i++ {
if s[i:i+len(sub)] == sub {
return true
}
}
return false
}