Skip to content

Commit

Permalink
DLT SomeIP: Make solution more broad supporting templating
Browse files Browse the repository at this point in the history
* Resolving log messages provides an enum with text or template which
  need to be resolved.
* Sessions can try to resolve all the chunks from the templates
* Faulty messages are removed for now to keep the focus here on multiple
  parsers.
* Renaming modules, types and methods
  • Loading branch information
AmmarAbouZor committed Sep 6, 2024
1 parent c6a7b8f commit 6df3299
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 170 deletions.
8 changes: 4 additions & 4 deletions application/apps/indexer/indexer_cli/src/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use parsers::{dlt::DltParser, MessageStreamItem, ParseYield};
use processor::grabber::LineRange;
use rustyline::{error::ReadlineError, DefaultEditor};
use session::{
parse_err::{get_log_text, ParseErrorReslover},
parse_rest_resolver::{resolve_log_msg, ParseRestReslover},
session::Session,
};
use sources::{
Expand Down Expand Up @@ -49,7 +49,7 @@ pub(crate) async fn handle_interactive_session(input: Option<PathBuf>) {
let udp_source = UdpSource::new(RECEIVER, vec![]).await.unwrap();
let dlt_parser = DltParser::new(None, None, None, false);
let mut dlt_msg_producer = MessageProducer::new(dlt_parser, udp_source, None);
let mut parse_reslover = ParseErrorReslover::new();
let mut parse_reslover = ParseRestReslover::new();
let msg_stream = dlt_msg_producer.as_stream();
pin_mut!(msg_stream);
loop {
Expand All @@ -61,11 +61,11 @@ pub(crate) async fn handle_interactive_session(input: Option<PathBuf>) {
item = msg_stream.next() => {
match item {
Some((_, MessageStreamItem::Item(ParseYield::Message(item)))) => {
let msg = get_log_text(item, &mut parse_reslover);
let msg = resolve_log_msg(item, &mut parse_reslover);
println!("msg: {msg}");
}
Some((_, MessageStreamItem::Item(ParseYield::MessageAndAttachment((item, attachment))))) => {
let msg = get_log_text(item, &mut parse_reslover);
let msg = resolve_log_msg(item, &mut parse_reslover);
println!("msg: {msg}, attachment: {attachment:?}");
}
Some((_, MessageStreamItem::Item(ParseYield::Attachment(attachment)))) => {
Expand Down
18 changes: 9 additions & 9 deletions application/apps/indexer/parsers/src/dlt/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use std::{
str,
};

use crate::{LogMessage, ParseLogError, ResolveErrorHint, ToTextResult};
use crate::{LogMessage, LogMessageContent, ResolveParseHint, TemplateLogMsg, TemplateLogMsgChunk};

const DLT_COLUMN_SENTINAL: char = '\u{0004}';
const DLT_ARGUMENT_SENTINAL: char = '\u{0005}';
Expand Down Expand Up @@ -538,8 +538,6 @@ impl<'a> FormattableMessage<'a> {
}

impl LogMessage for FormattableMessage<'_> {
const CAN_ERROR: bool = true;

fn to_writer<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
let bytes = self.message.as_bytes();
let len = bytes.len();
Expand All @@ -563,7 +561,7 @@ impl LogMessage for FormattableMessage<'_> {
/// context-id
///
/// payload
fn to_text(&self) -> ToTextResult {
fn try_resolve(&self) -> LogMessageContent {
let mut msg = String::new();
// Taken from Documentation: string formatting is considered an infallible operation.
// Thus we can ignore `fmt::Error` errors.
Expand Down Expand Up @@ -623,12 +621,14 @@ impl LogMessage for FormattableMessage<'_> {

if is_someip {
if let Some(slice) = slices.get(1) {
let err = ParseLogError::new(
slice.to_owned(),
crate::ParseErrorType::Other("Need Some IP".into()),
Some(ResolveErrorHint::SomeIP),
let template = TemplateLogMsg::new(
vec![
TemplateLogMsgChunk::Text(msg),
TemplateLogMsgChunk::Bytes(slice.to_owned()),
],
vec![ResolveParseHint::SomeIP],
);
return ToTextResult::new(msg, Some(err));
return LogMessageContent::Template(template);
}
}

Expand Down
8 changes: 2 additions & 6 deletions application/apps/indexer/parsers/src/dlt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,26 @@ impl std::fmt::Display for RawMessage {
}

impl LogMessage for RangeMessage {
const CAN_ERROR: bool = false;

/// A RangeMessage only has range information and cannot serialize to bytes
fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
writer.write_u64::<BigEndian>(self.range.start as u64)?;
writer.write_u64::<BigEndian>(self.range.end as u64)?;
Ok(8 + 8)
}

fn to_text(&self) -> crate::ToTextResult {
fn try_resolve(&self) -> crate::LogMessageContent {
self.into()
}
}

impl LogMessage for RawMessage {
const CAN_ERROR: bool = false;

fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
let len = self.content.len();
writer.write_all(&self.content)?;
Ok(len)
}

fn to_text(&self) -> crate::ToTextResult {
fn try_resolve(&self) -> crate::LogMessageContent {
self.into()
}
}
Expand Down
168 changes: 97 additions & 71 deletions application/apps/indexer/parsers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,99 +78,125 @@ pub enum ByteRepresentation {
Range((usize, usize)),
}

#[derive(Debug, Clone)]
pub enum ParseErrorType {
Fmt(String),
Other(String),
#[derive(Debug)]
pub enum MessageStreamItem<T: LogMessage> {
Item(ParseYield<T>),
Skipped,
Incomplete,
Empty,
Done,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// Gives Hint about how this error can be resolved by processor
pub enum ResolveErrorHint {
/// The message needs to be parsed with SomeIP Parser.
SomeIP,
pub trait LogMessage: Serialize {
/// Serializes a message directly into a Writer
/// returns the size of the serialized message
fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error>;

/// Tries to resolve the message to get its text representation.
///
/// TODO: This function should return another optional field, containing information
/// about errors, warning ...
fn try_resolve(&self) -> LogMessageContent;
}

#[derive(Debug, Clone)]
pub struct ParseLogError {
pub remain_bytes: Vec<u8>,
pub error_type: ParseErrorType,
pub resolve_hint: Option<ResolveErrorHint>,
}

impl ParseLogError {
pub fn new(
remain_bytes: Vec<u8>,
error_type: ParseErrorType,
resolve_hint: Option<ResolveErrorHint>,
) -> Self {
Self {
remain_bytes,
error_type,
resolve_hint,
}
}
/// Represents The content of a log message after trying to resolve it.
pub enum LogMessageContent {
Text(String),
Template(TemplateLogMsg),
}

impl Display for ParseLogError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.error_type {
ParseErrorType::Other(msg) | ParseErrorType::Fmt(msg) => write!(f, "{msg}"),
}
}
#[derive(Debug, Clone)]
/// Represents an unresolved log messages that contains chunks that needs to be resolved.
pub struct TemplateLogMsg {
chunks: Vec<TemplateLogMsgChunk>,
resolve_hints: Vec<ResolveParseHint>,
}

impl From<std::fmt::Error> for ParseLogError {
fn from(value: std::fmt::Error) -> Self {
Self {
remain_bytes: Vec::new(),
error_type: ParseErrorType::Fmt(value.to_string()),
resolve_hint: None,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Gives Hint about how the payload rest can be resolved
pub enum ResolveParseHint {
/// The message needs to be parsed with SomeIP Parser.
SomeIP,
}

impl std::error::Error for ParseLogError {}

#[derive(Debug, Clone)]
pub struct ToTextResult {
pub msg: String,
pub error: Option<ParseLogError>,
}

impl ToTextResult {
pub fn new(msg: String, error: Option<ParseLogError>) -> Self {
Self { msg, error }
}
/// Represents a chunk in [`TemplateLogMsg`]
pub enum TemplateLogMsgChunk {
/// Resolved Chunk
Text(String),
/// Unresolved Chunk
Bytes(Vec<u8>),
}

impl<T> From<T> for ToTextResult
impl<T> From<T> for LogMessageContent
where
T: Display,
{
fn from(value: T) -> Self {
Self::new(value.to_string(), None)
Self::Text(value.to_string())
}
}

pub trait LogMessage: Serialize {
//TODO AAZ: Measure this an remove if rust already optimize the code without it.
/// Indicates that parsing this struct to text can error.
const CAN_ERROR: bool;
impl TemplateLogMsg {
pub fn new(chunks: Vec<TemplateLogMsgChunk>, resolve_hints: Vec<ResolveParseHint>) -> Self {
Self {
chunks,
resolve_hints,
}
}

/// Serializes a message directly into a Writer
/// returns the size of the serialized message
fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error>;
pub fn get_resolve_hints(&self) -> Vec<ResolveParseHint> {
self.resolve_hints.to_vec()
}

/// Get the text representation of this message.
fn to_text(&self) -> ToTextResult;
}
/// Applies the given [`FnMut`] on the unresolved chunks, replacing them with texts if succeed.
/// This function will return a String once chunks get resolved.
///
/// * `parse_fn`: Function to apply on the unresolved chunks.
pub fn try_resolve<F>(&mut self, mut parse_fn: F) -> Option<String>
where
F: FnMut(&[u8]) -> Option<String>,
{
let mut all_resolved = true;
for ch in self.chunks.iter_mut() {
match ch {
TemplateLogMsgChunk::Text(_) => continue,
TemplateLogMsgChunk::Bytes(bytes) => match parse_fn(&bytes) {
Some(resolved) => *ch = TemplateLogMsgChunk::Text(resolved),
None => all_resolved = false,
},
}
}

#[derive(Debug)]
pub enum MessageStreamItem<T: LogMessage> {
Item(ParseYield<T>),
Skipped,
Incomplete,
Empty,
Done,
if all_resolved {
self.chunks
.iter()
.map(|ch| match ch {
TemplateLogMsgChunk::Text(msg) => msg,
TemplateLogMsgChunk::Bytes(_) => panic!("All must be resolved"),
})
.cloned()
.reduce(|mut acc, msg| {
acc.push_str(&msg);
acc
})
} else {
None
}
}

/// Concatenates the chunks to a string, replacing the unresolved chunks with their bytes
/// representation.
pub fn resolve_lossy(self) -> String {
self.chunks
.into_iter()
.fold(String::new(), |mut acc, ch| match ch {
TemplateLogMsgChunk::Text(msg) => {
acc.push_str(&msg);
acc
}
TemplateLogMsgChunk::Bytes(bytes) => format!("{acc} {bytes:?}"),
})
}
}
6 changes: 2 additions & 4 deletions application/apps/indexer/parsers/src/someip.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Error, LogMessage, ParseYield, Parser, ToTextResult};
use crate::{Error, LogMessage, LogMessageContent, ParseYield, Parser};
use std::{borrow::Cow, fmt, fmt::Display, io::Write, path::PathBuf};

use someip_messages::*;
Expand Down Expand Up @@ -325,14 +325,12 @@ impl SomeipLogMessage {
}

impl LogMessage for SomeipLogMessage {
const CAN_ERROR: bool = false;

fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
writer.write_all(&self.bytes)?;
Ok(self.bytes.len())
}

fn to_text(&self) -> ToTextResult {
fn try_resolve(&self) -> LogMessageContent {
self.into()
}
}
Expand Down
6 changes: 2 additions & 4 deletions application/apps/indexer/parsers/src/text.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Error, LogMessage, ParseYield, Parser, ToTextResult};
use crate::{Error, LogMessage, LogMessageContent, ParseYield, Parser};
use serde::Serialize;
use std::{fmt, io::Write};

Expand All @@ -16,15 +16,13 @@ impl fmt::Display for StringMessage {
}

impl LogMessage for StringMessage {
const CAN_ERROR: bool = false;

fn to_writer<W: Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> {
let len = self.content.len();
writer.write_all(self.content.as_bytes())?;
Ok(len)
}

fn to_text(&self) -> ToTextResult {
fn try_resolve(&self) -> LogMessageContent {
self.into()
}
}
Expand Down
Loading

0 comments on commit 6df3299

Please sign in to comment.