golang.org/x/tools@v0.21.0/go/analysis/passes/slog/testdata/src/a/a.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file contains tests for the slog checker.
     6  
     7  //go:build go1.21
     8  
     9  package a
    10  
    11  import (
    12  	"context"
    13  	"errors"
    14  	"fmt"
    15  	"log/slog"
    16  )
    17  
    18  func F() {
    19  	var (
    20  		l *slog.Logger
    21  		r slog.Record
    22  	)
    23  
    24  	// Unrelated call.
    25  	fmt.Println("ok")
    26  
    27  	// Valid calls.
    28  	slog.Info("msg")
    29  	slog.Info("msg", "a", 1)
    30  	slog.Info("", "a", 1, "b", "two")
    31  	l.Debug("msg", "a", 1)
    32  	l.With("a", 1)
    33  	slog.Warn("msg", slog.Int("a", 1))
    34  	slog.Warn("msg", slog.Int("a", 1), "k", 2)
    35  	l.WarnContext(nil, "msg", "a", 1, slog.Int("b", 2), slog.Int("c", 3), "d", 4)
    36  	l.DebugContext(nil, "msg", "a", 1, slog.Int("b", 2), slog.Int("c", 3), "d", 4, slog.Int("e", 5))
    37  	r.Add("a", 1, "b", 2)
    38  	(*slog.Logger).Debug(l, "msg", "a", 1, "b", 2)
    39  
    40  	var key string
    41  	r.Add(key, 1)
    42  
    43  	// bad
    44  	slog.Info("msg", 1)                        // want `slog.Info arg "1" should be a string or a slog.Attr`
    45  	l.Info("msg", 2)                           // want `slog.Logger.Info arg "2" should be a string or a slog.Attr`
    46  	slog.Debug("msg", "a")                     // want `call to slog.Debug missing a final value`
    47  	slog.Warn("msg", slog.Int("a", 1), "k")    // want `call to slog.Warn missing a final value`
    48  	slog.ErrorContext(nil, "msg", "a", 1, "b") // want `call to slog.ErrorContext missing a final value`
    49  	r.Add("K", "v", "k")                       // want `call to slog.Record.Add missing a final value`
    50  	l.With("a", "b", 2)                        // want `slog.Logger.With arg "2" should be a string or a slog.Attr`
    51  
    52  	// Report the first problem if there are multiple bad keys.
    53  	slog.Debug("msg", "a", 1, 2, 3, 4) // want `slog.Debug arg "2" should be a string or a slog.Attr`
    54  	slog.Debug("msg", "a", 1, 2, 3, 4) // want `slog.Debug arg "2" should be a string or a slog.Attr`
    55  
    56  	slog.Log(nil, slog.LevelWarn, "msg", "a", "b", 2) // want `slog.Log arg "2" should be a string or a slog.Attr`
    57  
    58  	// Test method expression call.
    59  	(*slog.Logger).Debug(l, "msg", "a", 1, 2, 3) // want `slog.Logger.Debug arg "2" should be a string or a slog.Attr`
    60  
    61  	// Skip calls with spread args.
    62  	var args []any
    63  	slog.Info("msg", args...)
    64  
    65  	// Report keys that are statically not exactly "string".
    66  	type MyString string
    67  	myKey := MyString("a")  // any(x) looks like <MyString, "a">.
    68  	slog.Info("", myKey, 1) // want `slog.Info arg "myKey" should be a string or a slog.Attr`
    69  
    70  	// The variadic part of all the calls below begins with an argument of
    71  	// static type any, followed by an integer.
    72  	// Even though the we don't know the dynamic type of the first arg, and thus
    73  	// whether it is a key, an Attr, or something else, the fact that the
    74  	// following integer arg cannot be a key allows us to assume that we should
    75  	// expect a key to follow.
    76  	var a any = "key"
    77  
    78  	// This is a valid call for which  we correctly produce no diagnostic.
    79  	slog.Info("msg", a, 7, "key2", 5)
    80  
    81  	// This is an invalid call because the final value is missing, but we can't
    82  	// be sure that's the reason.
    83  	slog.Info("msg", a, 7, "key2") // want `call to slog.Info has a missing or misplaced value`
    84  
    85  	// Here our guess about the unknown arg (a) is wrong: we assume it's a string, but it's an Attr.
    86  	// Therefore the second argument should be a key, but it is a number.
    87  	// Ideally our diagnostic would pinpoint the problem, but we don't have enough information.
    88  	a = slog.Int("a", 1)
    89  	slog.Info("msg", a, 7, "key2") // want `call to slog.Info has a missing or misplaced value`
    90  
    91  	// This call is invalid for the same reason as the one above, but we can't
    92  	// detect that.
    93  	slog.Info("msg", a, 7, "key2", 5)
    94  
    95  	// Another invalid call we can't detect. Here the first argument is wrong.
    96  	a = 1
    97  	slog.Info("msg", a, 7, "b", 5)
    98  
    99  	// We can detect the first case as the type of key is UntypedNil,
   100  	// e.g. not yet assigned to any and not yet an interface.
   101  	// We cannot detect the second.
   102  	slog.Debug("msg", nil, 2) // want `slog.Debug arg "nil" should be a string or a slog.Attr`
   103  	slog.Debug("msg", any(nil), 2)
   104  
   105  	// Recovery from unknown value.
   106  	slog.Debug("msg", any(nil), "a")
   107  	slog.Debug("msg", any(nil), "a", 2)
   108  	slog.Debug("msg", any(nil), "a", 2, "b") // want `call to slog.Debug has a missing or misplaced value`
   109  	slog.Debug("msg", any(nil), 2, 3, 4)     // want "slog.Debug arg \\\"3\\\" should probably be a string or a slog.Attr \\(previous arg \\\"2\\\" cannot be a key\\)"
   110  
   111  	// In these cases, an argument in key position is an interface, but we can glean useful information about it.
   112  
   113  	// An error interface in key position is definitely invalid: it can't be a string
   114  	// or slog.Attr.
   115  	var err error
   116  	slog.Error("msg", err) // want `slog.Error arg "err" should be a string or a slog.Attr`
   117  
   118  	// slog.Attr implements fmt.Stringer, but string does not, so assume the arg is an Attr.
   119  	var stringer fmt.Stringer
   120  	slog.Info("msg", stringer, "a", 1)
   121  	slog.Info("msg", stringer, 1) // want `slog.Info arg "1" should be a string or a slog.Attr`
   122  }
   123  
   124  func All() {
   125  	// Test all functions and methods at least once.
   126  	var (
   127  		l   *slog.Logger
   128  		r   slog.Record
   129  		ctx context.Context
   130  	)
   131  	slog.Debug("msg", 1, 2) // want `slog.Debug arg "1" should be a string or a slog.Attr`
   132  	slog.Error("msg", 1, 2) // want `slog.Error arg "1" should be a string or a slog.Attr`
   133  	slog.Info("msg", 1, 2)  // want `slog.Info arg "1" should be a string or a slog.Attr`
   134  	slog.Warn("msg", 1, 2)  // want `slog.Warn arg "1" should be a string or a slog.Attr`
   135  
   136  	slog.DebugContext(ctx, "msg", 1, 2) // want `slog.DebugContext arg "1" should be a string or a slog.Attr`
   137  	slog.ErrorContext(ctx, "msg", 1, 2) // want `slog.ErrorContext arg "1" should be a string or a slog.Attr`
   138  	slog.InfoContext(ctx, "msg", 1, 2)  // want `slog.InfoContext arg "1" should be a string or a slog.Attr`
   139  	slog.WarnContext(ctx, "msg", 1, 2)  // want `slog.WarnContext arg "1" should be a string or a slog.Attr`
   140  
   141  	slog.Log(ctx, slog.LevelDebug, "msg", 1, 2) // want `slog.Log arg "1" should be a string or a slog.Attr`
   142  
   143  	l.Debug("msg", 1, 2) // want `slog.Logger.Debug arg "1" should be a string or a slog.Attr`
   144  	l.Error("msg", 1, 2) // want `slog.Logger.Error arg "1" should be a string or a slog.Attr`
   145  	l.Info("msg", 1, 2)  // want `slog.Logger.Info arg "1" should be a string or a slog.Attr`
   146  	l.Warn("msg", 1, 2)  // want `slog.Logger.Warn arg "1" should be a string or a slog.Attr`
   147  
   148  	l.DebugContext(ctx, "msg", 1, 2) // want `slog.Logger.DebugContext arg "1" should be a string or a slog.Attr`
   149  	l.ErrorContext(ctx, "msg", 1, 2) // want `slog.Logger.ErrorContext arg "1" should be a string or a slog.Attr`
   150  	l.InfoContext(ctx, "msg", 1, 2)  // want `slog.Logger.InfoContext arg "1" should be a string or a slog.Attr`
   151  	l.WarnContext(ctx, "msg", 1, 2)  // want `slog.Logger.WarnContext arg "1" should be a string or a slog.Attr`
   152  
   153  	l.Log(ctx, slog.LevelDebug, "msg", 1, 2) // want `slog.Logger.Log arg "1" should be a string or a slog.Attr`
   154  
   155  	_ = l.With(1, 2) // want `slog.Logger.With arg "1" should be a string or a slog.Attr`
   156  
   157  	r.Add(1, 2) // want `slog.Record.Add arg "1" should be a string or a slog.Attr`
   158  
   159  	_ = slog.Group("key", "a", 1, "b", 2)
   160  	_ = slog.Group("key", "a", 1, 2, 3) // want `slog.Group arg "2" should be a string or a slog.Attr`
   161  
   162  	slog.Error("foo", "err", errors.New("oops")) // regression test for #61228.
   163  }
   164  
   165  // Used in tests by package b.
   166  var MyLogger = slog.Default()