128 lines
3.7 KiB
Go
128 lines
3.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
"Yimaru-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)
|
|
}
|
|
}
|