Skip to content

Commit

Permalink
Fix FTrace Text in the case of Docker/K8S traces
Browse files Browse the repository at this point in the history
Docker containers have exec names like "comm=runc:[2:INIT]",
the regular expressions need to be updated to accommodate this.

1- the separator type (=:) needs to be retained and
consistent on a per-event basis
2- the fields need to be parsed in a more aggressive way,
allowing consumption of the elems
3- Brackets are acceptable for comms even though they are also arrays

This lead to an "excemption" for the patterns  command:[level:phase]
from the value parser.

Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I19d54073ab5ac6fd9b93fdc0e6a48c1d35e6913c
Reviewed-on: https://git.eclipse.org/r/c/tracecompass.incubator/org.eclipse.tracecompass.incubator/+/200223
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
  • Loading branch information
MatthewKhouzam committed Feb 28, 2023
1 parent 7013173 commit ffbbc08
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@

package org.eclipse.tracecompass.incubator.ftrace.core.tests.event;

import org.eclipse.tracecompass.incubator.internal.ftrace.core.event.GenericFtraceField;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.tracecompass.incubator.internal.ftrace.core.event.GenericFtraceField;
import org.junit.Test;

/**
* FtraceField test class
*
Expand Down Expand Up @@ -53,9 +60,9 @@ public void testParseSchedWakeupLine() {
}

/**
* Testing of parse line with function using line from an ftrace output where
* the command name contains a space (comm=daemo su), check that the parsed
* comm field value is the complete name, including the space.
* Testing of parse line with function using line from an ftrace output
* where the command name contains a space (comm=daemo su), check that the
* parsed comm field value is the complete name, including the space.
*/
@Test
public void testParseEventWithCommPropertyWithSpace() {
Expand Down Expand Up @@ -166,8 +173,8 @@ public void testParseSysCallExitTraceCmd() {
}

/**
* Testing of parse line with Irq_raise event function using line from an ftrace
* output
* Testing of parse line with Irq_raise event function using line from an
* ftrace output
*/
@Test
public void testParseIrqRaise() {
Expand All @@ -176,10 +183,66 @@ public void testParseIrqRaise() {
GenericFtraceField field = GenericFtraceField.parseLine(line);

assertNotNull(field);
assertEquals(2, field.getContent().getFields().size());
assertEquals((Integer) 1, field.getCpu());
assertEquals("softirq_raise", field.getName());

assertEquals((Long) 9L, field.getContent().getFieldValue(Long.class, "vec"));
assertEquals("RCU", field.getContent().getFieldValue(String.class, "action"));
}

/**
* Testing of parse line with odd comm names
*/
@Test
public void testSpecialCharsInComm() {
List<@NonNull ResultsParse> tests = List.of(new ResultsParse(
" <...>-919973 [019] ..... 40313.809636: sched_process_fork: comm=runc:[2:INIT] pid=919973 child_comm=runc:[2:INIT] child_pid=919974",
19, "sched_process_fork", Objects.requireNonNull(Map.of("comm", "runc:[2:INIT]")), 4),
new ResultsParse("ksoftirqd/16-112 [016] ..s.. 40318.937233: sched_process_free: comm=runc:[2:INIT] pid=920437 prio=120",
16, "sched_process_free", Objects.requireNonNull(Map.of("comm", "runc:[2:INIT]")), 3),
new ResultsParse("<idle>-0 [021] ..s1. 40318.941173: sched_process_free: comm=runc:[0:PARENT] pid=920430 prio=120",
21, "sched_process_free", Objects.requireNonNull(Map.of("comm", "runc:[0:PARENT]")), 3),
new ResultsParse("<idle>-0 [021] ..s1. 40318.941177: sched_process_free: comm=runc:[1:CHILD] pid=920431 prio=120",
21, "sched_process_free", Objects.requireNonNull(Map.of("comm", "runc:[1:CHILD]")), 3),
new ResultsParse("kworker/0:0-9514 [000] d..4 3210.263482: sched_wakeup: comm=daemo su pid=16620 prio=120 success=1 target_cpu=000",
0, "sched_wakeup", Objects.requireNonNull(Map.of("comm", "daemo su")), 5));
for (ResultsParse test : tests) {
test.test();
}
}

@NonNullByDefault
private static class ResultsParse {

private final String fInput;
private final Integer fCpu;
private final String fName;
private Map<String, Object> fFields;
private int fFieldCount;

public ResultsParse(String input, Integer cpu, String name, Map<String, Object> fields, int fieldCount) {
assertNotNull(input);
assertNotNull(cpu);
assertNotNull(name);
assertNotNull(fields);
assertNotNull(fieldCount);
fInput = input;
fCpu = cpu;
fName = name;
fFields = fields;
fFieldCount = fieldCount;
}

public void test() {
GenericFtraceField field = GenericFtraceField.parseLine(fInput);
assertNotNull(fInput, field);
assertEquals(fInput, fCpu, field.getCpu());
assertEquals(fInput, fName, field.getName());
assertEquals(fInput, fFieldCount, field.getContent().getFields().size());
for (Entry<String, Object> currentField : fFields.entrySet()) {
assertEquals(fInput + ' ' + currentField.getKey(), currentField.getValue(), field.getContent().getFieldValue(String.class, currentField.getKey()));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@
@NonNullByDefault
public class GenericFtraceField {

private static final Pattern KEYVAL_KEY_PATTERN = Pattern.compile("(?<key>[^\\s=\\[\\],]+)(=|:)"); //$NON-NLS-1$
private static final Pattern KEYVAL_KEY_PATTERN = Pattern.compile("(?<key>[^\\s=\\[\\],]+)(?<separator>[=:])"); //$NON-NLS-1$
private static final Pattern KEYVAL_VALUE_PATTERN = Pattern.compile("\\s*(?<value>[^\\[\\],]+).*"); //$NON-NLS-1$
private static final Pattern KEYVAL_VALUE_DOCKER_BYPASS = Pattern.compile("\\S+:\\[\\S+:\\S+\\]"); //$NON-NLS-1$
private static final Map<String, Pattern> KEYVAL_KEY_PATTERN_MAP = Map.of("=", Pattern.compile("(?<key>[^\\s=\\[\\],]+)(?<separator>=)"), //$NON-NLS-1$ //$NON-NLS-2$
":", Pattern.compile("(?<key>[^\\s=\\[\\],]+)(?<separator>:)"), //$NON-NLS-1$ //$NON-NLS-2$
"", KEYVAL_KEY_PATTERN); //$NON-NLS-1$
private static final String KEYVAL_KEY_GROUP = "key"; //$NON-NLS-1$
private static final String KEYVAL_VALUE_GROUP = "value"; //$NON-NLS-1$

Expand Down Expand Up @@ -136,18 +140,22 @@ public GenericFtraceField(String name, Integer cpu, Long ts, @Nullable Integer p
int valStart = 0;
Matcher keyvalMatcher = KEYVAL_KEY_PATTERN.matcher(attributes);
String key = null;
separator = null;
while (keyvalMatcher.find()) {
if (key != null && valStart > 0) {
String value = attributes.substring(valStart, keyvalMatcher.start());
if (key != null) {
int start = keyvalMatcher.start();
String value = attributes.substring(0, start);
putKeyValueField(name, fields, key, value);
}
valStart = keyvalMatcher.end();
key = keyvalMatcher.group(KEYVAL_KEY_GROUP);
separator = keyvalMatcher.group(IGenericFtraceConstants.FTRACE_SEPARATOR_GROUP);
attributes = attributes.substring(valStart);
keyvalMatcher = KEYVAL_KEY_PATTERN_MAP.getOrDefault(separator, KEYVAL_KEY_PATTERN).matcher(attributes);
}

if (key != null && valStart > 0) {
String value = attributes.substring(valStart, attributes.length());
putKeyValueField(name, fields, key, value);
putKeyValueField(name, fields, key, attributes);
}

/*
Expand All @@ -169,12 +177,12 @@ public GenericFtraceField(String name, Integer cpu, Long ts, @Nullable Integer p
}

private static void putKeyValueField(String name, Map<@NonNull String, @NonNull Object> fields, String key, String value) {
Matcher valMatcher = KEYVAL_VALUE_PATTERN.matcher(value);
String actualValue;
if (valMatcher.matches()) {
Matcher valMatcher = KEYVAL_VALUE_PATTERN.matcher(value);
if (!KEYVAL_VALUE_DOCKER_BYPASS.matcher(value).find() && valMatcher.matches()) {
actualValue = valMatcher.group(KEYVAL_VALUE_GROUP).trim();
} else {
actualValue = value;
actualValue = value.trim();
}
if (!actualValue.trim().isEmpty()) {
// This is a temporary solution. Refactor suggestions
Expand Down

0 comments on commit ffbbc08

Please sign in to comment.