Skip to content

Commit 9155be1

Browse files
author
Christian Muirhead
committed
Add a start time parameter to debug-log endpoint
This is needed to make the migration log transfer process step restartable without too many duplicated log records. Add the start time parameter to the client, but not to the debug-log command at the moment. I'll add a bug to add it there.
1 parent e9cbed5 commit 9155be1

File tree

6 files changed

+72
-1
lines changed

6 files changed

+72
-1
lines changed

api/client_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"net/url"
1414
"path"
1515
"strings"
16+
"time"
1617

1718
"github.com/juju/errors"
1819
"github.com/juju/httprequest"
@@ -445,6 +446,7 @@ func (s *clientSuite) TestWatchDebugLogParamsEncoded(c *gc.C) {
445446
Level: loggo.ERROR,
446447
Replay: true,
447448
NoTail: true,
449+
StartTime: time.Date(2016, 11, 30, 11, 48, 0, 100, time.UTC),
448450
}
449451

450452
client := s.APIState.Client()
@@ -463,6 +465,7 @@ func (s *clientSuite) TestWatchDebugLogParamsEncoded(c *gc.C) {
463465
"level": {"ERROR"},
464466
"replay": {"true"},
465467
"noTail": {"true"},
468+
"startTime": {"2016-11-30T11:48:00.0000001Z"},
466469
})
467470
}
468471

api/common/logs.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ type DebugLogParams struct {
5050
// NoTail tells the server to only return the logs it has now, and not
5151
// to wait for new logs to arrive.
5252
NoTail bool
53+
// StartTime should be a time in the past - only records with a
54+
// log time on or after StartTime will be returned.
55+
StartTime time.Time
5356
}
5457

5558
func (args DebugLogParams) URLQuery() url.Values {
@@ -74,6 +77,9 @@ func (args DebugLogParams) URLQuery() url.Values {
7477
if args.Level != loggo.UNSPECIFIED {
7578
attrs.Set("level", fmt.Sprint(args.Level))
7679
}
80+
if !args.StartTime.IsZero() {
81+
attrs.Set("startTime", args.StartTime.Format(time.RFC3339Nano))
82+
}
7783
return attrs
7884
}
7985

apiserver/debuglog.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/url"
1010
"strconv"
1111
"syscall"
12+
"time"
1213

1314
"github.com/juju/errors"
1415
"github.com/juju/loggo"
@@ -144,6 +145,7 @@ func (s *debugLogSocketImpl) sendLogRecord(record *params.LogMessage) error {
144145

145146
// debugLogParams contains the parsed debuglog API request parameters.
146147
type debugLogParams struct {
148+
startTime time.Time
147149
maxLines uint
148150
fromTheStart bool
149151
noTail bool
@@ -200,6 +202,17 @@ func readDebugLogParams(queryMap url.Values) (*debugLogParams, error) {
200202
params.filterLevel = level
201203
}
202204

205+
if value := queryMap.Get("startTime"); value != "" {
206+
startTime, err := time.Parse(time.RFC3339Nano, value)
207+
if err != nil {
208+
return nil, errors.Errorf("start time %q is not a valid time in RFC3339 format", value)
209+
}
210+
if startTime.After(time.Now()) {
211+
return nil, errors.Errorf("start time %q is in the future", value)
212+
}
213+
params.startTime = startTime
214+
}
215+
203216
params.includeEntity = queryMap["includeEntity"]
204217
params.excludeEntity = queryMap["excludeEntity"]
205218
params.includeModule = queryMap["includeModule"]

apiserver/debuglog_db.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func makeLogTailerParams(reqParams *debugLogParams) *state.LogTailerParams {
5858
params := &state.LogTailerParams{
5959
MinLevel: reqParams.filterLevel,
6060
NoTail: reqParams.noTail,
61+
StartTime: reqParams.startTime,
6162
InitialLines: int(reqParams.backlog),
6263
IncludeEntity: reqParams.includeEntity,
6364
ExcludeEntity: reqParams.excludeEntity,

apiserver/debuglog_db_internal_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ func (s *debugLogDBIntSuite) SetUpTest(c *gc.C) {
3030
}
3131

3232
func (s *debugLogDBIntSuite) TestParamConversion(c *gc.C) {
33+
t1 := time.Date(2016, 11, 30, 10, 51, 0, 0, time.UTC)
3334
reqParams := &debugLogParams{
3435
fromTheStart: false,
3536
noTail: true,
3637
backlog: 11,
38+
startTime: t1,
3739
filterLevel: loggo.INFO,
3840
includeEntity: []string{"foo"},
3941
includeModule: []string{"bar"},
@@ -47,7 +49,7 @@ func (s *debugLogDBIntSuite) TestParamConversion(c *gc.C) {
4749

4850
// Start time will be used once the client is extended to send
4951
// time range arguments.
50-
c.Assert(params.StartTime.IsZero(), jc.IsTrue)
52+
c.Assert(params.StartTime, gc.Equals, t1)
5153
c.Assert(params.NoTail, jc.IsTrue)
5254
c.Assert(params.MinLevel, gc.Equals, loggo.INFO)
5355
c.Assert(params.InitialLines, gc.Equals, 11)

featuretests/dblog_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,49 @@ func (s *debugLogDbSuite) TestLogsAPI(c *gc.C) {
210210
Message: "beep beep",
211211
})
212212
}
213+
214+
func (s *debugLogDbSuite) TestLogsUsesStartTime(c *gc.C) {
215+
dbLogger := state.NewEntityDbLogger(s.State, names.NewMachineTag("99"), version.Current)
216+
defer dbLogger.Close()
217+
218+
t1 := time.Date(2015, 6, 23, 13, 8, 49, 100, time.UTC)
219+
// Check that start time has subsecond resolution.
220+
t2 := time.Date(2015, 6, 23, 13, 8, 51, 50, time.UTC)
221+
t3 := t1.Add(2 * time.Second)
222+
t4 := t1.Add(4 * time.Second)
223+
dbLogger.Log(t1, "juju.foo", "code.go:42", loggo.INFO, "spinto band")
224+
dbLogger.Log(t2, "juju.quux", "ok.go:101", loggo.INFO, "king gizzard and the lizard wizard")
225+
dbLogger.Log(t3, "juju.bar", "go.go:99", loggo.ERROR, "born ruffians")
226+
dbLogger.Log(t4, "juju.baz", "go.go.go:23", loggo.WARNING, "cold war kids")
227+
228+
client := s.APIState.Client()
229+
logMessages, err := client.WatchDebugLog(api.DebugLogParams{
230+
StartTime: t3,
231+
})
232+
c.Assert(err, jc.ErrorIsNil)
233+
234+
assertMessage := func(expected api.LogMessage) {
235+
select {
236+
case actual := <-logMessages:
237+
c.Assert(actual, jc.DeepEquals, expected)
238+
case <-time.After(coretesting.LongWait):
239+
c.Fatal("timed out waiting for log line")
240+
}
241+
}
242+
assertMessage(api.LogMessage{
243+
Entity: "machine-99",
244+
Timestamp: t3,
245+
Severity: "ERROR",
246+
Module: "juju.bar",
247+
Location: "go.go:99",
248+
Message: "born ruffians",
249+
})
250+
assertMessage(api.LogMessage{
251+
Entity: "machine-99",
252+
Timestamp: t4,
253+
Severity: "WARNING",
254+
Module: "juju.baz",
255+
Location: "go.go.go:23",
256+
Message: "cold war kids",
257+
})
258+
}

0 commit comments

Comments
 (0)