dmesg: implement print json.

This commit is contained in:
Fuad Ismail 2024-11-15 19:05:31 +07:00
parent a044bece47
commit d1066420e7
4 changed files with 158 additions and 4 deletions

2
Cargo.lock generated

@ -905,6 +905,8 @@ version = "0.0.1"
dependencies = [
"clap",
"regex",
"serde",
"serde_json",
"uucore",
]

@ -14,3 +14,5 @@ path = "src/main.rs"
clap = { workspace = true }
uucore = { workspace = true }
regex = { workspace = true }
serde_json = { workspace = true }
serde = { workspace = true }

@ -3,6 +3,8 @@ use regex::Regex;
use std::fs;
use uucore::error::UResult;
mod json;
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let mut dmesg = Dmesg::new();
@ -42,7 +44,7 @@ mod options {
struct Dmesg<'a> {
kmsg_file: &'a str,
output_format: OutputFormat,
_records: Option<Vec<Record>>,
records: Option<Vec<Record>>,
}
impl Dmesg<'_> {
@ -50,7 +52,7 @@ impl Dmesg<'_> {
Dmesg {
kmsg_file: "/dev/kmsg",
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()));
}
}
self._records = Some(records);
self.records = Some(records);
Ok(self)
}
@ -91,7 +93,18 @@ impl Dmesg<'_> {
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 {

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())
}
}