Documentation ¶
Overview ¶
Package logging assists setting up test logging and using leveled logging in tests.
The TLogger is designed to assist the test writer in creating more useful tests and collecting log data in multiple streams, optimizing for human readability in one and machine readability in another. It's designed to mimic the testing.T object rather closely and use Zap logging semantics, both things already in use in Knative, to minimize the time developers need to spend learning the tool.
Inspired by and uses go-logr.
Advantages ¶
The TLogger enhances test design through subtle nudges and affordances:
* It encourages only logging with .V(), giving the writer a nudge to think about how important it is, but without requiring them to fit it in a narrowly-defined category.
* Reduces boilerplate of carrying around context for errors in several different variables, using .WithValues(), which results in more consistent and reusable code across the tests.
Porting ¶
To port code from using testing.T to logging.TLogger, the interfaces knative.dev/pkg/test.T and knative.dev/pkg/test.TLegacy have been created. All library functions should be refactored to use one interface and all .Log() calls rewritten to use structured format, which works with testing and TLogger. If a library function needs test functions not available even in test.TLegacy, it's probably badly written.
Then any test can be incrementally rewritten to use TLogger, as it coexists with testing.T without issue.
Index ¶
- func Error(msg string, keysAndValues ...interface{}) *structuredError
- func GetEmitableSpan(ctx context.Context, metricName string) *trace.Span
- func InitializeLogger()
- func InitializeMetricExporter(context string)
- type FormatLogger
- type SpewEncoder
- type StructuredError
- type TLogger
- func (o *TLogger) Collect(key string, value interface{})
- func (o *TLogger) Error(stringThenKeysAndValues ...interface{})
- func (o *TLogger) ErrorIfErr(err error, msg string, keysAndValues ...interface{})
- func (o *TLogger) Fatal(stringThenKeysAndValues ...interface{})
- func (o *TLogger) FatalIfErr(err error, msg string, keysAndValues ...interface{})
- func (o *TLogger) Helper()
- func (o *TLogger) Log(args ...interface{})
- func (o *TLogger) Logf(fmtS string, args ...interface{})
- func (o *TLogger) Name() string
- func (o *TLogger) Parallel()
- func (o *TLogger) Run(name string, f func(t *TLogger))
- func (o *TLogger) SkipNow()
- func (o *TLogger) V(level int) logr.InfoLogger
- func (o *TLogger) WithName(name string) *TLogger
- func (o *TLogger) WithValues(keysAndValues ...interface{}) *TLogger
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Error ¶
func Error(msg string, keysAndValues ...interface{}) *structuredError
Create a StructuredError. Gives a little better logging when given to a TLogger. This may prove to not be useful if users use the logger's WithValues() better.
func GetEmitableSpan ¶
GetEmitableSpan starts and returns a trace.Span with a name that is used by the ExportSpan method to emit the span.
func InitializeLogger ¶
func InitializeLogger()
InitializeLogger initializes logging for Knative tests. It should be called prior to executing tests but after command-line flags have been processed. Recommend doing it in a TestMain().
func InitializeMetricExporter ¶
func InitializeMetricExporter(context string)
InitializeMetricExporter initializes the metric exporter logger
Types ¶
type FormatLogger ¶
type FormatLogger func(template string, args ...interface{})
FormatLogger is a printf style function for logging in tests.
type SpewEncoder ¶
type SpewEncoder struct { *MapObjectEncoder *EncoderConfig }
SpewEncoder implements zapcore.Encoder interface
func NewSpewEncoder ¶
func NewSpewEncoder(cfg EncoderConfig) *SpewEncoder
NewSpewEncoder encodes logs using the spew library.
The JSON encoder (also used by the console encoder) included in Zap can only print objects that can be serialized to JSON and doesn't print them in the most readable way. This spew encoder is designed to make human-readable log only and get the most information to the user on any data type.
Code is mostly from console_encoder.go in zapcore.
func (*SpewEncoder) Clone ¶
func (enc *SpewEncoder) Clone() Encoder
Implements zapcore.Encoder interface
func (*SpewEncoder) EncodeEntry ¶
func (enc *SpewEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error)
Implements zapcore.Encoder interface.
type StructuredError ¶
type StructuredError interface { error GetValues() []interface{} WithValues(...interface{}) StructuredError DisableValuePrinting() EnableValuePrinting() }
StructuredError is an error which can hold arbitrary key-value arguments.
TODO(coryrc): The Structured Error is experimental and likely to be removed, but is currently in use in a refactored test.
type TLogger ¶
type TLogger struct {
// contains filtered or unexported fields
}
TLogger is TLogger
func NewTLogger ¶
Create a TLogger object using the global Zap logger and the current testing.T `defer` a call to second return value immediately after.
func (*TLogger) Collect ¶
Collect allows you to commingle multiple validations during one test execution. Under the hood, it creates a sub-test during cleanup and iterates through the collected values, printing them. If any are errors, it fails the subtest. Currently experimental and likely to be removed
func (*TLogger) Error ¶
func (o *TLogger) Error(stringThenKeysAndValues ...interface{})
Error is essentially a .V(errorLevel).Info() followed by failing the test. Intended usage is Error(msg string, key-value alternating arguments) Same effect as testing.T.Error Generic definition for compatibility with test.T interface Implements test.T
func (*TLogger) ErrorIfErr ¶
ErrorIfErr fails the current test if the err != nil. Remaining arguments function as if passed to .V(errorLevel).Info() (were that a thing) Same signature as logr.Logger.Error() method, but as this is a test, it functions slightly differently.
func (*TLogger) Fatal ¶
func (o *TLogger) Fatal(stringThenKeysAndValues ...interface{})
Fatal is essentially a .V(errorLevel).Info() followed by failing and immediately stopping the test. Intended usage is Fatal(msg string, key-value alternating arguments) Same effect as testing.T.Fatal Generic definition for compatibility with test.TLegacy interface Implements test.TLegacy
func (*TLogger) FatalIfErr ¶
FatalIfErr is just like ErrorIfErr() but test execution stops immediately
func (*TLogger) Helper ¶
func (o *TLogger) Helper()
Helper cannot work as an indirect call, so just do nothing :( Implements test.T
func (*TLogger) Log ¶
func (o *TLogger) Log(args ...interface{})
Log is deprecated: only existing for test.T compatibility Please use leveled logging via .V().Info() Will panic if given data incompatible with Info() function Implements test.T
func (*TLogger) Logf ¶
Logf is deprecated: only existing for test.TLegacy compatibility Please use leveled logging via .V().Info() Implements test.TLegacy
func (*TLogger) Parallel ¶
func (o *TLogger) Parallel()
Parallel allows tests or subtests to run in parallel Just calls the testing.T.Parallel() under the hood
func (*TLogger) SkipNow ¶
func (o *TLogger) SkipNow()
SkipNow immediately stops test execution Implements test.T
func (*TLogger) V ¶
func (o *TLogger) V(level int) logr.InfoLogger
V() returns an InfoLogger from go-logr.
This should be the main way your tests log. Most frequent usage is used directly:
t.V(2).Info("Something at regular level")
But if something computationally difficult is to be done, can do:
if l := t.V(8); l.Enabled() { x := somethingExpensive() l.Info("logging it", "expensiveThing", x) }
Elsewhere in this documentation refers to a hypothetical .V(errorLevel) to simplify explanations. The V() function cannot write to the error level; the Error, ErrorIfErr, Fatal, and FatalIfErr methods are the only way to write to the error level.
func (*TLogger) WithName ¶
WithName() acts like Zap's Named() method. Consistent with logr.Logger.WithName() Appends the name onto the current logger
func (*TLogger) WithValues ¶
WithValues() acts like Zap's With() method. Consistent with logr.Logger.WithValues() Whenever anything is logged with the returned TLogger, it will act as if these keys and values were passed into every logging call.