Skip to content

Commit 6845428

Browse files
Merge pull request #164 from sebastianrakel/better-logging
Switch to slog to improve logging
2 parents 2fec514 + 13da20f commit 6845428

7 files changed

Lines changed: 108 additions & 28 deletions

File tree

CONFIGURATION.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ but you can pass the -config parameter to define the location of the config file
3131
| puppetca.readonly | PUPPETCA_READONLY | true | bool | Whether to allow signing / revoking / cleaning certs |
3232
| puppetca.deactivate_nodes | PUPPETCA_DEACTIVATE_NODES | false | bool | Also deactivate node in PuppetDB with revoke / clean |
3333
| ui_default_refresh_interval_in_seconds | UI_DEFAULT_REFRESH_INTERVAL_IN_SECONDS | 300 | int | Default Refresh Interval in the UI (shouldn't be to small, to prevent DDoSing the openvoxdb) |
34+
| log_level | LOG_LEVEL | info | string | Log Level (info,debug,warn,error) |
35+
| log_format | LOG_FORMAT | text | string | Log Format (text,json) |
36+
3437

3538

3639

config/config.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,26 @@ package config
33
import (
44
"flag"
55
"fmt"
6-
"log"
6+
"log/slog"
7+
"os"
78
"sync"
89

910
"github.com/sebastianrakel/openvoxview/model"
1011
"github.com/spf13/viper"
1112
)
1213

14+
type LogLevel string
15+
type LogFormat string
16+
17+
const (
18+
LOG_LEVEL_INFO LogLevel = "info"
19+
LOG_LEVEL_WARN LogLevel = "warn"
20+
LOG_LEVEL_ERROR LogLevel = "error"
21+
LOG_LEVEL_DEBUG LogLevel = "debug"
22+
LOG_FORMAT_JSON LogFormat = "json"
23+
LOG_FOMRAT_TEXT LogFormat = "text"
24+
)
25+
1326
var configPath = flag.String("config", "", "path to the config file")
1427
var printVersion = flag.Bool("version", false, "prints version")
1528

@@ -51,6 +64,8 @@ type Config struct {
5164
ReadOnly bool `mapstructure:"readonly"`
5265
DeactivateNodes bool `mapstructure:"deactivate_nodes"`
5366
} `mapstructure:"puppetca"`
67+
LogLevel LogLevel `mapstructure:"log_level"`
68+
LogFormat LogFormat `mapstructure:"log_format"`
5469
}
5570

5671
func PrintVersion(version string) bool {
@@ -74,7 +89,7 @@ func GetConfig() (*Config, error) {
7489
viper.AddConfigPath(".")
7590

7691
if *configPath != "" {
77-
log.Printf("Using config: %s", *configPath)
92+
slog.Info("Using config", "path", *configPath)
7893
viper.SetConfigFile(*configPath)
7994
}
8095

@@ -90,6 +105,8 @@ func GetConfig() (*Config, error) {
90105
viper.SetDefault("puppetca.readonly", true)
91106
viper.SetDefault("puppetca.deactivate_nodes", false)
92107
viper.SetDefault("ui_default_refresh_interval_in_seconds", 300)
108+
viper.SetDefault("log_level", "info")
109+
viper.SetDefault("log_format", "text")
93110

94111
viper.AutomaticEnv()
95112

@@ -115,6 +132,8 @@ func GetConfig() (*Config, error) {
115132
viper.BindEnv("puppetca.readonly", "PUPPETCA_READONLY")
116133
viper.BindEnv("puppetca.deactivate_nodes", "PUPPETCA_DEACTIVATE_NODES")
117134
viper.BindEnv("ui_default_refresh_interval_in_seconds", "UI_DEFAULT_REFRESH_INTERVAL_IN_SECONDS")
135+
viper.BindEnv("log_level", "LOG_LEVEL")
136+
viper.BindEnv("log_level", "LOG_FORMAT")
118137

119138
viper.ReadInConfig()
120139

@@ -144,3 +163,31 @@ func (c *Config) GetPuppetCAAddress() string {
144163

145164
return fmt.Sprintf("%s://%s:%d", scheme, c.PuppetCA.Host, c.PuppetCA.Port)
146165
}
166+
167+
func (c *Config) GetLogLevel() slog.Level {
168+
switch c.LogLevel {
169+
case LOG_LEVEL_DEBUG:
170+
return slog.LevelDebug
171+
case LOG_LEVEL_WARN:
172+
return slog.LevelWarn
173+
case LOG_LEVEL_ERROR:
174+
return slog.LevelError
175+
default:
176+
return slog.LevelInfo
177+
}
178+
}
179+
180+
func (c *Config) GetLogger() *slog.Logger {
181+
level := c.GetLogLevel()
182+
switch c.LogFormat {
183+
case LOG_FORMAT_JSON:
184+
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
185+
Level: level,
186+
}))
187+
default:
188+
return slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
189+
Level: level,
190+
}))
191+
}
192+
193+
}

