syslog-api: add helper for mini-journalreader

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
Dietmar Maurer 2024-07-09 10:26:16 +02:00
parent 3479a9afe4
commit 54dcb0942c
3 changed files with 116 additions and 4 deletions

View File

@ -38,7 +38,7 @@ use proxmox_schema::api_types::SYSTEMD_DATETIME_FORMAT;
},
)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
/// Syslog filtering options.
/// Syslog API filtering options.
pub struct SyslogFilter {
pub start: Option<u64>,
pub limit: Option<u64>,
@ -56,3 +56,45 @@ pub struct SyslogLine {
/// Line text.
pub t: String,
}
#[api(
properties: {
since: {
type: Integer,
optional: true,
description: "Display all log since this UNIX epoch. Conflicts with 'startcursor'.",
minimum: 0,
},
until: {
type: Integer,
optional: true,
description: "Display all log until this UNIX epoch. Conflicts with 'endcursor'.",
minimum: 0,
},
lastentries: {
type: Integer,
optional: true,
description: "Limit to the last X lines. Conflicts with a range.",
minimum: 0,
},
startcursor: {
type: String,
description: "Start after the given Cursor. Conflicts with 'since'.",
optional: true,
},
endcursor: {
type: String,
description: "End before the given Cursor. Conflicts with 'until'",
optional: true,
},
}
)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
/// Journal API filtering options.
pub struct JournalFilter {
pub since: Option<u64>,
pub until: Option<u64>,
pub lastentries: Option<u64>,
pub startcursor: Option<String>,
pub endcursor: Option<String>,
}

View File

@ -1,10 +1,18 @@
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use anyhow::Error;
use super::{SyslogFilter, SyslogLine};
use super::{JournalFilter, SyslogFilter, SyslogLine};
pub fn dump_journal(filter: SyslogFilter) -> Result<(u64, Vec<SyslogLine>), Error> {
/// Syslog API implementation
///
/// The syslog api uses `journalctl' to get the log entries, and
/// uses paging to limit the amount of data returned (start, limit).
///
/// Note: Please use [dump_journal] for live view, because that is more performant
/// for that case.
pub fn dump_syslog(filter: SyslogFilter) -> Result<(u64, Vec<SyslogLine>), Error> {
let mut args = vec!["-o", "short", "--no-pager"];
if let Some(service) = &filter.service {
@ -71,3 +79,65 @@ pub fn dump_journal(filter: SyslogFilter) -> Result<(u64, Vec<SyslogLine>), Erro
Ok((count, lines))
}
/// Journal API implementation
///
/// The journal api uses `mini-journalreader' binary to get the log entries.
/// The cursor based api allows to implement live view efficiently.
pub fn dump_journal(filter: JournalFilter) -> Result<Vec<String>, Error> {
let mut args = vec![];
if let Some(lastentries) = filter.lastentries {
args.push(String::from("-n"));
args.push(format!("{}", lastentries));
}
if let Some(since) = filter.since {
args.push(String::from("-b"));
args.push(since.to_string());
}
if let Some(until) = filter.until {
args.push(String::from("-e"));
args.push(until.to_string());
}
if let Some(startcursor) = &filter.startcursor {
args.push(String::from("-f"));
args.push(startcursor.to_string());
}
if let Some(endcursor) = &filter.endcursor {
args.push(String::from("-t"));
args.push(endcursor.to_string());
}
let mut lines: Vec<String> = vec![];
let mut child = Command::new("mini-journalreader")
.args(&args)
.stdout(Stdio::piped())
.spawn()?;
if let Some(ref mut stdout) = child.stdout {
for line in BufReader::new(stdout).lines() {
match line {
Ok(line) => {
lines.push(line);
}
Err(err) => {
log::error!("reading journal failed: {}", err);
let _ = child.kill();
break;
}
}
}
}
let status = child.wait().unwrap();
if !status.success() {
log::error!("journalctl failed with {}", status);
}
Ok(lines)
}

View File

@ -6,4 +6,4 @@ pub use api_types::*;
#[cfg(feature = "impl")]
mod journal;
#[cfg(feature = "impl")]
pub use journal::dump_journal;
pub use journal::{dump_journal, dump_syslog};