使用脚本(Linux或Windows或Python)从日志文件中提取特定信息

时间:2016-11-05 18:33:25

标签: python bash batch-file logging

我有兴趣学习如何提取信息

  • 计算关键字的出现次数
  • 获取特定匹配关键字的时间戳(请注意,时间戳将始终在同一天;通常是在同一天的几个小时内),
  • 获取特定日志条目的已用时间

来自文本日志文件(log.txt),通过脚本 Linux bash Windows批处理 Python )。所有这些信息都应写在​​另一个文本文件(results.txt)中或打印在终端上。

基本上,所有其他日志条目(即blah blah都被忽略)。

例如,对于以下文本日志文件,其中每行以时间戳开头,后跟空格虚线( - )和一个或多个空格,后跟关键字:

  

11:59:35.875 - 行动 - 写作(34)开始

     

11:59:35.875 - 等等等等      

11:59:35.875 - 等等等等      

11:59:35.877 - 等等等等      

11:59:35.897 - KEYWORD_1

     

11:59:35.975 - 行动 - 写作(34)结束

     

11:59:36.992 - KEYWORD_1

     

11:59:36.999 - KEYWORD_1

     

11:59:37.535 - 等等等等      

11:59:37.545 - ACTION_A - STATE:type 2

     

11:59:37.575 - 等等等等      

11:59:37.577 - 等等等等      

11:59:37.845 - KEYWORD_2

     

11:59:37.945 - ACTION_B结果

     

11:59:37.950 - 等等等等      

11:59:38.075 - action - WRITE(22)start

     

11:59:38.075 - 等等等等      

11:59:38.085 - blah blah

     

11:59:38.097 - KEYWORD_2

     

11:59:39.975 - 行动 - 写作(22)结束

首先,我想计算每个KEYWORD_1KEYWORD_2的出现次数(例如分别为2和2)。

其次,我希望能够打印每个KEYWORD次出现的时间戳,例如第一次出现11:59:35.897时会KEYWORD_1

