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  }