Skip to content

Commit 53bd413

Browse files
feat: configurable component-level logging (#575)
* Refactor logging to use centralized logger utility - Removed direct usage of zerolog in multiple files and replaced it with a centralized logging utility in the `utils` package. - Introduced `Loggers` struct to manage different loggers (Audit, HTTP, App) with configurable levels and outputs. - Updated all relevant files to utilize the new logging structure, ensuring consistent logging practices across the application. - Enhanced error handling and logging messages for better traceability and debugging. * refactor: update logging implementation to use new logger structure * Refactor logging to use tlog package - Replaced instances of utils logging with tlog in various controllers, services, and middleware. - Introduced audit logging for login success, login failure, and logout events. - Created tlog package with structured logging capabilities using zerolog. - Added tests for the new tlog logger functionality. * refactor: update logging configuration in environment files * fix: adding coderabbit suggestions * fix: ensure correct audit caller * fix: include reason in audit login failure logs
1 parent ba2d732 commit 53bd413

28 files changed

Lines changed: 486 additions & 214 deletions

.env.example

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
# The base URL where Tinyauth is accessible
44
TINYAUTH_APPURL="https://auth.example.com"
5-
# Log level: trace, debug, info, warn, error
6-
TINYAUTH_LOGLEVEL="info"
75
# Directory for static resources
86
TINYAUTH_RESOURCESDIR="/data/resources"
97
# Path to SQLite database file
@@ -14,8 +12,21 @@ TINYAUTH_DISABLEANALYTICS="false"
1412
TINYAUTH_DISABLERESOURCES="false"
1513
# Disable UI warning messages
1614
TINYAUTH_DISABLEUIWARNINGS="false"
15+
16+
# Logging Configuration
17+
18+
# Log level: trace, debug, info, warn, error
19+
TINYAUTH_LOG_LEVEL="info"
1720
# Enable JSON formatted logs
18-
TINYAUTH_LOGJSON="false"
21+
TINYAUTH_LOG_JSON="false"
22+
# Specific Log stream configurations
23+
# APP and HTTP log streams are enabled by default, and use the global log level unless overridden
24+
TINYAUTH_LOG_STREAMS_APP_ENABLED="true"
25+
TINYAUTH_LOG_STREAMS_APP_LEVEL="info"
26+
TINYAUTH_LOG_STREAMS_HTTP_ENABLED="true"
27+
TINYAUTH_LOG_STREAMS_HTTP_LEVEL="info"
28+
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED="false"
29+
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL="info"
1930

2031
# Server Configuration
2132

cmd/tinyauth/create.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@ package main
33
import (
44
"errors"
55
"fmt"
6-
"os"
76
"strings"
8-
"time"
97

108
"github.com/charmbracelet/huh"
11-
"github.com/rs/zerolog"
12-
"github.com/rs/zerolog/log"
9+
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
1310
"github.com/traefik/paerser/cli"
1411
"golang.org/x/crypto/bcrypt"
1512
)
@@ -43,7 +40,7 @@ func createUserCmd() *cli.Command {
4340
Configuration: tCfg,
4441
Resources: loaders,
4542
Run: func(_ []string) error {
46-
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
43+
tlog.NewSimpleLogger().Init()
4744

4845
if tCfg.Interactive {
4946
form := huh.NewForm(
@@ -77,7 +74,7 @@ func createUserCmd() *cli.Command {
7774
return errors.New("username and password cannot be empty")
7875
}
7976

80-
log.Info().Str("username", tCfg.Username).Msg("Creating user")
77+
tlog.App.Info().Str("username", tCfg.Username).Msg("Creating user")
8178

8279
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
8380
if err != nil {
@@ -90,7 +87,7 @@ func createUserCmd() *cli.Command {
9087
passwdStr = strings.ReplaceAll(passwdStr, "$", "$$")
9188
}
9289

93-
log.Info().Str("user", fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)).Msg("User created")
90+
tlog.App.Info().Str("user", fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)).Msg("User created")
9491

9592
return nil
9693
},

cmd/tinyauth/generate.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ import (
55
"fmt"
66
"os"
77
"strings"
8-
"time"
98

109
"github.com/steveiliop56/tinyauth/internal/utils"
10+
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
1111

1212
"github.com/charmbracelet/huh"
1313
"github.com/mdp/qrterminal/v3"
1414
"github.com/pquerna/otp/totp"
15-
"github.com/rs/zerolog"
16-
"github.com/rs/zerolog/log"
1715
"github.com/traefik/paerser/cli"
1816
)
1917

@@ -42,7 +40,7 @@ func generateTotpCmd() *cli.Command {
4240
Configuration: tCfg,
4341
Resources: loaders,
4442
Run: func(_ []string) error {
45-
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
43+
tlog.NewSimpleLogger().Init()
4644

4745
if tCfg.Interactive {
4846
form := huh.NewForm(
@@ -91,9 +89,9 @@ func generateTotpCmd() *cli.Command {
9189

9290
secret := key.Secret()
9391

94-
log.Info().Str("secret", secret).Msg("Generated TOTP secret")
92+
tlog.App.Info().Str("secret", secret).Msg("Generated TOTP secret")
9593

96-
log.Info().Msg("Generated QR code")
94+
tlog.App.Info().Msg("Generated QR code")
9795

9896
config := qrterminal.Config{
9997
Level: qrterminal.L,
@@ -112,7 +110,7 @@ func generateTotpCmd() *cli.Command {
112110
user.Password = strings.ReplaceAll(user.Password, "$", "$$")
113111
}
114112

115-
log.Info().Str("user", fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TotpSecret)).Msg("Add the totp secret to your authenticator app then use the verify command to ensure everything is working correctly.")
113+
tlog.App.Info().Str("user", fmt.Sprintf("%s:%s:%s", user.Username, user.Password, user.TotpSecret)).Msg("Add the totp secret to your authenticator app then use the verify command to ensure everything is working correctly.")
116114

117115
return nil
118116
},

cmd/tinyauth/healthcheck.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import (
99
"os"
1010
"time"
1111

12-
"github.com/rs/zerolog"
13-
"github.com/rs/zerolog/log"
12+
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
1413
"github.com/traefik/paerser/cli"
1514
)
1615

@@ -27,7 +26,7 @@ func healthcheckCmd() *cli.Command {
2726
Resources: nil,
2827
AllowArg: true,
2928
Run: func(args []string) error {
30-
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
29+
tlog.NewSimpleLogger().Init()
3130

3231
appUrl := os.Getenv("TINYAUTH_APPURL")
3332

@@ -39,7 +38,7 @@ func healthcheckCmd() *cli.Command {
3938
return errors.New("TINYAUTH_APPURL is not set and no argument was provided")
4039
}
4140

42-
log.Info().Str("app_url", appUrl).Msg("Performing health check")
41+
tlog.App.Info().Str("app_url", appUrl).Msg("Performing health check")
4342

4443
client := http.Client{
4544
Timeout: 30 * time.Second,
@@ -77,7 +76,7 @@ func healthcheckCmd() *cli.Command {
7776
return fmt.Errorf("failed to decode response: %w", err)
7877
}
7978

80-
log.Info().Interface("response", healthResp).Msg("Tinyauth is healthy")
79+
tlog.App.Info().Interface("response", healthResp).Msg("Tinyauth is healthy")
8180

8281
return nil
8382
},

cmd/tinyauth/tinyauth.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,18 @@ package main
22

33
import (
44
"fmt"
5-
"os"
6-
"strings"
7-
"time"
85

96
"github.com/steveiliop56/tinyauth/internal/bootstrap"
107
"github.com/steveiliop56/tinyauth/internal/config"
118
"github.com/steveiliop56/tinyauth/internal/utils/loaders"
9+
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
1210

13-
"github.com/rs/zerolog"
1411
"github.com/rs/zerolog/log"
1512
"github.com/traefik/paerser/cli"
1613
)
1714

1815
func NewTinyauthCmdConfiguration() *config.Config {
1916
return &config.Config{
20-
LogLevel: "info",
2117
ResourcesDir: "./resources",
2218
DatabasePath: "./tinyauth.db",
2319
Server: config.ServerConfig{
@@ -39,6 +35,24 @@ func NewTinyauthCmdConfiguration() *config.Config {
3935
Insecure: false,
4036
SearchFilter: "(uid=%s)",
4137
},
38+
Log: config.LogConfig{
39+
Level: "info",
40+
Json: false,
41+
Streams: config.LogStreams{
42+
HTTP: config.LogStreamConfig{
43+
Enabled: true,
44+
Level: "",
45+
},
46+
App: config.LogStreamConfig{
47+
Enabled: true,
48+
Level: "",
49+
},
50+
Audit: config.LogStreamConfig{
51+
Enabled: false,
52+
Level: "",
53+
},
54+
},
55+
},
4256
Experimental: config.ExperimentalConfig{
4357
ConfigFile: "",
4458
},
@@ -102,25 +116,14 @@ func main() {
102116
}
103117

104118
func runCmd(cfg config.Config) error {
105-
logLevel, err := zerolog.ParseLevel(strings.ToLower(cfg.LogLevel))
106-
107-
if err != nil {
108-
log.Error().Err(err).Msg("Invalid or missing log level, defaulting to info")
109-
} else {
110-
zerolog.SetGlobalLevel(logLevel)
111-
}
112-
113-
log.Logger = log.With().Caller().Logger()
114-
115-
if !cfg.LogJSON {
116-
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
117-
}
119+
logger := tlog.NewLogger(cfg.Log)
120+
logger.Init()
118121

119-
log.Info().Str("version", config.Version).Msg("Starting tinyauth")
122+
tlog.App.Info().Str("version", config.Version).Msg("Starting tinyauth")
120123

121124
app := bootstrap.NewBootstrapApp(cfg)
122125

123-
err = app.Setup()
126+
err := app.Setup()
124127

125128
if err != nil {
126129
return fmt.Errorf("failed to bootstrap app: %w", err)

cmd/tinyauth/verify.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ package main
33
import (
44
"errors"
55
"fmt"
6-
"os"
7-
"time"
86

97
"github.com/steveiliop56/tinyauth/internal/utils"
8+
"github.com/steveiliop56/tinyauth/internal/utils/tlog"
109

1110
"github.com/charmbracelet/huh"
1211
"github.com/pquerna/otp/totp"
13-
"github.com/rs/zerolog"
14-
"github.com/rs/zerolog/log"
1512
"github.com/traefik/paerser/cli"
1613
"golang.org/x/crypto/bcrypt"
1714
)
@@ -47,7 +44,7 @@ func verifyUserCmd() *cli.Command {
4744
Configuration: tCfg,
4845
Resources: loaders,
4946
Run: func(_ []string) error {
50-
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Caller().Logger().Level(zerolog.InfoLevel)
47+
tlog.NewSimpleLogger().Init()
5148

5249
if tCfg.Interactive {
5350
form := huh.NewForm(
@@ -101,9 +98,9 @@ func verifyUserCmd() *cli.Command {
10198

10299
if user.TotpSecret == "" {
103100
if tCfg.Totp != "" {
104-
log.Warn().Msg("User does not have TOTP secret")
101+
tlog.App.Warn().Msg("User does not have TOTP secret")
105102
}
106-
log.Info().Msg("User verified")
103+
tlog.App.Info().Msg("User verified")
107104
return nil
108105
}
109106

@@ -113,7 +110,7 @@ func verifyUserCmd() *cli.Command {
113110
return fmt.Errorf("TOTP code incorrect")
114111
}
115112

116-
log.Info().Msg("User verified")
113+
tlog.App.Info().Msg("User verified")
117114

118115
return nil
119116
},

config.example.yaml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
# The base URL where Tinyauth is accessible
44
appUrl: "https://auth.example.com"
5-
# Log level: trace, debug, info, warn, error
6-
logLevel: "info"
75
# Directory for static resources
86
resourcesDir: "./resources"
97
# Path to SQLite database file
@@ -14,8 +12,22 @@ disableAnalytics: false
1412
disableResources: false
1513
# Disable UI warning messages
1614
disableUIWarnings: false
17-
# Enable JSON formatted logs
18-
logJSON: false
15+
16+
# Logging Configuration
17+
log:
18+
# Log level: trace, debug, info, warn, error
19+
level: "info"
20+
json: false
21+
streams:
22+
app:
23+
enabled: true
24+
level: "warn"
25+
http:
26+
enabled: true
27+
level: "debug"
28+
audit:
29+
enabled: false
30+
level: "info"
1931

2032
# Server Configuration
2133
server:

0 commit comments

Comments
 (0)