日志文件转换为 Pandas 数据框架。

9
我有日志文件,其中有许多形如以下的行:
LogLevel    [13/10/2015 00:30:00.650]  [Message Text]

我的目标是将日志文件中的每一行转换为一个漂亮的数据框。我已经尝试通过在 [ 字符上分割行来做到这一点,但是我仍然没有得到一个整洁的数据框。

我的代码:

level = []
time = []
text = []

   with open(filename) as inf:
     for line in inf:
       parts = line.split('[')
         if len(parts) > 1:  
           level = parts[0]
           time = parts[1]
           text = parts[2]
        print (parts[0],parts[1],parts[2])

 s1 = pd.Series({'Level':level, 'Time': time, 'Text':text})
 df = pd.DataFrame(s1).reset_index()

这是我的数据框的打印结果:

Info      10/08/16 10:56:09.843]   In Function CCatalinaPrinter::ItemDescription()]

Info      10/08/16 10:56:09.843]   Sending UPC Description Message ]

如何改进这个程序以去除空格和其他的']'字符

谢谢


@atkawa7,不行,那个没起作用。 - ukbaz
2个回答

13
你可以使用具有分隔符\s*\[read_csv函数- 即空格和[
import pandas as pd
from pandas.compat import StringIO

temp=u"""LogLevel    [13/10/2015 00:30:00.650]  [Message Text]
LogLevel    [13/10/2015 00:30:00.650]  [Message Text]
LogLevel    [13/10/2015 00:30:00.650]  [Message Text]
LogLevel    [13/10/2015 00:30:00.650]  [Message Text]"""
#after testing replace StringIO(temp) to filename
df = pd.read_csv(StringIO(temp), sep="\s*\[", names=['Level','Time','Text'], engine='python')

然后通过strip方法去除],并将Time列使用to_datetime方法转换为日期时间格式:

df.Time = pd.to_datetime(df.Time.str.strip(']'), format='%d/%m/%Y %H:%M:%S.%f')
df.Text = df.Text.str.strip(']')

print (df)
      Level                    Time          Text
0  LogLevel 2015-10-13 00:30:00.650  Message Text
1  LogLevel 2015-10-13 00:30:00.650  Message Text
2  LogLevel 2015-10-13 00:30:00.650  Message Text
3  LogLevel 2015-10-13 00:30:00.650  Message Text

print (df.dtypes)
Level            object
Time     datetime64[ns]
Text             object
dtype: object

当我用文件名替换临时文件时,它就无法正常工作了,也许是因为我的文件是.log而不是.csv? - ukbaz
1
需要将 StringIO(temp) 替换为 filenam.log,这不是问题,只要它以 .log 结尾即可。 - jezrael
如果我的日志文件格式如下: LogLevel [13/10/2015 00:30:00.650] [Message Text1] [Message Text1A] [Message Text1B] LogLevel [13/10/2015 00:30:00.650] [Message Text2] LogLevel [13/10/2015 00:30:00.650] [Message Text3] - Vasu

3

由于我的分隔符出现在我的消息正文中,而且消息正文也可能跨越多行,例如如果我的Flask应用程序抛出异常并记录堆栈跟踪,因此我不得不手动解析我的日志。

这是我的日志创建格式...

logging.basicConfig( filename="%s/%s_MyApp.log" % ( Utilities.logFolder , datetime.datetime.today().strftime("%Y%m%d-%H%M%S")) , level=logging.DEBUG, format="%(asctime)s,%(name)s,%(process)s,%(levelno)u,%(message)s", datefmt="%Y-%m-%d %H:%M:%S" )

我的Utilities模块中的解析代码

Utilities.py

import re
import pandas

logFolder = "./Logs"

logLevelToString = { "50" : "CRITICAL",
                     "40" : "ERROR"   ,
                     "30" : "WARNING" ,
                     "20" : "INFO"    ,
                     "10" : "DEBUG"   ,
                     "0"  : "NOTSET"  } # https://docs.python.org/3.6/library/logging.html#logging-levels

def logFile2DataFrame( filePath ) :
    dfLog = pandas.DataFrame( columns=[ 'Timestamp' , 'Module' , 'ProcessID' , 'Level' , 'Message' ] )
    tsPattern = "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},"

    with open( filePath , 'r' ) as logFile :
        numRows = -1
        for line in logFile :
            if re.search( tsPattern , line ) :
                tokens    = line.split(",")
                timestamp = tokens[0]
                module    = tokens[1]
                processID = tokens[2]
                level     = logLevelToString[ tokens[3] ]
                message   = ",".join( tokens[4:] )
                numRows += 1
                dfLog.loc[ numRows ] = [ timestamp , module , processID , level , message ]
            else :
                # Multiline message, integrate it into last record
                dfLog.loc[ numRows , 'Message' ] += line
    return dfLog

我实际上创建了这个辅助消息,以便能够直接从我的Flask应用程序中查看日志,因为我有一个方便的模板可以呈现DataFrame。由于将flaskapp封装在Tornado WSGI服务器中会阻止在抛出异常时从Flask可见的常规调试页面的显示,因此应该加速调试过程。如果有人知道如何在这种用法中恢复该功能,请分享。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接