最后,找到两个日志条目之间经过的时间:

  1. - action - WRITE(#) start开头并以- action - WRITE(#) end结尾的人,其中#是任意整数,例如11:59:35.975 - 11:59:35.875 = 1ms第一个WRITE(34)
  2. - ACTION_A ...开头且以ACTION_B ...结尾的人,例如11:59:37.545 - 11:59:37.945 = 4ms为第一个ACTION_A .. ACTION_B
  3. 我已尝试find /c "KEYWORD_1" log.txt >results.txt(Windows批处理)来计算出现次数,但我无法提取相应的时间戳。对于其他要求,我不知道如何开始,因为我以前没有这种行为的经验。尝试根据我的需要调整此question的答案,但没有成功。

    非常感谢任何代码片段示例或与相关资源的链接。

4 个答案:

答案 0 :(得分:1)

嗯,因为看起来这不是一项艰巨的任务,我把它作为挑战。 我使用内部for /ffindstr.exe进行解析。 (完成:子:Procline需要更多的时间计算工作。)

Keywords.txt:

action
KEYWORD_1
ACTION_A
KEYWORD_2
ACTION_B

批处理文件

@echo off & setlocal EnableExtensions EnableDelayedExpansion
Set Log=LogFile.txt
Set Key=Keywords.txt
For /f "tokens=1-5* delims=-() " %%A in (
  'findstr /i /G:%Key% %Log% ^|Sort /+16'
) Do call :ProcLine "%%A" %%B %%C %%D %%E
Echo Count
set _
Pause 
Goto :Eof

:ProcLine
Set /A _%2+=1
Echo %~1 - %2 %3 %4 %5
:: Do we need to calc times? 
Echo %5 | findstr /i "end start" >Nul 2>&1 || Goto :Eof
Call :CalcMsecs %1 x%5
If /i %5 neq start Goto :Eof
Set /a xElap=xend-xstart
If %xElap% gtr 0 Echo Elapsed Time: %xElap% msec
Goto :Eof

:CalcMsecs
Setlocal&Set T=%~1
Set /A _h=%T:~0,2%,_m=%T:~3,2%,_s=%T:~6,2%,_ms=%T:~9,3%
Set /A _m+=_h*60
Set /A _s+=_m*60
Set /A _ms+=_s*1000
:: set _
Endlocal&Set %2=%_ms%&Goto :Eof

输出(到现在为止,仍在提炼)

11:59:39.975 - action WRITE 22 end
11:59:38.075 - action WRITE 22 start
Elapsed Time: 1914 msec
11:59:35.975 - action WRITE 34 end
11:59:35.875 - action WRITE 34 start
Elapsed Time: 100 msec
11:59:37.545 - ACTION_A STATE: type 2
11:59:37.945 - ACTION_B result
11:59:36.992 - KEYWORD_1
11:59:35.897 - KEYWORD_1
11:59:36.999 - KEYWORD_1
11:59:38.097 - KEYWORD_2
11:59:37.845 - KEYWORD_2
Count
_action=6
_ACTION_A=1
_ACTION_B=1
_KEYWORD_1=3
_KEYWORD_2=2

有一个14毫秒无处可来的缺陷,但对我来说已经太晚了

答案 1 :(得分:1)

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q40441783.txt"
:: occurrence count for KEYWORD_1,KEYWORD_2,KEYWORD_3
FOR %%k IN (KEYWORD_1 KEYWORD_2 KEYWORD_3) DO (
 FOR /f "delims=" %%c IN ('type "%filename1%"^|FIND /c "%%k"') DO ECHO %%k : %%c times
)
:: Timestamp display for KEYWORD_1,KEYWORD_2,KEYWORD_3
FOR %%k IN (KEYWORD_1 KEYWORD_2 KEYWORD_3) DO (
 type "%filename1%"|FIND "%%k"
)
:: remove variables starting $ or #
For %%b IN ($ #) DO FOR  /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="
:: action - WRITE(#)
FOR /f "usebackqtokens=1*delims=- " %%a IN ("%filename1%") DO (
 REM interested in "pattern - WRITE(#) start/end"
 FOR /f "tokens=1-3*delims=-()" %%A IN ("%%b") DO (
  REM %%A is action, %%B "WRITE" %%C # %%D " start"/" end"
  IF "%%B"==" WRITE" IF "%%D"==" start" SET "$%%C %%A$=%%a"
  IF "%%B"==" WRITE" IF "%%D"==" end" SET "#%%C %%A#=%%a"
  CALL :formatch&CALL :report "WRITE(%%C)"
 )
)
SET $ 2>nul
SET # 2>nul
:: remove variables starting $ or #
For %%b IN ($ #) DO FOR  /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="

FOR /f "usebackqtokens=1*delims=- " %%a IN ("%filename1%") DO (
 REM interested in "ACTION_A/ACTION_B elapsed time"
 FOR /f "tokens=1*delims=- " %%A IN ("%%b") DO (
  REM %%A is action, %%B remainder of line
  IF "%%A"=="ACTION_A" SET "$1$=%%a"&SET "_actiona=%%B"
  IF "%%A"=="ACTION_B" SET "#1#=%%a"
  CALL :formatch
  CALL :report "%%_actiona%% %%B"
 )
)
SET $ 2>nul
SET # 2>nul

GOTO :EOF


:: See whether a $something$ AND a #something# exist and report if so
:formatch
SET "elapsed="
FOR /f "tokens=1,2delims=$=" %%m IN ('set $ 2^>nul') DO (
 IF DEFINED #%%m# (
  CALL :elapsed %%n %%#%%m#%%
  SET "#%%m#="
  SET "$%%m$="
 )
)
GOTO :eof

:report
IF DEFINED elapsed ECHO %elapsed% %~1
GOTO :eof

:: get %2 - %1 both in HH:mm.ss.ttt format
:elapsed
FOR /f "tokens=1-4delims=:." %%w IN ("%2") DO (SET /a hh=2%%w&SET /a mm=2%%x&SET /a ss=2%%y&SET /a ttt=2%%z)
FOR /f "tokens=1-4delims=:." %%w IN ("%1") DO (SET /a hh-=1%%w&SET /a mm-=1%%x&SET /a ss-=1%%y&SET /a ttt-=1%%z)
:: compensate for "negatives"
IF %ttt% lss 1000 set/a ttt+=1000&set/a ss-=1
IF %ss% lss 100 set/a ss+=60&set/a mm-=1
IF %mm% lss 100 set/a mm+=60&set/a hh-=1
IF %hh% lss 100 set/a hh+=24
SET "elapsed=%hh:~-2%:%mm:~-2%:%ss:~-2%.%ttt:~-3%"
GOTO :eof

GOTO :eof

您需要更改sourcedir的设置以适合您的具体情况 我使用了一个名为q40441783.txt的文件,其中包含我的测试数据。

有趣的运动。

前两个步骤相当明显。我添加了KEYWORD_3以确保为"未找到"生成了正确的报告。请注意,您为KEYWORD_1声明了2次出现。实际上,在您发布的数据中有3个。

下一步需要一些解释。我要做的第一件事是确保没有变量从#$开始。

接下来 - 分析每一行,首先在第一个-空间上进行分割,然后在-()上的第一个分隔符序列标记之外处理该部分,以便使用该标记如REM声明中所述。然后,我们将变量$...$#...#设置为%%a中的时间。 ...这是日志条目的唯一部分 - 数字和操作。然后检查同一$...$是否同时存在#...#...,如果是,请清除$#...$#个变量,计算已用时间,重建行和报告。

经过时间的计算在每个变量的开头之前加上2,以确保它们不会启动0并可能被视为八进制。然后通过减去开始时间来拉动相同的技巧,使用前置1来产生应该是3位数的结果(4表示ms)。如果检测到的数字较少,那么我们需要添加一个合适的数字,并从下一个更高的时间元素中扣除一个。

action_a / _b时序的处理基本相同,但是在$!$ /#1#中记录开始/结束时间,因为没有迹象表明字符串的性质action_a和{{ 1}}我们被迫假设适当的事件不会重叠。

答案 2 :(得分:1)

这是python选项:

from datetime import datetime, timedelta

keywords = ['KEYWORD_1', 'KEYWORD_2']
actions = ['WRITE(']
kws_dict = {}
acts_dict = {}

with open('sample.log') as l:
    with open('filtered.log', 'w') as f:
        for line in l:
            if any(k in line for k in keywords) and len(line) > 1:
                entry = line.split('-')[1].strip()
                dt = line.split('-')[0].strip()
                if entry in kws_dict:
                    kws_dict[entry].append(datetime.strptime(dt, '%H:%M:%S.%f'))
                else:
                    kws_dict[entry] = [datetime.strptime(dt,'%H:%M:%S.%f')]
            elif any(a in line for a in actions) and len(line) > 1:
                dt = line.split('-')[0].strip()
                action = line.split(' ')[-2].strip()
                action_type = line.split(' ')[-1].strip()
                if action in acts_dict.keys():
                    acts_dict[action][action_type] = datetime.strptime(dt,'%H:%M:%S.%f')
                else:
                    acts_dict[action] = {action_type:datetime.strptime(dt,'%H:%M:%S.%f')}

# print results
for k in kws_dict.keys():
    print('%s occured %s times' % (k, len(kws_dict[k])))
# comment below if you don't need specific timestamps
    for i in kws_dict[k]:
        print('\t%s' % i.strftime('%H:%M:%S.%f'))

#iterate over actions, then action_types (start, end)
for a, at in acts_dict.iteritems():
    print('%s: Elapsed time %s' % (a, at['end'] - at['start']))
#    for at, t in acts_dict[a].iteritems():
#        print('\t%s: %s' % (at, t.strftime('%H:%M:%S.%f')))

## Raw data in case you need it
#print("Actions:\n", acts_dict)

产生:

  

KEYWORD_1发生了3次       11:59:35.897000
      11:59:36.992000
      11:59:36.999000
  KEYWORD_2发生了2次       11:59:37.845000
      11:59:38.097000
  写(34):经过时间0:00:00.100000
  写(22):经过时间0:00:01.900000

答案 3 :(得分:0)

我不知道这会有多好,但为什么不尝试阅读每一行,如果关键字在其中,请将其写在另一个文件上。 您可以尝试执行以下操作:

with open('log.txt','r') as f:
    for line in f:
        if 'KEYWORD' in line:
            with open('results.txt','a') as z:
                z.write(line)