-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathformatter_decorator_syslog.go
More file actions
154 lines (136 loc) · 4.74 KB
/
formatter_decorator_syslog.go
File metadata and controls
154 lines (136 loc) · 4.74 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//go:build !windows && !nacl && !plan9
// +build !windows,!nacl,!plan9
// Copyright The ActForGood Authors.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://github.com/actforgood/xlog/blob/main/LICENSE.
package xlog
import (
"bytes"
"errors"
"io"
"log/syslog"
)
// syslogWriter is an interface wrapping stdlib syslog Writer.
type syslogWriter interface {
// Write sends a log message to the syslog daemon.
Write([]byte) (int, error)
// Close closes a connection to the syslog daemon.
Close() error
// Emerg logs a message with severity LOG_EMERG, ignoring the severity
// passed to New.
Emerg(string) error
// Alert logs a message with severity LOG_ALERT, ignoring the severity
// passed to New.
Alert(string) error
// Crit logs a message with severity LOG_CRIT, ignoring the severity
// passed to New.
Crit(string) error
// Err logs a message with severity LOG_ERR, ignoring the severity
// passed to New.
Err(string) error
// Warning logs a message with severity LOG_WARNING, ignoring the
// severity passed to New.
Warning(string) error
// Notice logs a message with severity LOG_NOTICE, ignoring the
// severity passed to New.
Notice(string) error
// Info logs a message with severity LOG_INFO, ignoring the severity
// passed to New.
Info(string) error
// Debug logs a message with severity LOG_DEBUG, ignoring the severity
// passed to New.
Debug(string) error
}
// SyslogPrefixCee defines the @cee prefix for structured logging in syslog.
// See: http://cee.mitre.org/language/1.0-beta1/clt.html#appendix-1-cee-over-syslog-transport-mapping .
const SyslogPrefixCee = "@cee:"
// ErrNotSyslogWriter is the error returned in case the writer is not syslog specific.
var ErrNotSyslogWriter = errors.New("the writer should be a *syslog.Writer")
// SyslogLevelProvider is a function that extracts the syslog level.
type SyslogLevelProvider func(keyValues []any) syslog.Priority
const noLevel = syslog.Priority(-100000)
// NewDefaultSyslogLevelProvider returns a SyslogLevelProvider that maps xlog default Levels
// to their appropriate syslog Levels.
func NewDefaultSyslogLevelProvider(opts *CommonOpts) SyslogLevelProvider {
levelsMap := make(map[any]syslog.Priority, 5)
for lvl, label := range opts.LevelLabels {
switch lvl {
case LevelDebug:
levelsMap[label] = syslog.LOG_DEBUG
case LevelInfo:
levelsMap[label] = syslog.LOG_INFO
case LevelWarning:
levelsMap[label] = syslog.LOG_WARNING
case LevelError:
levelsMap[label] = syslog.LOG_ERR
case LevelCritical:
levelsMap[label] = syslog.LOG_CRIT
}
}
return NewExtractFromKeySyslogLevelProvider(opts.LevelKey, levelsMap)
}
// NewExtractFromKeySyslogLevelProvider extracts the value of given key as first param
// and returns the syslog level from provided map as second param.
func NewExtractFromKeySyslogLevelProvider(
key string,
syslogLevels map[any]syslog.Priority,
) SyslogLevelProvider {
return func(keyValues []any) syslog.Priority {
syslogLevel, found := syslogLevels[extractKeyValue(key, keyValues)]
if found {
return syslogLevel
}
return noLevel
}
}
// SyslogFormatter is a decorator which writes another formatter 's output to system syslog.
// The second param is a function that knows to return a syslog level for the current log.
// You can use [NewDefaultSyslogLevelProvider] / [NewExtractFromKeySyslogLevelProvider] or custom provider
// (maybe you want to support other syslog levels - for example nothing stops you from doing this:
// logger.Log("lvl","NOTICE", ...) and map also "NOTICE" to [syslog.LOG_NOTICE]).
// The third param is a prefix to be written with each log. You'll pass here empty string or [SyslogPrefixCee].
var SyslogFormatter = func(
formatter Formatter,
syslogLevelProvider SyslogLevelProvider,
prefix string,
) Formatter {
return func(w io.Writer, keyValues []any) error {
sw, ok := w.(syslogWriter)
if !ok {
return ErrNotSyslogWriter
}
keyValues = AppendNoValue(keyValues)
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
defer bufPool.Put(buf)
if prefix != "" {
_, _ = buf.WriteString(prefix)
}
if err := formatter(buf, keyValues); err != nil {
return err
}
syslogLevel := syslogLevelProvider(keyValues)
switch syslogLevel {
case syslog.LOG_EMERG:
return sw.Emerg(buf.String())
case syslog.LOG_ALERT:
return sw.Alert(buf.String())
case syslog.LOG_CRIT:
return sw.Crit(buf.String())
case syslog.LOG_ERR:
return sw.Err(buf.String())
case syslog.LOG_WARNING:
return sw.Warning(buf.String())
case syslog.LOG_NOTICE:
return sw.Notice(buf.String())
case syslog.LOG_INFO:
return sw.Info(buf.String())
case syslog.LOG_DEBUG:
return sw.Debug(buf.String())
default:
_, err := sw.Write(buf.Bytes())
return err
}
}
}