Add structured daemon lifecycle logs
VM start, image build, and network/setup failures were hard to diagnose because bangerd emitted almost no lifecycle logs and the Firecracker SDK logger was discarded. This adds a daemon-wide JSON logger with configurable log level so failures leave breadcrumbs instead of only side effects. Log the main daemon and VM lifecycle stages, preserve raw Firecracker and image-build helper output in dedicated files, and include those log paths in daemon status and returned errors. Bridge SDK logrus output into the daemon logger at debug level so low-level Firecracker diagnostics are available without making normal info logs unreadable. Validation: go test ./... and make build. Left unrelated worktree changes out of this commit, including internal/api/types.go, the deleted shell scripts, and my-rootfs.ext4.
This commit is contained in:
parent
5018bc6170
commit
644e60d739
13 changed files with 746 additions and 31 deletions
|
|
@ -3,6 +3,7 @@ package firecracker
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
|
@ -27,6 +28,7 @@ type MachineConfig struct {
|
|||
TapDevice string
|
||||
VCPUCount int
|
||||
MemoryMiB int
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
type Machine struct {
|
||||
|
|
@ -50,7 +52,7 @@ func NewMachine(ctx context.Context, cfg MachineConfig) (*Machine, error) {
|
|||
ctx,
|
||||
buildConfig(cfg),
|
||||
sdk.WithProcessRunner(cmd),
|
||||
sdk.WithLogger(newLogger()),
|
||||
sdk.WithLogger(newLogger(cfg.Logger)),
|
||||
)
|
||||
if err != nil {
|
||||
if logFile != nil {
|
||||
|
|
@ -80,8 +82,8 @@ func (m *Machine) PID() (int, error) {
|
|||
return m.machine.PID()
|
||||
}
|
||||
|
||||
func New(apiSock string) *Client {
|
||||
return &Client{client: sdk.NewClient(apiSock, newLogger(), false)}
|
||||
func New(apiSock string, logger *slog.Logger) *Client {
|
||||
return &Client{client: sdk.NewClient(apiSock, newLogger(logger), false)}
|
||||
}
|
||||
|
||||
func (c *Client) SendCtrlAltDel(ctx context.Context) error {
|
||||
|
|
@ -150,12 +152,44 @@ func shellQuote(value string) string {
|
|||
return "'" + strings.ReplaceAll(value, "'", `'"'"'`) + "'"
|
||||
}
|
||||
|
||||
func newLogger() *logrus.Entry {
|
||||
func newLogger(base *slog.Logger) *logrus.Entry {
|
||||
logger := logrus.New()
|
||||
logger.SetOutput(io.Discard)
|
||||
logger.SetLevel(logrus.DebugLevel)
|
||||
logger.AddHook(slogHook{logger: base})
|
||||
return logrus.NewEntry(logger)
|
||||
}
|
||||
|
||||
type slogHook struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (h slogHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (h slogHook) Fire(entry *logrus.Entry) error {
|
||||
if h.logger == nil {
|
||||
return nil
|
||||
}
|
||||
level := slog.LevelDebug
|
||||
switch entry.Level {
|
||||
case logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel:
|
||||
level = slog.LevelError
|
||||
case logrus.WarnLevel:
|
||||
level = slog.LevelWarn
|
||||
default:
|
||||
level = slog.LevelDebug
|
||||
}
|
||||
attrs := make([]any, 0, len(entry.Data)*2+2)
|
||||
attrs = append(attrs, "component", "firecracker_sdk")
|
||||
for key, value := range entry.Data {
|
||||
attrs = append(attrs, key, value)
|
||||
}
|
||||
h.logger.Log(context.Background(), level, entry.Message, attrs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Machine) closeLog() {
|
||||
m.closeOnce.Do(func() {
|
||||
if m.logFile != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue