Skip to content

Commit 596d194

Browse files
authored
Merge pull request #15 from hammercode-dev/feature/log
feat: add log, add tracing
2 parents 24192ec + 4446372 commit 596d194

File tree

9 files changed

+314
-65
lines changed

9 files changed

+314
-65
lines changed

app/middlewares/auth_middleware.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,41 @@ import (
55
"strconv"
66

77
"github.com/hammer-code/lms-be/domain"
8+
"github.com/hammer-code/lms-be/pkg/ngelog"
89
"github.com/hammer-code/lms-be/utils"
910
)
1011

1112
func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
1213
return func(next http.Handler) http.Handler {
1314
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
15+
ctx, span := tracer.Start(request.Context(), "auth middleware")
16+
defer span.End()
17+
1418
token := utils.ExtractBearerToken(request)
1519
if len(*token) < 5 {
20+
ngelog.Error(ctx, "failed to extract bearer token", nil)
1621
utils.Response(domain.HttpResponse{
1722
Code: 401,
1823
Message: "Unauthorized",
1924
Data: nil,
2025
}, writer)
2126
return
2227
}
23-
28+
2429
verifyToken, err := m.Jwt.VerifyToken(*token)
2530
if err != nil {
31+
ngelog.Error(ctx, "failed to verify token", err)
2632
utils.Response(domain.HttpResponse{
2733
Code: 500,
2834
Message: "failed to verify token",
2935
Data: nil,
3036
}, writer)
3137
return
3238
}
33-
39+
3440
logoutToken, err := m.UserRepo.GetToken(request.Context(), *token)
3541
if err != nil {
42+
ngelog.Error(ctx, "failed to get token", err)
3643
utils.Response(domain.HttpResponse{
3744
Code: 401,
3845
Message: "Unauthorized",
@@ -41,6 +48,7 @@ func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
4148
return
4249
}
4350
if logoutToken.Status == 0 {
51+
ngelog.Error(ctx, "unauthorized", nil)
4452
utils.Response(domain.HttpResponse{
4553
Code: 401,
4654
Message: "Unauthorized",
@@ -49,29 +57,30 @@ func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
4957
return
5058
}
5159

52-
5360
user, err := m.UserRepo.FindByEmail(request.Context(), verifyToken.Email)
5461
if err != nil {
62+
ngelog.Error(ctx, "failed to find by email", err)
5563
utils.Response(domain.HttpResponse{
5664
Code: 401,
5765
Message: "Unauthorized",
5866
Data: nil,
5967
}, writer)
6068
return
6169
}
62-
70+
6371
if user.Role != allowedRole {
72+
ngelog.Error(ctx, "role is not the role", nil)
6473
utils.Response(domain.HttpResponse{
6574
Code: 401,
6675
Message: "Unauthorized",
6776
Data: nil,
6877
}, writer)
6978
return
7079
}
71-
80+
7281
writer.Header().Set("x-user-id", strconv.Itoa(user.ID))
7382
writer.Header().Set("x-username", user.Username)
74-
83+
7584
next.ServeHTTP(writer, request)
7685
})
7786
}

app/middlewares/log.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
package middlewares
22

33
import (
4-
"fmt"
54
"net/http"
6-
"time"
7-
8-
"github.com/sirupsen/logrus"
95
)
106

117
func (m *Middleware) LogMiddleware(next http.Handler) http.Handler {
128
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13-
fmt.Println("hiteed")
14-
start := time.Now()
9+
ctx, span := tracer.Start(r.Context(), "HTTP "+r.Method+" "+r.URL.Path)
10+
defer span.End()
11+
12+
// Replace request context with the new one
13+
r = r.WithContext(ctx)
1514

1615
// Call the next handler
1716
next.ServeHTTP(w, r)
18-
19-
// Log request details with Logrus
20-
logrus.WithFields(logrus.Fields{
21-
"method": r.Method,
22-
"url": r.URL.Path,
23-
"duration": time.Since(start).String(),
24-
}).Info("Request processed")
17+
// ngelog.Info(ctx, "request process", ngelog.AddFields{
18+
// "method": r.Method,
19+
// "url": r.URL.Path,
20+
// "duration": time.Since(time.Now()).String(),
21+
// })
2522
})
2623
}

app/middlewares/middleware.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ package middlewares
33
import (
44
"github.com/hammer-code/lms-be/domain"
55
"github.com/hammer-code/lms-be/pkg/jwt"
6+
"go.opentelemetry.io/otel"
67
)
78

89
type Middleware struct {
910
Jwt jwt.JWT
1011
UserRepo domain.UserRepository
1112
}
1213

