【问题标题】:Multi line log parsing for service times in PHP/PythonPHP/Python中服务时间的多行日志解析
【发布时间】:2010-11-19 03:58:13
【问题描述】:

解析需要 php 和/或 python 中前几行的上下文知识的多行日志文件的最佳方法是什么?

例如

 Date    Time    ID    Call

1/1/10 00:00:00 1234 Start
1/1/10 00:00:01 1234 ServiceCall A Starts
1/1/10 00:00:05 1234 ServiceCall B Starts
1/1/10 00:00:06 1234 ServiceCall A Finishes
1/1/10 00:00:09 1234 ServiceCall B Finishes
1/1/10 00:00:10 1234 Stop

每个日志行都有一个唯一的 id 以将其绑定到会话,但不能保证每组连续的行都来自同一个会话。

最终目标是找出每笔交易花了多长时间以及每笔子交易花了多长时间。

如果已经存在一个库,我很想使用它。

【问题讨论】:

    标签: php python multiline


    【解决方案1】:

    我可以想到两种不同的方法。

    1) 您可以使用finite state machine 逐行处理文件。当您击中开始线时,请标记时间。当您到达具有相同 ID 的停止线时,区分时间并报告。

    2) 使用 PHP 的 Perl-Compatible Regular Expressions 和 m 修饰符来匹配每个开始/停止行集中的所有文本,然后只查看返回的每个匹配字符串的第一行和最后一行。

    在这两种情况下,我都会验证 ID 是否匹配,以防止匹配不同的集合。

    【讨论】:

      【解决方案2】:

      我的第一个想法是每次我的解析器遇到带有新键的启动模式时创建对象。我假设,从您的示例中,1234 是一个键,这样所有必须关联在一起的日志行都可以映射到一个“事物”(对象)的状态。

      因此,您会看到开始跟踪其中之一的模式,并且每次看到与其相关的日志条目时,您都会调用这些后续行所代表的事件类型(状态更改)的方法。

      从您的示例中,这些“日志状态”对象(由于缺少更恰当的术语)可能包含每个 ServiceCall 的列表或字典(或其他容器)(我希望这将是另一类对象)。

      所以整体设计将是一个读取日志的解析器/调度程序,如果日志项与某个现有对象(键)相关,那么该项目将被调度到该对象 然后可以进一步创建自己的(ServiceCall 或其他)对象和/或向这些对象分派事件或引发异常或调用回调或根据需要调用其他函数。

      大概您还需要一些收集或最终处置处理程序,当停止事件被分派给它们时,您的日志对象可以调用这些处理程序。

      我猜你还想支持某种排序或状态报告方法,以便应用程序可以枚举所有活动(未收集)对象以响应其他通道中的信号或命令(可能来自非阻塞解析器/调度程序执行的检查)

      【讨论】:

        【解决方案3】:

        这是我不久前编写的日志解析器的一个变体,根据您的日志格式量身定制。 (一般方法与 Jim Dennis 的描述非常接近,尽管我使用列表的默认字典来累积任何给定会话的所有条目。)

        from pyparsing import Suppress,Word,nums,restOfLine
        from datetime import datetime
        from collections import defaultdict
        
        def convertToDateTime(tokens):
            month,day,year,hh,mm,ss = tokens
            return datetime(year+2000, month, day, hh,mm,ss)
        
        # define building blocks for parsing and processing log file entries
        SLASH,COLON = map(Suppress,"/:")
        integer = Word(nums).setParseAction(lambda t:int(t[0]))
        date = integer + (SLASH + integer)*2
        time = integer + (COLON + integer)*2
        timestamp = date + time
        timestamp.setParseAction(convertToDateTime)
        
        # define format of a single line in the log file
        logEntry = timestamp("timestamp") + integer("sessionid") + restOfLine("descr")
        
        # summarize calls into single data structure
        calls = defaultdict(list)
        for logline in log:
            entry = logEntry.parseString(logline)
            calls[entry.sessionid].append(entry)
        
        # first pass to find start/end time for each call
        for sessionid in sorted(calls):
            calldata = calls[sessionid]
            print sessionid, calldata[-1].timestamp - calldata[0].timestamp
        

        对于您的数据,打印出来的是:

        1234 0:00:10
        

        您可以使用类似的方法处理每个会话的条目列表,以梳理子事务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-31
          • 1970-01-01
          • 2020-05-21
          • 2017-05-12
          • 1970-01-01
          • 2011-01-22
          • 1970-01-01
          相关资源
          最近更新 更多