2015-02-26 19 views
8

Chcę utworzyć globalny program obsługi błędów, aby wysłać go pocztą e-mail.globalny moduł obsługi odzyskiwania dla golang http panic

package main 

import (
    "github.com/gorilla/mux" 
    "log" 
    "net/http" 
) 

func main() { 
    rtr := mux.NewRouter() 
    rtr.HandleFunc("/", withPanic).Methods("GET") 

    http.Handle("/", rtr) 
    log.Println("Listening...") 

    http.ListenAndServe(":3001", http.DefaultServeMux) 
} 

func withPanic(w http.ResponseWriter, r *http.Request) { 
    panic("somewhere here will be panic, but I don't know where exactly") 
} 

Jak zrobić to globalnie. Byłoby łatwo, gdybym wiedział, gdzie wystąpi błąd:

if err != nil { 
sendMeMail(err) 
} 

Ale co zrobić w przypadku, gdy nie wiem dokładnie, gdzie wystąpi błąd? Więc powinienem dodać globalny program obsługi ish z obsługą recover. Ale jak to zrobić dokładnie nie wiem.

Aktualizacja

dodałem defer recover do początku main ale nigdy nie wykonuje na zainteresowanie http://localhost:3001. Więc panika nie jest wysyłana pocztą elektroniczną.

package main 

import (
    "errors" 
    "fmt" 
    "github.com/gorilla/mux" 
    "log" 
    "net/http" 
) 

func main() { 
    defer func() { 
     if r := recover(); r != nil { 
      fmt.Println("Recovered in f", r) 
      // find out exactly what the error was and set err 
      var err error 
      switch x := r.(type) { 
      case string: 
       err = errors.New(x) 
      case error: 
       err = x 
      default: 
       err = errors.New("Unknown panic") 
      } 
      if err != nil { 
       // sendMeMail(err) 
       fmt.Println("sendMeMail") 
      } 
     } 
    }() 
    rtr := mux.NewRouter() 
    rtr.HandleFunc("/", withPanic).Methods("GET") 

    http.Handle("/", rtr) 
    log.Println("Listening...") 

    http.ListenAndServe(":3001", http.DefaultServeMux) 
} 

func withPanic(w http.ResponseWriter, r *http.Request) { 
    panic("somewhere here will be panic, but I don't know where exactly") 
} 

Odpowiedz

20

Można owinąć teleskopowe w middleware odzyskiwania

package main 

import (
    "errors" 
    "github.com/gorilla/mux" 
    "log" 
    "net/http" 
) 

func main() { 
    m := mux.NewRouter() 
    m.Handle("/", RecoverWrap(http.HandlerFunc(handler))).Methods("GET") 

    http.Handle("/", m) 
    log.Println("Listening...") 

    http.ListenAndServe(":3001", nil) 

} 

func handler(w http.ResponseWriter, r *http.Request) { 
    panic(errors.New("panicing from error")) 
} 

func RecoverWrap(h http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     var err error 
     defer func() { 
      r := recover() 
      if r != nil { 
       switch t := r.(type) { 
       case string: 
        err = errors.New(t) 
       case error: 
        err = t 
       default: 
        err = errors.New("Unknown error") 
       } 
       sendMeMail(err) 
       http.Error(w, err.Error(), http.StatusInternalServerError) 
      } 
     }() 
     h.ServeHTTP(w, r) 
    }) 
} 

func sendMeMail(err error) { 
    // send mail 
} 

Można wziąć spojrzeć na codahale recovery handler lub negroni middleware więcej szczegółów.

+1

e.Error() powinien być err.Error()? –

+0

naprawiono @eyeAppsLLC. – tarrsalah

+0

Naprawdę podoba mi się rozwiązanie, działa dla mnie :) – Danie