Yimaru-BackEnd/internal/web_server/handlers/mongoLogger.go
2025-07-22 17:39:53 +03:00

128 lines
3.7 KiB
Go

package handlers
import (
"context"
"os"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/gofiber/fiber/v2"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// GetLogsHandler godoc
// @Summary Retrieve application logs with filtering and pagination
// @Description Fetches application logs from MongoDB with pagination, level filtering, and search
// @Tags Logs
// @Produce json
// @Param level query string false "Filter logs by level (debug, info, warn, error, dpanic, panic, fatal)"
// @Param search query string false "Search term to match against message or fields"
// @Param page query int false "Page number for pagination (default: 1)" default(1)
// @Param limit query int false "Number of items per page (default: 50, max: 100)" default(50)
// @Success 200 {object} domain.LogResponse "Paginated list of application logs"
// @Failure 400 {object} domain.ErrorResponse "Invalid request parameters"
// @Failure 500 {object} domain.ErrorResponse "Internal server error"
// @Router /api/v1/logs [get]
func GetLogsHandler(appCtx context.Context) fiber.Handler {
return func(c *fiber.Ctx) error {
// Get query parameters
levelFilter := c.Query("level")
searchTerm := c.Query("search")
page := c.QueryInt("page", 1)
limit := c.QueryInt("limit", 50)
// Validate pagination parameters
if page < 1 {
page = 1
}
if limit < 1 || limit > 100 {
limit = 50
}
// Calculate skip value for pagination
skip := (page - 1) * limit
client, err := mongo.Connect(appCtx, options.Client().ApplyURI(os.Getenv("MONGODB_URL")))
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "MongoDB connection failed: "+err.Error())
}
defer client.Disconnect(appCtx)
collection := client.Database("logdb").Collection("applogs")
// Build filter
filter := bson.M{}
// Add level filter if specified
if levelFilter != "" {
validLevels := map[string]bool{
"debug": true,
"info": true,
"warn": true,
"error": true,
"dpanic": true,
"panic": true,
"fatal": true,
}
if !validLevels[levelFilter] {
return fiber.NewError(fiber.StatusBadRequest, "Invalid log level specified")
}
filter["level"] = levelFilter
}
// Add search filter if specified
if searchTerm != "" {
filter["$or"] = []bson.M{
{"message": bson.M{"$regex": searchTerm, "$options": "i"}},
{"fields": bson.M{"$elemMatch": bson.M{"$regex": searchTerm, "$options": "i"}}},
}
}
// Find options with pagination and sorting
opts := options.Find().
SetSort(bson.D{{Key: "timestamp", Value: -1}}).
SetSkip(int64(skip)).
SetLimit(int64(limit))
// Get total count for pagination metadata
total, err := collection.CountDocuments(appCtx, filter)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to count logs: "+err.Error())
}
// Find logs
cursor, err := collection.Find(appCtx, filter, opts)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch logs: "+err.Error())
}
defer cursor.Close(appCtx)
var logs []domain.LogEntry = make([]domain.LogEntry, 0)
if err := cursor.All(appCtx, &logs); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Cursor decoding error: "+err.Error())
}
// Calculate pagination metadata
totalPages := int(total) / limit
if int(total)%limit != 0 {
totalPages++
}
// Prepare response
response := domain.LogResponse{
Message: "Logs fetched successfully",
Data: logs,
Pagination: domain.Pagination{
Total: int(total),
TotalPages: totalPages,
CurrentPage: page,
Limit: limit,
},
}
return c.JSON(response)
}
}