mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
do some variable flattening when extracting log messages
This commit is contained in:
parent
6b9211667d
commit
a463903d24
4 changed files with 186 additions and 131 deletions
|
|
@ -86,8 +86,9 @@ impl LogExtractor {
|
|||
let mut message_builder = MessageBuilder::with_capacity(16);
|
||||
|
||||
if let Some(argument) = call.arguments {
|
||||
let mut context = self.get_context_assignments(code, argument);
|
||||
let argument = argument.child(0)?;
|
||||
message_builder.push_node(argument, code);
|
||||
message_builder.push_node(argument, code, &mut context);
|
||||
}
|
||||
|
||||
let exception = call
|
||||
|
|
@ -211,6 +212,24 @@ impl LogExtractor {
|
|||
})
|
||||
.unwrap_or("")
|
||||
}
|
||||
|
||||
fn get_context_assignments<'a>(&'a self, code: &'a str, mut node: Node<'a>) -> HashMap<&'a str, Node<'a>> {
|
||||
let mut assignments = HashMap::new();
|
||||
let mut cursor = node.walk();
|
||||
while let Some(parent) = node.parent() {
|
||||
node = parent;
|
||||
if ["method_declaration", "function_definition"].contains(&parent.grammar_name()) {
|
||||
break;
|
||||
}
|
||||
let child_assignments = node.children(&mut cursor)
|
||||
.filter_map(|child| (child.grammar_name() == "expression_statement").then(|| child.child(0).unwrap()))
|
||||
.filter(|child| child.grammar_name() == "assignment_expression")
|
||||
.filter_map(|child| Some((child.child_by_field_name("left")?.child(1).unwrap(), child.child_by_field_name("right")?)))
|
||||
.map(|(left, right)| (left.utf8_text(code.as_bytes()).unwrap(), right));
|
||||
assignments.extend(child_assignments);
|
||||
}
|
||||
assignments
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LogExtractor {
|
||||
|
|
@ -247,6 +266,8 @@ fn test_extract_logging() {
|
|||
$this->logger->error("foo {bar} {asd}");
|
||||
$this->logger->error($this->l10n->t("translated %s", $foo));
|
||||
throw new InvalidArgumentException(sprintf('Argument "%s" not found.', $key));
|
||||
$baseMsg = 'Could not resolve ' . $name . '!';
|
||||
throw new QueryNotFoundException($baseMsg . ' ' . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
"#;
|
||||
|
|
@ -398,4 +419,20 @@ fn test_extract_logging() {
|
|||
]
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
logs[11],
|
||||
LoggingStatement {
|
||||
path: "foo.php",
|
||||
line: 19,
|
||||
level: LogLevel::Exception,
|
||||
has_meaningful_message: true,
|
||||
exception: Some("Test\\QueryNotFoundException".into()),
|
||||
message_parts: vec![
|
||||
MessagePart::Literal(r#"Could not resolve "#.into()),
|
||||
MessagePart::PlaceHolder("$name".into()),
|
||||
MessagePart::Literal(r#"! "#.into()),
|
||||
MessagePart::PlaceHolder(r#"$e->getMessage()"#.into()),
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use crate::string::{unescape, DoubleQuoteString, SingleQuoteString};
|
||||
use crate::MessagePart;
|
||||
use regex::Regex;
|
||||
|
|
@ -81,7 +82,7 @@ impl MessageBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn push_node(&mut self, node: Node, code: &str) {
|
||||
pub fn push_node(&mut self, node: Node, code: &str, context: &mut HashMap<&str, Node>) {
|
||||
let mut cursor = node.walk();
|
||||
match node.grammar_name() {
|
||||
"string" | "encapsed_string" => {
|
||||
|
|
@ -93,10 +94,21 @@ impl MessageBuilder {
|
|||
let operator = &code[start..end];
|
||||
if operator.trim() == "." {
|
||||
for part in node.named_children(&mut cursor) {
|
||||
self.push_node(part, code);
|
||||
self.push_node(part, code, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
"variable_name" => {
|
||||
let name = node.child(1).map(|c| c.utf8_text(code.as_bytes()).unwrap()).unwrap_or_default();
|
||||
if let Some(replacement) = context.remove(name) {
|
||||
if has_literal(replacement, code, context) {
|
||||
self.push_node(replacement, code, context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let placeholder = node.utf8_text(code.as_bytes()).unwrap();
|
||||
self.push_placeholder(placeholder);
|
||||
}
|
||||
"member_call_expression" | "function_call_expression" => {
|
||||
match node
|
||||
.child_by_field_name("name")
|
||||
|
|
@ -144,6 +156,12 @@ impl MessageBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_literal(node: Node, code: &str, context: &HashMap<&str, Node>) -> bool {
|
||||
let mut replacement_builder = MessageBuilder::with_capacity(4);
|
||||
replacement_builder.push_node(node.clone(), code, &mut context.clone());
|
||||
replacement_builder.parts.iter().any(|part| matches!(part, MessagePart::Literal(_)))
|
||||
}
|
||||
|
||||
impl From<MessageBuilder> for Vec<MessagePart> {
|
||||
fn from(value: MessageBuilder) -> Self {
|
||||
value.parts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue