bugsnag-go icon indicating copy to clipboard operation
bugsnag-go copied to clipboard

Example with go-chi

Open josemarluedke opened this issue 6 years ago • 7 comments

Can we have a example to setup bugsnag with go-chi?

josemarluedke avatar Mar 17 '19 00:03 josemarluedke

Anyone?

josemarluedke avatar Mar 26 '19 21:03 josemarluedke

Hi @josemarluedke, thanks for requesting this. I've made a note internally to confirm support for chi and if so to put together an example project. It could be some time until we get around to it as we have lots of higher priority things to do at the moment. Thanks for your patience!

bengourley avatar Mar 27 '19 10:03 bengourley

Any news on this?

josemarluedke avatar Apr 12 '19 18:04 josemarluedke

I think it's unlikely we will get to it any time in the near future as we are working on other things at the moment. Sorry I can't be more helpful right now!

snmaynard avatar Apr 12 '19 23:04 snmaynard

As go-chi is just a router, you can very easily get it up and running with yourrouter.Use(bugsnag.Handler) like in the example:

package main

import (
	"net/http"

	"github.com/bugsnag/bugsnag-go/v2"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := chi.NewRouter()
	r.Use(bugsnag.Handler) // <- here, make sure it's the first one on the chain
	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})

	http.ListenAndServe(":3333", r)
}

Note that you can't use chi's provided middleware.Recoverer as it will bury errors and prevent Bugsnag from capturing them.

jmonteiro avatar Jan 05 '22 01:01 jmonteiro

Edit

Default middleware only captures panics, but not errors that are returned to the user. Wrote a quick middlware, that captures panics and http errors >404:

note: since the error is created in the middleware itself, the stacktrace will always be the same. I plan to attach errors to the context and get them out in the defer statement.

package server

import (
	"fmt"
	"net/http"

	"github.com/bugsnag/bugsnag-go/v2"
	"github.com/go-chi/chi/v5/middleware"
)

func ErrorHandler(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		request := r
		ctx := bugsnag.StartSession(r.Context())
		defer bugsnag.AutoNotify(ctx) // capture panics
		ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)

		defer func() {
			status := ww.Status()
			if status > 404 { // capture http errors
				bugsnag.Notify(fmt.Errorf("%s %s returned %d", r.Method, r.URL, status), request)
			}
		}()

		next.ServeHTTP(ww, r.WithContext(ctx))
	}
	return http.HandlerFunc(fn)
}

Just panics:

I needed to wrap the handler (it was taking an extra variable). This worked for me:

package main

import (
	"net/http"

	"github.com/bugsnag/bugsnag-go/v2"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := chi.NewRouter()
	r.Use(func(next http.Handler) http.Handler { return bugsnag.Handler(next) }) // <- here, make sure it's the first one on the chain
	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})

	http.ListenAndServe(":3333", r)
}

jpoz avatar Aug 24 '23 19:08 jpoz