| 
									
										
										
										
											2014-10-31 12:56:05 +01:00
										 |  |  | package logger | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2014-10-14 14:35:16 +02:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2014-10-14 14:35:16 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TestLogSystem struct { | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 	mutex  sync.Mutex | 
					
						
							|  |  |  | 	output string | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	level  LogLevel | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-16 10:50:51 +02:00
										 |  |  | func (ls *TestLogSystem) LogPrint(level LogLevel, msg string) { | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 	ls.mutex.Lock() | 
					
						
							| 
									
										
										
										
											2014-10-16 10:50:51 +02:00
										 |  |  | 	ls.output += msg | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 	ls.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | func (ls *TestLogSystem) SetLogLevel(i LogLevel) { | 
					
						
							|  |  |  | 	ls.mutex.Lock() | 
					
						
							|  |  |  | 	ls.level = i | 
					
						
							|  |  |  | 	ls.mutex.Unlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ls *TestLogSystem) GetLogLevel() LogLevel { | 
					
						
							|  |  |  | 	ls.mutex.Lock() | 
					
						
							|  |  |  | 	defer ls.mutex.Unlock() | 
					
						
							|  |  |  | 	return ls.level | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ls *TestLogSystem) CheckOutput(t *testing.T, expected string) { | 
					
						
							|  |  |  | 	ls.mutex.Lock() | 
					
						
							|  |  |  | 	output := ls.output | 
					
						
							|  |  |  | 	ls.mutex.Unlock() | 
					
						
							|  |  |  | 	if output != expected { | 
					
						
							|  |  |  | 		t.Errorf("log output mismatch:\n   got: %q\n  want: %q\n", output, expected) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | type blockedLogSystem struct { | 
					
						
							|  |  |  | 	LogSystem | 
					
						
							|  |  |  | 	unblock chan struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-16 10:50:51 +02:00
										 |  |  | func (ls blockedLogSystem) LogPrint(level LogLevel, msg string) { | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | 	<-ls.unblock | 
					
						
							| 
									
										
										
										
											2014-10-16 10:50:51 +02:00
										 |  |  | 	ls.LogSystem.LogPrint(level, msg) | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | func TestLoggerFlush(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | 	ls := blockedLogSystem{&TestLogSystem{level: WarnLevel}, make(chan struct{})} | 
					
						
							|  |  |  | 	AddLogSystem(ls) | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | 	for i := 0; i < 5; i++ { | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | 		// these writes shouldn't hang even though ls is blocked | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | 		logger.Errorf(".") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	beforeFlush := time.Now() | 
					
						
							|  |  |  | 	time.AfterFunc(80*time.Millisecond, func() { close(ls.unblock) }) | 
					
						
							|  |  |  | 	Flush() // this should hang for approx. 80ms | 
					
						
							|  |  |  | 	if blockd := time.Now().Sub(beforeFlush); blockd < 80*time.Millisecond { | 
					
						
							|  |  |  | 		t.Errorf("Flush didn't block long enough, blocked for %v, should've been >= 80ms", blockd) | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ls.LogSystem.(*TestLogSystem).CheckOutput(t, "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .") | 
					
						
							| 
									
										
										
										
											2014-07-14 18:37:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | func TestLoggerPrintln(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	testLogSystem := &TestLogSystem{level: WarnLevel} | 
					
						
							|  |  |  | 	AddLogSystem(testLogSystem) | 
					
						
							|  |  |  | 	logger.Errorln("error") | 
					
						
							|  |  |  | 	logger.Warnln("warn") | 
					
						
							|  |  |  | 	logger.Infoln("info") | 
					
						
							|  |  |  | 	logger.Debugln("debug") | 
					
						
							|  |  |  | 	Flush() | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testLogSystem.CheckOutput(t, "[TEST] error\n[TEST] warn\n") | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestLoggerPrintf(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	testLogSystem := &TestLogSystem{level: WarnLevel} | 
					
						
							|  |  |  | 	AddLogSystem(testLogSystem) | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 	logger.Errorf("error to %v\n", []int{1, 2, 3}) | 
					
						
							| 
									
										
										
										
											2014-10-16 10:48:33 +02:00
										 |  |  | 	logger.Warnf("warn %%d %d", 5) | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger.Infof("info") | 
					
						
							|  |  |  | 	logger.Debugf("debug") | 
					
						
							|  |  |  | 	Flush() | 
					
						
							| 
									
										
										
										
											2014-10-16 10:48:33 +02:00
										 |  |  | 	testLogSystem.CheckOutput(t, "[TEST] error to [1 2 3]\n[TEST] warn %d 5") | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestMultipleLogSystems(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	testLogSystem0 := &TestLogSystem{level: ErrorLevel} | 
					
						
							|  |  |  | 	testLogSystem1 := &TestLogSystem{level: WarnLevel} | 
					
						
							|  |  |  | 	AddLogSystem(testLogSystem0) | 
					
						
							|  |  |  | 	AddLogSystem(testLogSystem1) | 
					
						
							|  |  |  | 	logger.Errorln("error") | 
					
						
							|  |  |  | 	logger.Warnln("warn") | 
					
						
							|  |  |  | 	Flush() | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testLogSystem0.CheckOutput(t, "[TEST] error\n") | 
					
						
							|  |  |  | 	testLogSystem1.CheckOutput(t, "[TEST] error\n[TEST] warn\n") | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestFileLogSystem(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	filename := "test.log" | 
					
						
							|  |  |  | 	file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) | 
					
						
							|  |  |  | 	testLogSystem := NewStdLogSystem(file, 0, WarnLevel) | 
					
						
							|  |  |  | 	AddLogSystem(testLogSystem) | 
					
						
							|  |  |  | 	logger.Errorf("error to %s\n", filename) | 
					
						
							|  |  |  | 	logger.Warnln("warn") | 
					
						
							|  |  |  | 	Flush() | 
					
						
							|  |  |  | 	contents, _ := ioutil.ReadFile(filename) | 
					
						
							|  |  |  | 	output := string(contents) | 
					
						
							|  |  |  | 	if output != "[TEST] error to test.log\n[TEST] warn\n" { | 
					
						
							| 
									
										
										
										
											2014-07-05 18:36:22 +01:00
										 |  |  | 		t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output) | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		os.Remove(filename) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestNoLogSystem(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2014-10-14 14:33:58 +02:00
										 |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	logger.Warnln("warn") | 
					
						
							|  |  |  | 	Flush() | 
					
						
							| 
									
										
										
										
											2014-06-23 12:49:04 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-14 14:35:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestConcurrentAddSystem(t *testing.T) { | 
					
						
							|  |  |  | 	rand.Seed(time.Now().Unix()) | 
					
						
							|  |  |  | 	Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	logger := NewLogger("TEST") | 
					
						
							|  |  |  | 	stop := make(chan struct{}) | 
					
						
							|  |  |  | 	writer := func() { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-stop: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2014-10-14 19:05:43 +02:00
										 |  |  | 			logger.Infoln("foo") | 
					
						
							| 
									
										
										
										
											2014-10-14 14:35:16 +02:00
										 |  |  | 			Flush() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go writer() | 
					
						
							|  |  |  | 	go writer() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stopTime := time.Now().Add(100 * time.Millisecond) | 
					
						
							|  |  |  | 	for time.Now().Before(stopTime) { | 
					
						
							|  |  |  | 		time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond) | 
					
						
							| 
									
										
										
										
											2014-10-14 19:07:19 +02:00
										 |  |  | 		AddLogSystem(NewStdLogSystem(ioutil.Discard, 0, InfoLevel)) | 
					
						
							| 
									
										
										
										
											2014-10-14 14:35:16 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	close(stop) | 
					
						
							|  |  |  | } |