dmesg: implement print json.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -905,6 +905,8 @@ version = "0.0.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"regex",
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"uucore",
|
"uucore",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -14,3 +14,5 @@ path = "src/main.rs"
|
|||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
uucore = { workspace = true }
|
uucore = { workspace = true }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
|
@ -3,6 +3,8 @@ use regex::Regex;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
|
|
||||||
|
mod json;
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let mut dmesg = Dmesg::new();
|
let mut dmesg = Dmesg::new();
|
||||||
@ -42,7 +44,7 @@ mod options {
|
|||||||
struct Dmesg<'a> {
|
struct Dmesg<'a> {
|
||||||
kmsg_file: &'a str,
|
kmsg_file: &'a str,
|
||||||
output_format: OutputFormat,
|
output_format: OutputFormat,
|
||||||
_records: Option<Vec<Record>>,
|
records: Option<Vec<Record>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dmesg<'_> {
|
impl Dmesg<'_> {
|
||||||
@ -50,7 +52,7 @@ impl Dmesg<'_> {
|
|||||||
Dmesg {
|
Dmesg {
|
||||||
kmsg_file: "/dev/kmsg",
|
kmsg_file: "/dev/kmsg",
|
||||||
output_format: OutputFormat::Normal,
|
output_format: OutputFormat::Normal,
|
||||||
_records: None,
|
records: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ impl Dmesg<'_> {
|
|||||||
records.push(Record::from_str_fields(pri_fac, seq, time, msg.to_string()));
|
records.push(Record::from_str_fields(pri_fac, seq, time, msg.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self._records = Some(records);
|
self.records = Some(records);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +93,18 @@ impl Dmesg<'_> {
|
|||||||
Ok(lines)
|
Ok(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print(&self) {}
|
fn print(&self) {
|
||||||
|
match self.output_format {
|
||||||
|
OutputFormat::Json => self.print_json(),
|
||||||
|
OutputFormat::Normal => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_json(&self) {
|
||||||
|
if let Some(records) = &self.records {
|
||||||
|
println!("{}", json::serialize_records(records));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OutputFormat {
|
enum OutputFormat {
|
||||||
|
137
src/uu/dmesg/src/json.rs
Normal file
137
src/uu/dmesg/src/json.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub fn serialize_records(records: &Vec<crate::Record>) -> String {
|
||||||
|
let json = Dmesg::from(records);
|
||||||
|
let formatter = DmesgFormatter::new();
|
||||||
|
let mut buf = vec![];
|
||||||
|
let mut serializer = serde_json::Serializer::with_formatter(&mut buf, formatter);
|
||||||
|
json.serialize(&mut serializer).unwrap();
|
||||||
|
String::from_utf8_lossy(&buf).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct Dmesg<'a> {
|
||||||
|
dmesg: Vec<Record<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct Record<'a> {
|
||||||
|
pri: u32,
|
||||||
|
time: u64,
|
||||||
|
msg: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Vec<crate::Record>> for Dmesg<'a> {
|
||||||
|
fn from(value: &'a Vec<crate::Record>) -> Self {
|
||||||
|
let mut dmesg_json = Dmesg { dmesg: vec![] };
|
||||||
|
for record in value {
|
||||||
|
let record_json = Record {
|
||||||
|
pri: record._priority_facility,
|
||||||
|
time: record._timestamp_us,
|
||||||
|
msg: &record._message,
|
||||||
|
};
|
||||||
|
dmesg_json.dmesg.push(record_json);
|
||||||
|
}
|
||||||
|
dmesg_json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DmesgFormatter {
|
||||||
|
nesting_depth: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DmesgFormatter {
|
||||||
|
const SINGLE_INDENTATION: &[u8] = b" ";
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
DmesgFormatter { nesting_depth: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_indentation<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
for _ in 0..self.nesting_depth {
|
||||||
|
writer.write_all(Self::SINGLE_INDENTATION)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde_json::ser::Formatter for DmesgFormatter {
|
||||||
|
fn begin_object<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
self.nesting_depth += 1;
|
||||||
|
writer.write_all(b"{\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_object<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
writer.write_all(b"\n")?;
|
||||||
|
self.nesting_depth -= 1;
|
||||||
|
self.write_indentation(writer)?;
|
||||||
|
writer.write_all(b"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_array<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
self.nesting_depth += 1;
|
||||||
|
writer.write_all(b"[\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_array<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
writer.write_all(b"\n")?;
|
||||||
|
self.nesting_depth -= 1;
|
||||||
|
self.write_indentation(writer)?;
|
||||||
|
writer.write_all(b"]")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_object_key<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
if !first {
|
||||||
|
writer.write_all(b",\n")?;
|
||||||
|
}
|
||||||
|
self.write_indentation(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_object_value<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
writer.write_all(b": ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_array_value<W>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
if first {
|
||||||
|
self.write_indentation(writer)
|
||||||
|
} else {
|
||||||
|
writer.write_all(b",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u64<W>(&mut self, writer: &mut W, value: u64) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: ?Sized + io::Write,
|
||||||
|
{
|
||||||
|
// The only u64 field in Dmesg is time, which requires a specific format
|
||||||
|
let seconds = value / 1000000;
|
||||||
|
let sub_seconds = value % 1000000;
|
||||||
|
let repr = format!("{:>5}.{:0>6}", seconds, sub_seconds);
|
||||||
|
writer.write_all(repr.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user