Merge pull request #180 from yawn/testhook

Added test hook
diff --git a/README.md b/README.md
index c2aea0e..2119b04 100644
--- a/README.md
+++ b/README.md
@@ -365,4 +365,21 @@
 | ---- | ----------- |
 |[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
 
-[godoc]: https://godoc.org/github.com/Sirupsen/logrus
+#### Testing
+
+Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
+
+```go
+logger, hook := NewNullLogger()
+logger.Error("Hello error")
+
+assert.Equal(1, len(hook.Entries))
+assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+assert.Equal("Hello error", hook.LastEntry().Message)
+
+hook.Reset()
+assert.Nil(hook.LastEntry())
+```
diff --git a/hooks/syslog/syslog.go b/hooks/syslog/syslog.go
index c59f331..a36e200 100644
--- a/hooks/syslog/syslog.go
+++ b/hooks/syslog/syslog.go
@@ -50,12 +50,5 @@
 }
 
 func (hook *SyslogHook) Levels() []logrus.Level {
-	return []logrus.Level{
-		logrus.PanicLevel,
-		logrus.FatalLevel,
-		logrus.ErrorLevel,
-		logrus.WarnLevel,
-		logrus.InfoLevel,
-		logrus.DebugLevel,
-	}
+	return logrus.AllLevels
 }
diff --git a/hooks/test/test.go b/hooks/test/test.go
new file mode 100644
index 0000000..0688125
--- /dev/null
+++ b/hooks/test/test.go
@@ -0,0 +1,67 @@
+package test
+
+import (
+	"io/ioutil"
+
+	"github.com/Sirupsen/logrus"
+)
+
+// test.Hook is a hook designed for dealing with logs in test scenarios.
+type Hook struct {
+	Entries []*logrus.Entry
+}
+
+// Installs a test hook for the global logger.
+func NewGlobal() *Hook {
+
+	hook := new(Hook)
+	logrus.AddHook(hook)
+
+	return hook
+
+}
+
+// Installs a test hook for a given local logger.
+func NewLocal(logger *logrus.Logger) *Hook {
+
+	hook := new(Hook)
+	logger.Hooks.Add(hook)
+
+	return hook
+
+}
+
+// Creates a discarding logger and installs the test hook.
+func NewNullLogger() (*logrus.Logger, *Hook) {
+
+	logger := logrus.New()
+	logger.Out = ioutil.Discard
+
+	return logger, NewLocal(logger)
+
+}
+
+func (t *Hook) Fire(e *logrus.Entry) error {
+	t.Entries = append(t.Entries, e)
+	return nil
+}
+
+func (t *Hook) Levels() []logrus.Level {
+	return logrus.AllLevels
+}
+
+// LastEntry returns the last entry that was logged or nil.
+func (t *Hook) LastEntry() (l *logrus.Entry) {
+
+	if i := len(t.Entries) - 1; i < 0 {
+		return nil
+	} else {
+		return t.Entries[i]
+	}
+
+}
+
+// Reset removes all Entries from this test hook.
+func (t *Hook) Reset() {
+	t.Entries = make([]*logrus.Entry, 0)
+}
diff --git a/hooks/test/test_test.go b/hooks/test/test_test.go
new file mode 100644
index 0000000..d69455b
--- /dev/null
+++ b/hooks/test/test_test.go
@@ -0,0 +1,39 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAllHooks(t *testing.T) {
+
+	assert := assert.New(t)
+
+	logger, hook := NewNullLogger()
+	assert.Nil(hook.LastEntry())
+	assert.Equal(0, len(hook.Entries))
+
+	logger.Error("Hello error")
+	assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+	assert.Equal("Hello error", hook.LastEntry().Message)
+	assert.Equal(1, len(hook.Entries))
+
+	logger.Warn("Hello warning")
+	assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
+	assert.Equal("Hello warning", hook.LastEntry().Message)
+	assert.Equal(2, len(hook.Entries))
+
+	hook.Reset()
+	assert.Nil(hook.LastEntry())
+	assert.Equal(0, len(hook.Entries))
+
+	hook = NewGlobal()
+
+	logrus.Error("Hello error")
+	assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+	assert.Equal("Hello error", hook.LastEntry().Message)
+	assert.Equal(1, len(hook.Entries))
+
+}
diff --git a/logrus.go b/logrus.go
index fa8a7cc..1e9670d 100644
--- a/logrus.go
+++ b/logrus.go
@@ -53,6 +53,16 @@
 	return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
 }
 
+// A constant exposing all logging levels
+var AllLevels = []Level{
+	PanicLevel,
+	FatalLevel,
+	ErrorLevel,
+	WarnLevel,
+	InfoLevel,
+	DebugLevel,
+}
+
 // These are the different logging levels. You can set the logging level to log
 // on your instance of logger, obtained with `logrus.New()`.
 const (