Skip to content

Instantly share code, notes, and snippets.

@mojocn
Created June 2, 2020 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mojocn/4c1196f144a18bd5a9fe20becde33837 to your computer and use it in GitHub Desktop.
Save mojocn/4c1196f144a18bd5a9fe20becde33837 to your computer and use it in GitHub Desktop.
logrus email hook
package common
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/mail"
"net/smtp"
"strconv"
"time"
"github.com/sirupsen/logrus"
)
//Logger 可以使用这个logger 也可直接使用logrus
var Logger = logrus.New()
//SetLogger 初始化logrus 同时把logrus的logger var 引用到这个common.Logger
func SetLogger(cfg Config, verbose bool) error {
//logFileName := fmt.Sprintf("app.gin.%s.%s.log", cfg.Web.Name, time.Now().Format("20060102T15"))
//
//f, err := os.Create(logFileName)
//if err != nil {
// return err
//}
logLvl, err := logrus.ParseLevel(cfg.LogLevel)
if err != nil {
return err
}
logrus.SetLevel(logLvl)
logrus.SetReportCaller(true)
//logrus.SetFormatter(&logrus.JSONFormatter{})
//使用console默认输出
if (cfg.Env == "dev" || cfg.Env == "test") && cfg.Mail.Host != "" {
hook, err := newMailAuthHook(cfg.Web.Name, cfg.Mail.Host, cfg.Mail.Port, cfg.Mail.Limit, cfg.Mail.User, cfg.Mail.User, cfg.Mail.Password, cfg.Mail.Receivers)
if err != nil {
return err
}
logrus.AddHook(hook)
}
//logrus.SetOutput(f)
//logrus.SetReportCaller(verbose)
Logger = logrus.StandardLogger()
return nil
}
const (
format = "20060102 15:04:05"
)
// mailHook to sends logs by email with authentication.
type mailHook struct {
appName string
emailHost string
emailPort int
emailFrom *mail.Address
emailTos []string
emailUserName string
emailPassword string
buff *bytes.Buffer
count int
limit int
}
// newMailAuthHook creates a hook to be added to an instance of logger.
func newMailAuthHook(app string, host string, port, limit int, from string, username string, password string, to []string) (*mailHook, error) {
// Check if server listens on that port.
conn, err := net.DialTimeout("tcp", host+":"+strconv.Itoa(port), 3*time.Second)
if err != nil {
return nil, err
}
defer conn.Close()
// Validate sender and recipient
sender, err := mail.ParseAddress(from)
if err != nil {
return nil, err
}
for _, v := range to {
_, err := mail.ParseAddress(v)
if err != nil {
return nil, fmt.Errorf("%s 不是有效的邮箱:%s", v, err)
}
}
return &mailHook{
appName: app,
emailHost: host,
emailPort: port,
emailFrom: sender,
emailTos: to,
emailUserName: username,
emailPassword: password,
buff: bytes.NewBufferString(""),
limit: limit,
count: 0,
}, nil
}
// Fire is called when a log event is fired.
func (hook *mailHook) Fire(entry *logrus.Entry) error {
if hook.count < hook.limit {
hook.storeError(entry)
return nil
}
return hook.sendEmail()
}
// Levels returns the available logging levels.
func (hook *mailHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
}
}
func (hook *mailHook) storeError(entry *logrus.Entry) {
body := entry.Time.Format(format) + " - " + entry.Message
hook.buff.WriteString(body)
fields, _ := json.MarshalIndent(entry.Data, "", "\t")
hook.buff.Write(fields)
hook.buff.Write([]byte("\r\n"))
callers, _ := json.MarshalIndent(entry.Caller, "", "\t")
hook.buff.Write(callers)
hook.buff.Write([]byte("\r\n"))
hook.count++
}
func (hook *mailHook) sendEmail() error {
auth := smtp.PlainAuth("", hook.emailUserName, hook.emailPassword, hook.emailHost)
subject := hook.appName + " - " + time.Now().Format(format)
body, _ := ioutil.ReadAll(hook.buff)
hook.buff.Reset()
contents := fmt.Sprintf("Subject: %s\r\n\r\n%s", subject, body)
hook.count = 0
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err := smtp.SendMail(
hook.emailHost+":"+strconv.Itoa(hook.emailPort),
auth,
hook.emailFrom.Address,
hook.emailTos,
[]byte(contents),
)
if err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment