master
Jordan Orelli 5 years ago
parent 2a6224532b
commit 7910f65eb8

@ -0,0 +1,22 @@
package blammo
import (
"time"
)
// Clock is used to allow for the injection of false clocks into log writers.
type Clock interface {
Now() time.Time
}
// SystemClock is the default system clock
type SystemClock struct{}
// Now returns the current system time
func (c SystemClock) Now() time.Time { return time.Now() }
// FixedClock is a Clock implementation that always returns the same time.
type FixedClock time.Time
// Now always returns the same time
func (c FixedClock) Now() time.Time { return time.Time(c) }

@ -0,0 +1,4 @@
package blammo
type ConsoleWriter struct {
}

@ -8,7 +8,8 @@ import (
// database row if you're writing to a database, etc. Everything internally is
// expressed as an event.
//
// Event is exported to support the implementation of custom log writers.
// Event is exported to support the implementation of custom log writers. Most
// users should not need to handle this type directly.
type Event struct {
// severity of the event
Level Level

@ -8,14 +8,10 @@ const (
Debug Level = iota
// Info is intended to be used to report expected behaviors; it's used to
// log usage and observe normal behaviors.
// log usage and observe normal behaviors. This is intended to be used
// along an applications "happy path".
Info
// Warn is intended to be used to report events that are not along the
// expected "happy path" of the application. These events should generally
// represent failures of -other- systems.
Warn
// Error is intended to b e used to report things that the application was
// not able to handle. These events should generally represent failures of
// the system at hand.

@ -1,4 +1,87 @@
package blammo
import (
"bytes"
"io"
"strconv"
"strings"
"sync"
"time"
)
type LineWriter struct {
pool sync.Pool
out struct {
sync.Mutex
io.Writer
}
}
func NewLineWriter(w io.Writer) *LineWriter {
lw := new(LineWriter)
lw.pool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
lw.out.Writer = w
return lw
}
func (l *LineWriter) WriteEvent(e *Event) {
buf := l.pool.Get().(*bytes.Buffer)
buf.Reset()
buf.WriteString(e.Time.Format(time.RFC3339))
buf.WriteRune(' ')
switch e.Level {
case Debug:
buf.WriteString("d ")
case Info:
buf.WriteString("i ")
case Error:
buf.WriteString("e ")
default:
buf.WriteString("? ")
}
buf.WriteRune('[')
buf.WriteString(e.Path.String())
buf.WriteRune(']')
buf.WriteRune(' ')
if e.Tags == nil {
buf.WriteString("[] ")
} else {
buf.WriteRune('[')
writeTags(buf, e.Tags)
buf.WriteString("] ")
}
buf.WriteString(strings.ReplaceAll(e.Text, string('\n'), "\n"))
l.out.Lock()
l.out.Write(buf.Bytes())
l.out.Unlock()
l.pool.Put(buf)
}
func writeTags(buf *bytes.Buffer, tags *Tags) {
if tags.parent != nil {
writeTags(buf, tags.parent)
buf.WriteRune('+')
}
buf.WriteString(tags.key)
if tags.value != nil {
buf.WriteRune('=')
switch v := tags.value.(type) {
case int:
buf.WriteString(strconv.Itoa(v))
case string:
buf.WriteString(MakeSafeName(v))
case float64:
buf.WriteString(strconv.FormatFloat(v, 'f', -1, 64))
default:
buf.WriteString("???")
}
}
}

@ -0,0 +1,26 @@
package blammo
import (
"bytes"
"testing"
"time"
)
func TestLineWriter(t *testing.T) {
var buf bytes.Buffer
w := NewLineWriter(&buf)
w.WriteEvent(&Event{
Level: Debug,
Time: time.Now(),
Path: NewPath("alice").Child("bob").Child("carol"),
Text: "hey you farthead",
Tags: &Tags{
key: "poop",
parent: &Tags{
key: "num_poops",
value: 27,
},
},
})
t.Error(buf.String())
}

@ -0,0 +1,55 @@
package blammo
import (
"fmt"
)
type Log struct {
lvl Level
dw EventWriter
iw EventWriter
ew EventWriter
path *Path
clock Clock
tags *Tags
}
type Options struct {
Debug EventWriter
Info EventWriter
Error EventWriter
}
var defaults Options
func init() {
defaults.Debug = NullWriter{}
}
func NewLog() *Log {
return new(Log)
}
func format(t string, args ...interface{}) string {
if len(args) == 0 {
return t
}
return fmt.Sprintf(t, args...)
}
func (l *Log) Debug(t string, args ...interface{}) {
}
func (l *Log) Info(t string, args ...interface{}) {
}
func (l *Log) Error(t string, args ...interface{}) {
}
func (l *Log) Child(name string) *Log {
return l
}
func (l *Log) Tag(key string, value interface{}) *Log {
return l
}

@ -59,6 +59,9 @@ func TestSafeNames(t *testing.T) {
"alice[bob]",
"alice{bob}",
"alice=bob",
"alice&bob",
"alice+bob",
"alice(bob",
}
for _, n := range unsafeNames {
if IsSafeName(n) {

@ -5,3 +5,19 @@ type Tags struct {
value interface{}
parent *Tags
}
func (t *Tags) Tag(key string) *Tags {
return &Tags{key: key, parent: t}
}
func (t *Tags) TagInt(key string, v int) *Tags {
return &Tags{key: key, value: v, parent: t}
}
func (t *Tags) TagString(key, v string) *Tags {
return &Tags{key: key, value: v, parent: t}
}
func (t *Tags) TagFloat(key string, v float64) *Tags {
return &Tags{key: key, value: v, parent: t}
}

@ -1,5 +1,7 @@
package blammo
type EventWriter interface {
WriteEvent(*Event) error
}
type EventWriter interface{ WriteEvent(*Event) }
type NullWriter struct{}
func (w NullWriter) WriteEvent(*Event) {}

Loading…
Cancel
Save