Skip to content

Commit de35e2a

Browse files
committed
Propagate all logging fields to the tty logger
The fields are serialized in JSON by the hostagent and then printed by the `limactl start` command to the console, so need to be explicitly added back to the logger entry. Signed-off-by: Jan Dubois <[email protected]>
1 parent 4ca34c5 commit de35e2a

File tree

4 files changed

+59
-20
lines changed

4 files changed

+59
-20
lines changed

pkg/hostagent/hostagent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,12 +598,12 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
598598
if err == nil {
599599
if err := a.processGuestAgentEvents(ctx, client); err != nil {
600600
if !errors.Is(err, context.Canceled) {
601-
logrus.WithError(err).Warn("guest agent events closed unexpectedly", err)
601+
logrus.WithError(err).Warn("guest agent events closed unexpectedly")
602602
}
603603
}
604604
} else {
605605
if !errors.Is(err, context.Canceled) {
606-
logrus.WithError(err).Warn("connection to the guest agent was closed unexpectedly", err)
606+
logrus.WithError(err).Warn("connection to the guest agent was closed unexpectedly")
607607
}
608608
}
609609
select {

pkg/logrusutil/logrusutil.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ func PropagateJSON(logger *logrus.Logger, jsonLine []byte, header string, begin
1919
}
2020

2121
var (
22-
lv logrus.Level
23-
j JSON
24-
err error
22+
entry *logrus.Entry
23+
fields logrus.Fields
24+
lv logrus.Level
25+
j JSON
26+
err error
2527
)
28+
entry = logrus.NewEntry(logger)
29+
2630
if err := json.Unmarshal(jsonLine, &j); err != nil {
2731
goto fallback
2832
}
@@ -33,24 +37,26 @@ func PropagateJSON(logger *logrus.Logger, jsonLine []byte, header string, begin
3337
if err != nil {
3438
goto fallback
3539
}
36-
switch lv {
37-
case logrus.PanicLevel, logrus.FatalLevel:
38-
logger.WithField("level", lv).Error(header + j.Msg)
39-
case logrus.ErrorLevel:
40-
logger.Error(header + j.Msg)
41-
case logrus.WarnLevel:
42-
logger.Warn(header + j.Msg)
43-
case logrus.InfoLevel:
44-
logger.Info(header + j.Msg)
45-
case logrus.DebugLevel:
46-
logger.Debug(header + j.Msg)
47-
case logrus.TraceLevel:
48-
logger.Trace(header + j.Msg)
40+
entry = entry.WithTime(j.Time)
41+
// Unmarshal jsonLine once more to capture all the "extra" fields that have been added by
42+
// WithError() and WithField(). The regular fields "level", "msg", and "time" are already
43+
// unmarshalled into j and are handled specially. They must not be added again.
44+
if err := json.Unmarshal(jsonLine, &fields); err == nil {
45+
delete(fields, "level")
46+
delete(fields, "msg")
47+
delete(fields, "time")
48+
entry = entry.WithFields(fields)
49+
}
50+
// Don't exit on Fatal or Panic entries
51+
if lv <= logrus.FatalLevel {
52+
entry = entry.WithField("level", lv)
53+
lv = logrus.ErrorLevel
4954
}
55+
entry.Log(lv, header+j.Msg)
5056
return
5157

5258
fallback:
53-
logger.Info(header + string(jsonLine))
59+
entry.Info(header + string(jsonLine))
5460
}
5561

5662
// JSON is the type used in logrus.JSONFormatter

pkg/logrusutil/logrusutil_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,35 @@ func TestPropagateJSON(t *testing.T) {
8181

8282
assert.Equal(t, "level=error msg=header fields.level=fatal\n", actual.String())
8383
})
84+
t.Run("SetLevel", func(t *testing.T) {
85+
actual := &bytes.Buffer{}
86+
logger := loggerWithoutTs(actual)
87+
logger.SetLevel(logrus.ErrorLevel)
88+
jsonLine := []byte(`{"level": "warning"}`)
89+
90+
PropagateJSON(logger, jsonLine, "header", time.Time{})
91+
92+
assert.Equal(t, "", actual.String())
93+
})
94+
t.Run("extra fields", func(t *testing.T) {
95+
actual := &bytes.Buffer{}
96+
logger := loggerWithoutTs(actual)
97+
jsonLine := []byte(`{"level": "warning", "error": "oops", "extra": "field"}`)
98+
99+
PropagateJSON(logger, jsonLine, "header", time.Time{})
100+
101+
assert.Equal(t, "level=warning msg=header error=oops extra=field\n", actual.String())
102+
})
103+
t.Run("timestamp", func(t *testing.T) {
104+
actual := &bytes.Buffer{}
105+
logger := loggerWithoutTs(actual)
106+
logger.SetFormatter(&logrus.TextFormatter{DisableTimestamp: false})
107+
jsonLine := []byte(`{"level": "warning", "time": "2024-03-06T00:20:53-08:00"}`)
108+
109+
PropagateJSON(logger, jsonLine, "header", time.Time{})
110+
111+
assert.Equal(t, "time=\"2024-03-06T00:20:53-08:00\" level=warning msg=header\n", actual.String())
112+
})
84113
t.Run("empty json line", func(t *testing.T) {
85114
actual := &bytes.Buffer{}
86115
logger := loggerWithoutTs(actual)

pkg/qemu/qemu_driver.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,11 @@ func (l *LimaQemuDriver) shutdownQEMU(ctx context.Context, timeout time.Duration
324324
deadline := time.After(timeout)
325325
select {
326326
case qWaitErr := <-qWaitCh:
327-
logrus.WithError(qWaitErr).Info("QEMU has exited")
327+
entry := logrus.NewEntry(logrus.StandardLogger())
328+
if qWaitErr != nil {
329+
entry = entry.WithError(qWaitErr)
330+
}
331+
entry.Info("QEMU has exited")
328332
_ = l.removeVNCFiles()
329333
return errors.Join(qWaitErr, l.killVhosts())
330334
case <-deadline:

0 commit comments

Comments
 (0)