...

Source file src/github.com/rs/zerolog/journald/journald.go

Documentation: github.com/rs/zerolog/journald

     1  //go:build !windows
     2  // +build !windows
     3  
     4  // Package journald provides a io.Writer to send the logs
     5  // to journalD component of systemd.
     6  
     7  package journald
     8  
     9  // This file provides a zerolog writer so that logs printed
    10  // using zerolog library can be sent to a journalD.
    11  
    12  // Zerolog's Top level key/Value Pairs are translated to
    13  // journald's args - all Values are sent to journald as strings.
    14  // And all key strings are converted to uppercase before sending
    15  // to journald (as required by journald).
    16  
    17  // In addition, entire log message (all Key Value Pairs), is also
    18  // sent to journald under the key "JSON".
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io"
    25  	"strings"
    26  
    27  	"github.com/coreos/go-systemd/v22/journal"
    28  	"github.com/rs/zerolog"
    29  	"github.com/rs/zerolog/internal/cbor"
    30  )
    31  
    32  const defaultJournalDPrio = journal.PriNotice
    33  
    34  // NewJournalDWriter returns a zerolog log destination
    35  // to be used as parameter to New() calls. Writing logs
    36  // to this writer will send the log messages to journalD
    37  // running in this system.
    38  func NewJournalDWriter() io.Writer {
    39  	return journalWriter{}
    40  }
    41  
    42  type journalWriter struct {
    43  }
    44  
    45  // levelToJPrio converts zerolog Level string into
    46  // journalD's priority values. JournalD has more
    47  // priorities than zerolog.
    48  func levelToJPrio(zLevel string) journal.Priority {
    49  	lvl, _ := zerolog.ParseLevel(zLevel)
    50  
    51  	switch lvl {
    52  	case zerolog.TraceLevel:
    53  		return journal.PriDebug
    54  	case zerolog.DebugLevel:
    55  		return journal.PriDebug
    56  	case zerolog.InfoLevel:
    57  		return journal.PriInfo
    58  	case zerolog.WarnLevel:
    59  		return journal.PriWarning
    60  	case zerolog.ErrorLevel:
    61  		return journal.PriErr
    62  	case zerolog.FatalLevel:
    63  		return journal.PriCrit
    64  	case zerolog.PanicLevel:
    65  		return journal.PriEmerg
    66  	case zerolog.NoLevel:
    67  		return journal.PriNotice
    68  	}
    69  	return defaultJournalDPrio
    70  }
    71  
    72  func (w journalWriter) Write(p []byte) (n int, err error) {
    73  	var event map[string]interface{}
    74  	origPLen := len(p)
    75  	p = cbor.DecodeIfBinaryToBytes(p)
    76  	d := json.NewDecoder(bytes.NewReader(p))
    77  	d.UseNumber()
    78  	err = d.Decode(&event)
    79  	jPrio := defaultJournalDPrio
    80  	args := make(map[string]string)
    81  	if err != nil {
    82  		return
    83  	}
    84  	if l, ok := event[zerolog.LevelFieldName].(string); ok {
    85  		jPrio = levelToJPrio(l)
    86  	}
    87  
    88  	msg := ""
    89  	for key, value := range event {
    90  		jKey := strings.ToUpper(key)
    91  		switch key {
    92  		case zerolog.LevelFieldName, zerolog.TimestampFieldName:
    93  			continue
    94  		case zerolog.MessageFieldName:
    95  			msg, _ = value.(string)
    96  			continue
    97  		}
    98  
    99  		switch v := value.(type) {
   100  		case string:
   101  			args[jKey] = v
   102  		case json.Number:
   103  			args[jKey] = fmt.Sprint(value)
   104  		default:
   105  			b, err := zerolog.InterfaceMarshalFunc(value)
   106  			if err != nil {
   107  				args[jKey] = fmt.Sprintf("[error: %v]", err)
   108  			} else {
   109  				args[jKey] = string(b)
   110  			}
   111  		}
   112  	}
   113  	args["JSON"] = string(p)
   114  	err = journal.Send(msg, jPrio, args)
   115  
   116  	if err == nil {
   117  		n = origPLen
   118  	}
   119  
   120  	return
   121  }
   122  

View as plain text