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()