0

I designed the regex to match the exception message field.

^.*\s([^:,\s]+):\s+([^:]+)\sat\s+\S+\((\w+)\.\w+:(\d+)\)$

It matches only few fields.

Test Strings is :

ERROR java.lang.NullPointerException: Sample Java Logback Exception

at Sample.errorLevel3(Sample.java:35)

at Sample.errorLevel4(Sample.java:34)

at Sample.errorLevel5(Sample.java:30)

at Sample.errorLevel6(Sample.java:3)

Matches found :

java.lang.NullPointerException

Sample Java Logback Exception

Sample

35

Expected Match :

java.lang.NullPointerException 

Sample Java Logback Exception

Sample.errorLevel3

Sample.java

35

Sample.errorLevel4

Sample.java

34

Sample.errorLevel5

Sample.java

30

Sample.errorLevel6

Sample.java

3

Anyone have better regex for matching fields of Exception Message?

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Amit
  • 47
  • 1
  • 11

3 Answers3

1

Any time you use ( ) you're creating a capturing group. So in your regex, you have 4 capturing groups from where you can extract data.

The first one captures the exception name and I believe it's correct, though I do not know all of the possibilities.

The second captures the message. I believe it should be optional, all exceptions have messages? Including the custom ones? Besides that, it seems correct. I would only add a $ after to ensure it hits the end of line.

The problem begins with the third capture group that should capture the method name, I believe. Change this part: \S+\((\w+)\.\w+:(\d+)\)$ to ([\w.]+\w+)\(([\w.]+\w+)\:(\d+)\)$

The 3 capture groups added are for the method name, file name and line number.

Also, add an additional + to allow you to capture multiple error lines

The final regex is: ^.*\s([^:,\s]+):\s+([^:]+)$(?:\s*at\s+([\w\.]+\w+)\(([\w\.]+\w+)\:(\d+)\))+

However, as pointed out by Doro, you cannot capture multiple partial matches with the same regex, which is what you're trying to do with the error lines.

You should break into 2 regexes: ^.*\s([^:,\s]+):\s+([^:]+)$ and \s*at\s+([\w\.]+\w+)\(([\w\.]+\w+)\:(\d+)\)+

Besides all of that, I'm not sure about java regex, but in C# we can name the capture groups so you can easily get them later using the (?your group here) syntax. I will search how it's done in Java and post here.

EDIT: To see how Java supports named groups, see this answer.

A good site you can test your regexes is regex101.com.

Community
  • 1
  • 1
1

You can match the first line, and then use the \G assertion to match the following lines:

Regex

(?:^.*\s([^:,\s]+):\s+([^:\n]+)|\G(?!\A))\s*at\s+(\S+)\((\w+\.\w+):(\d+)\)$

Where:

  • the first non-capturing group matches
    • ^.*\s([^:,\s]+):\s+([^:\n]+) the Exception description
    • or \G(?!\A) the end of last match
  • and then \s*at\s+ literal at surrounded by whitespace (newlines included)
  • (\S+) the errorlevel in group 3
  • \((\w+\.\w+) the source in group 4
  • :(\d+)\)$ the line in group 5

Code

String text = String.join("\n",
    "ERROR java.lang.NullPointerException: Sample Java Logback Exception",
    "at Sample.errorLevel3(Sample.java:35)",
    "at Sample.errorLevel4(Sample.java:34)",
    "at Sample.errorLevel5(Sample.java:30)",
    "at Sample.errorLevel6(Sample.java:3)"
);
String pattern = "(?:^.*\\s([^:,\\s]+):\\s+([^:\\n]+)|\\G(?!\\A))\\s*at\\s+(\\S+)\\((\\w+\\.\\w+):(\\d+)\\)$";
Pattern regex = Pattern.compile(pattern, Pattern.MULTILINE);
Matcher m = regex.matcher(text);
int matchNum = 0;

//Loop matches
while (m.find())
{
    matchNum++;

    // Loop groups
    for (int i = 1; i <= m.groupCount(); i++) 
    {
        if (m.group(i) != null) {
            System.out.println("Match " + matchNum + " - Group " + i + ": " + m.group(i));
        }
    }
}

Output

Match 1 - Group 1: java.lang.NullPointerException
Match 1 - Group 2: Sample Java Logback Exception
Match 1 - Group 3: Sample.errorLevel3
Match 1 - Group 4: Sample.java
Match 1 - Group 5: 35
Match 2 - Group 3: Sample.errorLevel4
Match 2 - Group 4: Sample.java
Match 2 - Group 5: 34
Match 3 - Group 3: Sample.errorLevel5
Match 3 - Group 4: Sample.java
Match 3 - Group 5: 30
Match 4 - Group 3: Sample.errorLevel6
Match 4 - Group 4: Sample.java
Match 4 - Group 5: 3

ideone demo

Mariano
  • 6,423
  • 4
  • 31
  • 47
0

You can't have dynamic number of matches with regex. You goal has to be reached within two steps.

Step 1 - extracting error header:

ERROR ([^:]+): (.*)

https://regex101.com/r/eQ3rI5/1

Step 2 - extracting error info

(?:\s+at ([^(]+)\(([^:]+):(\d+))\)

https://regex101.com/r/eQ3rI5/2

Doro
  • 755
  • 8
  • 25