-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathformat.go
137 lines (105 loc) · 2.98 KB
/
format.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package slogtelegram
import (
"bytes"
"fmt"
"log/slog"
"strings"
"text/template"
"time"
)
const defaultTemplate = `{{level .}}
{{time .}}
{{message .}}{{if hasAttrs .}}
<tg-spoiler><blockquote expandable>{{attrs .}}</blockquote></tg-spoiler>{{end}}
`
type Formatter interface {
Format(record slog.Record) (string, error)
}
type FormatterOptions struct {
// Template is a Go template to format the log record.
Template string
// LevelFormatter is a custom function to format the log level.
LevelFormatter func(slog.Record) string
// TimeFormatter is a custom function to format the log time.
TimeFormatter func(slog.Record) string
// MessageFormatter is a custom function to format the log message.
MessageFormatter func(slog.Record) string
// AttrsFormatter is a custom function to format the log attributes.
AttrsFormatter func(slog.Record) string
// Instance is a custom formatter instance to use.
Instance Formatter
}
type defaultFormatter struct {
template *template.Template
}
func NewFormatter(opts FormatterOptions) Formatter {
if opts.Instance != nil {
return opts.Instance
}
f := &defaultFormatter{}
if opts.Template == "" {
opts.Template = defaultTemplate
}
if opts.LevelFormatter == nil {
opts.LevelFormatter = f.formatLevel
}
if opts.TimeFormatter == nil {
opts.TimeFormatter = f.formatTime
}
if opts.MessageFormatter == nil {
opts.MessageFormatter = f.formatMessage
}
if opts.AttrsFormatter == nil {
opts.AttrsFormatter = f.formatAttrs
}
f.template = template.Must(template.New("default").Funcs(template.FuncMap{
"level": opts.LevelFormatter,
"time": opts.TimeFormatter,
"message": opts.MessageFormatter,
"hasAttrs": func(record slog.Record) bool {
return record.NumAttrs() > 0
},
"attrs": opts.AttrsFormatter,
}).Parse(opts.Template))
return f
}
func (f *defaultFormatter) Format(record slog.Record) (string, error) {
var res bytes.Buffer
if err := f.template.Execute(&res, record); err != nil {
return "", err
}
return res.String(), nil
}
func (f *defaultFormatter) formatLevel(record slog.Record) string {
switch record.Level {
case slog.LevelDebug:
return "<i>🐞 Debug</i>"
case slog.LevelInfo:
return "<i>ℹ️ Info</i>"
case slog.LevelWarn:
return "<i>⚠️ Warning</i>"
case slog.LevelError:
return "<i>⛔ Error</i>"
}
return "<i>❔ Unknown</i>"
}
func (f *defaultFormatter) formatTime(record slog.Record) string {
return fmt.Sprintf("<i>⌚️ %s</i>", record.Time.Format(time.RFC3339))
}
func (f *defaultFormatter) formatMessage(record slog.Record) string {
return fmt.Sprintf("<b>💬 %s</b>", record.Message)
}
func (f *defaultFormatter) formatAttrs(record slog.Record) string {
if record.NumAttrs() == 0 {
return ""
}
var res strings.Builder
record.Attrs(func(attr slog.Attr) bool {
res.WriteString(f.formatAttr(attr) + "\n")
return true
})
return res.String()
}
func (f *defaultFormatter) formatAttr(attr slog.Attr) string {
return fmt.Sprintf("🔘 %s: %v", attr.Key, attr.Value)
}