The JSON message handler is left as a separate implementation, for any that want to use it.main
parent
07f3889a70
commit
47c8c5b850
@ -0,0 +1,155 @@ |
||||
package mlog |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"path" |
||||
"sync" |
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/v2/mctx" |
||||
) |
||||
|
||||
// MessageHandler is a type which can process Messages in some way.
|
||||
//
|
||||
// NOTE that Logger does not handle thread-safety, that must be done inside the
|
||||
// MessageHandler if necessary.
|
||||
type MessageHandler interface { |
||||
Handle(FullMessage) error |
||||
|
||||
// Sync flushes any buffered data to the handler's output, e.g. a file or
|
||||
// network connection. If the handler doesn't buffer data then this will be
|
||||
// a no-op.
|
||||
Sync() error |
||||
} |
||||
|
||||
func maybeSyncWriter(w io.Writer) error { |
||||
if s, ok := w.(interface{ Sync() error }); ok { |
||||
return s.Sync() |
||||
} else if f, ok := w.(interface{ Flush() error }); ok { |
||||
return f.Flush() |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type msgHandler struct { |
||||
l sync.Mutex |
||||
out io.Writer |
||||
aa mctx.Annotations |
||||
} |
||||
|
||||
// NewMessageHandler initializes and returns a MessageHandler which will write
|
||||
// all messages to the given io.Writer in a human-readable format.
|
||||
//
|
||||
// If the io.Writer also implements a Sync or Flush method then that will be
|
||||
// called when Sync is called on the returned MessageHandler.
|
||||
func NewMessageHandler(out io.Writer) MessageHandler { |
||||
return &msgHandler{ |
||||
out: out, |
||||
aa: mctx.Annotations{}, |
||||
} |
||||
} |
||||
|
||||
func (h *msgHandler) Sync() error { |
||||
h.l.Lock() |
||||
defer h.l.Unlock() |
||||
return maybeSyncWriter(h.out) |
||||
} |
||||
|
||||
func (h *msgHandler) Handle(msg FullMessage) error { |
||||
h.l.Lock() |
||||
defer h.l.Unlock() |
||||
|
||||
var namespaceStr string |
||||
|
||||
if len(msg.Namespace) > 0 { |
||||
namespaceStr = "[" + path.Join(msg.Namespace...) + "] " |
||||
} |
||||
|
||||
var annotationsStr string |
||||
|
||||
if ss := mctx.EvaluateAnnotations(msg.Context, h.aa).StringSlice(true); len(ss) > 0 { |
||||
for i := range ss { |
||||
annotationsStr += fmt.Sprintf(" %q=%q", ss[i][0], ss[i][1]) |
||||
} |
||||
} |
||||
|
||||
fmt.Fprintf( |
||||
h.out, "%s %s%s%s\n", |
||||
msg.Level.String(), |
||||
namespaceStr, |
||||
msg.Description, |
||||
annotationsStr, |
||||
) |
||||
|
||||
for k := range h.aa { |
||||
delete(h.aa, k) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type jsonMsgHandler struct { |
||||
l sync.Mutex |
||||
out io.Writer |
||||
enc *json.Encoder |
||||
aa mctx.Annotations |
||||
} |
||||
|
||||
// NewJSONMessageHandler initializes and returns a MessageHandler which will
|
||||
// write all messages to the given io.Writer as JSON objects.
|
||||
//
|
||||
// If the io.Writer also implements a Sync or Flush method then that will be
|
||||
// called when Sync is called on the returned MessageHandler.
|
||||
func NewJSONMessageHandler(out io.Writer) MessageHandler { |
||||
return &jsonMsgHandler{ |
||||
out: out, |
||||
enc: json.NewEncoder(out), |
||||
aa: mctx.Annotations{}, |
||||
} |
||||
} |
||||
|
||||
type messageJSON struct { |
||||
TimeDate string `json:"td"` |
||||
Timestamp int64 `json:"ts"` |
||||
Level string `json:"level"` |
||||
Namespace []string `json:"ns,omitempty"` |
||||
Description string `json:"descr"` |
||||
LevelInt int `json:"level_int"` |
||||
|
||||
// key -> value
|
||||
Annotations map[string]string `json:"annotations,omitempty"` |
||||
} |
||||
|
||||
const msgTimeFormat = "06/01/02 15:04:05.000000" |
||||
|
||||
func (h *jsonMsgHandler) Handle(msg FullMessage) error { |
||||
h.l.Lock() |
||||
defer h.l.Unlock() |
||||
|
||||
msgJSON := messageJSON{ |
||||
TimeDate: msg.Time.UTC().Format(msgTimeFormat), |
||||
Timestamp: msg.Time.UnixNano(), |
||||
Level: msg.Level.String(), |
||||
LevelInt: msg.Level.Int(), |
||||
Namespace: msg.Namespace, |
||||
Description: msg.Description, |
||||
Annotations: mctx.EvaluateAnnotations(msg.Context, h.aa).StringMap(), |
||||
} |
||||
|
||||
for k := range h.aa { |
||||
delete(h.aa, k) |
||||
} |
||||
|
||||
return h.enc.Encode(msgJSON) |
||||
} |
||||
|
||||
func (h *jsonMsgHandler) Sync() error { |
||||
h.l.Lock() |
||||
defer h.l.Unlock() |
||||
return maybeSyncWriter(h.out) |
||||
} |
Loading…
Reference in new issue