Skip to content

Commit 561c949

Browse files
authored
change: replace log with log/slog for logging (#1280)
* change: replace log with log/slog for logging * add TODO about slog.DiscardHandler
1 parent 88e5689 commit 561c949

File tree

4 files changed

+90
-23
lines changed

4 files changed

+90
-23
lines changed

DEVELOPING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ make build
1919

2020
The command will produce the `revive` binary in the root of the project.
2121

22+
## Debug
23+
24+
To enable debug logging, set the `DEBUG` environment variable:
25+
26+
```sh
27+
DEBUG=1 go run main.go
28+
```
29+
30+
This will output debug information to `stderr` and to the log file `revive.log` created in the current working directory.
31+
2232
## Development of rules
2333

2434
If you want to develop a new rule, follow as an example the already existing rules in the [rule package](https://github.com/mgechev/revive/tree/master/rule).

logging/logger.go

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,35 @@ package logging
33

44
import (
55
"io"
6-
"log"
6+
"log/slog"
77
"os"
88
)
99

10-
var logger *log.Logger
10+
const logFile = "revive.log"
11+
12+
var logger *slog.Logger
1113

1214
// GetLogger retrieves an instance of an application logger which outputs
1315
// to a file if the debug flag is enabled
14-
func GetLogger() (*log.Logger, error) {
16+
func GetLogger() (*slog.Logger, error) {
1517
if logger != nil {
1618
return logger, nil
1719
}
1820

19-
var writer io.Writer
20-
var err error
21-
22-
writer = io.Discard // by default, suppress all logging output
23-
debugModeEnabled := os.Getenv("DEBUG") == "1"
24-
if debugModeEnabled {
25-
writer, err = os.Create("revive.log")
26-
if err != nil {
27-
return nil, err
28-
}
21+
debugModeEnabled := os.Getenv("DEBUG") != ""
22+
if !debugModeEnabled {
23+
// by default, suppress all logging output
24+
return slog.New(slog.NewTextHandler(io.Discard, nil)), nil // TODO: change to slog.New(slog.DiscardHandler) when we switch to Go 1.24
2925
}
3026

31-
logger = log.New(writer, "", log.LstdFlags)
32-
33-
if !debugModeEnabled {
34-
// Clear all flags to skip log output formatting step to increase
35-
// performance somewhat if we're not logging anything
36-
logger.SetFlags(0)
27+
fileWriter, err := os.Create(logFile)
28+
if err != nil {
29+
return nil, err
3730
}
3831

39-
logger.Println("Logger initialized")
32+
logger = slog.New(slog.NewTextHandler(io.MultiWriter(os.Stderr, fileWriter), nil))
33+
34+
logger.Info("Logger initialized", "logFile", logFile)
4035

4136
return logger, nil
4237
}

logging/logger_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package logging_test
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/mgechev/revive/logging"
8+
)
9+
10+
func TestGetLogger(t *testing.T) {
11+
t.Run("no debug", func(t *testing.T) {
12+
t.Setenv("DEBUG", "")
13+
14+
logger, err := logging.GetLogger()
15+
16+
if err != nil {
17+
t.Fatalf("expected no error, got %v", err)
18+
}
19+
if logger == nil {
20+
t.Fatal("expected logger to be non-nil")
21+
}
22+
logger.Info("msg") // no output
23+
})
24+
25+
t.Run("debug", func(t *testing.T) {
26+
t.Setenv("DEBUG", "1")
27+
t.Cleanup(func() { os.Remove("revive.log") })
28+
29+
logger, err := logging.GetLogger()
30+
31+
if err != nil {
32+
t.Fatalf("expected no error, got %v", err)
33+
}
34+
if logger == nil {
35+
t.Fatal("expected logger to be non-nil")
36+
}
37+
if _, err := os.Stat("revive.log"); os.IsNotExist(err) {
38+
t.Error("expected revive.log file to be created")
39+
}
40+
})
41+
42+
t.Run("reuse logger", func(t *testing.T) {
43+
t.Setenv("DEBUG", "1")
44+
t.Cleanup(func() { os.Remove("revive.log") })
45+
46+
logger1, err := logging.GetLogger()
47+
if err != nil {
48+
t.Fatalf("expected no error, got %v", err)
49+
}
50+
51+
logger2, err := logging.GetLogger()
52+
if err != nil {
53+
t.Fatalf("expected no error, got %v", err)
54+
}
55+
56+
if logger1 != logger2 {
57+
t.Errorf("expected the same logger instance to be returned: logger1=%+v, logger2=%+v", logger1, logger2)
58+
}
59+
})
60+
}

revivelib/core.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package revivelib
33

44
import (
55
"fmt"
6-
"log"
6+
"log/slog"
7+
"maps"
78
"os"
9+
"slices"
810
"strings"
911

1012
"github.com/mgechev/dots"
@@ -18,7 +20,7 @@ import (
1820
type Revive struct {
1921
config *lint.Config
2022
lintingRules []lint.Rule
21-
logger *log.Logger
23+
logger *slog.Logger
2224
maxOpenFiles int
2325
}
2426

@@ -56,7 +58,7 @@ func New(
5658
return nil, fmt.Errorf("initializing revive - getting lint rules: %w", err)
5759
}
5860

59-
logger.Println("Config loaded")
61+
logger.Info("Config loaded", "rules", slices.Collect(maps.Keys(conf.Rules)))
6062

6163
return &Revive{
6264
logger: logger,

0 commit comments

Comments
 (0)