Skip to content

Commit 0bccd85

Browse files
authored
Logging and Refactoring (#143)
* refactor logging to use zap * refactor to encapsulate secretslack as a service
1 parent cbe5cdc commit 0bccd85

18 files changed

+189
-114
lines changed

.devcontainer/.env.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
1212
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-us-central-0.grafana.net/otlp"
1313
export OTEL_EXPORTER_OTLP_HEADERS="{{ .secrets.OTEL_EXPORTER_OTLP_HEADERS }}"
1414
export SURVEY_LINK="https://secretmessage.xyz"
15+
export APP_ENV="development"

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ require (
3636
github.com/davecgh/go-spew v1.1.1 // indirect
3737
github.com/elastic/go-licenser v0.3.1 // indirect
3838
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
39+
github.com/gin-contrib/zap v1.1.5 // indirect
3940
github.com/go-logr/logr v1.4.2 // indirect
4041
github.com/go-logr/stdr v1.2.2 // indirect
4142
github.com/google/go-cmp v0.7.0 // indirect
@@ -49,6 +50,8 @@ require (
4950
go.opentelemetry.io/otel/metric v1.36.0 // indirect
5051
go.opentelemetry.io/otel/trace v1.36.0 // indirect
5152
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
53+
go.uber.org/multierr v1.11.0 // indirect
54+
go.uber.org/zap v1.27.0 // indirect
5255
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
5356
golang.org/x/mod v0.25.0 // indirect
5457
golang.org/x/sync v0.15.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFA
3838
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
3939
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
4040
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
41+
github.com/gin-contrib/zap v1.1.5 h1:qKwhWb4DQgPriCl1AHLLob6hav/KUIctKXIjTmWIN3I=
42+
github.com/gin-contrib/zap v1.1.5/go.mod h1:lAchUtGz9M2K6xDr1rwtczyDrThmSx6c9F384T45iOE=
4143
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
4244
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
4345
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
@@ -345,10 +347,14 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
345347
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
346348
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
347349
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
350+
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
351+
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
348352
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
349353
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
350354
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
351355
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
356+
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
357+
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
352358
golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU=
353359
golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
354360
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

main.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,17 @@ package main
33
import (
44
"context"
55
"fmt"
6-
"net/http"
7-
"time"
86

97
"strconv"
108

119
"os"
1210

11+
"github.com/gin-gonic/gin"
1312
"github.com/neufeldtech/secretmessage-go/pkg/secretmessage"
14-
"github.com/neufeldtech/secretmessage-go/pkg/secretslack"
15-
log "github.com/sirupsen/logrus"
1613
_ "go.elastic.co/apm/module/apmgormv2"
1714
postgres "go.elastic.co/apm/module/apmgormv2/driver/postgres"
15+
"go.uber.org/zap"
1816

19-
"go.elastic.co/apm/module/apmhttp"
2017
"golang.org/x/oauth2"
2118
"gorm.io/gorm"
2219
)
@@ -56,24 +53,31 @@ func resolvePort() int64 {
5653
}
5754

5855
func main() {
56+
57+
var logger *zap.Logger
58+
switch {
59+
case os.Getenv("APP_ENV") == "development":
60+
logger = zap.Must(zap.NewDevelopment())
61+
gin.SetMode(gin.DebugMode)
62+
default:
63+
gin.SetMode(gin.ReleaseMode)
64+
logger = zap.Must(zap.NewProduction())
65+
}
66+
5967
tp, err := secretmessage.InitTracer(secretmessage.ServiceName)
6068
if err != nil {
61-
log.Fatal(err)
69+
logger.Fatal(err.Error())
6270
}
6371
defer func() {
72+
logger.Sync()
6473
if err := tp.Shutdown(context.Background()); err != nil {
65-
log.Printf("Error shutting down tracer provider: %v", err)
74+
logger.Error("error shutting down trace provider", zap.Error(err))
6675
}
6776
}()
68-
// Setup custom HTTP Client for calling Slack
69-
secretslack.SetHTTPClient(apmhttp.WrapClient(
70-
&http.Client{
71-
Timeout: time.Second * 5,
72-
},
73-
))
77+
7478
for k, v := range configMap {
7579
if v == "" {
76-
log.Fatalf("error initializaing config. key %v was not set", k)
80+
logger.Fatal("error initializing config", zap.String("key", k), zap.String("value", v))
7781
}
7882
}
7983

@@ -98,7 +102,7 @@ func main() {
98102

99103
db, err := gorm.Open(postgres.Open(conf.DatabaseURL), &gorm.Config{})
100104
if err != nil {
101-
log.Fatal(err)
105+
logger.Fatal("error connecting to database", zap.Error(err))
102106
}
103107
d, _ := db.DB()
104108
d.SetMaxIdleConns(10)
@@ -110,10 +114,12 @@ func main() {
110114
controller := secretmessage.NewController(
111115
conf,
112116
db,
117+
logger,
113118
)
114119

115-
go secretmessage.StayAwake(conf)
120+
go controller.StayAwake()
116121
r := controller.ConfigureRoutes()
117-
log.Infof("Booted and listening on port %v", conf.Port)
122+
logger.Sugar().Infof("Booted and listening on port %v", conf.Port)
123+
118124
r.Run(fmt.Sprintf("0.0.0.0:%v", conf.Port))
119125
}

pkg/secretmessage/config.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ import (
44
"golang.org/x/oauth2"
55
)
66

7-
var (
8-
config Config
9-
)
10-
117
type Config struct {
128
SkipSignatureValidation bool
139
Port int64

pkg/secretmessage/controller.go

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,82 @@
11
package secretmessage
22

33
import (
4+
"net/http"
45
"os"
6+
"time"
57

8+
ginzap "github.com/gin-contrib/zap"
69
"github.com/gin-gonic/gin"
10+
"github.com/neufeldtech/secretmessage-go/pkg/secretslack"
711
"go.elastic.co/apm/module/apmgin"
12+
"go.elastic.co/apm/module/apmhttp"
813
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
14+
"go.uber.org/zap"
915
"gorm.io/gorm"
1016
)
1117

1218
type PublicController struct {
13-
db *gorm.DB
14-
config Config
19+
db *gorm.DB
20+
config Config
21+
logger *zap.Logger
22+
slackService *secretslack.SlackService
1523
}
1624

17-
func NewController(config Config, db *gorm.DB) *PublicController {
25+
func NewController(config Config, db *gorm.DB, logger *zap.Logger) *PublicController {
26+
if logger == nil {
27+
logger = zap.Must(zap.NewProduction())
28+
}
29+
30+
slackService := secretslack.NewSlackService().
31+
WithHTTPClient(
32+
apmhttp.WrapClient(
33+
&http.Client{
34+
Timeout: 5 * time.Second},
35+
)).
36+
WithLogger(logger)
37+
1838
return &PublicController{
19-
db: db,
20-
config: config,
39+
db: db,
40+
config: config,
41+
logger: logger,
42+
slackService: slackService,
2143
}
2244
}
2345

2446
func (ctl *PublicController) ConfigureRoutes() *gin.Engine {
2547

26-
r := gin.Default()
48+
r := gin.New()
49+
r.Use(ginzap.Ginzap(ctl.logger, time.RFC3339, true))
50+
r.Use(ginzap.RecoveryWithZap(ctl.logger, true))
51+
2752
r.Use(otelgin.Middleware(os.Getenv("HOSTNAME")))
2853
r.Use(apmgin.Middleware(r))
29-
54+
r.Use(func(c *gin.Context) {
55+
c.Next()
56+
db, err := ctl.db.DB()
57+
if err == nil {
58+
stats := db.Stats()
59+
ctl.logger.Info("DB Stats",
60+
zap.Int("OpenConnections", stats.OpenConnections),
61+
zap.Int("InUse", stats.InUse),
62+
zap.Int("Idle", stats.Idle),
63+
zap.Int64("WaitCount", stats.WaitCount),
64+
zap.Duration("WaitDuration", stats.WaitDuration),
65+
zap.Int("MaxOpenConnections", stats.MaxOpenConnections),
66+
zap.Int64("MaxIdleClosed", stats.MaxIdleClosed),
67+
zap.Int64("MaxIdleTimeClosed", stats.MaxIdleTimeClosed),
68+
zap.Int64("MaxLifetimeClosed", stats.MaxLifetimeClosed),
69+
)
70+
}
71+
})
3072
r.GET("/health", ctl.HandleHealth)
3173

3274
r.GET("/auth/slack", ctl.HandleOauthBegin)
3375
r.GET("/auth/slack/callback", ctl.HandleOauthCallback)
3476

3577
// Signature validation required
36-
r.POST("/slash", ValidateSignature(ctl.config), ctl.HandleSlash)
37-
r.POST("/interactive", ValidateSignature(ctl.config), ctl.HandleInteractive)
78+
r.POST("/slash", ctl.ValidateSignature(), ctl.HandleSlash)
79+
r.POST("/interactive", ctl.ValidateSignature(), ctl.HandleInteractive)
3880

3981
return r
4082
}

pkg/secretmessage/handle_health.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"os"
66

77
"github.com/gin-gonic/gin"
8-
log "github.com/sirupsen/logrus"
8+
"go.uber.org/zap"
99
)
1010

1111
func (ctl *PublicController) HandleHealth(c *gin.Context) {
@@ -15,14 +15,14 @@ func (ctl *PublicController) HandleHealth(c *gin.Context) {
1515
}
1616
db, err := ctl.db.DB()
1717
if err != nil {
18-
log.Error(err)
18+
ctl.logger.Error("error retrieving database connection", zap.Error(err))
1919
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"status": "DOWN", "sha": version})
2020
return
2121
}
2222

2323
err = db.PingContext(c.Request.Context())
2424
if err != nil {
25-
log.Error(err)
25+
ctl.logger.Error("error pinging database", zap.Error(err))
2626
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"status": "DOWN", "sha": version})
2727
return
2828
}

pkg/secretmessage/handle_interactive.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import (
77

88
"github.com/gin-gonic/gin"
99
"github.com/neufeldtech/secretmessage-go/pkg/secretmessage/actions"
10-
log "github.com/sirupsen/logrus"
1110
"github.com/slack-go/slack"
1211
"go.elastic.co/apm"
12+
"go.uber.org/zap"
1313
)
1414

1515
func (ctl *PublicController) HandleInteractive(c *gin.Context) {
@@ -19,7 +19,7 @@ func (ctl *PublicController) HandleInteractive(c *gin.Context) {
1919
payload := c.PostForm("payload")
2020
err = json.Unmarshal([]byte(payload), &i)
2121
if err != nil {
22-
log.Error(err)
22+
ctl.logger.Error("error parsing interaction payload", zap.Error(err), zap.String("payload", payload))
2323
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"status": "Error with the stuffs"})
2424
tx.Context.SetLabel("errorCode", "interaction_payload_parse_error")
2525
return
@@ -38,7 +38,7 @@ func (ctl *PublicController) HandleInteractive(c *gin.Context) {
3838
case actions.DeleteMessage:
3939
CallbackDeleteSecret(ctl, tx, c, i)
4040
default:
41-
log.Error("Hit the default case. bad things happened")
41+
ctl.logger.Error("unknown interaction type", zap.String("type", string(i.Type)), zap.String("callbackID", i.CallbackID))
4242
c.Data(http.StatusInternalServerError, gin.MIMEPlain, nil)
4343
}
4444
}

pkg/secretmessage/handle_interactive_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var _ = Describe("/interactive", func() {
5454
ctl = secretmessage.NewController(
5555
secretmessage.Config{SkipSignatureValidation: true},
5656
gdb,
57+
nil,
5758
)
5859
})
5960
JustBeforeEach(func() {
@@ -157,6 +158,7 @@ var _ = Describe("/interactive", func() {
157158
ctl = secretmessage.NewController(
158159
secretmessage.Config{SkipSignatureValidation: true},
159160
gdb,
161+
nil,
160162
)
161163
})
162164
JustBeforeEach(func() {
@@ -227,6 +229,7 @@ var _ = Describe("/interactive", func() {
227229
ctl = secretmessage.NewController(
228230
secretmessage.Config{SkipSignatureValidation: true},
229231
gdb,
232+
nil,
230233
)
231234

232235
})

0 commit comments

Comments
 (0)