2015-04-17 12:19:20 +00:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
|
2017-06-23 19:45:04 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2015-04-17 12:19:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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 {
|
replace strings.Split(N) for strings.Cut() or alternatives
Go 1.18 and up now provides a strings.Cut() which is better suited for
splitting key/value pairs (and similar constructs), and performs better:
```go
func BenchmarkSplit(b *testing.B) {
b.ReportAllocs()
data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
for i := 0; i < b.N; i++ {
for _, s := range data {
_ = strings.SplitN(s, "=", 2)[0]
}
}
}
func BenchmarkCut(b *testing.B) {
b.ReportAllocs()
data := []string{"12hello=world", "12hello=", "12=hello", "12hello"}
for i := 0; i < b.N; i++ {
for _, s := range data {
_, _, _ = strings.Cut(s, "=")
}
}
}
```
BenchmarkSplit
BenchmarkSplit-10 8244206 128.0 ns/op 128 B/op 4 allocs/op
BenchmarkCut
BenchmarkCut-10 54411998 21.80 ns/op 0 B/op 0 allocs/op
While looking at occurrences of `strings.Split()`, I also updated some for alternatives,
or added some constraints;
- for cases where an specific number of items is expected, I used `strings.SplitN()`
with a suitable limit. This prevents (theoretical) unlimited splits.
- in some cases it we were using `strings.Split()`, but _actually_ were trying to match
a prefix; for those I replaced the code to just match (and/or strip) the prefix.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-11-02 19:32:03 +00:00
|
|
|
host, _, ok := strings.Cut(hook.Mail.Addr, ":")
|
|
|
|
if !ok || host == "" {
|
2019-02-05 00:01:04 +00:00
|
|
|
return errors.New("invalid Mail Address")
|
2015-04-17 12:19:20 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
2019-02-05 00:01:04 +00:00
|
|
|
body := b.String()
|
2015-04-17 12:19:20 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|