GithubHelp home page GithubHelp logo

gofiber / contrib Goto Github PK

View Code? Open in Web Editor NEW
192.0 3.0 98.0 2.34 MB

๐Ÿงฌ Repository for third party middlewares with dependencies

Home Page: https://docs.gofiber.io/contrib/

License: MIT License

Go 99.93% Dockerfile 0.07%
middleware golang hacktoberfest

contrib's Introduction

contrib's People

Contributors

antoniodipinto avatar arsmn avatar behzad-khokher avatar bndrmrtn avatar danielalvarenga avatar dependabot[bot] avatar efectn avatar efumagal avatar emanuelef avatar gaby avatar gzuidhof avatar jamess-lucass avatar jcyamacho avatar jictyvoo avatar joffref avatar kaptinlin avatar kohnalex avatar ledex avatar max-cheng avatar mstryoda avatar onematchfox avatar piyongcai-liucai avatar raphielscape avatar renewerner87 avatar sixcolors avatar skyenought avatar t0jc avatar willfaught avatar wlun001 avatar ziyaozclk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

contrib's Issues

OTel: use semconv functions for filling out attributes

Currently, otel middleware add all the attributes manually.
I think it's better to use semconv functions for cases when fasthttp.Request is compatible with http.Request because this will automatically add all recommended attributes. This is easier to maintain because following spec requires semconv package update only.

Besides, I think it should use SpanStatusFromHTTPStatusCodeAndSpanKind instead of SpanStatusFromHTTPStatusCode

๐Ÿ› [Bug]: i18n middleware panics

Bug Description

While running multiple requests in parallel fiber panics due to i18n translations. Of course it can be handled with recover package but this is not ideal in my case.

panic: runtime error: slice bounds out of range [:-1]

goroutine 63 [running]:
github.com/valyala/fasthttp.releaseArg(...)
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/args.go:469
github.com/valyala/fasthttp.(*Args).ParseBytes(0x1400028a200, {0x0?, 0x140004218b8?, 0x104cf4fc8?})
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/args.go:102 +0x30c
github.com/valyala/fasthttp.(*URI).parseQueryArgs(...)
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/uri.go:895
github.com/valyala/fasthttp.(*URI).QueryArgs(...)
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/uri.go:887
github.com/valyala/fasthttp.(*RequestCtx).QueryArgs(0x1400028a000)
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/server.go:989 +0x4c
github.com/gofiber/fiber/v2.(*Ctx).Query(0x1400044e000, {0x104d29384, 0x4}, {0x0, 0x0, 0x0?})
        /Users/kacper/go/pkg/mod/github.com/gofiber/fiber/[email protected]/ctx.go:1050 +0x38
github.com/gofiber/contrib/fiberi18n.defaultLangHandler(0x860086?, {0x104d48450, 0x2})
        /Users/kacper/go/pkg/mod/github.com/gofiber/contrib/[email protected]/config.go:82 +0x40
github.com/gofiber/contrib/fiberi18n.GetMessage({0x104e186a0?, 0x104e98b50})
        /Users/kacper/go/pkg/mod/github.com/gofiber/contrib/[email protected]/i18n.go:101 +0x78
github.com/gofiber/contrib/fiberi18n.MustGetMessage(...)
        /Users/kacper/go/pkg/mod/github.com/gofiber/contrib/[email protected]/i18n.go:83
main.main.func1(0x1400044e000)
        /Users/kacper/GolandProjects/i18nbugfix/main.go:20 +0x30
github.com/gofiber/fiber/v2.(*App).next(0x14000080d80, 0x1400044e000)
        /Users/kacper/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:144 +0x184
github.com/gofiber/fiber/v2.(*Ctx).Next(0x14000028488?)
        /Users/kacper/go/pkg/mod/github.com/gofiber/fiber/[email protected]/ctx.go:909 +0x5c
github.com/gofiber/contrib/fiberi18n.New.func1(0x104e343c0?)
        /Users/kacper/go/pkg/mod/github.com/gofiber/contrib/[email protected]/i18n.go:31 +0x78
github.com/gofiber/fiber/v2.(*App).next(0x14000080d80, 0x1400044e000)
        /Users/kacper/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:144 +0x184
github.com/gofiber/fiber/v2.(*App).handler(0x14000080d80, 0x104c69dc0?)
        /Users/kacper/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:171 +0x74
github.com/valyala/fasthttp.(*Server).serveConn(0x140001c6000, {0x104e9e838?, 0x1400048e180})
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/server.go:2363 +0xdd0
github.com/valyala/fasthttp.(*workerPool).workerFunc(0x140000d2fa0, 0x14000068360)
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:224 +0x70
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:196 +0x38
created by github.com/valyala/fasthttp.(*workerPool).getCh
        /Users/kacper/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:195 +0x220

How to Reproduce

Steps to reproduce the behavior:

  1. Run server
  2. Run command ab -n 10000 -c 50 http://127.0.0.1:3000/ few times (just wait for each of it to finish)

Expected Behavior

Program should work and return translated response without panicking

Contrib package Version

v1.0.0

Code Snippet (optional)

package main

import (
	"github.com/gofiber/contrib/fiberi18n"
	"github.com/gofiber/fiber/v2"
	"golang.org/x/text/language"
)

func main() {
  app := fiber.New()
	app.Use(
		fiberi18n.New(&fiberi18n.Config{
			RootPath:         "./localize",
			AcceptLanguages:  []language.Tag{language.English, language.Polish},
			FormatBundleFile: "json",
			DefaultLanguage:  language.English,
		}),
	)
	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString(fiberi18n.MustGetMessage("hello"))
	})

	app.Listen("127.0.0.1:3000")
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

How to get client's real ip?

image

When make a remote request to my Gofiber endpoint, it gives http.client_ip = 10.8.11.189, which is container's local ip, but in Rust version of opentelemetry, used with Actix Web, it gives my real public ip out there, how can I make Gofiber's otel show public client ip?

Otel v1.15.1 breaking changes

image
I've tried updating to latest commit (as of today, it's feaa1ed), but it's not able to build due to the following errors, but I've seen the dependabots updated all the otel modules to v1.15.1 and passed GitHub Actions tests in this repo, I wonder why mine is not working?

image

๐Ÿš€ [Feature]: otelfiber - Propergate tracing headers in outbound response

Feature Description

When using the otelfiber middleware it would be nice to propergate the tracing headers to the outbound response in order to unify tracing across the call-chain. It would be needed to inject the coresponding headers from the TextMapPropagator, similar to the code snippet below.

This is already done in the limiter middleware for propergating the X-Ratelimit* headers (also see https://github.com/gofiber/fiber/blob/master/middleware/limiter/limiter_fixed.go#L100-L102).

Additional Context (optional)

No response

Code Snippet (optional)

func AddTracingHeadersToContext(ctx *fiber.Ctx) {
	var tracingHeader = make(propagation.HeaderCarrier)
	otel.GetTextMapPropagator().Inject(ctx.UserContext(), tracingHeader)

	for _, headerKey := range tracingHeader.Keys() {
		ctx.Set(headerKey, tracingHeader.Get(headerKey))
	}
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

Otelfiber should change how to deal with the Authorization header.

When otelfiber is checking the Authorization header it will always panic if the provided header doesn't have at least 5 of length.

Normally this is acceptable, but to prevent a unnecessary panic, we should check the length first and return "", false if the length is invalid.

fiber.go:128

	// Decode the header contents
	raw, err := base64.StdEncoding.DecodeString(auth[6:])
	if err != nil {
		return "", false
	}

๐Ÿš€ [Feature]: Casbin: Allow users to use other types of Enforcers

Feature Description

Currently, Casbin supports multiple types of Enforcer:

  • Enforcer
  • SyncedEnforcer
  • CachedEnforcer
  • SyncedCachedEnforcer
  • DistributedEnforcer

This doesn't deviate from the core functionalities of the Enforcer, which is described in the interface IEnforcer. The types of enforcers acts as a decorator to the actual Enforcer. As such, users should be able to use the middleware with other types of Enforcer.

Additional Context (optional)

No response

Code Snippet (optional)

package main

import (
	c "github.com/casbin/casbin/v2"
	"github.com/gofiber/contrib/casbin"
	"github.com/gofiber/fiber/v2"
)

func main() {
	enforcer, _ := c.NewEnforcer("path/to/basic_model.conf", "path/to/basic_policy.csv")
	//enforcer, _ := c.NewSyncedEnforcer("path/to/basic_model.conf", "path/to/basic_policy.csv") // This fails, but it should work.
	return casbin.New(casbin.Config{
		Enforcer: enforcer,
		Lookup: func(c *fiber.Ctx) string {
			claims, ok := c.UserContext().Value(model.AuthContextKey).(*model.AuthClaims)
			if !ok {
				logger.Error(nil, "failed to get auth claims")
				return ""
			}
			return claims.Role
		},
		Unauthorized: func(c *fiber.Ctx) error {
			return model.Response(c, http.StatusUnauthorized)
		},
		Forbidden: func(c *fiber.Ctx) error {
			return model.Response(c, http.StatusForbidden)
		},
	})
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

๐Ÿš€ [Feature]: Add ability to ignore health checks in otelfiber

Feature Description

Something that was done for fiberzap but for otelfiber: #272

Additional Context (optional)

No response

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

fiberi18n error on concurrent requests

Hi team!

I have an issue. When there are many concurrent requests to our system, fiberi18n throws error like this

[2023-05-16T04:55:32.634958995Z] 57398fb9-da68-4ea2-b008-51da27c5a0ab:: 200  -  GET      /threads 7.703849ms -โ€‹
fatal error: concurrent map writes
fatal error: concurrent map writes

goroutine 172 [running]:
github.com/gofiber/contrib/fiberi18n.New.func1(0xc0002282c0)
	/go/pkg/mod/github.com/gofiber/contrib/[email protected]/i18n.go:42 +0x209
github.com/gofiber/fiber/v2.(*App).next(0xc0001b8480, 0xc0002282c0)
	/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:134 +0x1b6
github.com/gofiber/fiber/v2.(*App).handler(0xc0001b8480, 0x4cc317?)
	/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:160 +0x87
github.com/valyala/fasthttp.(*Server).serveConn(0xc00054c200, {0xf7e6f8?, 0xc0000aa1b0})
	/go/pkg/mod/github.com/valyala/[email protected]/server.go:2371 +0x11d3
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc000539720, 0xc0000c0b60)
	/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:224 +0xa9
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
	/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:196 +0x38
created by github.com/valyala/fasthttp.(*workerPool).getCh
	/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:195 +0x1b0

goroutine 1 [IO wait, 1 minutes]:
internal/poll.runtime_pollWait(0x7fb9247119b8, 0x72)
	/usr/local/go/src/runtime/netpoll.go:306 +0x89
internal/poll.(*pollDesc).wait(0xc0004ad100?, 0x4?, 0x0)
	/usr/local/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/local/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Accept(0xc0004ad100)
	/usr/local/go/src/internal/poll/fd_unix.go:614 +0x2bd
net.(*netFD).accept(0xc0004ad100)
	/usr/local/go/src/net/fd_unix.go:172 +0x35
net.(*TCPListener).accept(0xc0004c5950)
	/usr/local/go/src/net/tcpsock_posix.go:148 +0x25
net.(*TCPListener).Accept(0xc0004c5950)
	/usr/local/go/src/net/tcpsock.go:297 +0x3d
github.com/valyala/fasthttp.acceptConn(0xc00054c200, {0xf7a710, 0xc0004c5950}, 0xc0006938b8)
	/go/pkg/mod/github.com/valyala/[email protected]/server.go:1930 +0x62
github.com/valyala/fasthttp.(*Server).Serve(0xc00054c200, {0xf7a710?, 0xc0004c5950})
	/go/pkg/mod/github.com/valyala/[email protected]/server.go:1823 +0x4f4
github.com/gofiber/fiber/v2.(*App).Listen(0xc0001b8480, {0xe3e28a?, 0xd52f40?})
	/go/pkg/mod/github.com/gofiber/fiber/[email protected]/listen.go:82 +0x110
main.main()
	/build/cmd/api/api.go:119 +0x357

My code implemented:

app.Use(
		fiberi18n.New(&fiberi18n.Config{
			RootPath:        "./localize",
			AcceptLanguages: []language.Tag{language.Vietnamese, language.English},
			DefaultLanguage: language.English,
		}),
	)
 msg := fiberi18n.MustGetMessage("successfully")

Please help me to solve this problem.

SkipURIs: route parameter support

In fiberzaplog, fiberzerolog middleware, the configuration item SkipURIs only supports equal to comparison. In fact, many routes have parameters, for URL with routing parameters, cannot be effectively excluded by SkipURIs.

All, SkipURIs need to be set to a regular expression or other routing matching pattern to effectively solve this problem.

I hope this feature will be realized soon.

thanks.

๐Ÿค— [Question]: otelfiber + otelmongo spans are not being grouped correctly

Question Description

I recently added Opentelemetry to a project I'm involved in. My setup includes using Zipkin as the collector and Fiber (otelfiber) and MongoDB (otelmongo) instrumentation to automate the capturing of their information. However, I've been facing an issue where the generated spans are not correctly setting the Parent ID, resulting in a lack of grouping for this information.

To ease the reproduction of this behavior, I've put together a simple code. In this code, I've launched two webservers: one using the Gin framework and the other utilizing Fiber. Both servers are configured to perform trace information collection.

As a result, requests directed to the Gin service generate spans grouped correctly. However, for requests to the Fiber service, the spans are not being grouped, leading to the situation I mentioned.

zipkin

I would like to express my gratitude in advance for any guidance, suggestions, or insights that could be shared to assist in resolving this behavior. If anyone has encountered a similar situation or has any tips, I would be grateful for your contribution.

Code Snippet (optional)

to reproduce the error:
// Clone repo
https://github.com/marcelobiao/gofiber-otel-issues

// run local containers
$task run 

// In the browser:
Gin server:
http://localhost:8080/todo
Fiber server:
http://localhost:8081/todo

// Access Zipkin Client:
http://localhost:9411

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

Otel: add ability to override span name

Use case: we use session middleware. When some middleware interrupts request processing before any handler invocation, the span name is always / which is not informative and leads to grouping of all operations ended by any middleware.
Suggestion: Fiber supports names for routes. The instrumentation could check c.Route().Name and if it's not empty, then use it as a span name instead of c.Route().Path

Opentelemetry - read baggage

Hi, are there any changes needs to be done to read the telemetry baggage?
so we would have full flow between services?

currently, if call comes to the server, from a different server which is also using opentelemetry, we cannot see this relation

thanks!

Error is not returned from otelfiber.Middleware() handler

The middleware returned from otelfiber.Middleware() always returns nil, even if the next middleware in the stack returned an error.

When using multiple middlewares together, this can prevent a middleware earlier in the stack from also having access to the error. This is undesirable, for example, if an earlier-added logging middleware should also log the error (and which is outside of the fiber application's configured ErrorHandler).

[Improvement]: ๐Ÿš€๐Ÿ“’ Sync documentation with our docs repository

Currently in fiber we have a mechanism that synchronizes the documentation into the docs repository.
https://github.com/gofiber/fiber/blob/master/.github/workflows/sync-docs.yml ->
https://github.com/gofiber/fiber/tree/master/docs ->
https://github.com/gofiber/docs

The idea is to have a similar process that provides further versioned documentation for the other packages and extends the documentation page, besides the core documentation with the documentation about these packages.
https://github.com/gofiber/contrib ->
https://docusaurus.io/docs/next/docs-multi-instance#versioned-and-unversioned-doc

This will also make them more present and more enhancements, bugfixes or similar improvements can be expected

Open Policy Agent middleware

Hi, is it be useful to add OPA as middleware?

So in this way, we can add various policies as middleware like JWT authorization. WDYT?

New version of go.opentelemetry.io/otel/sdk/metric ( v.035.0 ) breaks

New version of opentelemetry-go/metric v.035.0, breaks this library.

../../../../go/pkg/mod/github.com/gofiber/contrib/[email protected]/fiber.go:55:35: meter.SyncFloat64 undefined (type metric.Meter has no field or method SyncFloat64)
../../../../go/pkg/mod/github.com/gofiber/contrib/[email protected]/fiber.go:59:38: meter.SyncInt64 undefined (type metric.Meter has no field or method SyncInt64)
../../../../go/pkg/mod/github.com/gofiber/contrib/[email protected]/fiber.go:63:39: meter.SyncInt64 undefined (type metric.Meter has no field or method SyncInt64)
../../../../go/pkg/mod/github.com/gofiber/contrib/[email protected]/fiber.go:67:41: meter.SyncInt64 undefined (type metric.Meter has no field or method SyncInt64)

๐Ÿค— [Question]: Otelfiber - How to set span status to Error on panic?

Question Description

I've been using otel-fiber for a while, and I've noticed that by editing the fiber.go (around line 123) file in this way, I can set the main span status to error:

if err := c.Next(); err != nil {
	span.RecordError(err)
	span.SetStatus(codes.Error, err.Message) //<-- added this line
			
	// invokes the registered HTTP error handler
	// to get the correct response status code
	_ = c.App().Config().ErrorHandler(c, err)
}

Now, this solution works every time there is an error returned, but clearly not when there is a panic inside the handler function or one of the sub-functions, since no error is returned from the handler. I checked with breaks in debug mode, and the program never enters the if statemen, so the span is not set to Error.
What sounds strange is that the error is still recorded and logged as "event" in the span, and i can find it in the Uptrace application, with all the exception-related info, even if span.RecordError(err) is (apparently) never called.

Can anyone explain this behavior? I'm sure I'm missing something.

Is worth noting that i am using the recover middleware, in this order:

router.Use(logger.New())
router.Use(recover.New())
router.Use(cors.New())
router.Use(otelfiber.Middleware())

Thanks

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

๐Ÿ› [Bug]: I have upgraded i18n/v2, but there will still be problems.

Bug Description

Because I started with air, I can see the specific panic information only when the project stops.
The contents are as follows:

panic: interface conversion: interface {} is nil, not *fiberi18n.Config

goroutine 6396 [running]:
github.com/gofiber/contrib/fiberi18n/v2.Localize(0x0?, {0x192c520?, 0xc00231f6f0})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/contrib/fiberi18n/[email protected]/i18n.go:106 +0x2cc
github.com/gofiber/contrib/fiberi18n/v2.MustLocalize(...)
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/contrib/fiberi18n/[email protected]/i18n.go:85
github.com/biuaxia/crawling_FLiNGTrainer/pkg/i18n.Msg(0x9045ff?, {0x1a0f386, 0xf})
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/pkg/i18n/i18n.go:11 +0x33
github.com/biuaxia/crawling_FLiNGTrainer/pkg/resp.(*Resp).Build(0xc00231f910)
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/pkg/resp/resp.go:76 +0x3f
github.com/biuaxia/crawling_FLiNGTrainer/bootstrap.NewApplication.func2(0xc004080300, {0x1ca21a0, 0xc00029eb70})
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/bootstrap/bootstrap.go:109 +0xe49
github.com/gofiber/fiber/v2.(*App).ErrorHandler(0xc0004d0a00, 0xc004080300, {0x1ca21a0, 0xc00029eb70})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/fiber/[email protected]/app.go:1061 +0x1ff
github.com/gofiber/fiber/v2.(*App).serverErrorHandler(0xc0004d0a00, 0xc00231fc20?, {0x1ca3460, 0xc008fff590})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/fiber/[email protected]/app.go:1093 +0x2fb
github.com/valyala/fasthttp.(*Server).writeErrorResponse(0xc0002a6c00?, 0x0, 0xc001601800, {0x0, 0x0}, {0x1ca3460?, 0xc008fff590?})
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/server.go:2850 +0x57
github.com/valyala/fasthttp.(*Server).serveConn(0xc0002a6c00, {0x1ca93c0?, 0xc002afbc00})
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/server.go:2285 +0x1de5
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc0002b0500, 0xc002f83580)
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:224 +0xa4
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:196 +0x32
created by github.com/valyala/fasthttp.(*workerPool).getCh in goroutine 1
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:195 +0x1ab
panic: interface conversion: interface {} is nil, not *fiberi18n.Config

goroutine 6331 [running]:
github.com/gofiber/contrib/fiberi18n/v2.Localize(0x0?, {0x192c520?, 0xc001ac16f0})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/contrib/fiberi18n/[email protected]/i18n.go:106 +0x2cc
github.com/gofiber/contrib/fiberi18n/v2.MustLocalize(...)
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/contrib/fiberi18n/[email protected]/i18n.go:85
github.com/biuaxia/crawling_FLiNGTrainer/pkg/i18n.Msg(0x9045ff?, {0x1a0f386, 0xf})
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/pkg/i18n/i18n.go:11 +0x33
github.com/biuaxia/crawling_FLiNGTrainer/pkg/resp.(*Resp).Build(0xc001ac1910)
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/pkg/resp/resp.go:76 +0x3f
github.com/biuaxia/crawling_FLiNGTrainer/bootstrap.NewApplication.func2(0xc004080000, {0x1ca21a0, 0xc00029eb70})
        C:/Users/Administrator/GolandProjects/crawling_FLiNGTrainer/bootstrap/bootstrap.go:109 +0xe49
github.com/gofiber/fiber/v2.(*App).ErrorHandler(0xc0004d0a00, 0xc004080000, {0x1ca21a0, 0xc00029eb70})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/fiber/[email protected]/app.go:1061 +0x1ff
github.com/gofiber/fiber/v2.(*App).serverErrorHandler(0xc0004d0a00, 0xc001ac1c20?, {0x1ca3460, 0xc00051b680})
        C:/Users/Administrator/go/pkg/mod/github.com/gofiber/fiber/[email protected]/app.go:1093 +0x2fb
github.com/valyala/fasthttp.(*Server).writeErrorResponse(0xc0002a6c00?, 0x0, 0xc005f81800, {0x0, 0x0}, {0x1ca3460?, 0xc00051b680?})
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/server.go:2850 +0x57
github.com/valyala/fasthttp.(*Server).serveConn(0xc0002a6c00, {0x1ca93c0?, 0xc002901c00})
        C:/Users/Administrator/go/pkg/mod/github.com/valyala/[email protected]/server.go:2285 +0x1de5

This is the error message from fiber.Config 's ErrorHandler before I stopped the project:

2023-09-07 09:35:55     WARN    bootstrap/bootstrap.go:93       ErrorHandler    {"marshalString": "{\"error\":{\"code\":502,\"message\":\"Bad Gateway\"},\"errorMsg\":\"Bad Gateway\",\"exception\":{\"protocol\":\"https\",\"port\":\"62080\",\"route\":\"/\",\"resBody\":null,\"ips\":\"\",\"ua\":\"\",\"bytesSent\":0,\"queryParams\":\"\",\"requestid\":null,\"ip\":\"127.0.0.1\",\"host\":\"\",\"path\":\"/\",\"url\":\"/\",\"bytesReceived\":0,\"referer\":\"\",\"body\":\"{}\",\"reqHeaders\":{}}}"}
2023-09-07 09:35:55     WARN    bootstrap/bootstrap.go:93       ErrorHandler    {"marshalString": "{\"error\":{\"code\":502,\"message\":\"Bad Gateway\"},\"errorMsg\":\"Bad Gateway\",\"exception\":{\"body\":\"{}\",\"bytesReceived\":0,\"resBody\":null,\"requestid\":null,\"protocol\":\"https\",\"ua\":\"\",\"reqHeaders\":{},\"port\":\"61938\",\"path\":\"/\",\"bytesSent\":0,\"route\":\"/\",\"queryParams\":\"\",\"ips\":\"\",\"host\":\"\",\"url\":\"/\",\"referer\":\"\",\"ip\":\"127.0.0.1\"}}"}

This is my code for using i18n:

package i18n

import (
	"github.com/duke-git/lancet/strutil"
	"github.com/gofiber/contrib/fiberi18n/v2"
	"github.com/gofiber/fiber/v2"
	"github.com/nicksnyder/go-i18n/v2/i18n"
)

func Msg(c *fiber.Ctx, key string) string {
	i18nMsg := fiberi18n.MustLocalize(c, key)
	if !strutil.IsBlank(i18nMsg) {
		return i18nMsg
	}
	return key
}

func MsgByTemplate(c *fiber.Ctx, msgKey string, msgParamMap map[string]string) string {
	params := &i18n.LocalizeConfig{
		MessageID:    msgKey,
		TemplateData: msgParamMap,
	}
	i18nMsg := fiberi18n.MustLocalize(c, params)
	if !strutil.IsBlank(i18nMsg) {
		return i18nMsg
	}

	return msgKey
}

Say hello to the maintainers of the entire open source software, and sincerely seek relevant solutions, if you need source code reproduction problems, you can provide an email, I will send it to you.

How to Reproduce

I'm not sure about the recurrence of this problem, which is usually caused by the use of the application process.

Expected Behavior

I want him to run normally, instead of staying in 502, and the whole application stops running completely.

Fiber Version

v2.49.1

Code Snippet (optional)

ErrorHandler:


ErrorHandler: func(c *fiber.Ctx, err error) error {
	var body map[string]any
	exceptionErr := c.BodyParser(&body)
	if exceptionErr != nil {
		body = make(map[string]any)
	}
	marshalBody, exceptionErr := encoder.Encode(body, encoder.SortMapKeys)
	if exceptionErr != nil {
		marshalBody = []byte(constant.ErrorDefaultMarshalBody)
	}
	exceptionMap := fiber.Map{
		constant.ErrorExceptionMapKeyForError:    err,
		constant.ErrorExceptionMapKeyForErrorMsg: err.Error(),
		constant.ErrorExceptionMapKeyForException: fiber.Map{
			constant.FiberRequestId: c.Locals(constant.FiberRequestId),

			logger.TagReferer:           c.Get(fiber.HeaderReferer),
			logger.TagProtocol:          c.Protocol(),
			logger.TagPort:              c.Port(),
			logger.TagIP:                c.IP(),
			logger.TagIPs:               c.Get(fiber.HeaderXForwardedFor),
			logger.TagHost:              c.Hostname(),
			logger.TagPath:              c.Path(),
			logger.TagURL:               c.OriginalURL(),
			logger.TagUA:                c.Get(fiber.HeaderUserAgent),
			logger.TagBody:              string(marshalBody),
			logger.TagBytesReceived:     len(c.Request().Body()),
			logger.TagBytesSent:         len(c.Response().Body()),
			logger.TagRoute:             c.Route().Path,
			logger.TagResBody:           c.Response().Body(),
			logger.TagReqHeaders:        c.GetReqHeaders(),
			logger.TagQueryStringParams: c.Request().URI().QueryArgs().String(),
		},
	}
	marshalString, _ := sonic.MarshalString(exceptionMap)
	zap.L().Warn("ErrorHandler", zap.String("marshalString", marshalString))

	respData := resp.ERR(c).Data(exceptionMap)

	var e *fiber.Error
	if errors.As(err, &e) {
		if e.Code == fiber.StatusNotFound {
			return c.Status(fiber.StatusNotFound).SendString(i18n2.Msg(c, constant.I18N_RespPageNotFound))
		}
	}

	return respData.Build()
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

There should be an option to pass the existing NewRelic app without creating a new one

Greetings,

Currently, NewRelic middleware requires the configuration parameters to be passed and creates a new NewRelic application. However, on the project I am working on, I already have a NewRelic app and I use it some other places as well. I totally understand the basic-friendly approach, however, can we also have a function something like fibernewrelic.NewWithApp(app *newrelic.Application) that enables using the existing app? If so, I can start a PR that implements such a change.

๐Ÿค— [Question]: swagger yaml support?

Question Description

I'm using github.com/gofiber/contrib/swagger and would like to write my spec in yaml format.

// Use swagger 2.0 middleware
app.Use(swagger.New(swagger.Config{
    BasePath: "/",
    FilePath: "./swagger.yaml",
}))

This works but in the UI the link to the file is set as /swagger.json not /swagger.yaml this causes the validator to fail:

screenshot
(see lower right corner in the UI)

The second question I have is, how do I deal with multiple openapi yaml files? Can we use FilePath: "./spec/*?

Code Snippet (optional)

// Use swagger 2.0 middleware
app.Use(swagger.New(swagger.Config{
    BasePath: "/",
    FilePath: "./swagger.yaml",
}))

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

otelfiber: issue with Method

This line:

semconv.HTTPMethodKey.String(c.Method()),

is problematic in real use: the method may be sent asynchronously to a collector/monitoring service outside of the request scope. It results in this arriving on the other end:
Screenshot 2022-04-05 at 20 22 42

We should be making a copy of the method.

๐Ÿ› [Bug]: Swagger - not test-able (`./swagger.json` file does not exist)

Bug Description

Testing a function that provide swagger.Config struct (while swagger.json path is default) panics and returns

panic: ./swagger.json file does not exist

System works fine without testing

How to Reproduce

Steps to reproduce the behavior:

  1. Make sure swagger.json located in ./swagger.json
  2. Run the code snippet below
  3. Assert ProvideSwagger() not nil

Expected Behavior

TestSwagger should pass when ProvideSwagger() not nil

=== RUN   TestSwagger
--- PASS: TestSwagger (0.00s)
PASS

Contrib package Version

swagger/v1.1.0

Code Snippet (optional)

func ProvideSwagger() *swagger.Config {
  return &swagger.Config{
    FilePath: "./swagger.json",
  }
}

swag := ProvideSwagger()

func TestSwagger(t *testing.T) {
  assert.NotNil(t, swag)
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

๐Ÿš€ [Feature]: websocket middleware unit tests

Feature Description

Currently there is no unit tests for websocket middleware, I would like to add it.

Additional Context (optional)

No response

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

๐Ÿš€ [Feature]: HTMX component

Feature Description

htmx allows backend devs to build html based GUI using https://github.com/gofiber/template and then updating the html i the browser.

The core concept with HTMX is that you update the GUI from the backend sending html that then replaces a target html DOM. Its highly productive and fast. Then you do not need React, Vue and all those complex gui libs.

Visual Demo

You can see running examples here with source code: https://htmx.org/examples/

Golang examples

Here are a few golang examples:

https://github.com/donseba/go-htmx

https://github.com/livefir/fir

All you need is to include one js in your html page.

Additional Context (optional)

htmx (and hyperscript, alpinejs) too.

Code Snippet (optional)

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

newrelic middleware

Hi, I would like to add go newrelic as middleware to fiber if it feasible.

WDYT?

I will create a pr if it sounds feasible.

๐Ÿš€ [Feature]: expose the underlying FastHTTP upgrade error

Feature Description

Hi everyone,

Debugging websocket connection errors can be quite difficult in some scenarios and I was wondering whether it would be possible to expose the underlying Upgrade error.

I may be wrong but it does not seem to be possible to retrieve the error returned by the FastHTTP Upgrade function as the middleware always returns a ErrUpgradeRequired error.

https://github.com/gofiber/contrib/blob/main/websocket/websocket.go#L132

The idea is to add a new struct to wrap the original error

type UpgradeError struct {
	reason error
}

func (e *UpgradeError) Error() string {
	return fiber.ErrUpgradeRequired.Error()
}

func (e *UpgradeError) Unwrap() error {
	return e.reason
}

// ...

if err := upgrader.Upgrade(c.Context(), func(fconn *websocket.Conn) {
	conn.Conn = fconn
	defer releaseConn(conn)
	handler(conn)
}); err != nil { // Upgrading required
	return &UpgradeError{reason: err}
}

Users can then wrap the middleware with their own error handler

handleErrors(websocket.New(func(c *websocket.Conn) {})
func handleErrors(handler fiber.Handler) fiber.Handler {
	return func(c *fiber.Ctx) error {
		err := handler(c)

		var upgradeError *UpgradeError
		if errors.As(err, &upgradeError ) {
			lg.Println(upgradeError.Unwrap())
		}
		return err
	}
}

Hopefully my explanation makes sense. I'm happy to submit a pull request if you find this useful.

Thanks for the great work on fiber!

Additional Context (optional)

No response

Code Snippet (optional)

package main

import "github.com/gofiber/contrib/%package%"

func main() {
  // Steps to reproduce
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

๐Ÿš€ [Feature]: Stringify zerolog latency

Feature Description

Currently, zerolog latency uses Dur, which outputs raw duration value compared to other logging middlewares in fiber, changing it to String should make it in line with other logging behaviour.

Additional Context (optional)

No response

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

๐Ÿค— [Question]: Deprecation message opentelemetry

Question Description

Got this deprecation message:
SA1019: "go.opentelemetry.io/otel/oteltest" is deprecated: This package contains an alternate implementation of the OpenTelemetry SDK. This means it will diverge from the one commonly used in real world operations and therefore will not provide adequate testing guarantees for users. Because of this, this package should not be used to test performance or behavior of code running OpenTelemetry. Instead, the SpanRecorder from the go.opentelemetry.io/otel/sdk/trace/tracetest package can be registered with the default SDK (go.opentelemetry.io/otel/sdk/trace) as a SpanProcessor and used to test. This will ensure code will work with the default SDK. If users do not want to include a dependency on the default SDK it is recommended to run integration tests in their own module to isolate the dependency (see go.opentelemetry.io/otel/bridge/opencensus/test as an example).

https://pkg.go.dev/go.opentelemetry.io/otel/oteltest

This is the approach to use if moving to go.opentelemetry.io/otel/sdk/trace/tracetest
https://github.com/open-telemetry/opentelemetry-go/tree/main/bridge/opencensus/test

If this makes sense I can maybe prepare a PR for that.

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

๐Ÿค— [Question]: Must Websocket Locals be read-only?

Question Description

I notice that the Locals are read-only within the Websocket, and I was wonder if there is a reason for that?

I'm looking to persist user context through-out the length of the connection and was hoping to use Locals.

Would something like the below change be feasible? (I can submit a PR if so)

Code Snippet (optional)

// Locals makes it possible to pass interface{} values under string keys scoped to the request
// and therefore available to all following routes that match the request.
func (conn *Conn) Locals(key string, value ...interface{}) interface{} {
	if len(value) == 0 {
		return conn.locals[key]
	}
	conn.locals[key] = value[0]
	return value[0]
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

๐Ÿš€ [Feature]: fiberzap accepts custom fields

Feature Description

I'd like to have a custom field that are user defined zap.Fields.

  • For custom structured logging
  • To add user defined fields
  • Support different entry formats, etc.

Additional Context (optional)

Currently I have an client that want's http headers response into the logging file, that's post processed later. They want all headers, now the fiberzap doesn't have an option for it. Instead of just adding a "respHeaders" field it'll be more extensible to add a custom field that are user definied fields

Code Snippet (optional)

package main

import (
	"log"

	"github.com/gofiber/contrib/fiberzap/v2"
	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"
)

func main() {
	app := fiber.New()
	logger, _ := zap.NewProduction()

	app.Use(fiberzap.New(fiberzap.Config{
		Logger: logger,
		Fields: []string{"custom"},
		CustomFieldFunc: func(c *fiber.Ctx) []zap.Field {
			var fields []zap.Field

			headers := make(map[string]interface{})

			c.Response().Header.VisitAll(func(k, v []byte) {
				headers[string(k)] = string(v)
			})

			fields = append(fields, zap.Any("headers", headers))

			return fields
		},
	}))

	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("Hello, World!")
	})

	log.Fatal(app.Listen(":3000"))
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my suggestion prior to opening this one.
  • I understand that improperly formatted feature requests may be closed without explanation.

๐Ÿ› [Bug]: Updated struct `value` in `map` after `websoket` connection.

Bug Description

go version 1.20.6

Backend service with some endpoints without database. Three endpoints with working with http protocol and one with websoket.

image

If look at scheen in the end of the terminal cls.Rooms changed client id from test to m_te. I can't understand this behavior, because in all of the endpoints I don't have any domain logic that can change in cls.Rooms ClientID in Room struct. After some of time I realized that m_te is peace of RoomID. I don't have any idea how peace of RoomID that key in map replaced client id.

How to Reproduce

Steps to reproduce the behavior:

  1. Make POST request byregister url endpoint and didn't pass any input values in body.
  2. Make GET request by /rooms/:user_uuid url.
  3. Make POST request to create room struct in map and also didn't pass any values in http body.
  4. Make ws connection.

Expected Behavior

Data in Clients.Rooms map by key room_test after connection by ws client id should not changed.

Fiber Version

v2.49.0, ws - v2.2.1

Code Snippet (optional)

package main

import (
	"fmt"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/websocket/v2"
)

type Clients struct {
	Clients map[string]*Client
	Rooms   map[string]ClientRoom
}
type ClientRoom struct {
	RoomID   string `json:"roomId"`
	Name     string `json:"name"`
	ClientID string `json:"clientId"`
}
type Room struct {
	ID   string
	Name string
	JoinClients map[string]string
}
type Client struct {
	ID             string
	Rooms          map[string]*Room
	Username       string
}

func NewClients() *Clients {
	cls := &Clients{
		Clients: make(map[string]*Client),
		Rooms:   make(map[string]ClientRoom),
	}

	return cls
}

func NewClient(username, uuid string) *Client {

	c := &Client{
		ID:       uuid,
		Username: username,
		Rooms:    make(map[string]*Room),
	}

	return c
}

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

//Register
app.Post("/register", func(c *fiber.Ctx) error {
                id := "test"
                username := "username"
		client := NewClient(username, id)

		cls.Clients[id] = client

		fmt.Println("REGISTER", cls.Clients)
		fmt.Println("REGISTER", cls.Rooms)

		return c.Status(200).JSON(&fiber.Map{
			"success":    true,
			"clientUUID": client.ID,
			"username":   username,
		})
	})
	
//Just for create room
app.Post("/rooms/:user_uuid", func(c *fiber.Ctx) error {
		uuid := c.Params("user_uuid")

		cl := cls.Clients[uuid]
		id := "room_test"
		roomName := "room"
		r := &Room{
			ID:          id,
			Name:        roomName,
			JoinClients: make(map[string]string),
		}

		cl.Rooms[id] = r

		cls.Rooms[id] = ClientRoom{ClientID: uuid, RoomID: id, Name: roomName}

		fmt.Println("CREATE_ROOM", cls.Clients)
		fmt.Println("CREATE_ROOM", cls.Rooms)

		return c.Status(200).JSON(&fiber.Map{
			"success":  true,
			"roomUUID": id,
			"roomName": roomName,
		})
	})
	
//Get all rooms
app.Get("/rooms/:user_uuid", func(c *fiber.Ctx) error {
		fmt.Println("GET_ROOMS", cls.Clients)
		fmt.Println("GET_ROOMS", cls.Rooms)

		return c.Status(200).JSON(&fiber.Map{
			"success": true,
			"rooms":   []string{},
		})
	})
	
//Websocket
app.Get("/ws/:roomId", websocket.New(func(c *websocket.Conn) {
		defer func() {
			c.Close()
		}()

		fmt.Println("WS", cls.Clients)
		fmt.Println("WS", cls.Rooms)
	}))

log.Fatal(app.Listen(":3001"))
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

๐Ÿค— [Question]: When use `fiberzap` with `WithContext`, caller maybe not show properly. How do I change it๏ผŸ

Question Description

Run the code snippet, and the logging is as follows

{"level":"info","ts":1695283707.964828,"caller":"backend2/main.go:23","msg":">>>"}
{"level":"info","ts":1695283707.965184,"caller":"[email protected]/router.go:145","msg":"ready"}
{"level":"info","ts":1695283707.965214,"caller":"backend2/main.go:25","msg":"<<<"}

caller is [email protected]/router.go:145, but it is backend2/main.go:24 actually

Code Snippet (optional)

package main

import (
	"github.com/gofiber/contrib/fiberzap/v2"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/log"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	//setup.Init()

	app := fiber.New()
	log.SetLogger(fiberzap.NewLogger(fiberzap.LoggerConfig{
		ZapOptions: []zap.Option{
			zap.AddCaller(),
			zap.AddCallerSkip(3),
			zap.AddStacktrace(zapcore.PanicLevel),
		},
	}))
	app.Get("/ready", func(c *fiber.Ctx) error {
		log.Info(">>>")
		log.WithContext(c.UserContext()).Info("ready")
		log.Info("<<<")
		return c.SendString("ready")
	})
	err := app.Listen(":3000")
	if err != nil {
		log.Error(err)
		return
	}
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

OTel: add method to span name

Currently, otel middleware sets span name to route path. However, it's possible to register multiple routes with the same path but different methods. For example, POST /orders and GET /orders.
I believe, span name should include method along with path.

๐Ÿ› [Bug]: Can't close websocket connection

Bug Description

I want to close a websocket connection but nothing happens (no error etc.).
The client remains connected and can also send messages.

How to Reproduce

Steps to reproduce the behavior:

  1. Run the code below
  2. Connect to the server with a websocket client

Expected Behavior

The server should close the connection after 5 seconds

Contrib package Version

websocket/v1.1.0

Code Snippet (optional)

package main

import (
	"log"
	"time"

	"github.com/gofiber/contrib/websocket"
	"github.com/gofiber/fiber/v2"
)

func main() {
	app := fiber.New()
	app.Use("/ws", middleware)
	app.Get("/ws", websocket.New(handler))
	log.Fatal(app.Listen(":8080"))
}

func middleware(c *fiber.Ctx) error {
	if websocket.IsWebSocketUpgrade(c) {
		return c.Next()
	}
	return fiber.ErrUpgradeRequired
}

func handler(conn *websocket.Conn) {
	go func() {
		time.Sleep(5 * time.Second)
		if err := conn.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	for {
		_, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		log.Printf("msg: %s", msg)
	}
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

OTel: tracer name looks strange

It's recommended to set tracer name to the package name. However, currently, tracer name is go.opentelemetry.io/contrib/instrumentation/github.com/gofiber/fiber/otelfiber.

Perhaps, it should be github.com/gofiber/contrib/otelfiber

Otel: the instrumentation sets empty `http.server_name`

According to the spec:

This should be obtained via configuration. If no such configuration can be obtained, this attribute MUST NOT be set

However, this instrumentation always sets http.server_name even when the provided server name is empty

OTel: add metrics

OpenTelemetry metrics sdk is going to stabilize soon. It would be nice to add http metrics according to semconv

๐Ÿ› [Bug]: OTeL duplicate and wrong counter metrics are generated infinitely

Bug Description

I have raised a bug issue in opentelemetry-go SDK repository.

When using fiber to manually reporting request count with delta temporality, the server will keep reporting wrong attributes value and wrong datapoint size infinitely.

While using go http library or something else, everything work as expected so I got the right request count.

How to Reproduce

See my demo repository:

https://github.com/oliverdding/otel-test

Start with:

docker compose up -d --build

Or you can run go cmd program manually with:

docker compose up -d otel-collector

Expected Behavior

There should be ten datapoints, with app_id from 1 to 10.

Fiber Version

v2.49.2

Code Snippet (optional)

package main

import (
	"context"
	"fmt"
	"math/rand"
	"net/http"
	"os"
	"time"

	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
	"go.opentelemetry.io/otel/metric"
	sdkmetric "go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/metric/metricdata"
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var (
	logger *zap.Logger
)

func init() {
	var cfg zap.Config
	cfg = zap.NewDevelopmentConfig()

	// set time format
	cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.DateTime)
	// add color for console
	cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
	logger = zap.New(zapcore.NewCore(zapcore.NewConsoleEncoder(cfg.EncoderConfig), zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), zapcore.DebugLevel))
}

func preferDeltaTemporalitySelector(kind sdkmetric.InstrumentKind) metricdata.Temporality {
	switch kind {
	case sdkmetric.InstrumentKindCounter,
		sdkmetric.InstrumentKindObservableCounter,
		sdkmetric.InstrumentKindHistogram:
		return metricdata.DeltaTemporality
	default:
		return metricdata.CumulativeTemporality
	}
}

func initProvider(ctx context.Context) func() {
	res, err := resource.New(ctx,
		resource.WithFromEnv(),
		resource.WithProcess(),
		resource.WithTelemetrySDK(),
		resource.WithHost(),
		resource.WithAttributes(
			semconv.ServiceName("client"),
			semconv.ServiceNamespace("demo"),
			semconv.ServiceVersion("0.1.0"),
		),
	)
	if err != nil {
		logger.Fatal("failed to create resource", zap.Error(err))
	}

	otelAgentAddr, ok := os.LookupEnv("OTEL_EXPORTER_OTLP_ENDPOINT")
	if !ok {
		otelAgentAddr = "127.0.0.1:4317"
	}
	metricExp, err := otlpmetricgrpc.New(
		ctx,
		otlpmetricgrpc.WithInsecure(),
		otlpmetricgrpc.WithEndpoint(otelAgentAddr),
		otlpmetricgrpc.WithCompressor("gzip"),
		otlpmetricgrpc.WithTemporalitySelector(preferDeltaTemporalitySelector),
	)

	meterProvider := sdkmetric.NewMeterProvider(
		sdkmetric.WithResource(res),
		sdkmetric.WithReader(
			sdkmetric.NewPeriodicReader(
				metricExp,
				sdkmetric.WithInterval(2*time.Second),
			),
		),
	)
	otel.SetMeterProvider(meterProvider)

	return func() {
		cxt, cancel := context.WithTimeout(ctx, time.Second)
		defer cancel()
		// pushes any last exports to the receiver
		if err := meterProvider.Shutdown(cxt); err != nil {
			otel.Handle(err)
		}
	}
}

var (
	rng       = rand.New(rand.NewSource(time.Now().UnixNano()))
	meter     metric.Meter
	appIDList = []string{"1024", "568", "106", "1025", "197"}
)

func main() {
	ctx := context.Background()
	otelShutdownHook := initProvider(ctx)
	defer otelShutdownHook()

	meter = otel.Meter("demo-server")

	requestLatency, _ := meter.Float64Histogram(
		"demo_client/request_latency",
		metric.WithDescription("The latency of requests processed"),
	)

	requestCount, _ := meter.Int64Counter(
		"demo_client/request_counts",
		metric.WithDescription("The number of requests processed"),
	)

	for {
		appID := appIDList[rng.Intn(len(appIDList))]
		startTime := time.Now()
		makeHelloRequest(ctx, appID)
		latencyMs := float64(time.Since(startTime)) / 1e6
		requestLatency.Record(ctx, latencyMs, metric.WithAttributes(attribute.String("interface", "hello"), attribute.String("app_id", appID)))
		requestCount.Add(ctx, 1, metric.WithAttributes(attribute.String("interface", "hello"), attribute.String("app_id", appID)))

		fmt.Printf("Latency: %.3fms\n", latencyMs)
		time.Sleep(time.Duration(1) * time.Second)

	}
}

func makeHelloRequest(ctx context.Context, appID string) {
	demoServerAddr, ok := os.LookupEnv("DEMO_SERVER_ENDPOINT")
	if !ok {
		demoServerAddr = "0.0.0.0:2333"
	}

	// Trace an HTTP client by wrapping the transport
	client := http.Client{
		Transport: otelhttp.NewTransport(http.DefaultTransport),
	}

	// Make sure we pass the context to the request to avoid broken traces.
	req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://%s/hello/%s", demoServerAddr, appID), nil)
	if err != nil {
		logger.Fatal("failed to create request", zap.Error(err))
	}

	// All requests made with this client will create spans.
	res, err := client.Do(req)
	if err != nil {
		logger.Fatal("failed to execute request", zap.Error(err))
	}
	res.Body.Close()
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

๐Ÿค— [Question]: Swagger - Support for openapi v3?

Question Description

Is there support for the openapi standard v3? When I try to load a openapi v3 spec it fails

screenshot

I can see that the latest version of swagger-ui is being used as the bundle link is https://unpkg.com/[email protected]/swagger-ui-bundle.js which shows version 5.3.1 of swagger-ui. So I would expect openapi v3 to work. Maybe this problem is related to the default file name of swagger.json?

Code Snippet (optional)

openapi: 3.0.0
info:
  version: 1.0.0
  title: Simple API Example
  description: A basic API example for testing Swagger UI

paths:
  /greet:
    get:
      summary: Get a friendly greeting
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                message: Hello, Swagger UI!

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.

๐Ÿ› [Bug]: Websocket middleware is not compatible with Recover middleware

Bug Description

Hi team!
I have an issue. Websocket middleware is not compatible with Recover middleware.
If panic happens in websocket handler, process will quit.

Possible reason:
In this code block, websocket middleware reigsters a handler to FastHTTPUpgrader.

        if err := upgrader.Upgrade(c.Context(), func(fconn *websocket.Conn) {
            conn.Conn = fconn
            defer releaseConn(conn)
            handler(conn)
        }); err != nil { // Upgrading required
            return fiber.ErrUpgradeRequired
        }

FastHTTPUpgrader also registers a HijackHandler.

func (u *FastHTTPUpgrader) Upgrade(ctx *fasthttp.RequestCtx, handler FastHTTPHandler) error {
        // ....
	ctx.Hijack(func(netConn net.Conn) {
                // ....
		handler(c)
                // ....
	})
        // ....
	return nil
}

FastHttp runs hijackConnHandler in a new goroutine. If a panic occurs within this goroutine, the Recover middleware is unable to catch it.

func (s *Server) serveConn(c net.Conn) (err error) {
        // ....
	if hijackHandler != nil {
                // ....
		go hijackConnHandler(ctx, hjr, c, s, hijackHandler)
                // ....
	}
        // ....
}

How to Reproduce

func main() {
	app := fiber.New()
	app.Use(recover.New(recover.Config{EnableStackTrace: true}))

	app.Get("/foo", websocket.New(func(c *websocket.Conn) {
		panic("foo")
	}))

	_ = app.Listen(":3000")
}

Expected Behavior

panic: foo
goroutine 20 [running]:
main.main.func1(0x6b8daf?)
        /home/leo/project/main.go:16 +0x27
github.com/gofiber/contrib/websocket.New.func2.5(0x0?)
        /home/leo/go/pkg/mod/github.com/gofiber/contrib/[email protected]/websocket.go:130 +0x75
github.com/fasthttp/websocket.(*FastHTTPUpgrader).Upgrade.func1({0x9cf848, 0xc0000961e0})
        /home/leo/go/pkg/mod/github.com/fasthttp/[email protected]/server_fasthttp.go:201 +0x1bf
github.com/valyala/fasthttp.hijackConnHandler(0x0?, {0x9cb180?, 0xc00009c060}, {0x9cf950, 0xc000090008}, 0xc00027e800, 0xc0000a2100)
        /home/leo/go/pkg/mod/github.com/valyala/[email protected]/server.go:2505 +0x68
created by github.com/valyala/fasthttp.(*Server).serveConn
        /home/leo/go/pkg/mod/github.com/valyala/[email protected]/server.go:2460 +0x1c1c

Contrib package Version

websocket v1.0.0

Code Snippet (optional)

package main

import "github.com/gofiber/contrib/%package%"

func main() {
  // Steps to reproduce
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.

Prefix version tags with module names

According to https://go.dev/doc/modules/managing-source#multiple-module-source, when you have multiple modules in a single repository, version tags must have the module name as a prefix. Otherwise, attempting to use tagged versions would fail:

โฏ go get github.com/gofiber/contrib/[email protected]
go: module github.com/gofiber/[email protected] found, but does not contain package github.com/gofiber/contrib/fiberzap

Instead of having a single v1.0.1 tag, tag each module individually.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.