Skip to content
Open
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
32 changes: 32 additions & 0 deletions .github/workflows/test-prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "Test Prometheus"

on:
push:
branches:
- main
paths:
- 'v3/prometheus/**/*.go'
- 'v3/prometheus/go.mod'
pull_request:
paths:
- 'v3/prometheus/**/*.go'
- 'v3/prometheus/go.mod'
Comment on lines +9 to +13

Copilot AI Apr 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow only triggers on changes to Go files and go.mod, but dependency-only updates can be done by modifying go.sum. Consider including v3/prometheus/go.sum in the workflow paths filters so CI still runs when module dependencies change.

Suggested change
- 'v3/prometheus/go.mod'
pull_request:
paths:
- 'v3/prometheus/**/*.go'
- 'v3/prometheus/go.mod'
- 'v3/prometheus/go.mod'
- 'v3/prometheus/go.sum'
pull_request:
paths:
- 'v3/prometheus/**/*.go'
- 'v3/prometheus/go.mod'
- 'v3/prometheus/go.sum'

Copilot uses AI. Check for mistakes.

jobs:
Tests:
runs-on: ubuntu-latest
strategy:
matrix:
go-version:
- 1.25.x
- 1.26.x
steps:
- name: Fetch Repository
uses: actions/checkout@v6
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: '${{ matrix.go-version }}'
- name: Run Test
working-directory: ./v3/prometheus
run: go test -v -race ./...
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Repository for third party middlewares and service implementations, with depende
* [loadshed](./v3/loadshed/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+loadshed%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-loadshed.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="loadshed workflow status" /> </a>
* [new relic](./v3/newrelic/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+newrelic%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-newrelic.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="new relic workflow status" /> </a>
* [monitor](./v3/monitor/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+Monitor%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-monitor.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="monitor workflow status" /> </a>
* [prometheus](./v3/prometheus/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+Prometheus%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-prometheus.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="prometheus workflow status" /> </a>
* [open policy agent](./v3/opa/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+opa%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-opa.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="OPA workflow status" /> </a>
* [otel (opentelemetry)](./v3/otel/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+otel%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-otel.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="otel workflow status" /> </a>
* [paseto](./v3/paseto/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+paseto%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-paseto.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="paseto workflow status" /> </a>
Expand Down
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use (
./v3/opa
./v3/otel
./v3/paseto
./v3/prometheus
./v3/sentry
./v3/socketio
./v3/swaggerui
Expand Down
1 change: 1 addition & 0 deletions v3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Repository for third party middlewares and service implementations, with depende
* [loadshed](./loadshed/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+loadshed%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-loadshed.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="loadshed workflow status" /> </a>
* [new relic](./newrelic/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+newrelic%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-newrelic.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="new relic workflow status" /> </a>
* [monitor](./monitor/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+Monitor%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-monitor.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="monitor workflow status" /> </a>
* [prometheus](./prometheus/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+Prometheus%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-prometheus.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="prometheus workflow status" /> </a>
* [open policy agent](./opa/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+opa%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-opa.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="OPA workflow status" /> </a>
* [otel (opentelemetry)](./otel/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+otel%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-otel.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="otel workflow status" /> </a>
* [paseto](./paseto/README.md) <a href="https://github.com/gofiber/contrib/actions?query=workflow%3A%22Test+paseto%22"> <img src="https://img.shields.io/github/actions/workflow/status/gofiber/contrib/test-paseto.yml?branch=main&label=%F0%9F%A7%AA%20&style=flat&color=75C46B" alt="paseto workflow status" /> </a>
Expand Down
106 changes: 106 additions & 0 deletions v3/prometheus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Prometheus

Prometheus middleware for [Fiber v3](https://github.com/gofiber/fiber) based on [ansrivas/fiberprometheus](https://github.com/ansrivas/fiberprometheus).

![Release](https://img.shields.io/github/release/ansrivas/fiberprometheus.svg)
[![Discord](https://img.shields.io/badge/discord-join%20channel-7289DA)](https://gofiber.io/discord)

Following metrics are available by default:

```text
http_requests_total
http_requests_status_class_total
http_request_duration_seconds
http_requests_in_progress
http_request_size_bytes
http_response_size_bytes
```

`http_requests_in_progress` exposes both the HTTP method and normalized
route path so you can pinpoint which handlers are currently running.

> [!NOTE]
> The middleware requires Go 1.25 or newer and Fiber v3 (currently RC).
Comment thread
gaby marked this conversation as resolved.

## 🚀 Installation

```bash
go get github.com/gofiber/contrib/v3/prometheus
```

## 📄 Example

```go
package main

import (
fiberprometheus "github.com/gofiber/contrib/v3/prometheus"
"github.com/gofiber/fiber/v3"
)

func main() {
app := fiber.New()

app.Use("/metrics", fiberprometheus.New(fiberprometheus.Config{
Service: "my-service-name",
SkipURIs: []string{"/ping"},
IgnoreStatusCodes: []int{401, 403, 404},
}))

Comment on lines +44 to +49

Copilot AI Apr 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example mounts the middleware only at /metrics (app.Use("/metrics", ...)). With Fiber's path-based middleware, that would generally only run for /metrics requests, so it won't instrument other routes unless the handler is also registered as a global middleware. Consider updating the example to show registering the returned handler twice (global + metrics path), or clarify explicitly how to mount it so it both instruments traffic and serves the scrape endpoint.

Suggested change
app.Use("/metrics", fiberprometheus.New(fiberprometheus.Config{
Service: "my-service-name",
SkipURIs: []string{"/ping"},
IgnoreStatusCodes: []int{401, 403, 404},
}))
prometheus := fiberprometheus.New(fiberprometheus.Config{
Service: "my-service-name",
SkipURIs: []string{"/ping"},
IgnoreStatusCodes: []int{401, 403, 404},
})
app.Use(prometheus)
app.Use("/metrics", prometheus)

Copilot uses AI. Check for mistakes.
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello World")
})

app.Get("/ping", func(c fiber.Ctx) error {
return c.SendString("pong")
})

app.Post("/some", func(c fiber.Ctx) error {
return c.SendString("Welcome!")
})

app.Listen(":3000")
}
```
Comment on lines +41 to +64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Fiber v3, does app.Use("/prefix", handler) execute the handler for requests outside that prefix?

💡 Result:

No, in Fiber v3, app.Use("/prefix", handler) does not execute the handler for requests outside that prefix. The prefix limits the middleware/handler to paths that begin with the specified prefix, with stricter matching requiring an exact match or slash boundary (e.g., "/api" matches "/api" and "/api/users" but not "/apiv2").

Citations:


🏁 Script executed:

# Find the Prometheus test files to verify the double-mount pattern claim
find . -path "*/prometheus/*" -name "*.go" -o -name "*.md" | head -20

Repository: gofiber/contrib

Length of output: 522


🏁 Script executed:

# Also check the README.md file location and content
find . -path "*/prometheus/README.md"

Repository: gofiber/contrib

Length of output: 85


🏁 Script executed:

# Search for newAppWithMiddleware to verify the double-mount pattern
rg "newAppWithMiddleware" --type go

Repository: gofiber/contrib

Length of output: 2137


🏁 Script executed:

# Extract the newAppWithMiddleware function implementation
sed -n '/^func newAppWithMiddleware/,/^}/p' v3/prometheus/prometheus_test.go

Repository: gofiber/contrib

Length of output: 315


🏁 Script executed:

# Now check the README.md file around line 91 and the example code
cat -n v3/prometheus/README.md | sed -n '85,100p'

Repository: gofiber/contrib

Length of output: 1053


🏁 Script executed:

# Check the indentation of the README example (lines 41-64)
cat -n v3/prometheus/README.md | sed -n '41,65p'

Repository: gofiber/contrib

Length of output: 836


Example only mounts at /metrics — other routes won't be instrumented.

The example uses app.Use("/metrics", handler) which, in Fiber v3, limits the middleware to requests under the /metrics prefix only. Requests to /, /ping, and /some never reach the middleware, so:

  • No counters/histograms/in-flight metrics are recorded for any application route.
  • Service, SkipURIs, and IgnoreStatusCodes in the example are effectively dead options.
  • /metrics would expose only the Go/process collectors.

The test suite's newAppWithMiddleware (prometheus_test.go) registers the handler twice: app.Use(handler) for global instrumentation, then app.Use(metricsPath, handler) for the metrics endpoint. The README must follow the same pattern.

Additionally, lines 93–96 claim the middleware "continues to instrument all routed traffic," which is false given the single prefix-mount behavior. Line 91 also incorrectly states "All of the options default to false" when RequestDurationBuckets, RequestSizeBuckets, and ResponseSizeBuckets have explicit numeric array defaults (lines 86–89).

📝 Suggested example fix
 func main() {
         app := fiber.New()

-	app.Use("/metrics", fiberprometheus.New(fiberprometheus.Config{
+	prom := fiberprometheus.New(fiberprometheus.Config{
 		Service:           "my-service-name",
 		SkipURIs:          []string{"/ping"},
 		IgnoreStatusCodes: []int{401, 403, 404},
-	}))
+	})
+
+	// Instrument every request.
+	app.Use(prom)
+	// Expose the metrics endpoint at /metrics.
+	app.Use("/metrics", prom)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func main() {
app := fiber.New()
app.Use("/metrics", fiberprometheus.New(fiberprometheus.Config{
Service: "my-service-name",
SkipURIs: []string{"/ping"},
IgnoreStatusCodes: []int{401, 403, 404},
}))
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello World")
})
app.Get("/ping", func(c fiber.Ctx) error {
return c.SendString("pong")
})
app.Post("/some", func(c fiber.Ctx) error {
return c.SendString("Welcome!")
})
app.Listen(":3000")
}
```
func main() {
app := fiber.New()
prom := fiberprometheus.New(fiberprometheus.Config{
Service: "my-service-name",
SkipURIs: []string{"/ping"},
IgnoreStatusCodes: []int{401, 403, 404},
})
// Instrument every request.
app.Use(prom)
// Expose the metrics endpoint at /metrics.
app.Use("/metrics", prom)
app.Get("/", func(c fiber.Ctx) error {
return c.SendString("Hello World")
})
app.Get("/ping", func(c fiber.Ctx) error {
return c.SendString("pong")
})
app.Post("/some", func(c fiber.Ctx) error {
return c.SendString("Welcome!")
})
app.Listen(":3000")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v3/prometheus/README.md` around lines 41 - 64, The README example mounts the
Prometheus middleware only at "/metrics" using app.Use("/metrics", ...), which
prevents instrumentation of other routes; change the example to register the
middleware globally (call app.Use(handler) with the fiberprometheus middleware
returned by fiberprometheus.New(...)) and then separately mount the metrics
endpoint (app.Use("/metrics", handler) or similar) so application routes ("/",
"/ping", "/some") are instrumented and metrics are exposed; also update the
prose that currently claims the middleware "continues to instrument all routed
traffic" to reflect that instrumentation only occurs when the middleware is
registered globally and correct the statement that "All of the options default
to `false`" to list the actual numeric defaults for RequestDurationBuckets,
RequestSizeBuckets, and ResponseSizeBuckets as shown in the config.


### Collector, OpenMetrics, and response options

The middleware exposes Prometheus collector toggles and `HandlerOpts` via
`Config`. By default it creates a private `Registerer`/`Gatherer` pair and uses
that for both registration and scraping. When customizing the registry, ensure
that the `Registerer` and `Gatherer` refer to the same metrics source (for
example, a `*prometheus.Registry`). Supplying only one that does not implement
the other interface or providing a mismatched pair will cause initialization to
panic so metrics are not silently dropped.

- `DisableGoCollector` disables the default Go runtime metrics collector when set to `true`.
- `DisableProcessCollector` disables the default process metrics collector when set to `true`.

- `EnableOpenMetrics` negotiates the experimental OpenMetrics encoding so exemplars are exported.
- `EnableOpenMetricsTextCreatedSamples` adds synthetic `_created` samples when OpenMetrics is enabled.
- `DisableCompression` disables gzip/zstd compression even when clients request it.

- `TrackUnmatchedRequests` records metrics for requests that miss all registered routes using `UnmatchedRouteLabel` as the path label. Defaults to `false`.
- `UnmatchedRouteLabel` customizes the path label applied to unmatched requests when tracking is enabled. Defaults to `/__unmatched__`.

- `RequestDurationBuckets`, `RequestSizeBuckets`, and `ResponseSizeBuckets` customize the histogram buckets used for latency and payload metrics. They default to:
- Duration: `[0.005 0.01 0.025 0.05 0.075 0.1 0.25 0.5 0.75 1 2.5 5 10 15 30 60]`
- Request size: `[256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 5242880]`
- Response size: `[256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 5242880]`

All of the options default to `false` and can be enabled or disabled individually as needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inaccurate defaults statement.

The bullets immediately above this line include UnmatchedRouteLabel (defaults to /__unmatched__), RequestDurationBuckets, RequestSizeBuckets, and ResponseSizeBuckets (all non-false defaults), so "All of the options default to false" is incorrect and contradicts the surrounding text.

📝 Proposed wording
-All of the options default to `false` and can be enabled or disabled individually as needed.
+All boolean toggles default to `false` and can be enabled individually as needed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v3/prometheus/README.md` at line 91, The sentence "All of the options default
to `false`" is incorrect — update the README text to accurately state that some
options default to false while others have non-false defaults; explicitly
mention the exceptions by name (UnmatchedRouteLabel defaults to
`/__unmatched__`, and RequestDurationBuckets, RequestSizeBuckets,
ResponseSizeBuckets have non-false default bucket values) or reword to "Most
options default to `false`; the following have non-false defaults:
UnmatchedRouteLabel, RequestDurationBuckets, RequestSizeBuckets,
ResponseSizeBuckets" so the statement no longer contradicts the bullets.


The metrics endpoint path is derived from how the middleware is mounted. In the
example above, calling `app.Use("/metrics", fiberprometheus.New(...))` exposes
the handler at `/metrics` while the middleware continues to instrument all
routed traffic.

## 📊 Result

- Hit the default url at http://localhost:3000
- Navigate to http://localhost:3000/metrics
- Metrics are recorded only for routes registered with Fiber unless `TrackUnmatchedRequests` is enabled, in which case unmatched requests are labeled with `UnmatchedRouteLabel`.

## 📈 Grafana Dashboard

- https://grafana.com/grafana/dashboards/14331
187 changes: 187 additions & 0 deletions v3/prometheus/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package prometheus

import (
"strings"

"github.com/gofiber/fiber/v3"
"github.com/prometheus/client_golang/prometheus"
)

// Config defines the middleware configuration.
type Config struct {
// Service is added as the `service` const label on every metric.
//
// Optional. Default: "" (label omitted).
Service string

// Namespace prefixes every metric name.
//
// Optional. Default: "http".
Namespace string

// Subsystem prefixes every metric name after Namespace.
//
// Optional. Default: "".
Subsystem string

// Labels are attached to every metric.
//
// Optional. Default: no labels.
Labels prometheus.Labels

// Registerer is used to register metrics.
//
// Optional. Default: a private registry.
Registerer prometheus.Registerer

// Gatherer provides metrics to the HTTP handler.
//
// Optional. Default: a private registry/gatherer pair created when neither
// Registerer nor Gatherer is supplied. If only one is provided, it must also
// implement the other interface or the middleware will panic to prevent
// silently omitting metrics.
Gatherer prometheus.Gatherer

// DisableGoCollector disables the Go runtime metrics collector registration.
//
// Optional. Default: false (collector enabled).
DisableGoCollector bool

// DisableProcessCollector disables the process metrics collector registration.
//
// Optional. Default: false (collector enabled).
DisableProcessCollector bool

// RequestDurationBuckets configures the histogram buckets used for request
// latency metrics. Provide nil to use the defaults.
//
// Optional. Default: []float64{0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 10, 15, 30, 60}.
RequestDurationBuckets []float64

// RequestSizeBuckets configures the histogram buckets used for request
// payload size metrics. Provide nil to use the defaults.
//
// Optional. Default: []float64{256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 5242880}.
RequestSizeBuckets []float64

// ResponseSizeBuckets configures the histogram buckets used for response
// payload size metrics. Provide nil to use the defaults.
//
// Optional. Default: []float64{256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 5242880}.
ResponseSizeBuckets []float64

// TrackUnmatchedRequests toggles metrics for requests that do not resolve to a
// registered Fiber route.
//
// Optional. Default: false.
TrackUnmatchedRequests bool

// UnmatchedRouteLabel is the path label used when TrackUnmatchedRequests is
// enabled and a request does not match a registered route.
//
// Optional. Default: "/__unmatched__".
UnmatchedRouteLabel string

// EnableOpenMetrics exposes the experimental OpenMetrics encoding.
//
// Optional. Default: false.
EnableOpenMetrics bool

// EnableOpenMetricsTextCreatedSamples adds synthetic `_created` samples to
// OpenMetrics responses.
//
// Optional. Default: false.
EnableOpenMetricsTextCreatedSamples bool

// DisableCompression prevents gzip compression of metrics responses, even when
// requested by the client (both gzip and zstd).
//
// Optional. Default: false.
DisableCompression bool

// SkipURIs excludes matching routes from instrumentation.
//
// Optional. Default: none.
SkipURIs []string

// IgnoreStatusCodes excludes matching response status codes from metrics.
//
// Optional. Default: none.
IgnoreStatusCodes []int

// Next skips the middleware when it returns true.
//
// Optional. Default: nil.
Next func(fiber.Ctx) bool
}

var (
defaultRequestDurationBuckets = []float64{0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 10, 15, 30, 60}
defaultRequestSizeBuckets = []float64{256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 5242880}
defaultResponseSizeBuckets = []float64{256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 5242880}
)

// ConfigDefault holds the default middleware configuration.
var ConfigDefault = Config{
Namespace: "http",
UnmatchedRouteLabel: "/__unmatched__",
RequestDurationBuckets: defaultRequestDurationBuckets,
RequestSizeBuckets: defaultRequestSizeBuckets,
ResponseSizeBuckets: defaultResponseSizeBuckets,
}

func configDefault(config ...Config) Config {
if len(config) == 0 {
cfg := ConfigDefault
cfg.Labels = make(prometheus.Labels)
cfg.RequestDurationBuckets = append([]float64(nil), ConfigDefault.RequestDurationBuckets...)
cfg.RequestSizeBuckets = append([]float64(nil), ConfigDefault.RequestSizeBuckets...)
cfg.ResponseSizeBuckets = append([]float64(nil), ConfigDefault.ResponseSizeBuckets...)
return cfg
}

cfg := config[0]

if cfg.Namespace == "" {
cfg.Namespace = ConfigDefault.Namespace
}

if cfg.UnmatchedRouteLabel == "" {
cfg.UnmatchedRouteLabel = ConfigDefault.UnmatchedRouteLabel
} else {
cfg.UnmatchedRouteLabel = strings.Clone(cfg.UnmatchedRouteLabel)
}

if cfg.RequestDurationBuckets == nil {
cfg.RequestDurationBuckets = append([]float64(nil), ConfigDefault.RequestDurationBuckets...)
} else {
cfg.RequestDurationBuckets = append([]float64(nil), cfg.RequestDurationBuckets...)
}

if cfg.RequestSizeBuckets == nil {
cfg.RequestSizeBuckets = append([]float64(nil), ConfigDefault.RequestSizeBuckets...)
} else {
cfg.RequestSizeBuckets = append([]float64(nil), cfg.RequestSizeBuckets...)
}

if cfg.ResponseSizeBuckets == nil {
cfg.ResponseSizeBuckets = append([]float64(nil), ConfigDefault.ResponseSizeBuckets...)
} else {
cfg.ResponseSizeBuckets = append([]float64(nil), cfg.ResponseSizeBuckets...)
}

if cfg.Labels == nil {
cfg.Labels = make(prometheus.Labels)
} else {
labels := make(prometheus.Labels, len(cfg.Labels))
for key, value := range cfg.Labels {
labels[key] = value
}
cfg.Labels = labels
}

cfg.SkipURIs = append([]string(nil), cfg.SkipURIs...)
cfg.IgnoreStatusCodes = append([]int(nil), cfg.IgnoreStatusCodes...)

return cfg
}
41 changes: 41 additions & 0 deletions v3/prometheus/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module github.com/gofiber/contrib/v3/prometheus

go 1.25.0
Comment thread
gaby marked this conversation as resolved.

require (
github.com/gofiber/fiber/v3 v3.0.0-rc.3
github.com/gofiber/utils/v2 v2.0.0-rc.3
github.com/prometheus/client_golang v1.23.2
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
)

require (
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gofiber/schema v1.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/philhofer/fwd v1.2.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/tinylib/msgp v1.5.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.68.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/crypto v0.44.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)
Loading
Loading