made copying router, than copies messages (and contexts) it sees to memory, and then re-routes it to the sub-router it was given.

master
Charles Iliya Krempeaux 2015-10-10 13:24:16 -07:00
parent f747012ad3
commit 4b4695769b
4 changed files with 192 additions and 13 deletions

51
copying_router.go 100644
View File

@ -0,0 +1,51 @@
package flog
// NewCopyingRouter returns an initialized CopyingRouter.
func NewCopyingRouter(subrouter Router) *CopyingRouter {
copies := make([]struct{Message string ; Context map[string]interface{}}, 0, 8)
router := CopyingRouter {
subrouter:subrouter,
copies:copies,
}
return &router
}
// CopyingRouter is a Router that copies a message (and its context) to memory, and then
// re-routes a message (and its context) to a sub-router.
//
// This router is NOT designed to be used for an indefinite number of routings, and instead
// should only be used for a limited amount of routings, as it stores all the copies in
// memory.
type CopyingRouter struct {
subrouter Router
copies []struct{Message string ; Context map[string]interface{}}
}
func (router *CopyingRouter) Route(message string, context map[string]interface{}) error {
copy := struct{Message string ; Context map[string]interface{}}{
Message: message,
Context: context,
}
router.copies = append(router.copies, copy)
return router.subrouter.Route(message, context)
}
func (router *CopyingRouter) Copies() <-chan struct{Message string ; Context map[string]interface{}} {
ch := make(chan struct{Message string ; Context map[string]interface{}})
go func() {
for _, copy := range router.copies {
ch <- copy
}
close(ch)
}()
return ch
}

View File

@ -0,0 +1,141 @@
package flog
import (
"testing"
"fmt"
"math/rand"
"time"
)
func TestNewCopyingRouter(t *testing.T) {
randomness := rand.New(rand.NewSource( time.Now().UTC().UnixNano() ))
router := NewCopyingRouter(NewDiscardRouter())
if nil == router {
t.Errorf("After trying to create a copying router, expected it to be not nil, but was: %v", router)
}
lenInitialCopies := 0
for range router.Copies() {
lenInitialCopies++
}
if expected, actual := 0, lenInitialCopies; expected != actual {
t.Errorf("After creating a copying router, expected copies to be length %d, but was actually %d,", expected, actual)
}
message := fmt.Sprint("%x", randomness.Int63n(9999999999))
context := make(map[string]interface{})
limit := randomness.Int63n(30)
for i:=int64(0); i<limit; i++ {
context[ fmt.Sprintf("%x", randomness.Int63n(1000*limit)) ] = fmt.Sprintf("%x", randomness.Int63n(999999999999999))
}
router.Route(message, context) // Just make sure it doesn't panic or deadlok, by calling this.
}
func TestCopyingRouterRoute(t *testing.T) {
tests := []struct{
Data []struct{Message string ; Context map[string]interface{}}
}{
{
Data: []struct{Message string ; Context map[string]interface{}}{
},
},
{
Data: []struct{Message string ; Context map[string]interface{}}{
struct{Message string ; Context map[string]interface{}}{
Message: "apple banana cherry",
Context: map[string]interface{}{
"one":1,
"two":2,
"three":3,
},
},
},
},
{
Data: []struct{Message string ; Context map[string]interface{}}{
struct{Message string ; Context map[string]interface{}}{
Message: "apple",
Context: map[string]interface{}{
"one":1,
},
},
struct{Message string ; Context map[string]interface{}}{
Message: "banana",
Context: map[string]interface{}{
"two":2,
},
},
struct{Message string ; Context map[string]interface{}}{
Message: "cherry",
Context: map[string]interface{}{
"cherry":3,
},
},
},
},
}
TLoop: for testNumber, test := range tests {
router := NewCopyingRouter(NewDiscardRouter())
for _, datum := range test.Data {
router.Route(datum.Message, datum.Context)
}
lenCopies := 0
for range router.Copies() {
lenCopies++
}
if expected, actual := len(test.Data), lenCopies; expected != actual {
t.Errorf("For test #%d, after creating a copying router and (potentially) doing some routing, expected copies to be length %d, but was actually %d.", testNumber, expected, actual)
continue TLoop
}
datumNumber := 0
for actualDatum := range router.Copies() {
if expected, actual := test.Data[datumNumber].Message, actualDatum.Message; expected != actual {
t.Errorf("For test #%d, after creating a copying router and (potentially) doing some routing, expected message for copies datum #%d to be %q, but was actually %q.", testNumber, datumNumber, expected, actual)
continue TLoop
}
if expected, actual := len(test.Data[datumNumber].Context), len(actualDatum.Context); expected != actual {
t.Errorf("For test #%d, after creating a copying router and (potentially) doing some routing, expected length of context for copies datum #%d to be %d, but was actually %d.", testNumber, datumNumber, expected, actual)
continue TLoop
}
for expectedKey, expectedValue := range test.Data[datumNumber].Context {
if _, ok := actualDatum.Context[expectedKey]; !ok {
t.Errorf("For test #%d, after creating a copying router and (potentially) doing some routing, expected context for copies datum #%d to have key %q, but didn't.", testNumber, datumNumber, expectedKey)
continue TLoop
}
if actualValue := actualDatum.Context[expectedKey]; expectedValue != actualValue {
t.Errorf("For test #%d, after creating a copying router and (potentially) doing some routing, expected value for context for copies datum #%d at key %q to have value [%v], but actually had [%v].", testNumber, datumNumber, expectedKey, expectedValue, actualValue)
continue TLoop
}
}
datumNumber++
}
}
}