14+
var (
15+
tracer = otel.Tracer("Start Trace")
16+
)
17+
1318
func InitMiddleware(jwt jwt.JWT, userRepo domain.UserRepository) domain.Middleware {
1419
return &Middleware{
1520
Jwt: jwt,

cmd/serve_http.go

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,25 @@ import (
1010

1111
"github.com/gorilla/mux"
1212

13+
"go.opentelemetry.io/otel"
14+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
15+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
16+
"google.golang.org/grpc"
17+
1318
"github.com/hammer-code/lms-be/app"
1419
"github.com/hammer-code/lms-be/config"
1520
"github.com/hammer-code/lms-be/constants"
1621
_ "github.com/hammer-code/lms-be/docs"
1722
"github.com/hammer-code/lms-be/domain"
23+
"github.com/hammer-code/lms-be/pkg/ngelog"
1824
"github.com/hammer-code/lms-be/utils"
19-
"github.com/sirupsen/logrus"
2025
httpSwagger "github.com/swaggo/http-swagger"
2126

2227
// _ "swagger-mux/docs"
2328
"github.com/rs/cors"
2429
"github.com/spf13/cobra"
2530
"github.com/swaggo/swag"
31+
sdktrace "go.opentelemetry.io/otel/sdk/trace"
2632
)
2733

2834
var serveHttpCmd = &cobra.Command{
@@ -33,13 +39,25 @@ var serveHttpCmd = &cobra.Command{
3339
// load add package serve http here
3440
ctx := context.Background()
3541

42+
// Init OpenTelemetry
43+
exporter := newOTLPTraceExporter(ctx, "localhost:4317")
44+
45+
tp := sdktrace.NewTracerProvider(
46+
sdktrace.WithBatcher(exporter),
47+
sdktrace.WithSampler(sdktrace.AlwaysSample()), // <--- force sampling
48+
)
49+
50+
otel.SetTracerProvider(tp)
51+
3652
cfg := config.GetConfig()
3753

54+
ngelog.SetNameSpace(cfg.APP_NAME)
55+
ngelog.SetNameSpace(cfg.APP_ENV)
56+
3857
app := app.InitApp(cfg)
3958

4059
// route
4160
router := registerHandler(app)
42-
router.Use(app.Middleware.LogMiddleware)
4361

4462
// build cors
4563
muxCorsWithRouter := cors.AllowAll().Handler(router)
@@ -51,34 +69,21 @@ var serveHttpCmd = &cobra.Command{
5169

5270
go func() {
5371
done := make(chan os.Signal, 1)
54-
5572
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
5673
<-done
57-
logrus.Info("svr.Shutdown: start shutdown")
74+
ngelog.Info(ctx, "service shutdown")
5875
if err := srv.Shutdown(ctx); err == context.DeadlineExceeded {
59-
logrus.Error("svr.Shutdown: context deadline exceeded", err)
76+
ngelog.Error(ctx, "svr.Shutdown: context deadline exceeded", err)
6077
}
61-
logrus.Info("svr.Shutdown: shutdown success")
6278
}()
6379

64-
logrus.Info(fmt.Sprintf("server started, running on port %s", cfg.APP_PORT))
80+
ngelog.Info(ctx, fmt.Sprintf("server started, running on port %s", cfg.APP_PORT))
6581
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
66-
logrus.Fatal("starting server failed", err)
82+
ngelog.Fatal(ctx, "starting server failed", err)
6783
}
6884
},
6985
}
7086

71-
// func LoadJSON(path string) string {
72-
// jsonBytes, err := os.ReadFile(path)
73-
74-
// // jsonBytes, err := os.ReadFile("documentation/users.json")
75-
// if err != nil {
76-
// fmt.Println("Error reading JSON file:", err)
77-
// return ""
78-
// }
79-
// return string(jsonBytes)
80-
// }
81-
8287
func LoadJSON(path string) string {
8388
jsonBytes, err := os.ReadFile(path)
8489

@@ -105,7 +110,13 @@ func init() {
105110

106111
}
107112

108-
func health(w http.ResponseWriter, _ *http.Request) {
113+
func health(w http.ResponseWriter, r *http.Request) {
114+
tracer := otel.Tracer("Test Trace")
115+
116+
ctx, span := tracer.Start(r.Context(), "health controller")
117+
defer span.End()
118+
119+
ngelog.Info(ctx, "service health good")
109120
utils.Response(domain.HttpResponse{
110121
Code: 200,
111122
Message: "good",
@@ -116,6 +127,7 @@ func health(w http.ResponseWriter, _ *http.Request) {
116127
func registerHandler(app app.App) *mux.Router {
117128

118129
router := mux.NewRouter()
130+
router.Use(app.Middleware.LogMiddleware)
119131
router.HandleFunc("/health", health)
120132

121133
router.PathPrefix("/docs/").Handler(httpSwagger.WrapHandler)
@@ -168,3 +180,17 @@ func registerHandler(app app.App) *mux.Router {
168180

169181
return router
170182
}
183+
184+
func newOTLPTraceExporter(ctx context.Context, otlpEndpoint string) *otlptrace.Exporter {
185+
traceClient := otlptracegrpc.NewClient(
186+
otlptracegrpc.WithInsecure(),
187+
otlptracegrpc.WithEndpoint(otlpEndpoint),
188+
otlptracegrpc.WithDialOption(grpc.WithBlock()))
189+
traceExp, err := otlptrace.New(ctx, traceClient)
190+
if err != nil {
191+
// ngelog.Fatal().Err(err).Msgf("Failed to create the collector trace exporter")
192+
ngelog.FatalPanic(ctx, "Failed to create the collector trace exporter", err)
193+
}
194+
195+
return traceExp
196+
}

docker-compose.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,34 @@ services:
1111
volumes:
1212
- lms-be:/var/lib/postgresql/data
1313
restart: always
14+
# loki:
15+
# image: grafana/loki:latest
16+
# ports:
17+
# - 3100:3100
18+
# volumes:
19+
# - ./loki-config.yml:/etc/loki/loki-config.yaml
20+
# promtail:
21+
# image: grafana/promtail:latest
22+
# volumes:
23+
# - ./promtail-config.yml:/etc/promtail/promtail-config.yaml
24+
jaeger:
25+
image: jaegertracing/all-in-one:latest
26+
environment:
27+
COLLECTOR_ZIPKIN_HOST_PORT: 9411
28+
expose:
29+
- "16686"
30+
ports:
31+
- 16686:16686
32+
- 4317:4317
33+
- 4318:4318
34+
command:
35+
- "--memory.max-traces"
36+
- "1000"
37+
- "--collector.otlp.grpc.host-port"
38+
- ":4317"
39+
- "--collector.otlp.http.host-port"
40+
- ":4318"
41+
restart: always
1442

1543
volumes:
1644
lms-be:

go.mod

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/hammer-code/lms-be
22

3-
go 1.19
3+
go 1.23.0
4+
5+
toolchain go1.24.2
46

57
require (
68
github.com/golang-jwt/jwt/v5 v5.2.0
@@ -12,7 +14,11 @@ require (
1214
github.com/spf13/viper v1.18.2
1315
github.com/swaggo/http-swagger v1.3.4
1416
github.com/swaggo/swag v1.16.3
15-
golang.org/x/crypto v0.21.0
17+
go.opentelemetry.io/otel v1.36.0
18+
go.opentelemetry.io/otel/exporters/prometheus v0.58.0
19+
go.opentelemetry.io/otel/sdk/metric v1.36.0
20+
go.opentelemetry.io/otel/trace v1.36.0
21+
golang.org/x/crypto v0.38.0
1622
gopkg.in/guregu/null.v4 v4.0.0
1723
gorm.io/driver/postgres v1.5.6
1824
gorm.io/gorm v1.25.7
@@ -29,6 +35,13 @@ require (
2935
)
3036

3137
require (
38+
github.com/beorn7/perks v1.0.1 // indirect
39+
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
40+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
41+
github.com/go-logr/logr v1.4.2 // indirect
42+
github.com/go-logr/stdr v1.2.2 // indirect
43+
github.com/google/uuid v1.6.0 // indirect
44+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
3245
github.com/hashicorp/hcl v1.0.0 // indirect
3346
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3447
github.com/jackc/pgpassfile v1.0.0 // indirect
@@ -40,7 +53,12 @@ require (
4053
github.com/magiconair/properties v1.8.7 // indirect
4154
github.com/mailru/easyjson v0.7.7 // indirect
4255
github.com/mitchellh/mapstructure v1.5.0 // indirect
56+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
4357
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
58+
github.com/prometheus/client_golang v1.22.0 // indirect
59+
github.com/prometheus/client_model v0.6.2 // indirect
60+
github.com/prometheus/common v0.64.0 // indirect
61+
github.com/prometheus/procfs v0.16.1 // indirect
4462
github.com/sagikazarmark/locafero v0.4.0 // indirect
4563
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
4664
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -49,13 +67,23 @@ require (
4967
github.com/spf13/pflag v1.0.6 // indirect
5068
github.com/subosito/gotenv v1.6.0 // indirect
5169
github.com/swaggo/files v1.0.1 // indirect
70+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
71+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect
72+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect
73+
go.opentelemetry.io/otel/metric v1.36.0 // indirect
74+
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
75+
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
5276
go.uber.org/atomic v1.9.0 // indirect
5377
go.uber.org/multierr v1.9.0 // indirect
5478
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
55-
golang.org/x/net v0.22.0 // indirect
56-
golang.org/x/sys v0.18.0 // indirect
57-
golang.org/x/text v0.14.0 // indirect
58-
golang.org/x/tools v0.19.0 // indirect
79+
golang.org/x/net v0.40.0 // indirect
80+
golang.org/x/sys v0.33.0 // indirect
81+
golang.org/x/text v0.25.0 // indirect
82+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
83+
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
84+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
85+
google.golang.org/grpc v1.72.1 // indirect
86+
google.golang.org/protobuf v1.36.6 // indirect
5987
gopkg.in/ini.v1 v1.67.0 // indirect
6088
gopkg.in/yaml.v3 v3.0.1 // indirect
6189
)

0 commit comments

Comments
 (0)