1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-01-23 11:14:48 +02:00
2018-11-14 19:41:16 +06:00

126 lines
3.4 KiB
Go

package honeybadger
import (
"net/http"
"strings"
)
// The Payload interface is implemented by any type which can be handled by the
// Backend interface.
type Payload interface {
toJSON() []byte
}
// The Backend interface is implemented by the server type by default, but a
// custom implementation may be configured by the user.
type Backend interface {
Notify(feature Feature, payload Payload) error
}
type noticeHandler func(*Notice) error
// Client is the manager for interacting with the Honeybadger service. It holds
// the configuration and implements the public API.
type Client struct {
Config *Configuration
context *contextSync
worker worker
beforeNotifyHandlers []noticeHandler
}
// Configure updates the client configuration with the supplied config.
func (client *Client) Configure(config Configuration) {
client.Config.update(&config)
}
// SetContext updates the client context with supplied context.
func (client *Client) SetContext(context Context) {
client.context.Update(context)
}
// Flush blocks until the worker has processed its queue.
func (client *Client) Flush() {
client.worker.Flush()
}
// BeforeNotify adds a callback function which is run before a notice is
// reported to Honeybadger. If any function returns an error the notification
// will be skipped, otherwise it will be sent.
func (client *Client) BeforeNotify(handler func(notice *Notice) error) {
client.beforeNotifyHandlers = append(client.beforeNotifyHandlers, handler)
}
// Notify reports the error err to the Honeybadger service.
func (client *Client) Notify(err interface{}, extra ...interface{}) (string, error) {
extra = append([]interface{}{client.context.internal}, extra...)
notice := newNotice(client.Config, newError(err, 2), extra...)
for _, handler := range client.beforeNotifyHandlers {
if err := handler(notice); err != nil {
return "", err
}
}
workerErr := client.worker.Push(func() error {
if err := client.Config.Backend.Notify(Notices, notice); err != nil {
return err
}
return nil
})
if workerErr != nil {
client.Config.Logger.Printf("worker error: %v\n", workerErr)
return "", workerErr
}
return notice.Token, nil
}
// Monitor automatically reports panics which occur in the function it's called
// from. Must be deferred.
func (client *Client) Monitor() {
if err := recover(); err != nil {
client.Notify(newError(err, 2))
client.Flush()
panic(err)
}
}
// Handler returns an http.Handler function which automatically reports panics
// to Honeybadger and then re-panics.
func (client *Client) Handler(h http.Handler) http.Handler {
if h == nil {
h = http.DefaultServeMux
}
fn := func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
client.Notify(newError(err, 2), Params(r.Form), getCGIData(r), *r.URL)
panic(err)
}
}()
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// New returns a new instance of Client.
func New(c Configuration) *Client {
config := newConfig(c)
worker := newBufferedWorker(config)
client := Client{
Config: config,
worker: worker,
context: newContextSync(),
}
return &client
}
func getCGIData(request *http.Request) CGIData {
cgiData := CGIData{}
replacer := strings.NewReplacer("-", "_")
for k, v := range request.Header {
key := "HTTP_" + replacer.Replace(strings.ToUpper(k))
cgiData[key] = v[0]
}
return cgiData
}