mirror of
https://git.proxmox.com/git/proxmox
synced 2025-06-04 20:17:40 +00:00
system-config-api: add syslog feature
Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
87aaa4e30a
commit
15e3779331
@ -18,6 +18,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
nix = { workspace = true, optional = true }
|
||||
libc = { workspace = true, optional = true }
|
||||
log = { workspace = true, optional = true }
|
||||
|
||||
proxmox-sys = { workspace = true, optional = true }
|
||||
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
|
||||
@ -51,3 +52,8 @@ network-impl = [
|
||||
"dep:libc",
|
||||
"dep:proxmox-sys",
|
||||
]
|
||||
syslog = []
|
||||
syslog-impl = [
|
||||
"syslog",
|
||||
"dep:log",
|
||||
]
|
||||
|
@ -6,3 +6,6 @@ pub mod network;
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
pub mod time;
|
||||
|
||||
#[cfg(feature = "syslog")]
|
||||
pub mod syslog;
|
58
proxmox-system-config-api/src/syslog/api_types.rs
Normal file
58
proxmox-system-config-api/src/syslog/api_types.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use proxmox_schema::api;
|
||||
use proxmox_schema::api_types::SYSTEMD_DATETIME_FORMAT;
|
||||
|
||||
#[api(
|
||||
properties: {
|
||||
start: {
|
||||
type: Integer,
|
||||
description: "Start line number.",
|
||||
minimum: 0,
|
||||
optional: true,
|
||||
},
|
||||
limit: {
|
||||
type: Integer,
|
||||
description: "Max. number of lines.",
|
||||
optional: true,
|
||||
minimum: 0,
|
||||
},
|
||||
since: {
|
||||
type: String,
|
||||
optional: true,
|
||||
description: "Display all log since this date-time string.",
|
||||
format: &SYSTEMD_DATETIME_FORMAT,
|
||||
},
|
||||
until: {
|
||||
type: String,
|
||||
optional: true,
|
||||
description: "Display all log until this date-time string.",
|
||||
format: &SYSTEMD_DATETIME_FORMAT,
|
||||
},
|
||||
service: {
|
||||
type: String,
|
||||
optional: true,
|
||||
description: "Service ID.",
|
||||
max_length: 128,
|
||||
},
|
||||
},
|
||||
)]
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
/// Syslog filtering options.
|
||||
pub struct SyslogFilter {
|
||||
pub start: Option<u64>,
|
||||
pub limit: Option<u64>,
|
||||
pub since: Option<String>,
|
||||
pub until: Option<String>,
|
||||
pub service: Option<String>,
|
||||
}
|
||||
|
||||
#[api]
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
/// Syslog line with line number.
|
||||
pub struct SyslogLine {
|
||||
/// Line number.
|
||||
pub n: u64,
|
||||
/// Line text.
|
||||
pub t: String,
|
||||
}
|
73
proxmox-system-config-api/src/syslog/journal.rs
Normal file
73
proxmox-system-config-api/src/syslog/journal.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use anyhow::Error;
|
||||
|
||||
use super::{SyslogFilter, SyslogLine};
|
||||
|
||||
pub fn dump_journal(filter: SyslogFilter) -> Result<(u64, Vec<SyslogLine>), Error> {
|
||||
let mut args = vec!["-o", "short", "--no-pager"];
|
||||
|
||||
if let Some(service) = &filter.service {
|
||||
args.extend(["--unit", service]);
|
||||
}
|
||||
if let Some(since) = &filter.since {
|
||||
args.extend(["--since", since]);
|
||||
}
|
||||
if let Some(until) = &filter.until {
|
||||
args.extend(["--until", until]);
|
||||
}
|
||||
|
||||
let mut lines: Vec<SyslogLine> = Vec::new();
|
||||
let mut limit = filter.limit.unwrap_or(50);
|
||||
let start = filter.start.unwrap_or(0);
|
||||
let mut count: u64 = 0;
|
||||
|
||||
let mut child = Command::new("journalctl")
|
||||
.args(&args)
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
if let Some(ref mut stdout) = child.stdout {
|
||||
for line in BufReader::new(stdout).lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
count += 1;
|
||||
if count < start {
|
||||
continue;
|
||||
};
|
||||
if limit == 0 {
|
||||
continue;
|
||||
};
|
||||
|
||||
lines.push(SyslogLine { n: count, t: line });
|
||||
|
||||
limit -= 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// HACK: ExtJS store.guaranteeRange() does not like empty array
|
||||
// so we add a line
|
||||
if count == 0 {
|
||||
count += 1;
|
||||
lines.push(SyslogLine {
|
||||
n: count,
|
||||
t: String::from("no content"),
|
||||
});
|
||||
}
|
||||
|
||||
Ok((count, lines))
|
||||
}
|
8
proxmox-system-config-api/src/syslog/mod.rs
Normal file
8
proxmox-system-config-api/src/syslog/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
mod api_types;
|
||||
pub use api_types::*;
|
||||
|
||||
|
||||
#[cfg(feature = "syslog-impl")]
|
||||
mod journal;
|
||||
#[cfg(feature = "syslog-impl")]
|
||||
pub use journal::dump_journal;
|
Loading…
Reference in New Issue
Block a user