Skip to content

Commit

Permalink
1. More tests
Browse files Browse the repository at this point in the history
2. More documentation
3. Structure refactored
  • Loading branch information
blaubaer committed Oct 10, 2020
1 parent 8fdd263 commit da79e15
Show file tree
Hide file tree
Showing 46 changed files with 1,269 additions and 397 deletions.
77 changes: 56 additions & 21 deletions event.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
package log

import "github.com/echocat/slf4g/fields"
import (
"github.com/echocat/slf4g/fields"
"github.com/echocat/slf4g/level"
)

// Event represents an event which can be logged using a Logger (or CoreLogger).
//
// Contents
//
// Events are haven dynamic contents (such as messages, errors, ...) provided
// by GetFields(). Only be contract always provided information are provided by
// GetLevel() and GetCalDepth().
// Events containing always present content provided by GetLevel() and
// GetCallDepth().
//
// They are providing additionally dynamic content (messages, errors, ...)
// which are accessible via ForEach() and Get(). None of this fields are
// required to exists by contract. The keys of these fields are defined by
// Provider.GetFieldKeysSpec(). For example using fields.KeysSpec.GetMessage()
// it might be possible to get the key of the message.
//
// The keys are always of type string and should be only printable characters
// which can be printed in any context. Recommended are everything that matches:
// ^[a-zA-Z0-9._-]+$
//
// The values could be everything including nils.
//
// Immutability
//
Expand All @@ -19,7 +33,7 @@ import "github.com/echocat/slf4g/fields"
// instance.
type Event interface {
// GetLevel returns the Level of this event.
GetLevel() Level
GetLevel() level.Level

// GetCallDepth returns the call depth inside of the call stack that should
// be ignored before capturing the caller position (if required). This could
Expand All @@ -33,13 +47,13 @@ type Event interface {
// WithContext().
GetContext() interface{}

// GetFields will return all fields which are associated with this Event.
// This could contain a message, timestamp, error and so on. None of this
// fields is required to exists by contract. The keys of these fields is
// defined by Provider.GetFieldKeysSpec(). For example using
// fields.KeysSpec.GetMessage() it might be possible to get the
// key of the message.
GetFields() fields.Fields
// ForEach will call the provided consumer for each field which is provided
// by this Fields instance.
ForEach(consumer func(key string, value interface{}) error) error

// Get will return for the given key the corresponding value if exists.
// Otherwise it will return nil.
Get(key string) interface{}

// With returns an variant of this Event with the given key
// value pair contained inside. If the given key already exists in the
Expand All @@ -52,6 +66,9 @@ type Event interface {
// fields.Fields.Get())
Withf(key string, format string, args ...interface{}) Event

// WithError is similar to With but it adds an error as field.
WithError(error) Event

// WithAll is similar to With but it can consume more than one field at
// once. Be aware: There is neither a guarantee that this instance will be
// copied or not.
Expand All @@ -74,15 +91,33 @@ type Event interface {
WithContext(ctx interface{}) Event
}

// NewEvent creates a new instance of Event from the given Level, fields.Fields
// and the given callDepth.
func NewEvent(level Level, f fields.Fields, callDepth int) Event {
if f == nil {
f = fields.Empty()
// NewEvent creates a new instance of Event from the given Provider, Level,
// callDepth and fields.Fields.
func NewEvent(provider Provider, level level.Level, callDepth int, f ...fields.Fields) Event {
var tf fields.Fields
if len(f) > 0 {
tf = f[0]
} else {
tf = fields.Empty()
}
return &eventImpl{
Level: level,
Fields: f,
CallDepth: callDepth,

var result Event = &eventImpl{
provider: provider,
level: level,
fields: tf,
callDepth: callDepth,
}

if len(f) > 1 {
for _, sf := range f[1:] {
if err := sf.ForEach(func(k string, v interface{}) error {
result = result.With(k, v)
return nil
}); err != nil {
panic(err)
}
}
}

return result
}
75 changes: 52 additions & 23 deletions event_impl.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
package log

import "github.com/echocat/slf4g/fields"
import (
"github.com/echocat/slf4g/fields"
level2 "github.com/echocat/slf4g/level"
)

type eventImpl struct {
Fields fields.Fields
Level Level
CallDepth int
Context interface{}
provider Provider
fields fields.Fields
level level2.Level
callDepth int
context interface{}
}

func (instance *eventImpl) GetFields() fields.Fields {
return instance.Fields
func (instance *eventImpl) ForEach(consumer func(key string, value interface{}) error) error {
if instance == nil {
return nil
}
if v := instance.fields; v != nil {
return v.ForEach(consumer)
}
return nil
}

func (instance *eventImpl) Get(key string) interface{} {
if instance == nil {
return nil
}
if v := instance.fields; v != nil {
return v.Get(key)
}
return nil
}

func (instance *eventImpl) GetLevel() Level {
return instance.Level
func (instance *eventImpl) GetLevel() level2.Level {
return instance.level
}

func (instance *eventImpl) GetCallDepth() int {
return instance.CallDepth
return instance.callDepth
}

func (instance *eventImpl) GetContext() interface{} {
return instance.Context
return instance.context
}

func (instance *eventImpl) With(key string, value interface{}) Event {
Expand All @@ -37,6 +57,12 @@ func (instance *eventImpl) Withf(key string, format string, args ...interface{})
})
}

func (instance *eventImpl) WithError(err error) Event {
return instance.with(func(s fields.Fields) fields.Fields {
return s.With(instance.provider.GetFieldKeysSpec().GetError(), err)
})
}

func (instance *eventImpl) WithAll(of map[string]interface{}) Event {
return instance.with(func(s fields.Fields) fields.Fields {
return s.WithAll(of)
Expand All @@ -51,27 +77,30 @@ func (instance *eventImpl) Without(keys ...string) Event {

func (instance *eventImpl) WithContext(ctx interface{}) Event {
return &eventImpl{
Fields: instance.Fields,
Level: instance.Level,
CallDepth: instance.CallDepth,
Context: ctx,
provider: instance.provider,
fields: instance.fields,
level: instance.level,
callDepth: instance.callDepth,
context: ctx,
}
}

func (instance *eventImpl) WithCallDepth(add int) Event {
return &eventImpl{
Fields: instance.Fields,
Level: instance.Level,
CallDepth: instance.CallDepth + add,
Context: instance.Context,
provider: instance.provider,
fields: instance.fields,
level: instance.level,
callDepth: instance.callDepth + add,
context: instance.context,
}
}

func (instance *eventImpl) with(mod func(fields.Fields) fields.Fields) Event {
return &eventImpl{
Fields: mod(instance.Fields),
Level: instance.Level,
CallDepth: instance.CallDepth,
Context: instance.Context,
provider: instance.provider,
fields: mod(instance.fields),
level: instance.level,
callDepth: instance.callDepth,
context: instance.context,
}
}
8 changes: 4 additions & 4 deletions event_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func GetMessageOf(e Event, using Provider) *string {
if e == nil {
return nil
}
pv := e.GetFields().Get(using.GetFieldKeysSpec().GetMessage())
pv := e.Get(using.GetFieldKeysSpec().GetMessage())
if pv == nil {
return nil
}
Expand All @@ -38,7 +38,7 @@ func GetErrorOf(e Event, using Provider) error {
if e == nil {
return nil
}
pv := e.GetFields().Get(using.GetFieldKeysSpec().GetError())
pv := e.Get(using.GetFieldKeysSpec().GetError())
if lv, ok := pv.(fields.Lazy); ok {
pv = lv.Get()
}
Expand All @@ -62,7 +62,7 @@ func GetTimestampOf(e Event, using Provider) *time.Time {
if e == nil {
return nil
}
pv := e.GetFields().Get(using.GetFieldKeysSpec().GetTimestamp())
pv := e.Get(using.GetFieldKeysSpec().GetTimestamp())
if lv, ok := pv.(fields.Lazy); ok {
pv = lv.Get()
}
Expand Down Expand Up @@ -91,7 +91,7 @@ func GetLoggerOf(e Event, using Provider) *string {
if e == nil {
return nil
}
pv := e.GetFields().Get(using.GetFieldKeysSpec().GetLogger())
pv := e.Get(using.GetFieldKeysSpec().GetLogger())
if lv, ok := pv.(fields.Lazy); ok {
pv = lv.Get()
}
Expand Down
2 changes: 1 addition & 1 deletion fields/empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type empty struct{}

var emptyV = &empty{}

func (instance *empty) ForEach(Consumer) error {
func (instance *empty) ForEach(func(key string, value interface{}) error) error {
return nil
}

Expand Down
9 changes: 2 additions & 7 deletions fields/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
package fields

type Fields interface {
// ForEach will call the provided Consumer for each field which is provided
// ForEach will call the provided consumer for each field which is provided
// by this Fields instance.
ForEach(consumer Consumer) error
ForEach(consumer func(key string, value interface{}) error) error

// Get will return for the given key the corresponding value if exists.
// Otherwise it will return nil.
Expand All @@ -45,8 +45,3 @@ type Fields interface {
// call either ForEach() or Get() nothing with this key(s) will be returned.
Without(keys ...string) Fields
}

// Consumer will be called on each field that needs to be consumed.
//
// See Fields.ForEach() for more details.
type Consumer func(key string, value interface{}) error
11 changes: 11 additions & 0 deletions fields/key_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@ package fields

// KeysSpec defines the keys for common usages inside of a Fields instance.
type KeysSpec interface {
// GetTimestamp returns the key where the timestamp is stored inside, if
// available.
GetTimestamp() string

// GetMessage returns the key where the message is stored inside, if
// available.
GetMessage() string

// GetError returns the key where an error is stored inside, if
// available.
GetError() string

// GetLogger returns the key where the Logger is stored inside, which is
// managed a Fields instance. (if available)
GetLogger() string
}

Expand Down
2 changes: 1 addition & 1 deletion fields/lineage.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func newLineage(target Fields, parent Fields) Fields {
return &lineage{target, parent}
}

func (instance *lineage) ForEach(consumer Consumer) error {
func (instance *lineage) ForEach(consumer func(key string, value interface{}) error) error {
if instance == nil || consumer == nil {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion fields/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func WithAll(of map[string]interface{}) Fields {

type mapped map[string]interface{}

func (instance mapped) ForEach(consumer Consumer) error {
func (instance mapped) ForEach(consumer func(key string, value interface{}) error) error {
if instance == nil || consumer == nil {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion fields/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type single struct {
value interface{}
}

func (instance *single) ForEach(consumer Consumer) error {
func (instance *single) ForEach(consumer func(key string, value interface{}) error) error {
if instance == nil || consumer == nil {
return nil
}
Expand Down
17 changes: 16 additions & 1 deletion fields/sorted.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ func Sort(fields Fields, sorter KeySorter) Fields {
return &result
}

// SortedForEach is like Sort but calls the ForEach immediately.
func SortedForEach(input ForEachEnabled, sorter KeySorter, consumer func(key string, value interface{}) error) error {
if sorter == nil || isEmpty(input) {
return nil
}
m := asMap(input)
keys := make([]string, len(m))
for _, key := range keys {
if err := consumer(key, m[key]); err != nil {
return err
}
}
return nil
}

// KeySorter is used to sort all keys. See Sort() for more details.
type KeySorter func(keys []string)

Expand All @@ -36,7 +51,7 @@ type sorted struct {
keys []string
}

func (instance *sorted) ForEach(consumer Consumer) error {
func (instance *sorted) ForEach(consumer func(key string, value interface{}) error) error {
if instance == nil || consumer == nil {
return nil
}
Expand Down
8 changes: 6 additions & 2 deletions fields/support.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package fields

func asMap(f Fields) mapped {
type ForEachEnabled interface {
ForEach(func(key string, value interface{}) error) error
}

func asMap(f ForEachEnabled) mapped {
switch v := f.(type) {
case mapped:
return v
Expand All @@ -19,7 +23,7 @@ func asMap(f Fields) mapped {
return result
}

func isEmpty(given Fields) bool {
func isEmpty(given ForEachEnabled) bool {
if given == nil {
return true
}
Expand Down
Loading

0 comments on commit da79e15

Please sign in to comment.