View File

@ -2,8 +2,6 @@ package flog
type internalFlogger struct { type internalFlogger struct {
//@TODO: Do we really want this here?
// logs []string
context map[string]interface{} context map[string]interface{}
router Router router Router
} }
@ -11,14 +9,9 @@ type internalFlogger struct {
// New returns an initialized Flogger. // New returns an initialized Flogger.
func New(router Router, cascade ...interface{}) Flogger { func New(router Router, cascade ...interface{}) Flogger {
//@TODO: Do we really want this here?
// logs := make([]string, 0, 8)
context := newContext(cascade...) context := newContext(cascade...)
flogger := internalFlogger{ flogger := internalFlogger{
//@TODO: Do we really want this here?
// logs:logs,
context:context, context:context,
router:router, router:router,
} }

View File

@ -9,8 +9,6 @@ import (
func (flogger *internalFlogger) Print(v ...interface{}) { func (flogger *internalFlogger) Print(v ...interface{}) {
msg := fmt.Sprint(v...) msg := fmt.Sprint(v...)
//@TODO: Do we really want this here?
// flogger.logs = append(flogger.logs, msg)
flogger.router.Route(msg, flogger.context) flogger.router.Route(msg, flogger.context)
} }
@ -18,8 +16,6 @@ func (flogger *internalFlogger) Print(v ...interface{}) {
func (flogger *internalFlogger) Printf(format string, v ...interface{}) { func (flogger *internalFlogger) Printf(format string, v ...interface{}) {
msg := fmt.Sprintf(format, v...) msg := fmt.Sprintf(format, v...)
//@TODO: Do we really want this here?
// flogger.logs = append(flogger.logs, msg)
flogger.router.Route(msg, flogger.context) flogger.router.Route(msg, flogger.context)
} }
@ -27,8 +23,6 @@ func (flogger *internalFlogger) Printf(format string, v ...interface{}) {
func (flogger *internalFlogger) Println(v ...interface{}) { func (flogger *internalFlogger) Println(v ...interface{}) {
msg := fmt.Sprintln(v...) msg := fmt.Sprintln(v...)
//@TODO: Do we really want this here?
// flogger.logs = append(flogger.logs, msg)
flogger.router.Route(msg, flogger.context) flogger.router.Route(msg, flogger.context)
} }