proxmox-backup/src/api2/node/syslog.rs

134 lines
3.9 KiB
Rust
Raw Normal View History

use failure::*;
use proxmox::{sortable, identity};
2019-02-17 09:16:33 +00:00
use crate::api_schema::*;
2019-02-17 08:59:20 +00:00
use crate::api_schema::router::*;
use crate::api2::types::*;
use serde_json::{json, Value};
use std::process::{Command, Stdio};
fn dump_journal(
start: Option<u64>,
limit: Option<u64>,
since: Option<&str>,
until: Option<&str>,
service: Option<&str>,
) -> Result<(u64, Vec<Value>), Error> {
2019-01-26 09:56:11 +00:00
let mut args = vec!["-o", "short", "--no-pager"];
if let Some(service) = service { args.extend(&["--unit", service]); }
if let Some(since) = since { args.extend(&["--since", since]); }
if let Some(until) = until { args.extend(&["--until", until]); }
let mut lines: Vec<Value> = vec![];
let mut limit = limit.unwrap_or(50);
let start = start.unwrap_or(0);
let mut count: u64 = 0;
let mut child = Command::new("/bin/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 };
2019-10-25 16:04:37 +00:00
if limit == 0 { continue };
lines.push(json!({ "n": count, "t": line }));
limit -= 1;
}
Err(err) => {
2019-01-26 09:56:11 +00:00
log::error!("reading journal failed: {}", err);
let _ = child.kill();
break;
}
}
}
}
let status = child.wait().unwrap();
if !status.success() {
2019-01-26 09:56:11 +00:00
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(json!({ "n": count, "t": "no content"}));
}
Ok((count, lines))
}
fn get_syslog(
param: Value,
_info: &ApiMethod,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
let (count, lines) = dump_journal(
param["start"].as_u64(),
param["limit"].as_u64(),
param["since"].as_str(),
param["until"].as_str(),
param["service"].as_str())?;
rpcenv.set_result_attrib("total", Value::from(count));
Ok(json!(lines))
}
#[sortable]
2019-11-21 08:36:41 +00:00
pub const ROUTER: Router = Router::new()
.get(
&ApiMethod::new(
&ApiHandler::Sync(&get_syslog),
&ObjectSchema::new(
"Read server time and time zone settings.",
&sorted!([
2019-11-21 08:36:41 +00:00
("node", false, &NODE_SCHEMA),
("start", true, &IntegerSchema::new("Start line number.")
.minimum(0)
.schema()
),
("limit", true, &IntegerSchema::new("Max. number of lines.")
.minimum(0)
.schema()
),
("since", true, &StringSchema::new("Display all log since this date-time string.")
.format(&SYSTEMD_DATETIME_FORMAT)
.schema()
),
("until", true, &StringSchema::new("Display all log until this date-time string.")
.format(&SYSTEMD_DATETIME_FORMAT)
.schema()
),
("service", true, &StringSchema::new("Service ID.")
.max_length(128)
.schema()
),
]),
2019-11-21 08:36:41 +00:00
)
).returns(
&ObjectSchema::new(
"Returns a list of syslog entries.",
&sorted!([
2019-11-21 08:36:41 +00:00
("n", false, &IntegerSchema::new("Line number.").schema()),
("t", false, &StringSchema::new("Line text.").schema()),
]),
2019-11-21 08:36:41 +00:00
).schema()
).protected(true)
);