使用正则表达式提取堆栈跟踪的最后 'Caused by'
Extracting last 'Caused by' of stack trace with regex
不幸的是,我还不是正则表达式专家,因此遇到了以下问题:
假设我有一个包含多个链式异常的 Java 堆栈跟踪,我想要达到的是提取以 "Caused by" 开头的最后一行。
javax.servlet.ServletException: Something bad happened
at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
.
.
Caused by: com.example.myproject.MyProjectServletException
.
.
Caused by: This is the line I want to capture
到目前为止,我发现 Caused by.(?!.*Caused by)
基于否定的前瞻性,在我删除所有制表符和空格后给我最后一个 "Caused by" (但不是该行的其余部分)。有什么方法可以给我想要的结果吗?如果必须删除所有空格,那对我来说没问题。谢谢!
编辑:抱歉,我想我忘记了一些非常重要的事情。在 Java 中使用 'substring' 将是一个完美的解决方案,但我需要的是一个正则表达式,我可以将其用于 Logstash 中的 grok 模式。
我建议您将 substring
与 lastIndexOf
结合使用以获得最后一次出现的 Caused by
像那样:
String lastCaused = yourStacktraceAsString.substring(yourStacktraceAsString.lastIndexOf("Caused by"));
这可以通过正则表达式来完成,但在这种情况下,仅子字符串可能更简单。假设您的异常堆栈跟踪在字符串调用 ex:
中被捕获
ex.substring(ex.lastIndexOf('Caused by:'))
正则表达式很棘手、脆弱,而且难以阅读和维护。消极的前瞻使情况变得更糟。仅在需要时使用它们。我建议简单地迭代 text.split("\n")
,查找以 Caused by:
开头的行,并将该行保留在循环的末尾。
谢谢@Pshemo,你的想法让我找到了解决方案。经过数小时的反复试验,以下模式按预期工作:
(?m)(Caused by:)(?![\s\S.]*Caused by).*$
这与您在评论中的建议非常接近!
这是一个基于贪婪量词的非环视解决方案:
\A[\s\S]*\nCaused by:\s*(?<LastCausedBy>.*)\Z
模式匹配
\A
- 字符串的开头
[\s\S]*
- 任意 0+ 个字符尽可能多(实际上,抓取所有文本到末尾然后向后移动 - 回溯 - 找到最后一个...)
\nCaused by:
- 换行符后跟 Caused by:
\s*
- 0+ 个空格符号
(?<LastCausedBy>.*)
- 除换行符外的任何 0+ 个字符(捕获到 LastCausedBy
命名组
\Z
- 字符串结尾
在 Grok Debugger 测试:
不幸的是,我还不是正则表达式专家,因此遇到了以下问题: 假设我有一个包含多个链式异常的 Java 堆栈跟踪,我想要达到的是提取以 "Caused by" 开头的最后一行。
javax.servlet.ServletException: Something bad happened
at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
.
.
Caused by: com.example.myproject.MyProjectServletException
.
.
Caused by: This is the line I want to capture
到目前为止,我发现 Caused by.(?!.*Caused by)
基于否定的前瞻性,在我删除所有制表符和空格后给我最后一个 "Caused by" (但不是该行的其余部分)。有什么方法可以给我想要的结果吗?如果必须删除所有空格,那对我来说没问题。谢谢!
编辑:抱歉,我想我忘记了一些非常重要的事情。在 Java 中使用 'substring' 将是一个完美的解决方案,但我需要的是一个正则表达式,我可以将其用于 Logstash 中的 grok 模式。
我建议您将 substring
与 lastIndexOf
结合使用以获得最后一次出现的 Caused by
像那样:
String lastCaused = yourStacktraceAsString.substring(yourStacktraceAsString.lastIndexOf("Caused by"));
这可以通过正则表达式来完成,但在这种情况下,仅子字符串可能更简单。假设您的异常堆栈跟踪在字符串调用 ex:
中被捕获ex.substring(ex.lastIndexOf('Caused by:'))
正则表达式很棘手、脆弱,而且难以阅读和维护。消极的前瞻使情况变得更糟。仅在需要时使用它们。我建议简单地迭代 text.split("\n")
,查找以 Caused by:
开头的行,并将该行保留在循环的末尾。
谢谢@Pshemo,你的想法让我找到了解决方案。经过数小时的反复试验,以下模式按预期工作:
(?m)(Caused by:)(?![\s\S.]*Caused by).*$
这与您在评论中的建议非常接近!
这是一个基于贪婪量词的非环视解决方案:
\A[\s\S]*\nCaused by:\s*(?<LastCausedBy>.*)\Z
模式匹配
\A
- 字符串的开头[\s\S]*
- 任意 0+ 个字符尽可能多(实际上,抓取所有文本到末尾然后向后移动 - 回溯 - 找到最后一个...)\nCaused by:
- 换行符后跟Caused by:
\s*
- 0+ 个空格符号(?<LastCausedBy>.*)
- 除换行符外的任何 0+ 个字符(捕获到LastCausedBy
命名组\Z
- 字符串结尾
在 Grok Debugger 测试: