feat: prometheus

This commit is contained in:
2025-12-14 14:11:33 +08:00
parent 31b9fb5d45
commit a9d2f05562
10 changed files with 162 additions and 132 deletions

View File

@@ -8,6 +8,7 @@ import (
"nysoure/server/middleware"
"nysoure/server/model"
"nysoure/server/service"
"nysoure/server/stat"
"nysoure/server/utils"
"strconv"
"strings"
@@ -240,6 +241,7 @@ func downloadFile(c fiber.Ctx) error {
}
q.Set("token", token)
uri.RawQuery = q.Encode()
stat.RecordDownload()
return c.Redirect().Status(fiber.StatusFound).To(uri.String())
}
data := map[string]string{
@@ -251,6 +253,7 @@ func downloadFile(c fiber.Ctx) error {
if err != nil {
return model.NewInternalServerError("Failed to generate download token")
}
stat.RecordDownload()
return c.Redirect().Status(fiber.StatusFound).To(fmt.Sprintf("%s/api/files/download/local?token=%s", c.BaseURL(), token))
}

View File

@@ -7,6 +7,7 @@ import (
"nysoure/server/middleware"
"nysoure/server/model"
"nysoure/server/service"
"nysoure/server/stat"
"strconv"
"time"
@@ -24,6 +25,7 @@ func handleUserRegister(c fiber.Ctx) error {
if err != nil {
return err
}
stat.RecordRegister()
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserViewWithToken]{
Success: true,
Data: user,

View File

@@ -5,7 +5,6 @@ import (
"nysoure/server/model"
"github.com/gofiber/fiber/v3/log"
"gorm.io/gorm"
"github.com/gofiber/fiber/v3"
)
@@ -13,73 +12,22 @@ import (
func ErrorHandler(c fiber.Ctx) error {
err := c.Next()
if err != nil {
var requestErr *model.RequestError
var unauthorizedErr *model.UnAuthorizedError
var notFoundErr *model.NotFoundError
var fiberErr *fiber.Error
if errors.As(err, &requestErr) {
log.Error("Request Error: ", err)
return c.Status(fiber.StatusBadRequest).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: requestErr.Error(),
})
} else if errors.As(err, &unauthorizedErr) {
log.Error("Unauthorized Error: ", err)
return c.Status(fiber.StatusUnauthorized).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: unauthorizedErr.Error(),
})
} else if errors.As(err, &notFoundErr) {
log.Error("Not Found Error: ", err)
return c.Status(fiber.StatusNotFound).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: notFoundErr.Error(),
})
} else if errors.Is(err, fiber.ErrNotFound) {
return c.Status(fiber.StatusNotFound).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Not found",
})
} else if errors.Is(err, fiber.ErrMethodNotAllowed) {
return c.Status(fiber.StatusMethodNotAllowed).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Method not allowed",
})
} else if errors.As(err, &fiberErr) && fiberErr.Message != "" {
return c.Status(fiberErr.Code).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: fiberErr.Message,
})
} else if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(fiber.StatusNotFound).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Not found",
})
} else {
var fiberErr *fiber.Error
if errors.As(err, &fiberErr) {
if fiberErr.Code == fiber.StatusNotFound {
return c.Status(fiber.StatusNotFound).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Not found",
})
}
if errors.As(err, &fiberErr) {
if fiberErr.Code != fiber.StatusInternalServerError {
return c.Status(fiberErr.Code).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: fiberErr.Message,
})
}
log.Error("Internal Server Error: ", err)
return c.Status(fiber.StatusInternalServerError).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Internal server error",
})
}
log.Error("Internal Server Error: ", err)
return c.Status(fiber.StatusInternalServerError).JSON(model.Response[any]{
Success: false,
Data: nil,
Message: "Internal server error",
})
}
return nil
}

View File

@@ -20,6 +20,10 @@ func FrontendMiddleware(c fiber.Ctx) error {
return c.Next()
}
if strings.HasPrefix(c.Path(), "/metrics") {
return c.Next()
}
path := c.Path()
file := "static" + path

View File

@@ -0,0 +1,21 @@
package middleware
import (
"nysoure/server/stat"
"github.com/gofiber/fiber/v3"
)
func StatMiddleware(c fiber.Ctx) error {
err := c.Next()
status := "200"
if err != nil {
if e, ok := err.(*fiber.Error); ok {
status = string(rune(e.Code))
} else {
status = "500"
}
}
stat.RecordRequest(c.Method(), c.Path(), status)
return err
}

View File

@@ -2,78 +2,31 @@ package model
import (
"errors"
"github.com/gofiber/fiber/v3"
)
type RequestError struct {
Message string `json:"message"`
func NewRequestError(message string) error {
return fiber.NewError(400, message)
}
func (e *RequestError) Error() string {
return e.Message
func NewUnAuthorizedError(message string) error {
return fiber.NewError(403, message)
}
func NewRequestError(message string) *RequestError {
return &RequestError{
Message: message,
}
}
func IsRequestError(err error) bool {
var requestError *RequestError
ok := errors.As(err, &requestError)
return ok
}
type UnAuthorizedError struct {
Message string `json:"message"`
}
func (e *UnAuthorizedError) Error() string {
return e.Message
}
func NewUnAuthorizedError(message string) *UnAuthorizedError {
return &UnAuthorizedError{
Message: message,
}
}
func IsUnAuthorizedError(err error) bool {
var unAuthorizedError *UnAuthorizedError
ok := errors.As(err, &unAuthorizedError)
return ok
}
type NotFoundError struct {
Message string `json:"message"`
}
func (e *NotFoundError) Error() string {
return e.Message
}
func NewNotFoundError(message string) *NotFoundError {
return &NotFoundError{
Message: message,
}
func NewNotFoundError(message string) error {
return fiber.NewError(404, message)
}
func IsNotFoundError(err error) bool {
var notFoundError *NotFoundError
ok := errors.As(err, &notFoundError)
return ok
}
type InternalServerError struct {
Message string `json:"message"`
}
func (e *InternalServerError) Error() string {
return e.Message
}
func NewInternalServerError(message string) *InternalServerError {
return &InternalServerError{
Message: message,
var fiberError *fiber.Error
ok := errors.As(err, &fiberError)
if !ok {
return false
}
return fiberError.Code == 404
}
func NewInternalServerError(message string) error {
return fiber.NewError(500, message)
}

52
server/stat/stat.go Normal file
View File

@@ -0,0 +1,52 @@
package stat
import (
prom "github.com/prometheus/client_golang/prometheus"
)
var (
RequestCount = prom.NewCounterVec(
prom.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"path", "status"},
)
RegisterCount = prom.NewCounterVec(
prom.CounterOpts{
Name: "register_requests_total",
Help: "Total number of registration requests",
},
[]string{},
)
DownloadCount = prom.NewCounterVec(
prom.CounterOpts{
Name: "download_requests_total",
Help: "Total number of download requests",
},
[]string{},
)
)
func init() {
prom.MustRegister(RequestCount)
prom.MustRegister(RegisterCount)
prom.MustRegister(DownloadCount)
}
func RecordRequest(method, path string, status string) {
if status == "404" {
// Aggregate all 404s under a single label
path = "NOT_FOUND"
}
path = method + " " + path
RequestCount.WithLabelValues(path, status).Inc()
}
func RecordRegister() {
RegisterCount.WithLabelValues().Inc()
}
func RecordDownload() {
DownloadCount.WithLabelValues().Inc()
}