Merge pull request #394 from xiekeyang/feature-panic-hook
Feature: Add Hook for Web Application Panic
This commit is contained in:
commit
c703b9318e
3 changed files with 125 additions and 0 deletions
|
@ -9,6 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/configuration"
|
"github.com/docker/distribution/configuration"
|
||||||
ctxu "github.com/docker/distribution/context"
|
ctxu "github.com/docker/distribution/context"
|
||||||
|
@ -101,6 +102,7 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
|
||||||
|
|
||||||
app.configureEvents(&configuration)
|
app.configureEvents(&configuration)
|
||||||
app.configureRedis(&configuration)
|
app.configureRedis(&configuration)
|
||||||
|
app.configureLogHook(&configuration)
|
||||||
|
|
||||||
// configure storage caches
|
// configure storage caches
|
||||||
if cc, ok := configuration.Storage["cache"]; ok {
|
if cc, ok := configuration.Storage["cache"]; ok {
|
||||||
|
@ -291,6 +293,31 @@ func (app *App) configureRedis(configuration *configuration.Configuration) {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configureLogHook prepares logging hook parameters.
|
||||||
|
func (app *App) configureLogHook(configuration *configuration.Configuration) {
|
||||||
|
logger := ctxu.GetLogger(app).(*log.Entry).Logger
|
||||||
|
for _, configHook := range configuration.Log.Hooks {
|
||||||
|
if !configHook.Disabled {
|
||||||
|
switch configHook.Type {
|
||||||
|
case "mail":
|
||||||
|
hook := &logHook{}
|
||||||
|
hook.LevelsParam = configHook.Levels
|
||||||
|
hook.Mail = &mailer{
|
||||||
|
Addr: configHook.MailOptions.SMTP.Addr,
|
||||||
|
Username: configHook.MailOptions.SMTP.Username,
|
||||||
|
Password: configHook.MailOptions.SMTP.Password,
|
||||||
|
Insecure: configHook.MailOptions.SMTP.Insecure,
|
||||||
|
From: configHook.MailOptions.From,
|
||||||
|
To: configHook.MailOptions.To,
|
||||||
|
}
|
||||||
|
logger.Hooks.Add(hook)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.Context = ctxu.WithLogger(app.Context, logger)
|
||||||
|
}
|
||||||
|
|
||||||
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close() // ensure that request body is always closed.
|
defer r.Body.Close() // ensure that request body is always closed.
|
||||||
|
|
||||||
|
|
53
docs/handlers/hooks.go
Normal file
53
docs/handlers/hooks.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// logHook is for hooking Panic in web application
|
||||||
|
type logHook struct {
|
||||||
|
LevelsParam []string
|
||||||
|
Mail *mailer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire forwards an error to LogHook
|
||||||
|
func (hook *logHook) Fire(entry *logrus.Entry) error {
|
||||||
|
addr := strings.Split(hook.Mail.Addr, ":")
|
||||||
|
if len(addr) != 2 {
|
||||||
|
return errors.New("Invalid Mail Address")
|
||||||
|
}
|
||||||
|
host := addr[0]
|
||||||
|
subject := fmt.Sprintf("[%s] %s: %s", entry.Level, host, entry.Message)
|
||||||
|
|
||||||
|
html := `
|
||||||
|
{{.Message}}
|
||||||
|
|
||||||
|
{{range $key, $value := .Data}}
|
||||||
|
{{$key}}: {{$value}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
b := bytes.NewBuffer(make([]byte, 0))
|
||||||
|
t := template.Must(template.New("mail body").Parse(html))
|
||||||
|
if err := t.Execute(b, entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
body := fmt.Sprintf("%s", b)
|
||||||
|
|
||||||
|
return hook.Mail.sendMail(subject, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels contains hook levels to be catched
|
||||||
|
func (hook *logHook) Levels() []logrus.Level {
|
||||||
|
levels := []logrus.Level{}
|
||||||
|
for _, v := range hook.LevelsParam {
|
||||||
|
lv, _ := logrus.ParseLevel(v)
|
||||||
|
levels = append(levels, lv)
|
||||||
|
}
|
||||||
|
return levels
|
||||||
|
}
|
45
docs/handlers/mail.go
Normal file
45
docs/handlers/mail.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mailer provides fields of email configuration for sending.
|
||||||
|
type mailer struct {
|
||||||
|
Addr, Username, Password, From string
|
||||||
|
Insecure bool
|
||||||
|
To []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendMail allows users to send email, only if mail parameters is configured correctly.
|
||||||
|
func (mail *mailer) sendMail(subject, message string) error {
|
||||||
|
addr := strings.Split(mail.Addr, ":")
|
||||||
|
if len(addr) != 2 {
|
||||||
|
return errors.New("Invalid Mail Address")
|
||||||
|
}
|
||||||
|
host := addr[0]
|
||||||
|
msg := []byte("To:" + strings.Join(mail.To, ";") +
|
||||||
|
"\r\nFrom: " + mail.From +
|
||||||
|
"\r\nSubject: " + subject +
|
||||||
|
"\r\nContent-Type: text/plain\r\n\r\n" +
|
||||||
|
message)
|
||||||
|
auth := smtp.PlainAuth(
|
||||||
|
"",
|
||||||
|
mail.Username,
|
||||||
|
mail.Password,
|
||||||
|
host,
|
||||||
|
)
|
||||||
|
err := smtp.SendMail(
|
||||||
|
mail.Addr,
|
||||||
|
auth,
|
||||||
|
mail.From,
|
||||||
|
mail.To,
|
||||||
|
[]byte(msg),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in a new issue