handler/ca.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package handler
22

33
import (
4-
"log"
4+
"log/slog"
55
"net/http"
66
"slices"
77
"strings"
@@ -88,12 +88,12 @@ func (h *CaHandler) QueryCertificateStatuses(c *gin.Context) {
8888
func (h *CaHandler) SignCertificate(c *gin.Context) {
8989
name := c.Param("name")
9090

91-
log.Printf("[AUDIT] CA Signing: %s", name)
91+
slog.Info("ca signing", "certname", name)
9292

9393
err := h.caClient.SignCertificate(name)
9494

9595
if err != nil {
96-
log.Printf("Error signing certificate: %s", err)
96+
slog.Error("error signing certificate", "error", err)
9797
c.AbortWithStatusJSON(http.StatusInternalServerError, NewErrorResponse(err))
9898
return
9999
}
@@ -104,12 +104,12 @@ func (h *CaHandler) SignCertificate(c *gin.Context) {
104104
func (h *CaHandler) RevokeCertificate(c *gin.Context) {
105105
name := c.Param("name")
106106

107-
log.Printf("[AUDIT] CA Revoking: %s", name)
107+
slog.Info("ca revoking", "certname", name)
108108

109109
err := h.caClient.RevokeCertificate(name)
110110

111111
if err != nil {
112-
log.Printf("Error revoking certificate: %s", err)
112+
slog.Error("error revoking certificate", "error", err)
113113
c.AbortWithStatusJSON(http.StatusInternalServerError, NewErrorResponse(err))
114114
return
115115
}
@@ -126,12 +126,12 @@ func (h *CaHandler) RevokeCertificate(c *gin.Context) {
126126
func (h *CaHandler) CleanCertificate(c *gin.Context) {
127127
name := c.Param("name")
128128

129-
log.Printf("[AUDIT] CA Cleaning: %s", name)
129+
slog.Info("ca cleaning", "certname", name)
130130

131131
err := h.caClient.CleanCertificate(name)
132132

133133
if err != nil {
134-
log.Printf("Error cleaning certificate: %s", err)
134+
slog.Error("error cleaning certificate", "error", err)
135135
c.AbortWithStatusJSON(http.StatusInternalServerError, NewErrorResponse(err))
136136
return
137137
}
@@ -150,15 +150,15 @@ func (h *CaHandler) deactivateNode(certname string) error {
150150
return nil
151151
}
152152

153-
log.Printf("[AUDIT] Deactivating node: %s", certname)
153+
slog.Info("ca deactivating node", "certname", certname)
154154

155155
pdb := puppetdb.NewClient()
156156
resp, err := pdb.DeactivateNode(certname)
157157

158158
if err != nil {
159-
log.Printf("Error deactivating node: %s", err)
159+
slog.Error("error deactivating certificate", "error", err)
160160
} else {
161-
log.Printf("Deactivated node %s with command UUID: %s", certname, resp.Uuid)
161+
slog.Info("deactivated node", "certname", certname, "uuid", resp.Uuid)
162162
}
163163

164164
return err

handler/pdb.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package handler
22

33
import (
44
"encoding/json"
5-
"log"
5+
"log/slog"
66
"net/http"
77
"time"
88

@@ -47,7 +47,7 @@ func (h *PdbHandler) PdbExecuteQuery(c *gin.Context) {
4747
c.BindJSON(&queryRequest)
4848

4949
dbClient := puppetdb.NewClient()
50-
log.Printf("Executing Query: %s", queryRequest.Query)
50+
slog.Debug("executing query", "query", queryRequest.Query)
5151

5252
historyEntry := PqlHistoryEntry{
5353
Query: queryRequest,

main.go

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package main
33
import (
44
"fmt"
55
"io/fs"
6-
"log"
6+
"log/slog"
77
"net/http"
88
"strings"
9+
"time"
910

1011
"github.com/gin-gonic/gin"
1112
"github.com/sebastianrakel/openvoxview/config"
@@ -21,18 +22,22 @@ func main() {
2122
if config.PrintVersion(VERSION) {
2223
return
2324
}
24-
log.Printf("OpenVox View - %s (%s)", VERSION, COMMIT)
2525
cfg, err := config.GetConfig()
2626
if err != nil {
2727
panic(err)
2828
}
2929

30-
log.Printf("LISTEN: %s", cfg.Listen)
31-
log.Printf("PORT: %d", cfg.Port)
32-
log.Printf("PUPPETDB_ADDRESS: %s", cfg.GetPuppetDbAddress())
33-
log.Printf("TRUSTED_PROXIES: %#v", cfg.TrustedProxies)
30+
logger := cfg.GetLogger()
31+
slog.SetDefault(logger)
3432

35-
r := gin.Default()
33+
slog.Info(fmt.Sprintf("OpenVox View - %s (%s)", VERSION, COMMIT))
34+
slog.Info(fmt.Sprintf("LISTEN: %s", cfg.Listen))
35+
slog.Info(fmt.Sprintf("PORT: %d", cfg.Port))
36+
slog.Info(fmt.Sprintf("PUPPETDB_ADDRESS: %s", cfg.GetPuppetDbAddress()))
37+
slog.Info(fmt.Sprintf("TRUSTED_PROXIES: %s", cfg.TrustedProxies))
38+
39+
r := gin.New()
40+
r.Use(SlogMiddleware(logger))
3641

3742
r.NoRoute(func(c *gin.Context) {
3843
if strings.HasPrefix(c.Request.URL.Path, "/api/") {
@@ -45,7 +50,6 @@ func main() {
4550

4651
uiFSSub, _ := fs.Sub(uiFS, "ui/dist/spa")
4752
r.StaticFS("ui", http.FS(uiFSSub))
48-
4953
r.Use(AllowCORS)
5054

5155
if len(cfg.TrustedProxies) > 0 {
@@ -135,3 +139,29 @@ func AllowCORS(c *gin.Context) {
135139

136140
c.Next()
137141
}
142+
143+
func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc {
144+
return func(c *gin.Context) {
145+
start := time.Now()
146+
path := c.Request.URL.Path
147+
query := c.Request.URL.RawQuery
148+
149+
c.Next()
150+
151+
logger.Info("request",
152+
slog.String("method", c.Request.Method),
153+
slog.String("path", path),
154+
slog.String("query", query),
155+
slog.Int("status", c.Writer.Status()),
156+
slog.Duration("latency", time.Since(start)),
157+
slog.String("client_ip", c.ClientIP()),
158+
slog.Int("body_size", c.Writer.Size()),
159+
)
160+
161+
if len(c.Errors) > 0 {
162+
for _, err := range c.Errors {
163+
logger.Error("request error", slog.String("error", err.Error()))
164+
}
165+
}
166+
}
167+
}

puppetca/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/json"
88
"fmt"
99
"io"
10+
"log/slog"
1011
"net/http"
1112
"net/url"
1213
"os"
@@ -39,12 +40,11 @@ func (c *Client) call(httpMethod string, endpoint string, payload any, query url
3940
if payload != nil {
4041
data, err = json.Marshal(&payload)
4142
if err != nil {
42-
fmt.Printf("err: %s", err)
43+
slog.Error("error marshal payload", "error", err)
4344
}
44-
fmt.Printf("Payload:\n%s\n", data)
4545
}
4646

47-
fmt.Printf("HTTP: %#v: %#v\n", httpMethod, uri)
47+
slog.Debug("puppet ca call", "method", httpMethod, "url", uri)
4848

4949
if c.transport == nil {
5050
var tlsConfig *tls.Config

puppetdb/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"io"
11+
"log/slog"
1112
"net/http"
1213
"net/url"
1314
"os"
@@ -47,12 +48,11 @@ func (c *client) call(httpMethod string, endpoint string, payload any, query url
4748
if payload != nil {
4849
data, err = json.Marshal(&payload)
4950
if err != nil {
50-
fmt.Printf("err: %s", err)
51+
slog.Error("error marshal payload", "error", err)
5152
}
52-
fmt.Printf("Payload:\n%s\n", data)
5353
}
5454

55-
fmt.Printf("HTTP: %#v: %#v\n", httpMethod, uri)
55+
slog.Debug("puppet db call", "method", httpMethod, "url", uri)
5656

5757
var tlsConfig *tls.Config
5858

0 commit comments

Comments
 (0)