forked from Proxmox/proxmox
syslog-api: add helper for mini-journalreader
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
3479a9afe4
commit
54dcb0942c
@ -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>,
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user