Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions app/middlewares/auth_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,41 @@ import (
"strconv"

"github.com/hammer-code/lms-be/domain"
"github.com/hammer-code/lms-be/pkg/ngelog"
"github.com/hammer-code/lms-be/utils"
)

func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
ctx, span := tracer.Start(request.Context(), "auth middleware")
defer span.End()

token := utils.ExtractBearerToken(request)
if len(*token) < 5 {
ngelog.Error(ctx, "failed to extract bearer token", nil)
utils.Response(domain.HttpResponse{
Code: 401,
Message: "Unauthorized",
Data: nil,
}, writer)
return
}

verifyToken, err := m.Jwt.VerifyToken(*token)
if err != nil {
ngelog.Error(ctx, "failed to verify token", err)
utils.Response(domain.HttpResponse{
Code: 500,
Message: "failed to verify token",
Data: nil,
}, writer)
return
}

logoutToken, err := m.UserRepo.GetToken(request.Context(), *token)
if err != nil {
ngelog.Error(ctx, "failed to get token", err)
utils.Response(domain.HttpResponse{
Code: 401,
Message: "Unauthorized",
Expand All @@ -41,6 +48,7 @@ func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
return
}
if logoutToken.Status == 0 {
ngelog.Error(ctx, "unauthorized", nil)
utils.Response(domain.HttpResponse{
Code: 401,
Message: "Unauthorized",
Expand All @@ -49,29 +57,30 @@ func (m *Middleware) AuthMiddleware(allowedRole string) domain.MiddlewareFunc {
return
}


user, err := m.UserRepo.FindByEmail(request.Context(), verifyToken.Email)
if err != nil {
ngelog.Error(ctx, "failed to find by email", err)
utils.Response(domain.HttpResponse{
Code: 401,
Message: "Unauthorized",
Data: nil,
}, writer)
return
}

if user.Role != allowedRole {
ngelog.Error(ctx, "role is not the role", nil)
utils.Response(domain.HttpResponse{
Code: 401,
Message: "Unauthorized",
Data: nil,
}, writer)
return
}

writer.Header().Set("x-user-id", strconv.Itoa(user.ID))
writer.Header().Set("x-username", user.Username)

next.ServeHTTP(writer, request)
})
}
Expand Down
23 changes: 10 additions & 13 deletions app/middlewares/log.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
package middlewares

import (
"fmt"
"net/http"
"time"

"github.com/sirupsen/logrus"
)

func (m *Middleware) LogMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("hiteed")
start := time.Now()
ctx, span := tracer.Start(r.Context(), "HTTP "+r.Method+" "+r.URL.Path)
defer span.End()

// Replace request context with the new one
r = r.WithContext(ctx)

// Call the next handler
next.ServeHTTP(w, r)

// Log request details with Logrus
logrus.WithFields(logrus.Fields{
"method": r.Method,
"url": r.URL.Path,
"duration": time.Since(start).String(),
}).Info("Request processed")
// ngelog.Info(ctx, "request process", ngelog.AddFields{
// "method": r.Method,
// "url": r.URL.Path,
// "duration": time.Since(time.Now()).String(),
// })
})
}
5 changes: 5 additions & 0 deletions app/middlewares/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ package middlewares
import (
"github.com/hammer-code/lms-be/domain"
"github.com/hammer-code/lms-be/pkg/jwt"
"go.opentelemetry.io/otel"
)

type Middleware struct {
Jwt jwt.JWT
UserRepo domain.UserRepository
}

var (
tracer = otel.Tracer("Start Trace")
)

func InitMiddleware(jwt jwt.JWT, userRepo domain.UserRepository) domain.Middleware {
return &Middleware{
Jwt: jwt,
Expand Down
66 changes: 46 additions & 20 deletions cmd/serve_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@ import (

"github.com/gorilla/mux"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"google.golang.org/grpc"

"github.com/hammer-code/lms-be/app"
"github.com/hammer-code/lms-be/config"
"github.com/hammer-code/lms-be/constants"
_ "github.com/hammer-code/lms-be/docs"
"github.com/hammer-code/lms-be/domain"
"github.com/hammer-code/lms-be/pkg/ngelog"
"github.com/hammer-code/lms-be/utils"
"github.com/sirupsen/logrus"
httpSwagger "github.com/swaggo/http-swagger"

// _ "swagger-mux/docs"
"github.com/rs/cors"
"github.com/spf13/cobra"
"github.com/swaggo/swag"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

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

// Init OpenTelemetry
exporter := newOTLPTraceExporter(ctx, "localhost:4317")

tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithSampler(sdktrace.AlwaysSample()), // <--- force sampling
)

otel.SetTracerProvider(tp)

cfg := config.GetConfig()

ngelog.SetNameSpace(cfg.APP_NAME)
ngelog.SetNameSpace(cfg.APP_ENV)

app := app.InitApp(cfg)

// route
router := registerHandler(app)
router.Use(app.Middleware.LogMiddleware)

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

go func() {
done := make(chan os.Signal, 1)

signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-done
logrus.Info("svr.Shutdown: start shutdown")
ngelog.Info(ctx, "service shutdown")
if err := srv.Shutdown(ctx); err == context.DeadlineExceeded {
logrus.Error("svr.Shutdown: context deadline exceeded", err)
ngelog.Error(ctx, "svr.Shutdown: context deadline exceeded", err)
}
logrus.Info("svr.Shutdown: shutdown success")
}()

logrus.Info(fmt.Sprintf("server started, running on port %s", cfg.APP_PORT))
ngelog.Info(ctx, fmt.Sprintf("server started, running on port %s", cfg.APP_PORT))
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logrus.Fatal("starting server failed", err)
ngelog.Fatal(ctx, "starting server failed", err)
}
},
}

