Skip to content

Commit c984a46

Browse files
authored
refactor(tx-submit-api): Switched logging part to go slog and removed zap part (#397)
Signed-off-by: Akhil Repala <[email protected]> Signed-off-by: Akhil <[email protected]>
1 parent 306d1e3 commit c984a46

File tree

6 files changed

+141
-87
lines changed

6 files changed

+141
-87
lines changed

cmd/tx-submit-api/main.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var cmdlineFlags struct {
3434
}
3535

3636
func logPrintf(format string, v ...any) {
37-
logging.GetLogger().Infof(format, v...)
37+
logging.GetLogger().Info(fmt.Sprintf(format, v...))
3838
}
3939

4040
func main() {
@@ -56,31 +56,23 @@ func main() {
5656
// Configure logging
5757
logging.Setup(&cfg.Logging)
5858
logger := logging.GetLogger()
59-
// Sync logger on exit
60-
defer func() {
61-
if err := logger.Sync(); err != nil {
62-
// We don't actually care about the error here, but we have to do something
63-
// to appease the linter
64-
return
65-
}
66-
}()
6759

68-
logger.Infof("starting tx-submit-api %s", version.GetVersionString())
60+
logger.Info("starting tx-submit-api", "version", version.GetVersionString())
6961

7062
// Configure max processes with our logger wrapper, toss undo func
7163
_, err = maxprocs.Set(maxprocs.Logger(logPrintf))
7264
if err != nil {
7365
// If we hit this, something really wrong happened
74-
logger.Errorf(err.Error())
66+
logger.Error("maxprocs setup failed", "err", err)
7567
os.Exit(1)
7668
}
7769

7870
// Start debug listener
7971
if cfg.Debug.ListenPort > 0 {
80-
logger.Infof(
81-
"starting debug listener on %s:%d",
82-
cfg.Debug.ListenAddress,
83-
cfg.Debug.ListenPort,
72+
logger.Info(
73+
"starting debug listener",
74+
"address", cfg.Debug.ListenAddress,
75+
"port", cfg.Debug.ListenPort,
8476
)
8577
go func() {
8678
debugger := &http.Server{
@@ -93,14 +85,16 @@ func main() {
9385
}
9486
err := debugger.ListenAndServe()
9587
if err != nil {
96-
logger.Fatalf("failed to start debug listener: %s", err)
88+
logger.Error("failed to start debug listener", "err", err)
89+
os.Exit(1)
9790
}
9891
}()
9992
}
10093

10194
// Start API listener
10295
if err := api.Start(cfg); err != nil {
103-
logger.Fatalf("failed to start API: %s", err)
96+
logger.Error("failed to start API", "err", err)
97+
os.Exit(1)
10498
}
10599

106100
// Wait forever

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@ require (
88
github.com/blinklabs-io/gouroboros v0.141.0
99
github.com/fxamacker/cbor/v2 v2.9.0
1010
github.com/gin-contrib/cors v1.7.6
11-
github.com/gin-contrib/zap v1.1.6
1211
github.com/gin-gonic/gin v1.11.0
1312
github.com/kelseyhightower/envconfig v1.4.0
1413
github.com/penglongli/gin-metrics v0.1.13
1514
github.com/swaggo/files v1.0.1
1615
github.com/swaggo/gin-swagger v1.6.1
1716
github.com/swaggo/swag v1.16.6
1817
go.uber.org/automaxprocs v1.6.0
19-
go.uber.org/zap v1.27.1
2018
gopkg.in/yaml.v2 v2.4.0
2119
)
2220

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d
7878
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
7979
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
8080
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
81-
github.com/gin-contrib/zap v1.1.6 h1:TZcXi1UR8QG6OO4rewIMth7SmweyZuCeuUyJohpRcXg=
82-
github.com/gin-contrib/zap v1.1.6/go.mod h1:V/sSE4Rf6ptzsEW4vj1KpUUV8ptJSVdE1nqsX9HQ1II=
8381
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
8482
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
8583
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -233,8 +231,6 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
233231
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
234232
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
235233
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
236-
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
237-
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
238234
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
239235
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
240236
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

internal/api/api.go

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"io"
2222
"io/fs"
2323
"net/http"
24-
"time"
2524

2625
ouroboros "github.com/blinklabs-io/gouroboros"
2726
"github.com/blinklabs-io/gouroboros/protocol/localtxsubmission"
@@ -31,7 +30,6 @@ import (
3130
"github.com/blinklabs-io/tx-submit-api/submit"
3231
"github.com/fxamacker/cbor/v2"
3332
cors "github.com/gin-contrib/cors"
34-
ginzap "github.com/gin-contrib/zap"
3533
"github.com/gin-gonic/gin"
3634
"github.com/penglongli/gin-metrics/ginmetrics"
3735
swaggerFiles "github.com/swaggo/files" // swagger embed files
@@ -55,16 +53,16 @@ func Start(cfg *config.Config) error {
5553
// Standard logging
5654
logger := logging.GetLogger()
5755
if cfg.Tls.CertFilePath != "" && cfg.Tls.KeyFilePath != "" {
58-
logger.Infof(
59-
"starting API TLS listener on %s:%d",
60-
cfg.Api.ListenAddress,
61-
cfg.Api.ListenPort,
56+
logger.Info(
57+
"starting API TLS listener",
58+
"address", cfg.Api.ListenAddress,
59+
"port", cfg.Api.ListenPort,
6260
)
6361
} else {
64-
logger.Infof(
65-
"starting API listener on %s:%d",
66-
cfg.Api.ListenAddress,
67-
cfg.Api.ListenPort,
62+
logger.Info(
63+
"starting API listener",
64+
"address", cfg.Api.ListenAddress,
65+
"port", cfg.Api.ListenPort,
6866
)
6967
}
7068
// Disable gin debug and color output
@@ -90,14 +88,10 @@ func Start(cfg *config.Config) error {
9088
skipPaths := []string{}
9189
if cfg.Logging.Healthchecks {
9290
skipPaths = append(skipPaths, "/healthcheck")
93-
logger.Infof("disabling access logs for /healthcheck")
91+
logger.Info("disabling access logs for /healthcheck")
9492
}
95-
router.Use(ginzap.GinzapWithConfig(accessLogger, &ginzap.Config{
96-
TimeFormat: time.RFC3339,
97-
UTC: true,
98-
SkipPaths: skipPaths,
99-
}))
100-
router.Use(ginzap.RecoveryWithZap(accessLogger, true))
93+
router.Use(logging.GinLogger(accessLogger, skipPaths))
94+
router.Use(logging.GinRecovery(accessLogger, true))
10195

10296
// Configure static route
10397
fsys, err := fs.Sub(staticFS, "static")
@@ -158,9 +152,9 @@ func Start(cfg *config.Config) error {
158152
// Start metrics listener
159153
go func() {
160154
// TODO: return error if we cannot initialize metrics
161-
logger.Infof("starting metrics listener on %s:%d",
162-
cfg.Metrics.ListenAddress,
163-
cfg.Metrics.ListenPort)
155+
logger.Info("starting metrics listener",
156+
"address", cfg.Metrics.ListenAddress,
157+
"port", cfg.Metrics.ListenPort)
164158
_ = metricsRouter.Run(fmt.Sprintf("%s:%d",
165159
cfg.Metrics.ListenAddress,
166160
cfg.Metrics.ListenPort))
@@ -213,7 +207,7 @@ func handleHasTx(c *gin.Context) {
213207

214208
var uriParams TxHashPathParams
215209
if err := c.ShouldBindUri(&uriParams); err != nil {
216-
logger.Errorf("failed to bind transaction hash from path: %s", err)
210+
logger.Error("failed to bind transaction hash from path", "err", err)
217211
c.JSON(400, fmt.Sprintf("invalid transaction hash: %s", err))
218212
return
219213
}
@@ -222,7 +216,7 @@ func handleHasTx(c *gin.Context) {
222216
// convert to cbor bytes
223217
cborData, err := cbor.Marshal(txHash)
224218
if err != nil {
225-
logger.Errorf("failed to encode transaction hash to CBOR: %s", err)
219+
logger.Error("failed to encode transaction hash to CBOR", "err", err)
226220
c.JSON(
227221
400,
228222
fmt.Sprintf("failed to encode transaction hash to CBOR: %s", err),
@@ -236,19 +230,19 @@ func handleHasTx(c *gin.Context) {
236230
ouroboros.WithNodeToNode(false),
237231
)
238232
if err != nil {
239-
logger.Errorf("failure creating Ouroboros connection: %s", err)
233+
logger.Error("failure creating Ouroboros connection", "err", err)
240234
c.JSON(500, "failure communicating with node")
241235
return
242236
}
243237
if cfg.Node.Address != "" && cfg.Node.Port > 0 {
244238
if err := oConn.Dial("tcp", fmt.Sprintf("%s:%d", cfg.Node.Address, cfg.Node.Port)); err != nil {
245-
logger.Errorf("failure connecting to node via TCP: %s", err)
239+
logger.Error("failure connecting to node via TCP", "err", err)
246240
c.JSON(500, "failure communicating with node")
247241
return
248242
}
249243
} else {
250244
if err := oConn.Dial("unix", cfg.Node.SocketPath); err != nil {
251-
logger.Errorf("failure connecting to node via UNIX socket: %s", err)
245+
logger.Error("failure connecting to node via UNIX socket", "err", err)
252246
c.JSON(500, "failure communicating with node")
253247
return
254248
}
@@ -259,7 +253,7 @@ func handleHasTx(c *gin.Context) {
259253
}()
260254
hasTx, err := oConn.LocalTxMonitor().Client.HasTx(cborData)
261255
if err != nil {
262-
logger.Errorf("failure getting transaction: %s", err)
256+
logger.Error("failure getting transaction", "err", err)
263257
c.JSON(500, fmt.Sprintf("failure getting transaction: %s", err))
264258
return
265259
}
@@ -288,7 +282,7 @@ func handleSubmitTx(c *gin.Context) {
288282
// Check our headers for content-type
289283
if c.ContentType() != "application/cbor" {
290284
// Log the error, return an error to the user, and increment failed count
291-
logger.Errorf("invalid request body, should be application/cbor")
285+
logger.Error("invalid request body, should be application/cbor")
292286
c.JSON(415, "invalid request body, should be application/cbor")
293287
_ = ginmetrics.GetMonitor().GetMetric("tx_submit_fail_count").Inc(nil)
294288
return
@@ -297,15 +291,15 @@ func handleSubmitTx(c *gin.Context) {
297291
txRawBytes, err := io.ReadAll(c.Request.Body)
298292
if err != nil {
299293
// Log the error, return an error to the user, and increment failed count
300-
logger.Errorf("failed to read request body: %s", err)
294+
logger.Error("failed to read request body", "err", err)
301295
c.JSON(500, "failed to read request body")
302296
_ = ginmetrics.GetMonitor().GetMetric("tx_submit_fail_count").Inc(nil)
303297
return
304298
}
305299
// Close request body after read
306300
if c.Request.Body != nil {
307301
if err := c.Request.Body.Close(); err != nil {
308-
logger.Errorf("failed to close request body: %s", err)
302+
logger.Error("failed to close request body", "err", err)
309303
}
310304
}
311305
// Send TX
@@ -341,7 +335,7 @@ func handleSubmitTx(c *gin.Context) {
341335
go func() {
342336
err, ok := <-errorChan
343337
if ok {
344-
logger.Errorf("failure communicating with node: %s", err)
338+
logger.Error("failure communicating with node", "err", err)
345339
c.JSON(500, "failure communicating with node")
346340
_ = ginmetrics.GetMonitor().
347341
GetMetric("tx_submit_fail_count").

internal/logging/gin.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package logging
2+
3+
import (
4+
"log/slog"
5+
"net/http"
6+
"runtime/debug"
7+
"time"
8+
9+
"github.com/gin-gonic/gin"
10+
)
11+
12+
// GinLogger returns a middleware that logs HTTP requests with slog.
13+
func GinLogger(logger *slog.Logger, skipPaths []string) gin.HandlerFunc {
14+
skip := make(map[string]struct{}, len(skipPaths))
15+
for _, path := range skipPaths {
16+
skip[path] = struct{}{}
17+
}
18+
19+
return func(c *gin.Context) {
20+
start := time.Now()
21+
path := c.Request.URL.Path
22+
raw := c.Request.URL.RawQuery
23+
24+
c.Next()
25+
26+
if _, ok := skip[path]; ok {
27+
return
28+
}
29+
30+
latency := time.Since(start)
31+
entry := []any{
32+
"status", c.Writer.Status(),
33+
"method", c.Request.Method,
34+
"path", path,
35+
"query", raw,
36+
"ip", c.ClientIP(),
37+
"userAgent", c.Request.UserAgent(),
38+
"latency", latency.String(),
39+
"size", c.Writer.Size(),
40+
}
41+
if len(c.Errors) > 0 {
42+
entry = append(entry, "errors", c.Errors.String())
43+
}
44+
45+
logger.Info("request completed", entry...)
46+
}
47+
}
48+
49+
// GinRecovery recovers from panics and logs them.
50+
func GinRecovery(logger *slog.Logger, includeStack bool) gin.HandlerFunc {
51+
return func(c *gin.Context) {
52+
defer func() {
53+
if err := recover(); err != nil {
54+
fields := []any{"err", err}
55+
if includeStack {
56+
fields = append(fields, "stack", string(debug.Stack()))
57+
}
58+
logger.Error("panic recovered", fields...)
59+
c.AbortWithStatus(http.StatusInternalServerError)
60+
}
61+
}()
62+
c.Next()
63+
}
64+
}

0 commit comments

Comments
 (0)