From a9d2f0556282ba8510cddb49ae120953e38d5462 Mon Sep 17 00:00:00 2001 From: nyne Date: Sun, 14 Dec 2025 14:11:33 +0800 Subject: [PATCH] feat: prometheus --- go.mod | 11 +++- go.sum | 38 ++++++++++- main.go | 4 ++ server/api/file.go | 3 + server/api/user.go | 2 + server/middleware/error_handler.go | 78 ++++------------------- server/middleware/frontend_middleware.go | 4 ++ server/middleware/stat_middleware.go | 21 ++++++ server/model/error.go | 81 +++++------------------- server/stat/stat.go | 52 +++++++++++++++ 10 files changed, 162 insertions(+), 132 deletions(-) create mode 100644 server/middleware/stat_middleware.go create mode 100644 server/stat/stat.go diff --git a/go.mod b/go.mod index 181d144..e92711e 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/RoaringBitmap/roaring v0.4.23 // indirect + github.com/beorn7/perks v1.0.1 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/mmap-go v1.0.2 // indirect github.com/blevesearch/segment v0.9.0 // indirect @@ -39,15 +40,22 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/golang/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.0 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mschoch/smat v0.2.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/steveyen/gtreap v0.1.0 // indirect github.com/willf/bitset v1.1.10 // indirect go.etcd.io/bbolt v1.3.5 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + google.golang.org/protobuf v1.36.8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -76,6 +84,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect github.com/philhofer/fwd v1.2.0 // indirect + github.com/prometheus/client_golang v1.23.2 github.com/tinylib/msgp v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.65.0 // indirect diff --git a/go.sum b/go.sum index fb18b48..02ac797 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06 github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blevesearch/bleve v1.0.14 h1:Q8r+fHTt35jtGXJUM0ULwM3Tzg+MRfyai4ZkWDy2xO4= github.com/blevesearch/bleve v1.0.14/go.mod h1:e/LJTr+E7EaoVdkQZTfoz7dt4KoDNvDbLb8MSKuNTLQ= github.com/blevesearch/blevex v1.0.0 h1:pnilj2Qi3YSEGdWgLj1Pn9Io7ukfXPoQcpAI1Bv8n/o= @@ -45,6 +47,7 @@ github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37g github.com/couchbase/vellum v1.0.2 h1:BrbP0NKiyDdndMPec8Jjhy0U47CZ0Lgx3xUC2r9rZqw= github.com/couchbase/vellum v1.0.2/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= @@ -83,13 +86,17 @@ github.com/gofiber/utils/v2 v2.0.0-rc.1/go.mod h1:Y1g08g7gvST49bbjHJ1AVqcsmg9391 github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a h1:l7A0loSszR5zHd/qK53ZIHMO8b3bBSmENnQ6eKnUT0A= github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -121,6 +128,12 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -139,6 +152,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -148,10 +163,20 @@ github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.17.0 h1:K6E+ZlYN95KSMmZeEQPbU/c++wfmEvfFB17yEAq/VhM= github.com/redis/go-redis/v9 v9.17.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -198,6 +223,10 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= @@ -223,8 +252,13 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 624ddf0..cd7b4f1 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,9 @@ import ( "nysoure/server/middleware" "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/adaptor" "github.com/gofiber/fiber/v3/middleware/logger" + prom "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { @@ -29,6 +31,8 @@ func main() { app.Use(middleware.FrontendMiddleware) + app.Get("/metrics", adaptor.HTTPHandler(prom.Handler())) + apiG := app.Group("/api") { api.AddUserRoutes(apiG) diff --git a/server/api/file.go b/server/api/file.go index ecee15c..6c45419 100644 --- a/server/api/file.go +++ b/server/api/file.go @@ -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)) } diff --git a/server/api/user.go b/server/api/user.go index 66e99df..65572af 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -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, diff --git a/server/middleware/error_handler.go b/server/middleware/error_handler.go index d81e5ee..eab20e5 100644 --- a/server/middleware/error_handler.go +++ b/server/middleware/error_handler.go @@ -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, ¬FoundErr) { - 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 } diff --git a/server/middleware/frontend_middleware.go b/server/middleware/frontend_middleware.go index d0d3757..04ba841 100644 --- a/server/middleware/frontend_middleware.go +++ b/server/middleware/frontend_middleware.go @@ -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 diff --git a/server/middleware/stat_middleware.go b/server/middleware/stat_middleware.go new file mode 100644 index 0000000..342f9a3 --- /dev/null +++ b/server/middleware/stat_middleware.go @@ -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 +} diff --git a/server/model/error.go b/server/model/error.go index a900403..f688ceb 100644 --- a/server/model/error.go +++ b/server/model/error.go @@ -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, ¬FoundError) - 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) } diff --git a/server/stat/stat.go b/server/stat/stat.go new file mode 100644 index 0000000..781e372 --- /dev/null +++ b/server/stat/stat.go @@ -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() +}