Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
feat! make `cibtool log` read `cib` log output as well
Lars Wirzenius committed 8 months ago
commit b84fffaf02a598cbaed1b016e8d0ad25cf72bd6f
parent cf188b6
2 files changed +94 -20
modified ci-broker.md
@@ -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
~~~
modified src/bin/cibtoolcmd/log.rs
@@ -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),