Skip to content

Commit

Permalink
Merge pull request #26 from steenzout/issue#20
Browse files Browse the repository at this point in the history
guarantee order on log message processing.
  • Loading branch information
steenzout committed Nov 24, 2015
2 parents 710d08d + 69f5dc4 commit e2c30e3
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 52 deletions.
7 changes: 5 additions & 2 deletions gol.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ type LogFormatter interface {

// Logger the interface a log message consumer must implement.
type Logger interface {
Close()
Filter() LogFilter
Formatter() LogFormatter
Writer() io.Writer
Run(chan *LogMessage)
Send(*LogMessage) error
SetFilter(LogFilter) error
SetFormatter(LogFormatter) error
SetWriter(io.Writer) error
Status() bool
Writer() io.Writer
}

// LoggerManager the interface to manage an application set of loggers.
Expand All @@ -50,7 +53,7 @@ type LoggerManager interface {
IsEnabled(n string) (bool, error)
List() []string
Register(n string, l Logger) error
Run()
Run(chan *LogMessage)
Send(*LogMessage) (err error)
}

Expand Down
10 changes: 5 additions & 5 deletions internal/examples/application/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,22 @@ import (
manager_simple "github.com/mediaFORGE/gol/managers/simple"
)

// LogWorkers the number of log message workers.
const LogWorkers = 4

// Log holds the application LogManager instance.
var Log gol.LoggerManager

func init() {
fmt.Println("init():start")
Log = manager_simple.New(LogWorkers)
Log = manager_simple.New()

f := filter_severity.New(field_severity.Info)
formatter := formatters.Text{}
logger := logger_simple.New(f, formatter, os.Stdout)
Log.Register("main", logger)

Log.Run()
channel := make(chan *gol.LogMessage, 10)
Log.Run(channel)
Log.Send(gol.NewInfo("message", "main.Log has been configured"))
channel <- gol.NewInfo("message", "this message was sent directly to the log manager channel")

fmt.Println("init():end")
}
62 changes: 58 additions & 4 deletions loggers/simple/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,51 @@ package simple
import (
"fmt"
"io"
"sync"

"github.com/mediaFORGE/gol"
)

// Logger generic struct for a logger.
type Logger struct {
channel chan *gol.LogMessage
mutex sync.Mutex
waitGroup sync.WaitGroup
status bool
filter gol.LogFilter
formatter gol.LogFormatter
writer io.Writer
}

// New creates and initializes a generic logger struct.
func New(f gol.LogFilter, fmt gol.LogFormatter, w io.Writer) *Logger {
return &Logger{f, fmt, w}
return &Logger{
mutex: sync.Mutex{},
waitGroup: sync.WaitGroup{},
status: false,
filter: f,
formatter: fmt,
writer: w,
}
}

// Close closes the log message channel and waits for all processing to complete.
func (l *Logger) Close() {
l.mutex.Lock()
defer l.mutex.Unlock()

if l.status {
l.waitGroup.Wait()
l.status = false
}
}

// process processes messages from logger channel.
func (l *Logger) process() {
for msg := range l.channel {
l.Send(msg)
}
l.waitGroup.Done()
}

// Filter returns the logger filter.
Expand All @@ -45,9 +76,18 @@ func (l *Logger) Formatter() gol.LogFormatter {
return l.formatter
}

// Writer returns the logger writer.
func (l *Logger) Writer() io.Writer {
return l.writer
// Run runs a go routine to process messages from the logger channel.
func (l *Logger) Run(c chan *gol.LogMessage) {
l.mutex.Lock()
defer l.mutex.Unlock()

if !l.status {
l.waitGroup.Add(1)
l.channel = c

go l.process()
l.status = true
}
}

// Send process log message.
Expand Down Expand Up @@ -101,4 +141,18 @@ func (l *Logger) SetWriter(w io.Writer) error {
return nil
}

// Status returns the logger running status.
// True means the logger go routine is running; False otherwise.
func (l *Logger) Status() bool {
l.mutex.Lock()
defer l.mutex.Unlock()

return l.status
}

// Writer returns the logger writer.
func (l *Logger) Writer() io.Writer {
return l.writer
}

var _ gol.Logger = (*Logger)(nil)
91 changes: 78 additions & 13 deletions loggers/simple/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

"github.com/mediaFORGE/gol"
"github.com/mediaFORGE/gol/internal/mock"
"github.com/mediaFORGE/gol/loggers/simple"
logger_simple "github.com/mediaFORGE/gol/loggers/simple"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
Expand All @@ -34,14 +34,23 @@ type LoggerTestSuite struct {
type setupLogTest struct {
setUp func(
msg *gol.LogMessage, mf *mock.LogFilter, mfmt *mock.LogFormatter, mw *mock.Writer,
) *simple.Logger
) *logger_simple.Logger
message *gol.LogMessage
output string
}

func (s *LoggerTestSuite) TestClose() {

l := logger_simple.New(nil, nil, nil)

assert.False(s.T(), l.Status())
l.Close()
assert.False(s.T(), l.Status())
}

func (s *LoggerTestSuite) TestGetSetFilter() {

l := simple.New(nil, nil, nil)
l := logger_simple.New(nil, nil, nil)

assert.Nil(s.T(), l.Filter())
assert.Nil(s.T(), l.SetFilter(&mock.LogFilter{}))
Expand All @@ -52,7 +61,7 @@ func (s *LoggerTestSuite) TestGetSetFilter() {

func (s *LoggerTestSuite) TestGetSetFormatter() {

l := simple.New(nil, nil, nil)
l := logger_simple.New(nil, nil, nil)

assert.Nil(s.T(), l.Formatter())
assert.Nil(s.T(), l.SetFormatter(&mock.LogFormatter{}))
Expand All @@ -63,7 +72,7 @@ func (s *LoggerTestSuite) TestGetSetFormatter() {

func (s *LoggerTestSuite) TestGetSetWriter() {

l := simple.New(nil, nil, nil)
l := logger_simple.New(nil, nil, nil)

assert.Nil(s.T(), l.Writer())
assert.Nil(s.T(), l.SetWriter(&mock.Writer{}))
Expand All @@ -72,18 +81,74 @@ func (s *LoggerTestSuite) TestGetSetWriter() {
assert.Error(s.T(), l.SetWriter(nil))
}

func (s *LoggerTestSuite) TestRun() {

in := map[string]setupLogTest{
"error": setupLogTest{
setUp: func(
msg *gol.LogMessage, mf *mock.LogFilter, mfmt *mock.LogFormatter, mw *mock.Writer,
) (logger *logger_simple.Logger) {
mf.Mock.On("Filter", msg).Return(false, nil)
mfmt.Mock.On("Format", msg).Return("ERROR", nil)
mw.Mock.On("Write", []byte("ERROR")).Return(5, nil)

logger = logger_simple.New(mf, mfmt, mw)

return
},
message: gol.NewError(),
output: "ERROR",
},
"info": setupLogTest{
setUp: func(
msg *gol.LogMessage, mf *mock.LogFilter, mfmt *mock.LogFormatter, mw *mock.Writer,
) (logger *logger_simple.Logger) {
mf.Mock.On("Filter", msg).Return(true, nil)

logger = logger_simple.New(mf, mfmt, mw)

return
},
message: gol.NewInfo(),
output: "",
},
}

for _, t := range in {
mf := &mock.LogFilter{}
mfmt := &mock.LogFormatter{}
mw := &mock.Writer{}

logger := t.setUp(t.message, mf, mfmt, mw)

c := make(chan *gol.LogMessage, 1)
assert.False(s.T(), logger.Status())
logger.Run(c)
assert.True(s.T(), logger.Status())

c <- t.message
close(c)
logger.Close()
assert.False(s.T(), logger.Status())

mf.AssertExpectations(s.T())
mfmt.AssertExpectations(s.T())
mw.AssertExpectations(s.T())
}
}

func (s *LoggerTestSuite) TestSend() {

in := map[string]setupLogTest{
"error": setupLogTest{
setUp: func(
msg *gol.LogMessage, mf *mock.LogFilter, mfmt *mock.LogFormatter, mw *mock.Writer,
) (logger *simple.Logger) {
) (logger *logger_simple.Logger) {
mf.Mock.On("Filter", msg).Return(false, nil)
mfmt.Mock.On("Format", msg).Return("ERROR", nil)
mw.Mock.On("Write", []byte("ERROR")).Return(5, nil)

logger = simple.New(mf, mfmt, mw)
logger = logger_simple.New(mf, mfmt, mw)

return
},
Expand All @@ -93,10 +158,10 @@ func (s *LoggerTestSuite) TestSend() {
"info": setupLogTest{
setUp: func(
msg *gol.LogMessage, mf *mock.LogFilter, mfmt *mock.LogFormatter, mw *mock.Writer,
) (logger *simple.Logger) {
) (logger *logger_simple.Logger) {
mf.Mock.On("Filter", msg).Return(true, nil)

logger = simple.New(mf, mfmt, mw)
logger = logger_simple.New(mf, mfmt, mw)

return
},
Expand All @@ -123,7 +188,7 @@ func (s *LoggerTestSuite) TestSendNilMessage() {
mf := &mock.LogFilter{}
mfmt := &mock.LogFormatter{}
mw := &mock.Writer{}
logger := simple.New(mf, mfmt, mw)
logger := logger_simple.New(mf, mfmt, mw)

assert.Nil(s.T(), logger.Send(nil))
}
Expand All @@ -133,7 +198,7 @@ func (s *LoggerTestSuite) TestSendNilFormatter() {
mf := &mock.LogFilter{}
mf.Mock.On("Filter", msg).Return(false, nil)

logger := simple.New(mf, nil, nil)
logger := logger_simple.New(mf, nil, nil)

assert.Error(s.T(), logger.Send(msg))
}
Expand All @@ -145,7 +210,7 @@ func (s *LoggerTestSuite) TestSendFormatError() {
mfmt := &mock.LogFormatter{}
mfmt.Mock.On("Format", msg).Return("", fmt.Errorf("unknown"))

logger := simple.New(mf, mfmt, nil)
logger := logger_simple.New(mf, mfmt, nil)

assert.Error(s.T(), logger.Send(msg))
}
Expand All @@ -157,7 +222,7 @@ func (s *LoggerTestSuite) TestSendNilWriter() {
mfmt := &mock.LogFormatter{}
mfmt.Mock.On("Format", msg).Return("ERROR", nil)

logger := simple.New(mf, mfmt, nil)
logger := logger_simple.New(mf, mfmt, nil)

assert.Error(s.T(), logger.Send(msg))
}

0 comments on commit e2c30e3

Please sign in to comment.