【问题标题】:Generating Log Event Objects from Text Log File从文本日志文件生成日志事件对象
【发布时间】:2014-07-31 03:59:58
【问题描述】:

我有一个如下所示的文本日志文件:

第 1 行 - 日期/用户信息 第 2 行 - LogEvent 的类型 第 3-X 行,带有附加信息的可变行数, 可能是 1,可能是数百

然后序列重复。

大约有 20K 行日志,50 多种类型的日志事件,大约15K 单独的用户/日期事件。我想在 Python 中解析它并让这些信息可查询。

所以我想我会创建一个类 LogEvent 来记录用户、日期(我提取并转换为日期时间)、操作、描述......类似于:

类日志事件(): def __init__(self,date,user): self.date = date # 字符串转换为日期时间对象 self.user = 用户 自我内容 = ""

每次解析一行包含用户/日期信息的文本时,都会创建这样一个事件。

要添加日志事件信息和任何描述性内容,可能是这样的:

def 分类(自我,日志事件): self.logevent = 日志事件 def addContent(self,lineoftext): self.content += 文本行

要处理文本文件,我会使用 readline() 并一次处理一行。如果该行是用户/日期,我实例化一个新对象并将其添加到列表中......

新事件 = 日志事件(日期,用户) eventlist.append(新事件)

并开始添加动作/内容,直到遇到新对象。

事件列表[-1].classify(logevent) 事件列表[-1].addContent(line)

所有这些都是有道理的(除非你说服我有更聪明的方法或者我不知道的有用的 Python 模块)。我正在尝试确定在使用一组可能包含 50 多种可能类型的可能日志事件类型列表时如何最好地对日志事件类型进行分类,而且我不只是想接受整行文本作为日志事件类型。相反,我需要将行首与可能值列表进行比较...

我不想做的是拥有其中的 50 个:

如果 line.startswith("ABC"): 日志事件 = "foo" 如果 line.startswith("XYZ"): 日志事件 = “嘘”

我曾考虑使用 dict 作为查找表,但我不确定如何使用“startswith”来实现它......任何建议都将不胜感激,如果我啰嗦了太多,我深表歉意。

【问题讨论】:

  • 如果您告诉我们典型的“LogEvent 类型”行是什么样的以及您希望在logevent 属性中记录什么,将会有所帮助。此外,您是否将各种类型的日志事件放在一个列表中,或者更好的是一组?

标签: python events logging text processing


【解决方案1】:

如果你有一个 logEvent 类型的字典作为键,并且任何你想进入 logevent 属性的值作为值,你可以这样做,

logEvents = {"ABC":"foo", "XYZ":"boo", "Data Load":"DLtag"}

你的日志文件中的行是这样的,

line = "Data Load: 127 row uploaded"

您可以检查上面的任何键是否在行首,

for k in logEvents:
    if line.startswith(k): 
        logevent = logEvents[k]

这将遍历logEvents 中的所有键,并检查line 是否以其中一个开头。在 if 条件之后,您可以做任何您想做的事情。您可以将其放入一个函数中,该函数在解析包含用户/日期信息的一行文本后调用。如果你想在没有找到钥匙的情况下做某事,你可以这样做,

 for k in logEvents:
    if line.startswith(k): 
        logevent = logEvents[k]
        return
 raise ValueError( "logEvent not recognized.\n line = " + line )

请注意,您引发的异常的确切类型并不是非常重要。我选择了一种内置异常来避免子类化。 Here你可以看到所有的内置异常。

【讨论】:

  • 所以一个典型的日志事件可能看起来像这样“数据加载:127 行上传”,然后是 127 行详细说明上传的内容(这将映射到我的内容属性。——所以我真的应该'已经更清楚了。这不仅仅是根据前几个字符来决定如何处理行(尽管这适用于某些事件),而是定义了一系列处理不同类型的行(日志事件)的处理方法。跨度>
  • 所以也许我应该使用“event in line”逻辑而不是“startswith”和函数查找表...
  • 如果您愿意,可以使用startswith。如果日志的格式始终相同,则不会有任何问题。我不确定全局目标是什么,但这将检查日志事件行,之后您可以控制逻辑
【解决方案2】:

由于我提出问题的工作做得不好,所以我考虑了更多并想出了这个答案,类似于this thread

我想要一个干净、易于管理的解决方案,根据是否满足某些条件,以不同方式处理每一行文本。我不想使用一堆 if/else 子句。因此,我尝试将条件和结果(处理)都移到 decisionDict = {} 中。

### 满足某些条件时的响应 - 简单示例 def 缩短(线): 回线[:25] def abc_replace(行): 返回 line.replace("xyz","abc") ### 文本行内容的条件检查 - 简单示例 def check_if_string_in_line(行): 响应 = 假 如果“xyz”在行: 响应 = 真 返回响应 def check_if_longer_than25(行): 响应 = 假 如果长度(线)> 25: 响应 = 真 返回响应 ### DECISION DICTIONARY - 可以针对任意数量的条件/响应进行扩展 decisionDict = {check_if_string_in_line:abc_replace, check_if_longer_than25:shorten} ### 愚蠢文本的示例行 lines = ["警报级别提高到 xyz", "用户 5 刚刚上传了重复文件", “xyz 和 abc 之间存在混淆”] 对于行中的行: 对于 decisionDict.keys() 中的 k: if k(line):#in line: 打印decisionDict[k](line)

这样可以将所有条件和操作整齐地分开。它目前还不允许将多个条件应用于任何一行文本。一旦第一个条件解析为“真”,我们就转到下一行文本。

【讨论】: