从文本日志文件生成日志事件对象

1 投票
2 回答
667 浏览
提问于 2025-04-18 15:26

我有一个文本日志文件,内容大概是这样的:

Line 1 - Date/User Information
Line 2 - Type of LogEvent
Line 3-X, variable number of lines with additional information,
          could be 1, could be hundreds

然后这个序列会重复。

这个日志大约有2万行,包含50多种日志事件,大概有1.5万条不同的用户/日期事件。我想用Python来解析这些信息,并让它们可以被查询。

所以我想创建一个叫做LogEvent的类,记录用户、日期(我会提取并转换成日期时间格式)、动作、描述……大概是这样的:


    class LogEvent():
        def __init__(self,date,user):
            self.date = date # string converted to datetime object
            self.user = user
            self.content = ""

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

为了添加日志事件的信息和任何描述内容,可以有类似这样的东西:


    def classify(self,logevent):
        self.logevent = logevent

    def addContent(self,lineoftext):
        self.content += lineoftext

处理文本文件时,我会使用readline()方法,一次处理一行。如果这一行是用户/日期信息,我就创建一个新对象并把它加到一个列表里……


    newevent = LogEvent(date,user)
    eventlist.append(newevent)

然后开始添加动作/内容,直到遇到一个新对象。


    eventlist[-1].classify(logevent)
    eventlist[-1].addContent(line)

这些步骤听起来都很合理(除非你能说服我有更聪明的方法或者我不知道的有用的Python模块)。我在考虑如何最好地分类日志事件类型,因为我有一个固定的日志事件类型列表,可能会有超过50种类型,而我不想直接把整行文本当作日志事件类型。相反,我需要把这一行的开头和可能的值列表进行比较……

我不想这样做,创建50个这样的东西:


    if line.startswith("ABC"):
        logevent = "foo"
    if line.startswith("XYZ"):
        logevent = "boo"

我考虑过使用字典作为查找表,但不太确定如何用“startswith”来实现……如果有建议的话,我会很感激,对不起如果我说得太啰嗦了。

2 个回答

0

因为我之前提问的方式不太好,所以我想了想,得出了这个答案,跟这个讨论有点相似。

我想要一个干净、容易管理的办法,来根据特定条件不同地处理每一行文本。我不想用一堆if/else语句。所以我尝试把条件和结果(处理方式)放到一个叫decisionDict的字典里。

### RESPONSES WHEN CERTAIN CONDITIONS ARE MET - simple examples
def shorten(line):
    return line[:25]

def abc_replace(line):
    return line.replace("xyz","abc")

### CONDITIONAL CHECKS FOR CONTENTS OF LINES OF TEXT - simple examples
def check_if_string_in_line(line):
    response = False
    if "xyz" in line:
        response = True
    return response

def check_if_longer_than25(line):
    response = False
    if len(line)>25:
        response = True
    return response

### DECISION DICTIONARY - could be extended for any number of condition/response
decisionDict = {check_if_string_in_line:abc_replace, check_if_longer_than25:shorten}

### EXAMPLE LINES OF SILLY TEXT
lines = ["Alert level raised to xyz",
    "user 5 just uploaded duplicate file",
    "there is confusion between xyz and abc"]

for line in lines:
    for k in decisionDict.keys():
        if k(line):#in line:
            print decisionDict[k](line)

这样做可以把所有的条件和动作整齐地分开。而且目前这种方法不允许对同一行文本应用多个条件。一旦找到第一个条件为'True'(真的),就会继续处理下一行文本。

0

如果你有一个字典,里面的键是你的日志事件类型,而值是你想放进 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 )

需要注意的是,你抛出的具体异常类型并不是特别重要。我选择了一个内置的异常,以避免创建子类。在这里你可以看到所有内置的异常。

撰写回答