hive-c0re logs each container build with build_id, agent, kind, start and finish lines
Every output line of a nixos-container operation already reached the journal with its command line. They now also carry the build-log row id, the agent and the kind, and a start and a finish line (status, runtime) bracket them, so the swarm log store can group a build and a board can list builds.
This commit is contained in:
parent
9a773349a8
commit
febeb0d395
1 changed files with 209 additions and 21 deletions
|
|
@ -559,3 +559,93 @@ fn an_unknown_journal_op_keeps_the_start_error() {
|
|||
assert!(full.stderr.contains("Job failed"), "{}", full.stderr);
|
||||
assert!(!full.stderr.contains("unknown variant"), "{}", full.stderr);
|
||||
}
|
||||
|
||||
/// One logged event: its level and each field as `name=value`.
|
||||
type Event = (tracing::Level, Vec<(String, String)>);
|
||||
|
||||
/// Every event a block logged.
|
||||
#[derive(Clone, Default)]
|
||||
struct Events(std::sync::Arc<std::sync::Mutex<Vec<Event>>>);
|
||||
|
||||
impl tracing::Subscriber for Events {
|
||||
fn enabled(&self, _: &tracing::Metadata<'_>) -> bool {
|
||||
true
|
||||
}
|
||||
fn new_span(&self, _: &tracing::span::Attributes<'_>) -> tracing::span::Id {
|
||||
tracing::span::Id::from_u64(1)
|
||||
}
|
||||
fn record(&self, _: &tracing::span::Id, _: &tracing::span::Record<'_>) {}
|
||||
fn record_follows_from(&self, _: &tracing::span::Id, _: &tracing::span::Id) {}
|
||||
fn event(&self, event: &tracing::Event<'_>) {
|
||||
let mut fields = Vec::new();
|
||||
event.record(
|
||||
&mut |field: &tracing::field::Field, value: &dyn std::fmt::Debug| {
|
||||
fields.push((field.name().to_owned(), format!("{value:?}")));
|
||||
},
|
||||
);
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((*event.metadata().level(), fields));
|
||||
}
|
||||
fn enter(&self, _: &tracing::span::Id) {}
|
||||
fn exit(&self, _: &tracing::span::Id) {}
|
||||
}
|
||||
|
||||
fn field<'a>(fields: &'a [(String, String)], name: &str) -> Option<&'a str> {
|
||||
fields
|
||||
.iter()
|
||||
.find(|(n, _)| n == name)
|
||||
.map(|(_, v)| v.as_str())
|
||||
}
|
||||
|
||||
/// A build's log lines say which build they belong to, so the log store can
|
||||
/// group them: a `start` line, the output lines, then a `finish` line with the
|
||||
/// status and runtime. A nix error is a warning, chatter stays info, and a
|
||||
/// failed finish is a warning.
|
||||
#[test]
|
||||
fn a_build_logs_its_start_its_lines_and_its_finish_under_one_build_id() {
|
||||
use hive_priv_sock::PrivStream;
|
||||
let events = Events::default();
|
||||
let _guard = tracing::subscriber::set_default(events.clone());
|
||||
let tag = BuildTag::new(Some(7), "alice", "update", "nixos-container update h-alice");
|
||||
tag.started();
|
||||
tag.line(PrivStream::Stdout, "copying 3 paths");
|
||||
tag.line(PrivStream::Stderr, "error: builder failed");
|
||||
tag.finished(false, std::time::Duration::from_secs(12));
|
||||
|
||||
let logged = events.0.lock().unwrap();
|
||||
assert_eq!(logged.len(), 4);
|
||||
for (_, fields) in logged.iter() {
|
||||
assert_eq!(field(fields, "build_id"), Some("7"));
|
||||
assert_eq!(field(fields, "agent"), Some("alice"));
|
||||
assert_eq!(field(fields, "kind"), Some("update"));
|
||||
}
|
||||
let levels: Vec<_> = logged.iter().map(|(l, _)| *l).collect();
|
||||
assert_eq!(
|
||||
levels,
|
||||
[
|
||||
tracing::Level::INFO,
|
||||
tracing::Level::INFO,
|
||||
tracing::Level::WARN,
|
||||
tracing::Level::WARN
|
||||
]
|
||||
);
|
||||
assert_eq!(field(&logged[0].1, "event"), Some("\"start\""));
|
||||
assert_eq!(field(&logged[1].1, "event"), None);
|
||||
assert_eq!(field(&logged[3].1, "event"), Some("\"finish\""));
|
||||
assert_eq!(field(&logged[3].1, "status"), Some("\"fail\""));
|
||||
assert_eq!(field(&logged[3].1, "runtime_secs"), Some("12"));
|
||||
}
|
||||
|
||||
/// Without the build-log store there is no id; the lines still carry the
|
||||
/// agent and kind, with an empty `build_id`.
|
||||
#[test]
|
||||
fn a_build_without_a_log_row_has_an_empty_build_id() {
|
||||
let events = Events::default();
|
||||
let _guard = tracing::subscriber::set_default(events.clone());
|
||||
BuildTag::new(None, "alice", "create", "nixos-container create h-alice").started();
|
||||
let logged = events.0.lock().unwrap();
|
||||
assert_eq!(field(&logged[0].1, "build_id"), Some(""));
|
||||
assert_eq!(field(&logged[0].1, "agent"), Some("alice"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue