m/n/core/consensus: parse etcd server logs

This finally gives us easy to read etcd logs instead of raw JSON dumps
into stdout. Instead of simply parsing them as raw logs, we convert them
into leveled logs.

Change-Id: I7cfe18b9c4e24d7742a01a77f5d9c6ddee647493
Reviewed-on: https://review.monogon.dev/c/monogon/+/209
Reviewed-by: Leopold Schabel <leo@nexantic.com>
diff --git a/metropolis/node/core/consensus/consensus.go b/metropolis/node/core/consensus/consensus.go
index ed44140..8e74000 100644
--- a/metropolis/node/core/consensus/consensus.go
+++ b/metropolis/node/core/consensus/consensus.go
@@ -49,6 +49,7 @@
 	"source.monogon.dev/metropolis/node/core/consensus/ca"
 	"source.monogon.dev/metropolis/node/core/consensus/client"
 	"source.monogon.dev/metropolis/node/core/localstorage"
+	"source.monogon.dev/metropolis/pkg/logtree/unraw"
 	"source.monogon.dev/metropolis/pkg/supervisor"
 )
 
@@ -166,9 +167,24 @@
 		cfg.ClusterState = "existing"
 	}
 
+	converter := unraw.Converter{
+		Parser: parseEtcdLogEntry,
+		// The initial line from a starting etcd instance is fairly long.
+		MaximumLineLength: 8192,
+		LeveledLogger:     supervisor.Logger(ctx),
+	}
+	fifoPath := s.config.Ephemeral.ServerLogsFIFO.FullPath()
+	pipe, err := converter.NamedPipeReader(fifoPath)
+	if err != nil {
+		return nil, fmt.Errorf("could not get named pipe reader: %w", err)
+	}
+	if err := supervisor.Run(ctx, "pipe", pipe); err != nil {
+		return nil, fmt.Errorf("could not start server log reader: %w", err)
+	}
+
 	// TODO(q3k): pipe logs from etcd to supervisor.RawLogger via a file.
 	cfg.Logger = DefaultLogger
-	cfg.LogOutputs = []string{"stderr"}
+	cfg.LogOutputs = []string{fifoPath}
 
 	return cfg, nil
 }