【问题标题】:Parse out log file sections by thread按线程解析日志文件部分
【发布时间】:2021-02-11 09:42:30
【问题描述】:

假设下面的示例日志文件由 Java 程序中的多个线程异步写入。

使用像 grep/sed/awk/perl 这样的工具 - 有没有一种简单的方法可以解析出所有仅与 [ServerThread-4] 行相关的信息,以及可能在相关之后出现的任何 XML 数据到那个线程。

但我不想要任何 [ServerThread-10](或其他线程)行,或任何可能出现在那些不相关线程的行之后的 XML 数据。

我尝试像这样使用 sed 和 awk,但这些都不起作用,大概是因为我的开始和结束标记是相同的:

sed -n "/\[ServerThread-4\]/,/\[ServerThread-4\]/p" file.log > file-sed.log
awk "/\[ServerThread-4\]/{flag=1;next}/\[ServerThread-4\]/{flag=0}flag" file.log > file-awk.log

示例文件:

2020-09-22 18:06:24,333 [ServerThread-10] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-10,Request,7,linecount=2
2020-09-22 18:06:24,334 [ServerThread-10] DEBUG com.company.abc.webservice.wsc - Web service transfer time out set to: 130000 (ms)
2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - XYZ Function Handler: class com.company.abc.function.XYZCalcDocHandler
2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - num row 1
2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - TAX_PER_ITEM
2020-09-22 18:06:24,564 [ServerThread-4] DEBUG com.company.abc.function - Request XYZ XML
<SOME_XML><ITEM>THREAD-4-DATA</ITEM></SOME_XML>
2020-09-22 18:06:24,564 [ServerThread-4] DEBUG com.company.abc.function - Using transform: quote.xsl
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.function - transformXml() = 5 (ms)
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.function - Request XML
<?xml version="1.0" encoding="UTF-8"?>
<DataEnvelope xmlns="urn:inc:blah:tps:7:0">
<OtherXml>
   <Element>Thread-4-Data</Element>
</OtherXml>
</DataEnvelope>
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Request,6,linecount=1
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.webservice.wsc - Web service transfer time out set to: 130000 (ms)
2020-09-22 18:06:24,669 [ServerThread-10] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-10,Send,335,linecount=2
2020-09-22 18:06:24,669 [ServerThread-10] INFO  com.company.abc.function - Process response
2020-09-22 18:06:24,670 [ServerThread-10] DEBUG com.company.abc.function - Response XML
<DataEnvelope>
    <Login>Thread-10-User</Login>
</DataEnvelope>
2020-09-22 18:06:24,670 [ServerThread-10] DEBUG com.company.abc.function - Processing response line items
2020-09-22 18:06:24,670 [ServerThread-10] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-10,Response,1,linecount=2
2020-09-22 18:06:24,671 [ServerThread-10] DEBUG com.company.abc.function - Response XYZ XML
<CALCULATE_DATA><CLIENT>100</CLIENT><COMPANY>1000</COMPANY></CALCULATE_DATA>
2020-09-22 18:06:24,671 [ServerThread-10] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-10,Total,345,linecount=2
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Send,354,linecount=1
2020-09-22 18:06:24,923 [ServerThread-4] INFO  com.company.abc.function - Process response
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Normalizing CDATA elements
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Response XML
<DataEnvelope>
    <Login>Thread-4-User</Login>
</DataEnvelope>
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Processing response line items
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Response,1,linecount=1
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.function - Response XYZ XML
<CALCULATE_DATA><CLIENT>200</CLIENT><COMPANY>2000</COMPANY></CALCULATE_DATA>
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Total,361,linecount=1

【问题讨论】:

  • 特别感谢您在问题中的努力,继续努力。但是您的问题并不完全清楚,请您添加输出示例,这应该使问题更清楚,谢谢。

标签: bash perl awk sed grep


【解决方案1】:

问题中有一些我不确定的事情,包括所需输出的形式。

如果您想要以 [ServerThread-4] 开头和之后的所有行,直到 [ServerThread-N] 的任何一行,其中 N 不是 4,那么您可以使用 Perl 的range operator

perl -wne'print if /\[ServerThread-4\]/ .. /\[ServerThread-[^4]+\]/ 
                and not /\[ServerThread-( [^4][0-9]* | 4[0-9]+ )\]/x' file 

这会产生我认为需要的输出,如下所示,但请参阅注释

这种方法做了一些假设,因此请检查它与所需内容的关系。最重要的是,它假定每个 ServerThread-N 的部分是完全隔离的,彼此分开(不混合)。

文件是“由多个线程异步写入”的说法有点吓人;这些线程是否组装它们的输出,然后使用一些基于线程的“锁”(或每次打印的锁)写入这些块,或者将这些输出块发送到以良好顺序写入它们的主线程,或者发送以某种方式标记的单个行...?

如果线程只是简单地将行转储到磁盘,那么一个不能再可靠地将输出部分与各个线程分开。由于不同的执行线程会盲目地访问同一资源,因此即使是单独的行也可能重叠并被破坏。

上述单行的输出,在提供的文件中

2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - XYZ Function Handler: class com.company.abc.function.XYZCalcDocHandler
2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - num row 1
2020-09-22 18:06:24,563 [ServerThread-4] DEBUG com.company.abc.function - TAX_PER_ITEM
2020-09-22 18:06:24,564 [ServerThread-4] DEBUG com.company.abc.function - Request XYZ XML
<SOME_XML><ITEM>THREAD-4-DATA</ITEM></SOME_XML>
2020-09-22 18:06:24,564 [ServerThread-4] DEBUG com.company.abc.function - Using transform: quote.xsl
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.function - transformXml() = 5 (ms)
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.function - Request XML
<?xml version="1.0" encoding="UTF-8"?>
<DataEnvelope xmlns="urn:inc:blah:tps:7:0">
<OtherXml>
   <Element>Thread-4-Data</Element>
</OtherXml>
</DataEnvelope>
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Request,6,linecount=1
2020-09-22 18:06:24,569 [ServerThread-4] DEBUG com.company.abc.webservice.wsc - Web service transfer time out set to: 130000 (ms)
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Send,354,linecount=1
2020-09-22 18:06:24,923 [ServerThread-4] INFO  com.company.abc.function - Process response
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Normalizing CDATA elements
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Response XML
<DataEnvelope>
    <Login>Thread-4-User</Login>
</DataEnvelope>
2020-09-22 18:06:24,923 [ServerThread-4] DEBUG com.company.abc.function - Processing response line items
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Response,1,linecount=1
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.function - Response XYZ XML
<CALCULATE_DATA><CLIENT>200</CLIENT><COMPANY>2000</COMPANY></CALCULATE_DATA>
2020-09-22 18:06:24,924 [ServerThread-4] DEBUG com.company.abc.Time - CALCULATE_DATA,ServerThread-4,Total,361,linecount=1

(我在测试文件中添加了带有[ServerThread-14]...-40 的行)


注意两个额外的条件(在正则表达式的交替中),而不是建立范围的条件。第一个,明确排除带有关闭范围运算符的短语的行,因为

范围运算符保持为真,直到右操作数为真,之后范围运算符变为假

(重点——倾斜的大写字母——来自文档)当带有结束标记的行紧跟在范围开始的行之后时,这会咬人,所以它被明确地测试了。

取而代之的是,我们可以使用范围运算符返回范围内的序列号(如果为 false,则返回空字符串),在最后一行附加了 E0。这正是为了让人们可以检查范围的最后一行(当结束标记评估为真时)。那我们就可以了

perl -wne' print if 
    $r = /\[ServerThread-4\]/ .. /\[ServerThread-([^4][0-9]*|4[0-9]+)\]/ 
    and not $r =~ /E0/
' file

第二个额外条件现在被移到结束标记的正则表达式中作为替代。为了排除4 开始 然后有更多数字(如ServerThread-40)的服务器线程号,这是必需的,这仍然使这有点笨拙。但是如果不需要这个条件(很有可能),那么这会进一步简化,使用E0 确实给了我们更好的表达方式。

【讨论】:

  • @ikegami 哦..谢谢。修复了这个问题,现在将尝试集中精力检查这个......这里有点马虎:((。我现在才注意到你的编辑——谢谢。(顺便说一句,-E 对我来说是一个谜:它是正如你反复展示的那样,真的不是一个“好习惯”,但它是一个很大的捷径(可能重复)CORE::say ...)
  • 哇,感谢 zdim 和 @ikegami 的回复。一些澄清——log4j 是用来写入日志文件的,所以我认为这些写入并不是完全随意完成的。但是来自不同线程的某些“块”数据混合在日志中。我想要实现的是能够从我不关心的线程数据中消除原始文件中的许多“噪音”,而只关注我关心的给定线程中的数据关于。
  • 也就是说,这两个单行似乎都生成相同的输出日志文件,并产生我正在寻找的输出:(perl -wne'print if /\[ServerThread-4\]/ .. /\[ServerThread-[^4]+\]/ and not /\[ServerThread-( [^4][0-9]* | 4[0-9]+ )\]/x' file.log) &gt; file-Thread-4-perl1.log(perl -wne' print if $r = /\[ServerThread-4\]/ .. /\[ServerThread-([^4][0-9]*|4[0-9]+)\]/ and not $r =~ /E0/ ' file.log) &gt; file-Thread-4-perl2.log 谢谢,考虑这个回答!跨度>
  • @rziegler72 太好了,它可以按照您需要的方式工作 :) (这两个单行代码只是以不同的方式给出,它们应该做同样的事情)。
  • @rziegler72,关于“我认为写入操作并非完全随意”,Noone 随意地说。但它极有可能不使用锁定,所以我们发现的问题仍然存在。这是一种错误的日志格式。要点很简单:我们不能用这种格式写出完美的解决方案。对于某些日志文件,所有解决方案都将失败。
【解决方案2】:

只有当我们假设线程 4 的数据没有与另一个线程的数据混合时,您的请求才有可能。没有理由相信这个假设会永远成立,但我们对此无能为力。

my $target_id = 4;

my $print = 0;
while (<>) {
   if ( my ($id) = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},d{3} \[ServerThread-(\d+)\]/a) {
      $print = $id == $target_id;
   }

   print if $print;
}

作为“单线”:

perl -ne'
   $print = $1 == 4 if /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},d{3} \[ServerThread-(\d+)\]/a;
   print if $print;
'

作为缩短的“单线”:

perl -ne'$p = $1 == 4 if /^.{24}\[ServerThread-(\d+)\]/; print if $p'

如果我们允许自定义数字:

perl -sne'$p = $1 == $targ if /^.{24}\[ServerThread-(\d+)\]/; print if $p' -- -targ=4

可以删除或保留换行符。

Specifying file to process to Perl one-liner

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 2013-01-30
    • 2013-12-19
    • 1970-01-01
    相关资源
    最近更新 更多