// func LoadJSON(path string) string {
// jsonBytes, err := os.ReadFile(path)

// // jsonBytes, err := os.ReadFile("documentation/users.json")
// if err != nil {
// fmt.Println("Error reading JSON file:", err)
// return ""
// }
// return string(jsonBytes)
// }

func LoadJSON(path string) string {
jsonBytes, err := os.ReadFile(path)

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

}

func health(w http.ResponseWriter, _ *http.Request) {
func health(w http.ResponseWriter, r *http.Request) {
tracer := otel.Tracer("Test Trace")

ctx, span := tracer.Start(r.Context(), "health controller")
defer span.End()

ngelog.Info(ctx, "service health good")
utils.Response(domain.HttpResponse{
Code: 200,
Message: "good",
Expand All @@ -116,6 +127,7 @@ func health(w http.ResponseWriter, _ *http.Request) {
func registerHandler(app app.App) *mux.Router {

router := mux.NewRouter()
router.Use(app.Middleware.LogMiddleware)
router.HandleFunc("/health", health)

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

return router
}

func newOTLPTraceExporter(ctx context.Context, otlpEndpoint string) *otlptrace.Exporter {
traceClient := otlptracegrpc.NewClient(
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(otlpEndpoint),
otlptracegrpc.WithDialOption(grpc.WithBlock()))
traceExp, err := otlptrace.New(ctx, traceClient)
if err != nil {
// ngelog.Fatal().Err(err).Msgf("Failed to create the collector trace exporter")
ngelog.FatalPanic(ctx, "Failed to create the collector trace exporter", err)
}

return traceExp
}
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@ services:
volumes:
- lms-be:/var/lib/postgresql/data
restart: always
# loki:
# image: grafana/loki:latest
# ports:
# - 3100:3100
# volumes:
# - ./loki-config.yml:/etc/loki/loki-config.yaml
# promtail:
# image: grafana/promtail:latest
# volumes:
# - ./promtail-config.yml:/etc/promtail/promtail-config.yaml
jaeger:
image: jaegertracing/all-in-one:latest
environment:
COLLECTOR_ZIPKIN_HOST_PORT: 9411
expose:
- "16686"
ports:
- 16686:16686
- 4317:4317
- 4318:4318
command:
- "--memory.max-traces"
- "1000"
- "--collector.otlp.grpc.host-port"
- ":4317"
- "--collector.otlp.http.host-port"
- ":4318"
restart: always

volumes:
lms-be:
40 changes: 34 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/hammer-code/lms-be

go 1.19
go 1.23.0

toolchain go1.24.2

require (
github.com/golang-jwt/jwt/v5 v5.2.0
Expand All @@ -12,7 +14,11 @@ require (
github.com/spf13/viper v1.18.2
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.3
golang.org/x/crypto v0.21.0
go.opentelemetry.io/otel v1.36.0
go.opentelemetry.io/otel/exporters/prometheus v0.58.0
go.opentelemetry.io/otel/sdk/metric v1.36.0
go.opentelemetry.io/otel/trace v1.36.0
golang.org/x/crypto v0.38.0
gopkg.in/guregu/null.v4 v4.0.0
gorm.io/driver/postgres v1.5.6
gorm.io/gorm v1.25.7
Expand All @@ -29,6 +35,13 @@ require (
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
Expand All @@ -40,7 +53,12 @@ require (
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.64.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand All @@ -49,13 +67,23 @@ require (
github.com/spf13/pflag v1.0.6 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/swaggo/files v1.0.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.19.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
google.golang.org/grpc v1.72.1 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading