mirror of
https://seed.radicle.dev/rad:zwTxygwuz5LDGBq255RA2CbNGrz8.git
synced 2026-10-18 19:30:29 +08:00
feat! make cibtool log read cib log output as well
Previously we only supported reading `cib` log output wrapped into `journald` messages as JSON. This is a breaking change because the command line syntax changes slightly. Signed-off-by: Lars Wirzenius <liw@liw.fi>
This commit is contained in:
+2
-2
@@ -2411,11 +2411,11 @@ _Who:_ `cib-devs`
|
||||
given a Radicle node, with CI configured with broker.yaml and adapter dummy.sh
|
||||
given file journal.json
|
||||
|
||||
when I run cibtool log --journal journal.json --output x.json
|
||||
when I run cibtool log --format journald journal.json --output x.json
|
||||
when I run jq . x.json
|
||||
then command is successful
|
||||
|
||||
when I run cibtool log --journal journal.json --broker-run-id 62c45727-a4d8-4a29-9dae-88c6e8b61655 --output x.json
|
||||
when I run cibtool log --format journald journal.json --broker-run-id 62c45727-a4d8-4a29-9dae-88c6e8b61655 --output x.json
|
||||
when I run grep -c timestamp x.json
|
||||
then stdout has one line
|
||||
~~~
|
||||
|
||||
+92
-18
@@ -5,6 +5,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use clap::ValueEnum;
|
||||
use logger::LogLevel;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
@@ -19,10 +20,9 @@ use super::*;
|
||||
/// default text format that's hard to parse.
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct LogCmd {
|
||||
/// Read journalctl JSON output from this file. Default is to read
|
||||
/// from the standard input.
|
||||
/// Input is this format.
|
||||
#[clap(long)]
|
||||
journal: Option<PathBuf>,
|
||||
format: LogKind,
|
||||
|
||||
/// One JSON object per line.
|
||||
#[clap(long)]
|
||||
@@ -49,6 +49,10 @@ pub struct LogCmd {
|
||||
/// output.
|
||||
#[clap(long)]
|
||||
output: Option<PathBuf>,
|
||||
|
||||
/// Read input from this file. Default is to read from the
|
||||
/// standard input.
|
||||
log_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
@@ -146,10 +150,21 @@ fn jsonl(msg: Value) -> Result<String, LogError> {
|
||||
|
||||
impl Leaf for LogCmd {
|
||||
fn run(&self, _args: &Args) -> Result<(), CibToolError> {
|
||||
let journal = if let Some(filename) = &self.journal {
|
||||
JournalLines::from_file(filename)?
|
||||
} else {
|
||||
JournalLines::from_stdin()?
|
||||
let journal = match self.format {
|
||||
LogKind::Cib => {
|
||||
if let Some(filename) = &self.log_file {
|
||||
JournalLines::cib_from_file(filename)?
|
||||
} else {
|
||||
JournalLines::cib_from_stdin()?
|
||||
}
|
||||
}
|
||||
LogKind::Journald => {
|
||||
if let Some(filename) = &self.log_file {
|
||||
JournalLines::journal_from_file(filename)?
|
||||
} else {
|
||||
JournalLines::journal_from_stdin()?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(filename) = &self.output {
|
||||
@@ -174,22 +189,68 @@ impl Leaf for LogCmd {
|
||||
}
|
||||
|
||||
struct JournalLines {
|
||||
kind: LogKind,
|
||||
data: Vec<u8>,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl JournalLines {
|
||||
fn from_file(filename: &Path) -> Result<Self, LogError> {
|
||||
let data = read(filename).map_err(|err| LogError::Read(filename.into(), err))?;
|
||||
Ok(Self { data, next: 0 })
|
||||
fn read_file(filename: &Path) -> Result<Vec<u8>, LogError> {
|
||||
read(filename).map_err(|err| LogError::Read(filename.into(), err))
|
||||
}
|
||||
|
||||
fn from_stdin() -> Result<Self, LogError> {
|
||||
fn read_stdin() -> Result<Vec<u8>, LogError> {
|
||||
let mut data = vec![];
|
||||
std::io::stdin()
|
||||
.read_to_end(&mut data)
|
||||
.map_err(LogError::ReadStdin)?;
|
||||
Ok(Self { data, next: 0 })
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn journal_from_file(filename: &Path) -> Result<Self, LogError> {
|
||||
let data = Self::read_file(filename)?;
|
||||
Ok(Self {
|
||||
data,
|
||||
next: 0,
|
||||
kind: LogKind::Journald,
|
||||
})
|
||||
}
|
||||
|
||||
fn journal_from_stdin() -> Result<Self, LogError> {
|
||||
let data = Self::read_stdin()?;
|
||||
Ok(Self {
|
||||
data,
|
||||
next: 0,
|
||||
kind: LogKind::Journald,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_journal_line(line: String) -> Result<Value, LogError> {
|
||||
let jj: JournalJson = serde_json::from_str(&line)
|
||||
.map_err(|err| LogError::JsonParseJournal(line.clone(), err))?;
|
||||
serde_json::from_str(&jj.message).map_err(|err| (LogError::JsonParse(line, err)))
|
||||
}
|
||||
|
||||
fn cib_from_file(filename: &Path) -> Result<Self, LogError> {
|
||||
let data = Self::read_file(filename)?;
|
||||
Ok(Self {
|
||||
data,
|
||||
next: 0,
|
||||
kind: LogKind::Cib,
|
||||
})
|
||||
}
|
||||
|
||||
fn cib_from_stdin() -> Result<Self, LogError> {
|
||||
let data = Self::read_stdin()?;
|
||||
Ok(Self {
|
||||
data,
|
||||
next: 0,
|
||||
kind: LogKind::Cib,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_cib_line(line: String) -> Result<Value, LogError> {
|
||||
serde_json::from_str(&line).map_err(|err| LogError::JsonParseCib(line.clone(), err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,12 +264,9 @@ impl Iterator for JournalLines {
|
||||
let line = String::from_utf8_lossy(&self.data[self.next..i]).to_string();
|
||||
self.next = i + 1;
|
||||
|
||||
match serde_json::from_str::<JournalJson>(&line) {
|
||||
Err(err) => return Some(Err(LogError::JsonParseJournal(line, err))),
|
||||
Ok(jj) => match serde_json::from_str(&jj.message) {
|
||||
Err(err) => return Some(Err(LogError::JsonParse(line, err))),
|
||||
Ok(value) => return Some(Ok(value)),
|
||||
},
|
||||
match self.kind {
|
||||
LogKind::Cib => return Some(Self::parse_cib_line(line)),
|
||||
LogKind::Journald => return Some(Self::parse_journal_line(line)),
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
@@ -217,12 +275,25 @@ impl Iterator for JournalLines {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, ValueEnum)]
|
||||
enum LogKind {
|
||||
Journald,
|
||||
Cib,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct JournalJson {
|
||||
#[serde(rename = "MESSAGE")]
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct CibJson {
|
||||
name: String,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum LogError {
|
||||
#[error("failed to read journal file {0}")]
|
||||
@@ -237,6 +308,9 @@ pub enum LogError {
|
||||
#[error("failed to parse a log line as JSON: {0:?}")]
|
||||
JsonParse(String, #[source] serde_json::Error),
|
||||
|
||||
#[error("failed to parse a cib log line as JSON: {0:?}")]
|
||||
JsonParseCib(String, #[source] serde_json::Error),
|
||||
|
||||
#[error("failed to serialize a log line as pretty JSON: {0:?}")]
|
||||
JsonSer(serde_json::Value, #[source] serde_json::Error),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user