Skip to content

Commit

Permalink
Merge pull request #22 from truvami/feature/zap. ⚡
Browse files Browse the repository at this point in the history
Refactor Logger Module to Use `go.uber.org/zap` ⚡
  • Loading branch information
michaelbeutler authored Dec 19, 2024
2 parents c2269c5 + 8e94420 commit 8cd48ff
Show file tree
Hide file tree
Showing 18 changed files with 353 additions and 443 deletions.
74 changes: 54 additions & 20 deletions cmd/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ package cmd
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"time"

sloghttp "github.com/samber/slog-http"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/truvami/decoder/internal/logger"
"github.com/truvami/decoder/pkg/decoder"
"github.com/truvami/decoder/pkg/decoder/nomadxl/v1"
"github.com/truvami/decoder/pkg/decoder/nomadxs/v1"
"github.com/truvami/decoder/pkg/decoder/tagsl/v1"
"github.com/truvami/decoder/pkg/decoder/tagxl/v1"
"github.com/truvami/decoder/pkg/loracloud"
"go.uber.org/zap"
)

var host string
Expand All @@ -34,7 +36,7 @@ var httpCmd = &cobra.Command{
Short: "Start the HTTP server for the decoder.",
Run: func(cmd *cobra.Command, args []string) {
if len(accessToken) == 0 {
slog.Warn("no access token provided for loracloud API")
logger.Logger.Warn("no access token provided for loracloud API")
}

router := http.NewServeMux()
Expand Down Expand Up @@ -74,21 +76,20 @@ var httpCmd = &cobra.Command{
}

// middleware
handler := sloghttp.Recovery(router)
handler = sloghttp.New(slog.Default())(handler)
handler := loggingMiddleware(logger.Logger, router)

slog.Info("starting HTTP server", slog.String("host", host), slog.Uint64("port", uint64(port)))
logger.Logger.Info("starting HTTP server", zap.String("host", host), zap.Uint64("port", uint64(port)))
err := http.ListenAndServe(fmt.Sprintf("%v:%v", host, port), handler)

if err != nil {
slog.Error("error while starting HTTP server", slog.Any("error", err))
logger.Logger.Error("error while starting HTTP server", zap.Error(err))
os.Exit(1)
}
},
}

func addDecoder(router *http.ServeMux, path string, decoder decoder.Decoder) {
slog.Debug("adding decoder", slog.String("path", path))
logger.Logger.Debug("adding decoder", zap.String("path", path))
router.HandleFunc("POST /"+path, getHandler(decoder))
}

Expand All @@ -103,46 +104,46 @@ func getHandler(decoder decoder.Decoder) func(http.ResponseWriter, *http.Request
// decode the request
var req request

slog.Debug("decoding request")
logger.Logger.Debug("decoding request")
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
slog.Error("error while decoding request", slog.Any("error", err))
logger.Logger.Error("error while decoding request", zap.Error(err))
setHeaders(w, http.StatusBadRequest)
_, err = w.Write([]byte(err.Error()))

if err != nil {
slog.Error("error while sending response", slog.Any("error", err))
logger.Logger.Error("error while sending response", zap.Error(err))
}
return
}

// decode the payload
slog.Debug("decoding payload")
logger.Logger.Debug("decoding payload")
data, metadata, err := decoder.Decode(req.Payload, req.Port, req.DevEUI)
if err != nil {
slog.Error("error while decoding payload", slog.Any("error", err))
logger.Logger.Error("error while decoding payload", zap.Error(err))
setHeaders(w, http.StatusBadRequest)
_, err = w.Write([]byte(err.Error()))

if err != nil {
slog.Error("error while sending response", slog.Any("error", err))
logger.Logger.Error("error while sending response", zap.Error(err))
}
return
}

// data to json
slog.Debug("encoding response")
logger.Logger.Debug("encoding response")
data, err = json.Marshal(map[string]interface{}{
"data": data,
"metadata": metadata,
})
if err != nil {
slog.Error("error while encoding response", slog.Any("error", err))
logger.Logger.Error("error while encoding response", zap.Error(err))
setHeaders(w, http.StatusInternalServerError)
_, err = w.Write([]byte(err.Error()))

if err != nil {
slog.Error("error while sending response", slog.Any("error", err))
logger.Logger.Error("error while sending response", zap.Error(err))
}
return
}
Expand All @@ -151,14 +152,19 @@ func getHandler(decoder decoder.Decoder) func(http.ResponseWriter, *http.Request
setHeaders(w, http.StatusOK)
_, err = w.Write(data.([]byte))
if err != nil {
slog.Error("error while sending response", slog.Any("error", err))
logger.Logger.Error("error while sending response", zap.Error(err))
return
}

slog.Debug("response sent", slog.Any("response", string(data.([]byte))))
logger.Logger.Debug("response sent", zap.Any("response", string(data.([]byte))))
}
}

