Merge lp:~thumper/juju-core/tailer-tweaks into lp:~go-bot/juju-core/trunk

Proposed by Tim Penhey
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 2563
Proposed branch: lp:~thumper/juju-core/tailer-tweaks
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 150 lines (+45/-12)
3 files modified
container/lxc/clonetemplate.go (+1/-1)
utils/tailer/tailer.go (+25/-9)
utils/tailer/tailer_test.go (+19/-2)
To merge this branch: bzr merge lp:~thumper/juju-core/tailer-tweaks
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+214150@code.launchpad.net

Commit message

Extend the tailer utility.

When looking at the pyjuju debug-log, there was a replay
function that allowed getting the log from the start.
There was no way to tell the tailer to start from the
beginning of the file.

I changed the meaning of NewTailer to be one that doesn't
do any seeking. The NewTailerBacktrack does seek to the end,
and then goes back a certain number of lines.

There was a bug in the backtrack tailer when zero lines
were passed in. This is fixed and a test added.

The number of lines to look back is now a uint, as negative
values make no sense at all.

https://codereview.appspot.com/84290045/

Description of the change

Extend the tailer utility.

When looking at the pyjuju debug-log, there was a replay
function that allowed getting the log from the start.
There was no way to tell the tailer to start from the
beginning of the file.

I changed the meaning of NewTailer to be one that doesn't
do any seeking. The NewTailerBacktrack does seek to the end,
and then goes back a certain number of lines.

There was a bug in the backtrack tailer when zero lines
were passed in. This is fixed and a test added.

In order to provide a synchronization mechanism for other
tests, the Tailer has a public function param that is called
after the backtracking, and prior to starting tailing.

The number of lines to look back is now a unit, as negative
values make no sense at all.

https://codereview.appspot.com/84290045/

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :
Download full text (7.2 KiB)

Reviewers: mp+214150_code.launchpad.net,

Message:
Please take a look.

Description:
Extend the tailer utility.

When looking at the pyjuju debug-log, there was a replay
function that allowed getting the log from the start.
There was no way to tell the tailer to start from the
beginning of the file.

I changed the meaning of NewTailer to be one that doesn't
do any seeking. The NewTailerBacktrack does seek to the end,
and then goes back a certain number of lines.

There was a bug in the backtrack tailer when zero lines
were passed in. This is fixed and a test added.

In order to provide a synchronization mechanism for other
tests, the Tailer has a public function param that is called
after the backtracking, and prior to starting tailing.

The number of lines to look back is now a unit, as negative
values make no sense at all.

https://code.launchpad.net/~thumper/juju-core/tailer-tweaks/+merge/214150

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/84290045/

Affected files (+53, -12 lines):
   A [revision details]
   M container/lxc/clonetemplate.go
   M utils/tailer/tailer.go
   M utils/tailer/tailer_test.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-20140404003547-v7dzlndz9bq9h4qd
+New revision: <email address hidden>

Index: container/lxc/clonetemplate.go
=== modified file 'container/lxc/clonetemplate.go'
--- container/lxc/clonetemplate.go 2014-03-12 04:32:02 +0000
+++ container/lxc/clonetemplate.go 2014-04-04 03:33:01 +0000
@@ -179,7 +179,7 @@
   }

   tailWriter := &logTail{tick: time.Now()}
- consoleTailer := tailer.NewTailer(console, tailWriter, 0, nil)
+ consoleTailer := tailer.NewTailer(console, tailWriter, nil)
   defer consoleTailer.Stop()

   // We should wait maybe 1 minute between output?

Index: utils/tailer/tailer.go
=== modified file 'utils/tailer/tailer.go'
--- utils/tailer/tailer.go 2013-12-13 11:19:56 +0000
+++ utils/tailer/tailer.go 2014-04-04 03:20:53 +0000
@@ -35,25 +35,37 @@
   reader *bufio.Reader
   writeCloser io.WriteCloser
   writer *bufio.Writer
- lines int
+ lines uint
   filter TailerFilterFunc
   bufferSize int
   polltime time.Duration
+ lookBack bool
+ // StartedListening is purely a hook point for tests. It is a function
+ // that is called after the initial seek prior to reading.
+ StartedTailing func()
  }

-// NewTailer starts a Tailer which reads strings from the passed
+// NewTailerBacktrack starts a Tailer which reads strings from the passed
  // ReadSeeker line by line. If a filter function is specified the read
  // lines are filtered. The matching lines are written to the passed
  // Writer. The reading begins the specified number of matching lines
  // from the end.
