]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/syslog.rs
src/api2/node/syslog.rs: use api macro
[proxmox-backup.git] / src / api2 / node / syslog.rs
CommitLineData
a2479cfa
WB
1use std::process::{Command, Stdio};
2
4f9a7268 3use failure::*;
a2479cfa 4use serde_json::{json, Value};
4f9a7268 5
20197f7c 6use proxmox::api::{api, ApiMethod, Router, RpcEnvironment};
552c2259 7
4ebf0eab
DM
8use crate::api2::types::*;
9
04418868
DM
10fn dump_journal(
11 start: Option<u64>,
12 limit: Option<u64>,
13 since: Option<&str>,
14 until: Option<&str>,
15 service: Option<&str>,
16) -> Result<(u64, Vec<Value>), Error> {
17
d96d8273 18 let mut args = vec!["-o", "short", "--no-pager"];
04418868 19
e182ab4a
DM
20 if let Some(service) = service { args.extend(&["--unit", service]); }
21 if let Some(since) = since { args.extend(&["--since", since]); }
22 if let Some(until) = until { args.extend(&["--until", until]); }
04418868
DM
23
24 let mut lines: Vec<Value> = vec![];
25 let mut limit = limit.unwrap_or(50);
26 let start = start.unwrap_or(0);
27 let mut count: u64 = 0;
28
29 let mut child = Command::new("/bin/journalctl")
30 .args(&args)
31 .stdout(Stdio::piped())
32 .spawn()?;
33
34 use std::io::{BufRead,BufReader};
35
36 if let Some(ref mut stdout) = child.stdout {
37 for line in BufReader::new(stdout).lines() {
e182ab4a
DM
38 match line {
39 Ok(line) => {
40 count += 1;
41 if count < start { continue };
11377a47 42 if limit == 0 { continue };
e182ab4a
DM
43
44 lines.push(json!({ "n": count, "t": line }));
45
46 limit -= 1;
47 }
48 Err(err) => {
d96d8273 49 log::error!("reading journal failed: {}", err);
e182ab4a
DM
50 let _ = child.kill();
51 break;
52 }
53 }
04418868
DM
54 }
55 }
56
e182ab4a
DM
57 let status = child.wait().unwrap();
58 if !status.success() {
d96d8273 59 log::error!("journalctl failed with {}", status);
e182ab4a 60 }
04418868
DM
61
62 // HACK: ExtJS store.guaranteeRange() does not like empty array
63 // so we add a line
64 if count == 0 {
65 count += 1;
66 lines.push(json!({ "n": count, "t": "no content"}));
67 }
68
69 Ok((count, lines))
70}
4f9a7268 71
20197f7c
DM
72#[api(
73 protected: true,
74 input: {
75 properties: {
76 node: {
77 schema: NODE_SCHEMA,
78 },
79 start: {
80 type: Integer,
81 description: "Start line number.",
82 minimum: 0,
83 optional: true,
84 },
85 limit: {
86 type: Integer,
87 description: "Max. number of lines.",
88 optional: true,
89 minimum: 0,
90 },
91 since: {
92 type: String,
93 optional: true,
94 description: "Display all log since this date-time string.",
95 format: &SYSTEMD_DATETIME_FORMAT,
96 },
97 until: {
98 type: String,
99 optional: true,
100 description: "Display all log until this date-time string.",
101 format: &SYSTEMD_DATETIME_FORMAT,
102 },
103 service: {
104 type: String,
105 optional: true,
106 description: "Service ID.",
107 max_length: 128,
108 },
109 },
110 },
111 returns: {
112 type: Object,
113 description: "Returns a list of syslog entries.",
114 properties: {
115 n: {
116 type: Integer,
117 description: "Line number.",
118 },
119 t: {
120 type: String,
121 description: "Line text.",
122 }
123 },
124 },
125)]
126/// Read syslog entries.
6049b71f
DM
127fn get_syslog(
128 param: Value,
129 _info: &ApiMethod,
dd5495d6 130 rpcenv: &mut dyn RpcEnvironment,
6049b71f 131) -> Result<Value, Error> {
4f9a7268 132
04418868
DM
133 let (count, lines) = dump_journal(
134 param["start"].as_u64(),
135 param["limit"].as_u64(),
136 param["since"].as_str(),
137 param["until"].as_str(),
e182ab4a 138 param["service"].as_str())?;
04418868 139
6049b71f 140 rpcenv.set_result_attrib("total", Value::from(count));
4f9a7268 141
04418868 142 Ok(json!(lines))
4f9a7268
DM
143}
144
255f378a 145pub const ROUTER: Router = Router::new()
20197f7c 146 .get(&API_METHOD_GET_SYSLOG);
4f9a7268 147