type responseWriter struct {
http.ResponseWriter
statusCode int
}

func setHeaders(w http.ResponseWriter, status int) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
Expand All @@ -170,6 +176,34 @@ func healthHandler(w http.ResponseWriter, r *http.Request) {
setHeaders(w, http.StatusOK)
_, err := w.Write([]byte("OK"))
if err != nil {
slog.Error("error while sending response", slog.Any("error", err))
logger.Logger.Error("error while sending response", zap.Error(err))
}
}

func loggingMiddleware(logger *zap.Logger, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// generate a unique request ID
requestID := uuid.New().String()
w.Header().Set("X-Request-ID", requestID)

// start timer
start := time.Now()

// use a ResponseWriter wrapper to capture the status code
rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}

// process the request
next.ServeHTTP(rw, r)

// log the details
logger.Info("HTTP request",
zap.String("requestId", requestID),
zap.String("method", r.Method),
zap.String("url", r.URL.String()),
zap.Int("status", rw.statusCode),
zap.String("remoteAddress", r.RemoteAddr),
zap.String("userAgent", r.UserAgent()),
zap.Duration("latency", time.Since(start)),
)
})
}
4 changes: 4 additions & 0 deletions cmd/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import (
"testing"
"time"

"github.com/truvami/decoder/internal/logger"
"github.com/truvami/decoder/pkg/decoder/tagsl/v1"
)

func TestAddDecoder(t *testing.T) {
logger.NewLogger()
defer logger.Sync()

router := http.NewServeMux()
path := "test/path"
decoder := tagsl.NewTagSLv1Decoder()
Expand Down
11 changes: 6 additions & 5 deletions cmd/nomadxl.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package cmd

import (
"log/slog"
"strconv"

"github.com/spf13/cobra"
"github.com/truvami/decoder/internal/logger"
"github.com/truvami/decoder/pkg/decoder/nomadxl/v1"
"go.uber.org/zap"
)

func init() {
Expand All @@ -17,21 +18,21 @@ var nomadxlCmd = &cobra.Command{
Short: "decode nomad XL payloads",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
slog.Debug("initializing nomadxs decoder")
logger.Logger.Debug("initializing nomadxs decoder")
d := nomadxl.NewNomadXLv1Decoder(
nomadxl.WithAutoPadding(AutoPadding),
)

port, err := strconv.Atoi(args[0])
if err != nil {
slog.Error("error while parsing port", slog.Any("error", err), slog.String("port", args[0]))
logger.Logger.Error("error while parsing port", zap.Error(err), zap.String("port", args[0]))
return
}
slog.Debug("port parsed successfully", slog.Int("port", port))
logger.Logger.Debug("port parsed successfully", zap.Int("port", port))

data, metadata, err := d.Decode(args[1], int16(port), "")
if err != nil {
slog.Error("error while decoding data", slog.Any("error", err))
logger.Logger.Error("error while decoding data", zap.Error(err))
return
}

Expand Down
11 changes: 6 additions & 5 deletions cmd/nomadxs.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package cmd

import (
"log/slog"
"strconv"

"github.com/spf13/cobra"
"github.com/truvami/decoder/internal/logger"
"github.com/truvami/decoder/pkg/decoder/nomadxs/v1"
"go.uber.org/zap"
)

func init() {
Expand All @@ -17,21 +18,21 @@ var nomadxsCmd = &cobra.Command{
Short: "decode nomad XS payloads",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
slog.Debug("initializing nomadxs decoder")
logger.Logger.Debug("initializing nomadxs decoder")
d := nomadxs.NewNomadXSv1Decoder(
nomadxs.WithAutoPadding(AutoPadding),
)

port, err := strconv.Atoi(args[0])
if err != nil {
slog.Error("error while parsing port", slog.Any("error", err), slog.String("port", args[0]))
logger.Logger.Error("error while parsing port", zap.Error(err), zap.String("port", args[0]))
return
}
slog.Debug("port parsed successfully", slog.Int("port", port))
logger.Logger.Debug("port parsed successfully", zap.Int("port", port))

data, metadata, err := d.Decode(args[1], int16(port), "")
if err != nil {
slog.Error("error while decoding data", slog.Any("error", err))
logger.Logger.Error("error while decoding data", zap.Error(err))
return
}

Expand Down
Loading

0 comments on commit 8cd48ff

Please sign in to comment.