Documentation
¶
Overview ¶
Package slogassert provides a slog Handler that allows testing that expected logging messages were made in your test code.
Normal Usage ¶
Normal usage looks like this:
func TestSomething(t *testing.T) {
// This automatically registers a Cleanup function to assert
// that all log messages are accounted for.
handler := slogassert.New(t, slog.LevelWarn)
logger := slog.New(handler)
// inject the logger into your test code and run it
// Now start asserting things:
handler.AssertSomeOf("some log message")
// automatically at the end of your function, an
// assertion will run that all log messages are accounted
// for.
}
A variety of assertions at varying levels of detail are available on the Handler.
Index ¶
- Constants
- type Handler
- func (h *Handler) AssertEmpty()
- func (h *Handler) AssertMessage(msg string)
- func (h *Handler) AssertMessageLevel(msg string, level slog.Level)
- func (h *Handler) AssertPrecise(lmm LogMessageMatch)
- func (h *Handler) AssertSomeMessage(msg string)
- func (h *Handler) AssertSomeMessageLevel(msg string, level slog.Level)
- func (h *Handler) AssertSomePrecise(lmm LogMessageMatch)
- func (h *Handler) Enabled(_ context.Context, level slog.Level) bool
- func (h *Handler) Handle(_ context.Context, record slog.Record) error
- func (h *Handler) Reset()
- func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *Handler) WithGroup(name string) slog.Handler
- type LogMessageMatch
Constants ¶
const ( // LevelDontCare can be used in a LogMessageMatch to indicate // that the level does not need to match. LevelDontCare = slog.Level(-255000000) )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler implements the slog.Handler interface, with additional methods for testing.
func New ¶
New creates a new testing logger, logging with the given level.
This will automatically call a t.Cleanup to assert that the logger is empty. If you want to do this manually or not at all, call NewWithoutCleanup.
func NewWithoutCleanup ¶
NewWithoutCleanup creates a new testing logger, logging with the given level.
This does not automatically register a cleanup function to assert that the logger is empty.
func (*Handler) AssertEmpty ¶
func (h *Handler) AssertEmpty()
AssertEmpty asserts that all log messages have now been accounted for and there is nothing left.
A call to this method will be automatically deferred through the testing system if you use New(), but you can also use New
func (*Handler) AssertMessage ¶
AssertMessage asserts a logging message recorded with the giving logging message.
func (*Handler) AssertMessageLevel ¶
AssertMessageLevel asserts a logging message with the given message and level.
func (*Handler) AssertPrecise ¶
func (h *Handler) AssertPrecise(lmm LogMessageMatch)
AssertPrecise takes a LogMessageMatch and asserts the first log message that matches it.
func (*Handler) AssertSomeMessage ¶
AssertSomeMessage asserts that some logging events were recorded with the given message.
func (*Handler) AssertSomeMessageLevel ¶
AssertSomeMessageLevel is a weak assertion that asserts that some logging events were recorded with the given message, at the given logging level.
func (*Handler) AssertSomePrecise ¶
func (h *Handler) AssertSomePrecise(lmm LogMessageMatch)
AssertSomePrecise asserts all the messages in the log that match the LogMessageMatch criteria.
func (*Handler) Enabled ¶
Enabled implements slog.Handler, reporting back to slog whether or not the handler is enabled for this level of log message.
func (*Handler) Handle ¶
Handle implements slog.Handler, recording a log message into the root handler.
func (*Handler) Reset ¶
func (h *Handler) Reset()
Reset will simply empty out the log entirely. This can be used in anger to simply make tests pass, or when you legitimately have some logging messages you don't want to bind your tests to (for instance this package's own call to testing/slogtest).
type LogMessageMatch ¶
type LogMessageMatch struct {
Message string
Level slog.Level
Attrs map[string]any
AllAttrsMatch bool
}
LogMessageMatch defines a precise message to match.
The Message works as you'd expect; an equality check.
If Level is LevelDontCare, the level won't be matched. Otherwise, it will also be an equality check.
Attrs is a map of string to any. The strings will be the groups for the given attribute, joined together by dots. For instance, an ungrouped key called "url" will be "url". If it is in a "request" group, it will be keyed by "request.url". If that is also in a "webserver" group, the key will be "webserver.request.url". Any dots in the keys themselves will be backslash encoded, so a top-level key called "a.b" will be "a\.b" in this map.
The value is a matcher on the attribute, which may be one of three things.
It can be a function "func (slog.Value) bool", which will be passed the value. If it returns true, it is considered to match; false is considered to be not a match.
It can be a function "func (T) bool", where "T" matches the concrete value behind the Kind of the slog.Value. In that case, the same rules apply. For KindAny, this must be precisely "func(any) bool"; no further wrapping will be done.
It can be a concrete value, in which case it must be equal to the value contained in the attribute. Type-appropriate equality is used, e.g., time.Time's are compared via time.Equal.
AllAttrsMatch indicate whether the Attrs map must contain matches for all attributes in the match. If true, and there are unmatched attribtues in the log message, the match will fail. If false, extra attributes in the log message won't fail the match.
Note: This strikes me as likely to change to at least some degree going forward.