@@ -49,6 +49,27 @@ const tests = `
4949 - [expect, test line 4, logdir/logfile.log]
5050 - [log, test line 5, logdir/logfile.log]
5151 - [expect, test line 5, logdir/logfile.log]
52+
53+ - name: multiple logfiles
54+ commands:
55+ - [mkdir, logdir]
56+ - [log, test line 1 logfile 1, logdir/logfile1.log]
57+ - [start file tailer, readall=true, logdir/*.log]
58+ - [expect, test line 1 logfile 1, logdir/logfile1.log]
59+ - [log, test line 2 logfile 1, logdir/logfile1.log]
60+ - [log, test line 1 logfile 2, logdir/logfile2.log]
61+ - [log, test line 2 logfile 2, logdir/logfile2.log]
62+ - [expect, test line 2 logfile 1, logdir/logfile1.log]
63+ - [expect, test line 1 logfile 2, logdir/logfile2.log]
64+ - [expect, test line 2 logfile 2, logdir/logfile2.log]
65+ - [logrotate, logdir/logfile1.log, logdir/logfile1.log.1]
66+ - [logrotate, logdir/logfile2.log, logdir/logfile2.log.1]
67+ - [log, test line 3 logfile 2, logdir/logfile2.log]
68+ - [log, test line 3 logfile 1, logdir/logfile1.log]
69+ - [expect, test line 3 logfile 2, logdir/logfile2.log]
70+ - [expect, test line 3 logfile 1, logdir/logfile1.log]
71+ - [log, test line 4 logfile 2, logdir/logfile2.log]
72+ - [expect, test line 4 logfile 2, logdir/logfile2.log]
5273`
5374
5475// // The following test fails on Windows in tearDown() when removing logdir.
@@ -158,7 +179,6 @@ func runTest(t *testing.T, ctx *context, cmds [][]string) {
158179 for _ , writer := range ctx .logFileWriters {
159180 writer .close (t , ctx )
160181 }
161- fmt .Println ()
162182 })
163183}
164184
@@ -208,7 +228,6 @@ func setUp(t *testing.T, testName string, loggerCfg loggerConfig, tailerCfg file
208228 tailerCfg : tailerCfg ,
209229 logrotateCfg : logrotateCfg ,
210230 logrotateMvCfg : logrotateMvCfg ,
211- lines : make (map [string ]chan string ),
212231 }
213232 logger := logrus .New ()
214233 logger .Level = logrus .DebugLevel
@@ -223,16 +242,16 @@ func params(ctx *context) string {
223242}
224243
225244type context struct {
226- basedir string
227- logFileWriters map [string ]logFileWriter // path -> writer
228- testName string
229- loggerCfg loggerConfig
230- tailerCfg fileTailerConfig
231- logrotateCfg logrotateConfig
232- logrotateMvCfg logrotateMoveConfig
233- log logrus.FieldLogger
234- tailer fswatcher.FileTailer
235- lines map [ string ] chan string
245+ basedir string
246+ logFileWriters map [string ]logFileWriter // path -> writer
247+ testName string
248+ loggerCfg loggerConfig
249+ tailerCfg fileTailerConfig
250+ logrotateCfg logrotateConfig
251+ logrotateMvCfg logrotateMoveConfig
252+ log logrus.FieldLogger
253+ tailer fswatcher.FileTailer
254+ linesFromTailer * linesFromTailer
236255}
237256
238257func exec (t * testing.T , ctx * context , cmd []string ) {
@@ -493,64 +512,22 @@ func startFileTailer(t *testing.T, ctx *context, params []string) {
493512 fatalf (t , ctx , "%v" , err )
494513 }
495514 tailer = BufferedTailer (tailer )
496-
497- // We don't expect errors. However, start a go-routine listening on
498- // the tailer's errorChannel in case something goes wrong.
499- go func () {
500- for {
501- select {
502- case line , open := <- tailer .Lines ():
503- if ! open {
504- return // tailer closed
505- }
506- c , ok := ctx .lines [line .File ]
507- if ! ok {
508- c = make (chan string )
509- ctx .log .Debugf ("adding lines channel for %v" , line .File )
510- ctx .lines [line .File ] = c
511- }
512- c <- line .Line
513- case err , open := <- tailer .Errors ():
514- if ! open {
515- return // tailer closed
516- } else {
517- ctx .log .Errorf ("tailer failed: %v" , err )
518- t .Errorf ("tailer failed: %v" , err .Error ()) // Cannot call fatalf(t, ctx, ) in goroutine.
519- return
520- }
521- }
522- }
523- }()
524515 ctx .tailer = tailer
516+ ctx .linesFromTailer = makeLinesFromTailer (tailer )
525517}
526518
527519func expect (t * testing.T , ctx * context , line string , file string ) {
528- var (
529- timeout = 5 * time .Second
530- c = ctx .lines [filepath .Join (ctx .basedir , file )]
531- )
532- for c == nil {
533- time .Sleep (100 * time .Millisecond )
534- timeout = timeout - 10 * time .Millisecond
535- if timeout < 0 {
536- fatalf (t , ctx , "timeout waiting for lines from file %q" , file )
537- return
538- }
539- ctx .log .Debugf ("waiting for lines channel for %v" , filepath .Join (ctx .basedir , file ))
540- c = ctx .lines [filepath .Join (ctx .basedir , file )]
520+ actualLine , err := ctx .linesFromTailer .nextLine (filepath .Join (ctx .basedir , file ), 500 * time .Millisecond )
521+ if err != nil {
522+ fatalf (t , ctx , "%v: failed to read line %q: %v" , file , line , err )
541523 }
542- select {
543- case l := <- c :
544- if l != line {
545- fatalf (t , ctx , "%v: expected line %q but got line %q" , file , line , l )
546- }
547- case <- time .After (timeout ):
548- fatalf (t , ctx , "timeout waiting for line %q from file %q" , line , file )
524+ if line != actualLine {
525+ fatalf (t , ctx , "%v: expected line %q but got line %q" , file , line , actualLine )
549526 }
550527}
551528
552529func fatalf (t * testing.T , ctx * context , format string , args ... interface {}) {
553- ctx .log .Fatalf (format , args ... )
530+ ctx .log .Errorf (format , args ... ) // Don't use ctx.log.Fatalf() here because this calls logger.Exit( )
554531 t .Fatalf (format , args ... )
555532}
556533
@@ -883,3 +860,42 @@ func runTestShutdown(t *testing.T, mode string) {
883860 }
884861 assertGoroutinesTerminated (t , ctx , nGoroutinesBefore )
885862}
863+
864+ func makeLinesFromTailer (tailer fswatcher.FileTailer ) * linesFromTailer {
865+ return & linesFromTailer {
866+ tailer : tailer ,
867+ buf : make (map [string ][]string ),
868+ }
869+ }
870+
871+ // Wrapper around FileTailer to get the next lines for a specific file.
872+ type linesFromTailer struct {
873+ tailer fswatcher.FileTailer
874+ buf map [string ][]string
875+ }
876+
877+ // Reads the next line for a specific file.
878+ // If the tailer produces lines for other files they are buffered.
879+ // This call may take longer than timeout if we keep reading lines from another file
880+ func (l * linesFromTailer ) nextLine (file string , timeout time.Duration ) (string , error ) {
881+ if len (l .buf [file ]) > 0 {
882+ result := l .buf [file ][0 ]
883+ l .buf [file ] = l .buf [file ][1 :]
884+ return result , nil
885+ } else {
886+ for {
887+ select {
888+ case line := <- l .tailer .Lines ():
889+ if line .File == file {
890+ return line .Line , nil
891+ } else {
892+ l .buf [line .File ] = append (l .buf [line .File ], line .Line )
893+ }
894+ case err := <- l .tailer .Errors ():
895+ return "" , err
896+ case <- time .After (5 * time .Second ):
897+ return "" , fmt .Errorf ("timeout after %v" , timeout )
898+ }
899+ }
900+ }
901+ }
0 commit comments