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)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
/// Syslog filtering options.
|
/// Syslog API filtering options.
|
||||||
pub struct SyslogFilter {
|
pub struct SyslogFilter {
|
||||||
pub start: Option<u64>,
|
pub start: Option<u64>,
|
||||||
pub limit: Option<u64>,
|
pub limit: Option<u64>,
|
||||||
@ -56,3 +56,45 @@ pub struct SyslogLine {
|
|||||||
/// Line text.
|
/// Line text.
|
||||||
pub t: String,
|
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 std::process::{Command, Stdio};
|
||||||
|
|
||||||
use anyhow::Error;
|
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"];
|
let mut args = vec!["-o", "short", "--no-pager"];
|
||||||
|
|
||||||
if let Some(service) = &filter.service {
|
if let Some(service) = &filter.service {
|
||||||
@ -71,3 +79,65 @@ pub fn dump_journal(filter: SyslogFilter) -> Result<(u64, Vec<SyslogLine>), Erro
|
|||||||
|
|
||||||
Ok((count, lines))
|
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")]
|
#[cfg(feature = "impl")]
|
||||||
mod journal;
|
mod journal;
|
||||||
#[cfg(feature = "impl")]
|
#[cfg(feature = "impl")]
|
||||||
pub use journal::dump_journal;
|
pub use journal::{dump_journal, dump_syslog};
|
||||||
|
Loading…
Reference in New Issue
Block a user