summaryrefslogtreecommitdiffstats
path: root/pkg/logging/journald_core.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/logging/journald_core.go')
-rw-r--r--pkg/logging/journald_core.go85
1 files changed, 85 insertions, 0 deletions
diff --git a/pkg/logging/journald_core.go b/pkg/logging/journald_core.go
new file mode 100644
index 0000000..50dd39f
--- /dev/null
+++ b/pkg/logging/journald_core.go
@@ -0,0 +1,85 @@
+package logging
+
+import (
+ "github.com/icinga/icingadb/pkg/utils"
+ "github.com/pkg/errors"
+ "github.com/ssgreg/journald"
+ "go.uber.org/zap/zapcore"
+ "strings"
+ "unicode"
+)
+
+// priorities maps zapcore.Level to journal.Priority.
+var priorities = map[zapcore.Level]journald.Priority{
+ zapcore.DebugLevel: journald.PriorityDebug,
+ zapcore.InfoLevel: journald.PriorityInfo,
+ zapcore.WarnLevel: journald.PriorityWarning,
+ zapcore.ErrorLevel: journald.PriorityErr,
+ zapcore.FatalLevel: journald.PriorityCrit,
+ zapcore.PanicLevel: journald.PriorityCrit,
+ zapcore.DPanicLevel: journald.PriorityCrit,
+}
+
+// NewJournaldCore returns a zapcore.Core that sends log entries to systemd-journald and
+// uses the given identifier as a prefix for structured logging context that is sent as journal fields.
+func NewJournaldCore(identifier string, enab zapcore.LevelEnabler) zapcore.Core {
+ return &journaldCore{
+ LevelEnabler: enab,
+ identifier: identifier,
+ identifierU: strings.ToUpper(identifier),
+ }
+}
+
+type journaldCore struct {
+ zapcore.LevelEnabler
+ context []zapcore.Field
+ identifier string
+ identifierU string
+}
+
+func (c *journaldCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
+ if c.Enabled(ent.Level) {
+ return ce.AddCore(ent, c)
+ }
+
+ return ce
+}
+
+func (c *journaldCore) Sync() error {
+ return nil
+}
+
+func (c *journaldCore) With(fields []zapcore.Field) zapcore.Core {
+ cc := *c
+ cc.context = append(cc.context[:len(cc.context):len(cc.context)], fields...)
+
+ return &cc
+}
+
+func (c *journaldCore) Write(ent zapcore.Entry, fields []zapcore.Field) error {
+ pri, ok := priorities[ent.Level]
+ if !ok {
+ return errors.Errorf("unknown log level %q", ent.Level)
+ }
+
+ enc := zapcore.NewMapObjectEncoder()
+ c.addFields(enc, fields)
+ c.addFields(enc, c.context)
+ enc.Fields["SYSLOG_IDENTIFIER"] = c.identifier
+
+ message := ent.Message
+ if ent.LoggerName != c.identifier {
+ message = ent.LoggerName + ": " + message
+ }
+
+ return journald.Send(message, pri, enc.Fields)
+}
+
+func (c *journaldCore) addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) {
+ for _, field := range fields {
+ field.Key = c.identifierU +
+ "_" +
+ utils.ConvertCamelCase(field.Key, unicode.UpperCase, '_')
+ field.AddTo(enc)
+ }
+}