func (s *LogTailerSuite) TestNoTail(c *gc.C) { expected := logTemplate{Message: "want"} s.writeLogs(c, 2, expected) // Write a log entry that's only in the oplog. doc := s.logTemplateToDoc(logTemplate{Message: "dont want"}, time.Now()) err := s.writeLogToOplog(doc) c.Assert(err, jc.ErrorIsNil) tailer, err := state.NewLogTailer(s.otherState, &state.LogTailerParams{ NoTail: true, }) c.Assert(err, jc.ErrorIsNil) // Not strictly necessary, just in case NoTail doesn't work in the test. defer tailer.Stop() // Logs only in the oplog shouldn't be reported and the tailer // should stop itself once the log collection has been read. s.assertTailer(c, tailer, 2, expected) select { case _, ok := <-tailer.Logs(): if ok { c.Fatal("shouldn't be any further logs") } case <-time.After(coretesting.LongWait): c.Fatal("timed out waiting for logs channel to close") } select { case <-tailer.Dying(): // Success. case <-time.After(coretesting.LongWait): c.Fatal("tailer didn't stop itself") } }
func (s *LogTailerSuite) TestOplogTransition(c *gc.C) { // Ensure that logs aren't repeated as the log tailer moves from // reading from the logs collection to tailing the oplog. // // All logs are written out with the same timestamp to create a // challenging scenario for the tailer. for i := 0; i < 5; i++ { s.writeLogs(c, 1, logTemplate{Message: strconv.Itoa(i)}) } tailer, err := state.NewLogTailer(s.otherState, &state.LogTailerParams{ Oplog: s.oplogColl, }) c.Assert(err, jc.ErrorIsNil) defer tailer.Stop() for i := 0; i < 5; i++ { s.assertTailer(c, tailer, 1, logTemplate{Message: strconv.Itoa(i)}) } // Write more logs. These will be read from the the oplog. for i := 5; i < 10; i++ { lt := logTemplate{Message: strconv.Itoa(i)} s.writeLogs(c, 2, lt) s.assertTailer(c, tailer, 2, lt) } }
func (st logStreamState) newTailer(args *state.LogTailerParams) (state.LogTailer, error) { tailer, err := state.NewLogTailer(st, args) if err != nil { return nil, errors.Trace(err) } return tailer, nil }
func (s *LogTailerSuite) TestTimeFiltering(c *gc.C) { // Add 10 logs that shouldn't be returned. threshT := time.Now() s.writeLogsT(c, threshT.Add(-5*time.Second), threshT.Add(-time.Millisecond), 5, logTemplate{Message: "dont want"}, ) // Add 5 logs that should be returned. want := logTemplate{Message: "want"} s.writeLogsT(c, threshT, threshT.Add(5*time.Second), 5, want) tailer, err := state.NewLogTailer(s.otherState, &state.LogTailerParams{ StartTime: threshT, Oplog: s.oplogColl, }) c.Assert(err, jc.ErrorIsNil) defer tailer.Stop() s.assertTailer(c, tailer, 5, want) // Write more logs. These will be read from the the oplog. want2 := logTemplate{Message: "want 2"} s.writeLogsT(c, threshT.Add(6*time.Second), threshT.Add(10*time.Second), 5, want2) s.assertTailer(c, tailer, 5, want2) }
func (s *LogTailerSuite) TestInitialLinesWithNotEnoughLines(c *gc.C) { expected := logTemplate{Message: "want"} s.writeLogs(c, 2, expected) tailer := state.NewLogTailer(s.State, &state.LogTailerParams{ InitialLines: 5, }) defer tailer.Stop() // Should see just the 2 lines that existed, even though 5 were // asked for. s.assertTailer(c, tailer, 2, expected) }
func (s *LogTailerSuite) TestInitialLines(c *gc.C) { expected := logTemplate{Message: "want"} s.writeLogs(c, 3, logTemplate{Message: "dont want"}) s.writeLogs(c, 5, expected) tailer := state.NewLogTailer(s.State, &state.LogTailerParams{ InitialLines: 5, }) defer tailer.Stop() // Should see just the last 5 lines as requested. s.assertTailer(c, tailer, 5, expected) }
func (s *LogTailerSuite) checkLogTailerFiltering( params *state.LogTailerParams, writeLogs func(), assertTailer func(state.LogTailer), ) { // Check the tailer does the right thing when reading from the // logs collection. writeLogs() params.Oplog = s.oplogColl tailer := state.NewLogTailer(s.State, params) defer tailer.Stop() assertTailer(tailer) // Now write out logs and check the tailer again. These will be // read from the oplog. writeLogs() assertTailer(tailer) }
func (c *dumpLogsCommand) dumpLogsForEnv(ctx *cmd.Context, st0 *state.State, tag names.ModelTag) error { st, err := st0.ForModel(tag) if err != nil { return errors.Annotate(err, "failed open model") } defer st.Close() logName := ctx.AbsPath(filepath.Join(c.outDir, fmt.Sprintf("%s.log", tag.Id()))) ctx.Infof("writing to %s", logName) file, err := os.Create(logName) if err != nil { return errors.Annotate(err, "failed to open output file") } defer file.Close() writer := bufio.NewWriter(file) defer writer.Flush() tailer, err := state.NewLogTailer(st, &state.LogTailerParams{NoTail: true}) if err != nil { return errors.Annotate(err, "failed to create a log tailer") } logs := tailer.Logs() for { rec, ok := <-logs if !ok { break } writer.WriteString(c.format( rec.Time, rec.Level, rec.Entity.String(), rec.Module, rec.Message, ) + "\n") } return nil }
func _newLogTailer(st state.LoggingState, params *state.LogTailerParams) state.LogTailer { return state.NewLogTailer(st, params) }
func (s *LogTailerSuite) TestTailingAllLogsFromNonController(c *gc.C) { _, err := state.NewLogTailer(s.otherState, &state.LogTailerParams{AllModels: true}) c.Assert(err, gc.ErrorMatches, "not allowed to tail logs from all models: not a controller") }
func _newLogTailer(st state.LogTailerState, params *state.LogTailerParams) (state.LogTailer, error) { return state.NewLogTailer(st, params) }