github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/systemd_linux.go (about) 1 package send 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "log" 8 "os" 9 10 "github.com/coreos/go-systemd/journal" 11 "github.com/mongodb/grip/level" 12 "github.com/mongodb/grip/message" 13 ) 14 15 type systemdJournal struct { 16 options map[string]string 17 *Base 18 } 19 20 // NewSystemdLogger creates a Sender object that writes log messages 21 // to the system's systemd journald logging facility. If there's an 22 // error with the sending to the journald, messages fallback to 23 // writing to standard output. 24 func NewSystemdLogger(name string, l LevelInfo) (Sender, error) { 25 s, err := MakeSystemdLogger() 26 if err != nil { 27 return nil, err 28 } 29 30 return setup(s, name, l) 31 } 32 33 // MakeSystemdLogger constructs an unconfigured systemd journald 34 // logger. Pass to Journaler.SetSender or call SetName before using. 35 func MakeSystemdLogger() (Sender, error) { 36 if !journal.Enabled() { 37 return nil, errors.New("systemd journal logging is not available on this platform") 38 } 39 40 s := &systemdJournal{ 41 options: make(map[string]string), 42 Base: NewBase(""), 43 } 44 45 fallback := log.New(os.Stdout, "", log.LstdFlags) 46 _ = s.SetErrorHandler(ErrorHandlerFromLogger(fallback)) 47 48 s.reset = func() { 49 fallback.SetPrefix(fmt.Sprintf("[%s] ", s.Name())) 50 } 51 52 return s, nil 53 } 54 55 func (s *systemdJournal) Send(m message.Composer) { 56 defer func() { 57 if err := recover(); err != nil { 58 s.ErrorHandler()(fmt.Errorf("panic: %v", err), m) 59 } 60 }() 61 62 if s.Level().ShouldLog(m) { 63 err := journal.Send(m.String(), s.level.convertPrioritySystemd(m.Priority()), s.options) 64 if err != nil { 65 s.ErrorHandler()(err, m) 66 } 67 } 68 } 69 70 func (s *systemdJournal) Flush(_ context.Context) error { return nil } 71 72 func (l LevelInfo) convertPrioritySystemd(p level.Priority) journal.Priority { 73 switch p { 74 case level.Emergency: 75 return journal.PriEmerg 76 case level.Alert: 77 return journal.PriAlert 78 case level.Critical: 79 return journal.PriCrit 80 case level.Error: 81 return journal.PriErr 82 case level.Warning: 83 return journal.PriWarning 84 case level.Notice: 85 return journal.PriNotice 86 case level.Info: 87 return journal.PriInfo 88 case level.Debug, level.Trace: 89 return journal.PriDebug 90 default: 91 return l.convertPrioritySystemd(l.Default) 92 } 93 }