Merge pull request 'Miniserde refactor with custom error impls' (#11) from miniserde_refactor into main
Reviewed-on: #11
This commit is contained in:
commit
35a524e9db
|
@ -28,13 +28,13 @@ travis-ci = { repository = "peachcloud/peach-stats", branch = "master" }
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.6"
|
env_logger = "0.9"
|
||||||
jsonrpc-core = "11"
|
jsonrpc-core = "18"
|
||||||
jsonrpc-http-server = "11"
|
jsonrpc-http-server = "18"
|
||||||
jsonrpc-test = "11"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
probes = "0.3"
|
miniserde = "0.1.15"
|
||||||
serde = { version = "1", features = ["derive"] }
|
probes = "0.4.1"
|
||||||
serde_json = "1"
|
systemstat = "0.1.10"
|
||||||
snafu = "0.4"
|
|
||||||
systemstat = "0.1"
|
[dev-dependencies]
|
||||||
|
jsonrpc-test = "18"
|
||||||
|
|
|
@ -14,7 +14,7 @@ System statistics microservice module for PeachCloud. Provides a JSON-RPC wrappe
|
||||||
| `load_average` | Load average statistics | `one`, `five`, `fifteen` |
|
| `load_average` | Load average statistics | `one`, `five`, `fifteen` |
|
||||||
| `mem_stats` | Memory statistics | `total`, `free`, `used` |
|
| `mem_stats` | Memory statistics | `total`, `free`, `used` |
|
||||||
| `ping` | Microservice status | `success` if running |
|
| `ping` | Microservice status | `success` if running |
|
||||||
| `uptime` | System uptime | `secs`, `nanos` |
|
| `uptime` | System uptime | `secs` |
|
||||||
|
|
||||||
### Environment
|
### Environment
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ With microservice running, open a second terminal window and use `curl` to call
|
||||||
|
|
||||||
Server responds with:
|
Server responds with:
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"{\"secs\":840968,\"nanos\":0}","id":1}`
|
`{"jsonrpc":"2.0","result":"{\"secs\":840968}","id":1}`
|
||||||
|
|
||||||
### Licensing
|
### Licensing
|
||||||
|
|
||||||
|
|
|
@ -1,67 +1,69 @@
|
||||||
use std::{error, io};
|
use std::{error, fmt, io};
|
||||||
|
|
||||||
use jsonrpc_core::{types::error::Error, ErrorCode};
|
use jsonrpc_core::{types::error::Error, ErrorCode};
|
||||||
use probes::ProbeError;
|
use probes::ProbeError;
|
||||||
use serde_json::Error as SerdeError;
|
|
||||||
use snafu::Snafu;
|
|
||||||
|
|
||||||
pub type BoxError = Box<dyn error::Error>;
|
#[derive(Debug)]
|
||||||
|
|
||||||
#[derive(Debug, Snafu)]
|
|
||||||
#[snafu(visibility(pub(crate)))]
|
|
||||||
pub enum StatError {
|
pub enum StatError {
|
||||||
#[snafu(display("Failed to retrieve CPU statistics: {}", source))]
|
CpuStat { source: ProbeError },
|
||||||
ReadCpuStat { source: ProbeError },
|
DiskUsage { source: ProbeError },
|
||||||
|
LoadAvg { source: ProbeError },
|
||||||
|
MemStat { source: ProbeError },
|
||||||
|
Uptime { source: io::Error },
|
||||||
|
}
|
||||||
|
|
||||||
#[snafu(display("Failed to retrieve disk usage statistics: {}", source))]
|
impl error::Error for StatError {}
|
||||||
ReadDiskUsage { source: ProbeError },
|
|
||||||
|
|
||||||
#[snafu(display("Failed to retrieve load average statistics: {}", source))]
|
impl fmt::Display for StatError {
|
||||||
ReadLoadAvg { source: ProbeError },
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
#[snafu(display("Failed to retrieve memory statistics: {}", source))]
|
StatError::CpuStat { ref source } => {
|
||||||
ReadMemStat { source: ProbeError },
|
write!(f, "Failed to retrieve CPU statistics: {}", source)
|
||||||
|
}
|
||||||
#[snafu(display("Failed to retrieve system uptime: {}", source))]
|
StatError::DiskUsage { ref source } => {
|
||||||
ReadUptime { source: io::Error },
|
write!(f, "Failed to retrieve disk usage statistics: {}", source)
|
||||||
|
}
|
||||||
#[snafu(display("JSON serialization failed: {}", source))]
|
StatError::LoadAvg { ref source } => {
|
||||||
SerdeSerialize { source: SerdeError },
|
write!(f, "Failed to retrieve load average statistics: {}", source)
|
||||||
|
}
|
||||||
|
StatError::MemStat { ref source } => {
|
||||||
|
write!(f, "Failed to retrieve memory statistics: {}", source)
|
||||||
|
}
|
||||||
|
StatError::Uptime { ref source } => {
|
||||||
|
write!(f, "Failed to retrieve system uptime: {}", source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StatError> for Error {
|
impl From<StatError> for Error {
|
||||||
fn from(err: StatError) -> Self {
|
fn from(err: StatError) -> Self {
|
||||||
match &err {
|
match &err {
|
||||||
StatError::ReadCpuStat { source } => Error {
|
StatError::CpuStat { source } => Error {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("Failed to retrieve CPU statistics: {}", source),
|
message: format!("Failed to retrieve CPU statistics: {}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
StatError::ReadDiskUsage { source } => Error {
|
StatError::DiskUsage { source } => Error {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("Failed to retrieve disk usage statistics: {}", source),
|
message: format!("Failed to retrieve disk usage statistics: {}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
StatError::ReadLoadAvg { source } => Error {
|
StatError::LoadAvg { source } => Error {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("Failed to retrieve load average statistics: {}", source),
|
message: format!("Failed to retrieve load average statistics: {}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
StatError::ReadMemStat { source } => Error {
|
StatError::MemStat { source } => Error {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("Failed to retrieve memory statistics: {}", source),
|
message: format!("Failed to retrieve memory statistics: {}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
StatError::ReadUptime { source } => Error {
|
StatError::Uptime { source } => Error {
|
||||||
code: ErrorCode::ServerError(-32001),
|
code: ErrorCode::ServerError(-32001),
|
||||||
message: format!("Failed to retrieve system uptime: {}", source),
|
message: format!("Failed to retrieve system uptime: {}", source),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
StatError::SerdeSerialize { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32002),
|
|
||||||
message: format!("JSON serialization failed: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,56 +6,56 @@ use std::{env, result::Result};
|
||||||
|
|
||||||
use jsonrpc_core::{IoHandler, Value};
|
use jsonrpc_core::{IoHandler, Value};
|
||||||
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
|
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
|
||||||
#[allow(unused_imports)]
|
|
||||||
use jsonrpc_test as test;
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::error::BoxError;
|
use crate::error::StatError;
|
||||||
|
|
||||||
pub fn run() -> Result<(), BoxError> {
|
pub fn run() -> Result<(), StatError> {
|
||||||
info!("Starting up.");
|
info!("Starting up.");
|
||||||
|
|
||||||
info!("Creating JSON-RPC I/O handler.");
|
info!("Creating JSON-RPC I/O handler.");
|
||||||
let mut io = IoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
|
|
||||||
io.add_method("cpu_stats", move |_| {
|
io.add_method("cpu_stats", move |_| async {
|
||||||
info!("Fetching CPU statistics.");
|
info!("Fetching CPU statistics.");
|
||||||
let stats = stats::cpu_stats()?;
|
let stats = stats::cpu_stats()?;
|
||||||
|
|
||||||
Ok(Value::String(stats))
|
Ok(Value::String(stats))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_method("cpu_stats_percent", move |_| {
|
io.add_method("cpu_stats_percent", move |_| async {
|
||||||
info!("Fetching CPU statistics as percentages.");
|
info!("Fetching CPU statistics as percentages.");
|
||||||
let stats = stats::cpu_stats_percent()?;
|
let stats = stats::cpu_stats_percent()?;
|
||||||
|
|
||||||
Ok(Value::String(stats))
|
Ok(Value::String(stats))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_method("disk_usage", move |_| {
|
io.add_method("disk_usage", move |_| async {
|
||||||
info!("Fetching disk usage statistics.");
|
info!("Fetching disk usage statistics.");
|
||||||
let disks = stats::disk_usage()?;
|
let disks = stats::disk_usage()?;
|
||||||
|
|
||||||
Ok(Value::String(disks))
|
Ok(Value::String(disks))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_method("load_average", move |_| {
|
io.add_method("load_average", move |_| async {
|
||||||
info!("Fetching system load average statistics.");
|
info!("Fetching system load average statistics.");
|
||||||
let avg = stats::load_average()?;
|
let avg = stats::load_average()?;
|
||||||
|
|
||||||
Ok(Value::String(avg))
|
Ok(Value::String(avg))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_method("mem_stats", move |_| {
|
io.add_method("mem_stats", move |_| async {
|
||||||
info!("Fetching current memory statistics.");
|
info!("Fetching current memory statistics.");
|
||||||
let mem = stats::mem_stats()?;
|
let mem = stats::mem_stats()?;
|
||||||
|
|
||||||
Ok(Value::String(mem))
|
Ok(Value::String(mem))
|
||||||
});
|
});
|
||||||
|
|
||||||
io.add_method("ping", |_| Ok(Value::String("success".to_string())));
|
io.add_method("ping", |_| async {
|
||||||
|
Ok(Value::String("success".to_string()))
|
||||||
|
});
|
||||||
|
|
||||||
io.add_method("uptime", move |_| {
|
io.add_method("uptime", move |_| async {
|
||||||
info!("Fetching system uptime.");
|
info!("Fetching system uptime.");
|
||||||
let uptime = stats::uptime()?;
|
let uptime = stats::uptime()?;
|
||||||
|
|
||||||
|
@ -85,16 +85,17 @@ pub fn run() -> Result<(), BoxError> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use jsonrpc_test as test_rpc;
|
||||||
|
|
||||||
// test to ensure correct success response
|
// test to ensure correct success response
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_success() {
|
fn rpc_success() {
|
||||||
let rpc = {
|
let rpc = {
|
||||||
let mut io = IoHandler::new();
|
let mut io = IoHandler::new();
|
||||||
io.add_method("rpc_success_response", |_| {
|
io.add_method("rpc_success_response", |_| async {
|
||||||
Ok(Value::String("success".into()))
|
Ok(Value::String("success".into()))
|
||||||
});
|
});
|
||||||
test::Rpc::from(io)
|
test_rpc::Rpc::from(io)
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#);
|
assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
|
||||||
|
use miniserde::json;
|
||||||
use probes::{cpu, disk_usage, load, memory};
|
use probes::{cpu, disk_usage, load, memory};
|
||||||
use snafu::ResultExt;
|
|
||||||
use systemstat::{Platform, System};
|
use systemstat::{Platform, System};
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::StatError;
|
||||||
use crate::structs::{CpuStat, CpuStatPercentages, DiskUsage, LoadAverage, MemStat};
|
use crate::structs::{CpuStat, CpuStatPercentages, DiskUsage, LoadAverage, MemStat};
|
||||||
|
|
||||||
pub fn cpu_stats() -> Result<String, StatError> {
|
pub fn cpu_stats() -> Result<String, StatError> {
|
||||||
let cpu_stats = cpu::proc::read().context(ReadCpuStat)?;
|
let cpu_stats = cpu::proc::read().map_err(|source| StatError::CpuStat { source })?;
|
||||||
let s = cpu_stats.stat;
|
let s = cpu_stats.stat;
|
||||||
let cpu = CpuStat {
|
let cpu = CpuStat {
|
||||||
user: s.user,
|
user: s.user,
|
||||||
|
@ -16,13 +16,13 @@ pub fn cpu_stats() -> Result<String, StatError> {
|
||||||
nice: s.nice,
|
nice: s.nice,
|
||||||
idle: s.idle,
|
idle: s.idle,
|
||||||
};
|
};
|
||||||
let json_cpu = serde_json::to_string(&cpu).context(SerdeSerialize)?;
|
let json_cpu = json::to_string(&cpu);
|
||||||
|
|
||||||
Ok(json_cpu)
|
Ok(json_cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cpu_stats_percent() -> Result<String, StatError> {
|
pub fn cpu_stats_percent() -> Result<String, StatError> {
|
||||||
let cpu_stats = cpu::proc::read().context(ReadCpuStat)?;
|
let cpu_stats = cpu::proc::read().map_err(|source| StatError::CpuStat { source })?;
|
||||||
let s = cpu_stats.stat.in_percentages();
|
let s = cpu_stats.stat.in_percentages();
|
||||||
let cpu = CpuStatPercentages {
|
let cpu = CpuStatPercentages {
|
||||||
user: s.user,
|
user: s.user,
|
||||||
|
@ -30,13 +30,13 @@ pub fn cpu_stats_percent() -> Result<String, StatError> {
|
||||||
nice: s.nice,
|
nice: s.nice,
|
||||||
idle: s.idle,
|
idle: s.idle,
|
||||||
};
|
};
|
||||||
let json_cpu = serde_json::to_string(&cpu).context(SerdeSerialize)?;
|
let json_cpu = json::to_string(&cpu);
|
||||||
|
|
||||||
Ok(json_cpu)
|
Ok(json_cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disk_usage() -> Result<String, StatError> {
|
pub fn disk_usage() -> Result<String, StatError> {
|
||||||
let disks = disk_usage::read().context(ReadDiskUsage)?;
|
let disks = disk_usage::read().map_err(|source| StatError::DiskUsage { source })?;
|
||||||
let mut disk_usages = Vec::new();
|
let mut disk_usages = Vec::new();
|
||||||
for d in disks {
|
for d in disks {
|
||||||
let disk = DiskUsage {
|
let disk = DiskUsage {
|
||||||
|
@ -49,39 +49,42 @@ pub fn disk_usage() -> Result<String, StatError> {
|
||||||
};
|
};
|
||||||
disk_usages.push(disk);
|
disk_usages.push(disk);
|
||||||
}
|
}
|
||||||
let json_disks = serde_json::to_string(&disk_usages).context(SerdeSerialize)?;
|
let json_disks = json::to_string(&disk_usages);
|
||||||
|
|
||||||
Ok(json_disks)
|
Ok(json_disks)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_average() -> Result<String, StatError> {
|
pub fn load_average() -> Result<String, StatError> {
|
||||||
let l = load::read().context(ReadLoadAvg)?;
|
let l = load::read().map_err(|source| StatError::LoadAvg { source })?;
|
||||||
let load_avg = LoadAverage {
|
let load_avg = LoadAverage {
|
||||||
one: l.one,
|
one: l.one,
|
||||||
five: l.five,
|
five: l.five,
|
||||||
fifteen: l.fifteen,
|
fifteen: l.fifteen,
|
||||||
};
|
};
|
||||||
let json_load_avg = serde_json::to_string(&load_avg).context(SerdeSerialize)?;
|
let json_load_avg = json::to_string(&load_avg);
|
||||||
|
|
||||||
Ok(json_load_avg)
|
Ok(json_load_avg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mem_stats() -> Result<String, StatError> {
|
pub fn mem_stats() -> Result<String, StatError> {
|
||||||
let m = memory::read().context(ReadMemStat)?;
|
let m = memory::read().map_err(|source| StatError::MemStat { source })?;
|
||||||
let mem = MemStat {
|
let mem = MemStat {
|
||||||
total: m.total(),
|
total: m.total(),
|
||||||
free: m.free(),
|
free: m.free(),
|
||||||
used: m.used(),
|
used: m.used(),
|
||||||
};
|
};
|
||||||
let json_mem = serde_json::to_string(&mem).context(SerdeSerialize)?;
|
let json_mem = json::to_string(&mem);
|
||||||
|
|
||||||
Ok(json_mem)
|
Ok(json_mem)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uptime() -> Result<String, StatError> {
|
pub fn uptime() -> Result<String, StatError> {
|
||||||
let sys = System::new();
|
let sys = System::new();
|
||||||
let uptime = sys.uptime().context(ReadUptime)?;
|
let uptime = sys
|
||||||
let json_uptime = serde_json::to_string(&uptime).context(SerdeSerialize)?;
|
.uptime()
|
||||||
|
.map_err(|source| StatError::Uptime { source })?;
|
||||||
|
let uptime_secs = uptime.as_secs();
|
||||||
|
let json_uptime = json::to_string(&uptime_secs);
|
||||||
|
|
||||||
Ok(json_uptime)
|
Ok(json_uptime)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use serde::Serialize;
|
use miniserde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct CpuStat {
|
pub struct CpuStat {
|
||||||
|
|
Loading…
Reference in New Issue