Skip to content

Commit 1301dc6

Browse files
authored
feat: implement -context-only (#14)
1 parent bc45156 commit 1301dc6

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

README.md

+17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ The linter has several options, so you can adjust it to your own code style.
2424

2525
* Forbid mixing key-value pairs and attributes within a single function call (default)
2626
* Enforce using either key-value pairs or attributes for the entire project (optional)
27+
* Enforce using methods that accept a context (optional)
2728
* Enforce using constants instead of raw keys (optional)
2829
* Enforce putting arguments on separate lines (optional)
2930

@@ -53,6 +54,22 @@ In contrast, the `-attr-only` flag causes `sloglint` to report any use of key-va
5354
slog.Info("a user has logged in", "user_id", 42) // sloglint: key-value pairs should not be used
5455
```
5556

57+
### Context only
58+
59+
Some `slog.Handler` implementations make use of the given `context.Context` (e.g. to access context values).
60+
For them to work properly, you need to pass a context to all logger calls.
61+
The `-context-only` flag causes `sloglint` to report the use of methods without a context.
62+
63+
```go
64+
slog.Info("a user has logged in") // sloglint: methods without a context should not be used
65+
```
66+
67+
This report can be fixed by using the equivalent method with the `Context` suffix.
68+
69+
```go
70+
slog.InfoContext(ctx, "a user has logged in")
71+
```
72+
5673
### No raw keys
5774

5875
To prevent typos, you may want to forbid the use of raw keys altogether.

sloglint.go

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
type Options struct {
2020
KVOnly bool // Enforce using key-value pairs only (incompatible with AttrOnly).
2121
AttrOnly bool // Enforce using attributes only (incompatible with KVOnly).
22+
ContextOnly bool // Enforce using methods that accept a context.
2223
NoRawKeys bool // Enforce using constants instead of raw keys.
2324
ArgsOnSepLines bool // Enforce putting arguments on separate lines.
2425
}
@@ -56,6 +57,7 @@ func flags(opts *Options) flag.FlagSet {
5657

5758
boolVar(&opts.KVOnly, "kv-only", "enforce using key-value pairs only (incompatible with -attr-only)")
5859
boolVar(&opts.AttrOnly, "attr-only", "enforce using attributes only (incompatible with -kv-only)")
60+
boolVar(&opts.ContextOnly, "context-only", "enforce using methods that accept a context")
5961
boolVar(&opts.NoRawKeys, "no-raw-keys", "enforce using constants instead of raw keys")
6062
boolVar(&opts.ArgsOnSepLines, "args-on-sep-lines", "enforce putting arguments on separate lines")
6163

@@ -113,6 +115,13 @@ func run(pass *analysis.Pass, opts *Options) {
113115
return
114116
}
115117

118+
if opts.ContextOnly {
119+
typ := pass.TypesInfo.TypeOf(call.Args[0])
120+
if typ != nil && typ.String() != "context.Context" {
121+
pass.Reportf(call.Pos(), "methods without a context should not be used")
122+
}
123+
}
124+
116125
// NOTE: we assume that the arguments have already been validated by govet.
117126
args := call.Args[argsPos:]
118127
if len(args) == 0 {

sloglint_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ func TestAnalyzer(t *testing.T) {
2525
analysistest.Run(t, testdata, analyzer, "attr_only")
2626
})
2727

28+
t.Run("context only", func(t *testing.T) {
29+
analyzer := sloglint.New(&sloglint.Options{ContextOnly: true})
30+
analysistest.Run(t, testdata, analyzer, "context_only")
31+
})
32+
2833
t.Run("no raw keys", func(t *testing.T) {
2934
analyzer := sloglint.New(&sloglint.Options{NoRawKeys: true})
3035
analysistest.Run(t, testdata, analyzer, "no_raw_keys")
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package context_only
2+
3+
import (
4+
"context"
5+
"log/slog"
6+
)
7+
8+
func tests() {
9+
logger := slog.New(nil)
10+
ctx := context.Background()
11+
12+
slog.Log(ctx, slog.LevelInfo, "msg")
13+
slog.DebugContext(ctx, "msg")
14+
slog.InfoContext(ctx, "msg")
15+
slog.WarnContext(ctx, "msg")
16+
slog.ErrorContext(ctx, "msg")
17+
18+
logger.Log(ctx, slog.LevelInfo, "msg")
19+
logger.DebugContext(ctx, "msg")
20+
logger.InfoContext(ctx, "msg")
21+
logger.WarnContext(ctx, "msg")
22+
logger.ErrorContext(ctx, "msg")
23+
24+
slog.Debug("msg") // want `methods without a context should not be used`
25+
slog.Info("msg") // want `methods without a context should not be used`
26+
slog.Warn("msg") // want `methods without a context should not be used`
27+
slog.Error("msg") // want `methods without a context should not be used`
28+
29+
logger.Debug("msg") // want `methods without a context should not be used`
30+
logger.Info("msg") // want `methods without a context should not be used`
31+
logger.Warn("msg") // want `methods without a context should not be used`
32+
logger.Error("msg") // want `methods without a context should not be used`
33+
}

0 commit comments

Comments
 (0)