/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/logger/test_logger.go
209 строк
6 KB
chrisnojima-zoom
Version 670 - clean2 (#29122)
08 июн 2026, 19:31
Не верифицирован
08 июн 2026, 19:31
1943197
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package logger import ( "context" "fmt" "os" "runtime" "slices" "strings" "sync" "time" logging "github.com/keybase/go-logging" ) // TestLogBackend is an interface for logging to a test object (i.e., // a *testing.T). We define this in order to avoid pulling in the // "testing" package in exported code. type TestLogBackend interface { Error(args ...any) Errorf(format string, args ...any) Fatal(args ...any) Fatalf(format string, args ...any) Log(args ...any) Logf(format string, args ...any) Failed() bool Name() string } // TestLogger is a Logger that writes to a TestLogBackend. All // messages except Fatal are printed using Logf, to avoid failing a // test that is trying to test an error condition. No context tags // are logged. type TestLogger struct { log TestLogBackend extraDepth int sync.Mutex } func NewTestLogger(log TestLogBackend) *TestLogger { return &TestLogger{log: log} } // Verify TestLogger fully implements the Logger interface. var _ Logger = (*TestLogger)(nil) // Whether "TEST FAILED" has output for a particular test is stored globally. // Because some tests use multiple instances of TestLogger so storing // it there would result in multiple "TEST FAILED" per test. // This way has the drawback that when two tests in different packages // share a name, only one of their "TEST FAILED" will print. var ( globalFailReportedLock sync.Mutex globalFailReported = make(map[string]struct{}) ) // ctx can be `nil` func (log *TestLogger) common(ctx context.Context, lvl logging.Level, useFatal bool, fmts string, arg ...any) { if log.log.Failed() { globalFailReportedLock.Lock() name := log.log.Name() if _, reported := globalFailReported[name]; !reported { log.log.Logf("TEST FAILED: %s", name) globalFailReported[name] = struct{}{} } globalFailReportedLock.Unlock() if stringListContains(strings.ToLower(os.Getenv("KEYBASE_TEST_LOG_AFTER_FAIL")), []string{"0", "false", "n", "no"}) { return } } if os.Getenv("KEYBASE_TEST_DUP_LOG_TO_STDOUT") != "" { fmt.Printf(prepareString(ctx, log.prefixCaller(log.extraDepth, lvl, fmts))+"\n", arg...) } if ctx != nil { if useFatal { log.log.Fatalf(prepareString(ctx, log.prefixCaller(log.extraDepth, lvl, fmts)), arg...) } else { log.log.Logf(prepareString(ctx, log.prefixCaller(log.extraDepth, lvl, fmts)), arg...) } } else { if useFatal { log.log.Fatalf(log.prefixCaller(log.extraDepth, lvl, fmts), arg...) } else { log.log.Logf(log.prefixCaller(log.extraDepth, lvl, fmts), arg...) } } } func (log *TestLogger) prefixCaller(extraDepth int, lvl logging.Level, fmts string) string { // The testing library doesn't let us control the stack depth, // and it always prints out its own prefix, so use \r to clear // it out (at least on a terminal) and do our own formatting. _, file, line, _ := runtime.Caller(3 + extraDepth) elements := strings.Split(file, "/") failed := "" if log.log.Failed() { failed = "[X] " } fileLine := fmt.Sprintf("%s:%d", elements[len(elements)-1], line) return fmt.Sprintf("\r%s %s%-23s: [%.1s] %s", time.Now().Format("2006-01-02 15:04:05.00000"), failed, fileLine, lvl, fmts) } func (log *TestLogger) Debug(fmts string, arg ...any) { log.common(context.TODO(), logging.DEBUG, false, fmts, arg...) } func (log *TestLogger) CDebugf(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.DEBUG, false, fmts, arg...) } func (log *TestLogger) Info(fmts string, arg ...any) { log.common(context.TODO(), logging.INFO, false, fmts, arg...) } func (log *TestLogger) CInfof(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.INFO, false, fmts, arg...) } func (log *TestLogger) Notice(fmts string, arg ...any) { log.common(context.TODO(), logging.NOTICE, false, fmts, arg...) } func (log *TestLogger) CNoticef(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.NOTICE, false, fmts, arg...) } func (log *TestLogger) Warning(fmts string, arg ...any) { log.common(context.TODO(), logging.WARNING, false, fmts, arg...) } func (log *TestLogger) CWarningf(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.WARNING, false, fmts, arg...) } func (log *TestLogger) Error(fmts string, arg ...any) { log.common(context.TODO(), logging.ERROR, false, fmts, arg...) } func (log *TestLogger) Errorf(fmts string, arg ...any) { log.common(context.TODO(), logging.ERROR, false, fmts, arg...) } func (log *TestLogger) CErrorf(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.ERROR, false, fmts, arg...) } func (log *TestLogger) Critical(fmts string, arg ...any) { log.common(context.TODO(), logging.CRITICAL, false, fmts, arg...) } func (log *TestLogger) CCriticalf(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.CRITICAL, false, fmts, arg...) } func (log *TestLogger) Fatalf(fmts string, arg ...any) { log.common(context.TODO(), logging.CRITICAL, true, fmts, arg...) } func (log *TestLogger) CFatalf(ctx context.Context, fmts string, arg ...any, ) { log.common(ctx, logging.CRITICAL, true, fmts, arg...) } func (log *TestLogger) Profile(fmts string, arg ...any) { log.common(context.TODO(), logging.CRITICAL, false, fmts, arg...) } func (log *TestLogger) Configure(_ string, _ bool, _ string) { // no-op } func (log *TestLogger) CloneWithAddedDepth(depth int) Logger { log.Lock() defer log.Unlock() var clone TestLogger clone.log = log.log clone.extraDepth = log.extraDepth + depth return &clone } // no-op stubs to fulfill the Logger interface func (log *TestLogger) SetExternalHandler(_ ExternalHandler) {} func stringListContains(s string, a []string) bool { return slices.Contains(a, s) }