-func NewTailer(readSeeker io.ReadSeeker, writer io.Writer, lines int,
filter TailerFilterFunc) *Tailer {
- return newTailer(readSeeker, writer, lines, filter, bufferSize, polltime)
+func NewTailerBacktrack(readSeeker io.ReadSeeker, writer io.Writer, lines ...

Read more...

Revision history for this message
Andrew Wilkins (axwalk) wrote :

On 2014/04/04 03:42:04, thumper wrote:
> Please take a look.

Looks fine in general. As discussed on IRC, I would prefer if we didn't
expose StartedTailing for testing, but instead you override Seek for
your testing purposes.

I'm not crazy about NewTailer doing this seeking business. It seems like
that should be pulled out, and just have NewTailer do one thing.
Just a suggestion, but how about something like:

     func SeekLastMatching(r io.ReadSeeker, n int, filter
TailerFilterFunc) error
     func NewTailer(r io.Reader, writer io.Writer, filter
TailerFilterFunc) *Tailer

I see that Tailer does use Seek, but I'm not sure that it needs to.

https://codereview.appspot.com/84290045/

Revision history for this message
Tim Penhey (thumper) wrote :

On 2014/04/04 04:21:34, axw wrote:
> On 2014/04/04 03:42:04, thumper wrote:
> > Please take a look.

> Looks fine in general. As discussed on IRC, I would prefer if we
didn't expose
> StartedTailing for testing, but instead you override Seek for your
testing
> purposes.

> I'm not crazy about NewTailer doing this seeking business. It seems
like that
> should be pulled out, and just have NewTailer do one thing.
> Just a suggestion, but how about something like:

> func SeekLastMatching(r io.ReadSeeker, n int, filter
TailerFilterFunc) error
> func NewTailer(r io.Reader, writer io.Writer, filter
TailerFilterFunc)
> *Tailer

> I see that Tailer does use Seek, but I'm not sure that it needs to.

I'd rather keep the Tailer as unchanged as possible for now.

I've removed the StartedTailing testing callback

https://codereview.appspot.com/84290045/

Revision history for this message
Tim Penhey (thumper) wrote :
Revision history for this message
Andrew Wilkins (axwalk) wrote :

On 2014/04/04 04:33:10, thumper wrote:
> Please take a look.

LGTM, thanks.

https://codereview.appspot.com/84290045/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'container/lxc/clonetemplate.go'
2--- container/lxc/clonetemplate.go 2014-03-12 04:32:02 +0000
3+++ container/lxc/clonetemplate.go 2014-04-04 04:31:14 +0000
4@@ -179,7 +179,7 @@
5 }
6
7 tailWriter := &logTail{tick: time.Now()}
8- consoleTailer := tailer.NewTailer(console, tailWriter, 0, nil)
9+ consoleTailer := tailer.NewTailer(console, tailWriter, nil)
10 defer consoleTailer.Stop()
11
12 // We should wait maybe 1 minute between output?
13
14=== modified file 'utils/tailer/tailer.go'
15--- utils/tailer/tailer.go 2013-12-13 11:19:56 +0000
16+++ utils/tailer/tailer.go 2014-04-04 04:31:14 +0000
17@@ -35,25 +35,34 @@
18 reader *bufio.Reader
19 writeCloser io.WriteCloser
20 writer *bufio.Writer
21- lines int
22+ lines uint
23 filter TailerFilterFunc
24 bufferSize int
25 polltime time.Duration
26+ lookBack bool
27 }
28
29-// NewTailer starts a Tailer which reads strings from the passed
30+// NewTailerBacktrack starts a Tailer which reads strings from the passed
31 // ReadSeeker line by line. If a filter function is specified the read
32 // lines are filtered. The matching lines are written to the passed
33 // Writer. The reading begins the specified number of matching lines
34 // from the end.
35-func NewTailer(readSeeker io.ReadSeeker, writer io.Writer, lines int, filter TailerFilterFunc) *Tailer {
36- return newTailer(readSeeker, writer, lines, filter, bufferSize, polltime)
37+func NewTailerBacktrack(readSeeker io.ReadSeeker, writer io.Writer, lines uint, filter TailerFilterFunc) *Tailer {
38+ return newTailer(readSeeker, writer, lines, filter, bufferSize, polltime, true)
39+}
40+
41+// NewTailer starts a Tailer which reads strings from the passed
42+// ReadSeeker line by line. If a filter function is specified the read
43+// lines are filtered. The matching lines are written to the passed
44+// Writer.
45+func NewTailer(readSeeker io.ReadSeeker, writer io.Writer, filter TailerFilterFunc) *Tailer {
46+ return newTailer(readSeeker, writer, 0, filter, bufferSize, polltime, false)
47 }
48
49 // newTailer starts a Tailer like NewTailer but allows the setting of
50 // the read buffer size and the time between pollings for testing.
51-func newTailer(readSeeker io.ReadSeeker, writer io.Writer, lines int, filter TailerFilterFunc,
52- bufferSize int, polltime time.Duration) *Tailer {
53+func newTailer(readSeeker io.ReadSeeker, writer io.Writer, lines uint, filter TailerFilterFunc,
54+ bufferSize int, polltime time.Duration, lookBack bool) *Tailer {
55 t := &Tailer{
56 readSeeker: readSeeker,
57 reader: bufio.NewReaderSize(readSeeker, bufferSize),
58@@ -62,6 +71,7 @@
59 filter: filter,
60 bufferSize: bufferSize,
61 polltime: polltime,
62+ lookBack: lookBack,
63 }
64 go func() {
65 defer t.tomb.Done()
66@@ -98,8 +108,10 @@
67 // writer too.
68 func (t *Tailer) loop() error {
69 // Position the readSeeker.
70- if err := t.seekLastLines(); err != nil {
71- return err
72+ if t.lookBack {
73+ if err := t.seekLastLines(); err != nil {
74+ return err
75+ }
76 }
77 // Start polling.
78 // TODO(mue) 2013-12-06
79@@ -139,8 +151,12 @@
80 if err != nil {
81 return err
82 }
83+ if t.lines == 0 {
84+ // We are done, just seeking to the end is sufficient.
85+ return nil
86+ }
87 seekPos := int64(0)
88- found := 0
89+ found := uint(0)
90 buffer := make([]byte, t.bufferSize)
91 SeekLoop:
92 for offset > 0 {
93
94=== modified file 'utils/tailer/tailer_test.go'
95--- utils/tailer/tailer_test.go 2013-12-13 13:21:44 +0000
96+++ utils/tailer/tailer_test.go 2014-04-04 04:31:14 +0000
97@@ -59,12 +59,13 @@
98 description string
99 data []string
100 initialLinesWritten int
101- initialLinesRequested int
102+ initialLinesRequested uint
103 bufferSize int
104 filter tailer.TailerFilterFunc
105 injector func(*tailer.Tailer, *readSeeker) func([]string)
106 initialCollectedData []string
107 appendedCollectedData []string
108+ fromStart bool
109 err string
110 }{{
111 description: "lines are longer than buffer size",
112@@ -182,6 +183,19 @@
113 },
114 appendedCollectedData: alphabetData[5:],
115 }, {
116+ description: "ignore current lines",
117+ data: alphabetData,
118+ initialLinesWritten: 5,
119+ bufferSize: 5,
120+ appendedCollectedData: alphabetData[5:],
121+}, {
122+ description: "start from the start",
123+ data: alphabetData,
124+ initialLinesWritten: 5,
125+ bufferSize: 5,
126+ appendedCollectedData: alphabetData,
127+ fromStart: true,
128+}, {
129 description: "lines are longer than buffer size, less lines already written than initially requested",
130 data: alphabetData,
131 initialLinesWritten: 3,
132@@ -323,7 +337,7 @@
133 reader, writer := io.Pipe()
134 sigc := make(chan struct{}, 1)
135 rs := startReadSeeker(c, test.data, test.initialLinesWritten, sigc)
136- tailer := tailer.NewTestTailer(rs, writer, test.initialLinesRequested, test.filter, bufferSize, 2*time.Millisecond)
137+ tailer := tailer.NewTestTailer(rs, writer, test.initialLinesRequested, test.filter, bufferSize, 2*time.Millisecond, !test.fromStart)
138 linec := startReading(c, tailer, reader, writer)
139
140 // Collect initial data.
141@@ -386,6 +400,9 @@
142 // linec is closed due to stopping or an error only the values so far care
143 // compared. Checking the reason for termination is done in the test.
144 func assertCollected(c *gc.C, linec chan string, compare []string, injection func([]string)) {
145+ if len(compare) == 0 {
146+ return
147+ }
148 timeout := time.After(testing.LongWait)
149 lines := []string{}
150 for {

Subscribers

People subscribed via source and target branches

to status/vote changes: