从最近3分钟的日志文件中获取/提取数据?

时间:2014-01-10 10:56:35

标签: linux bash

我有agent.log文件。此文件以常规间隔更新。

条目如下2014-01-07 03:43:35,223 INFO ...some data

我想提取最后3分钟的数据,有没有办法让我使用bash脚本获取这些数据?

5 个答案:

答案 0 :(得分:8)

尝试以下解决方案:

awk \
-v start="$(date +"%F %R" --date=@$(expr `date +%s` - 180))" \
-v end="$(date "+%F %R")" \
'$0 ~ start, $0 ~ end' \
agent.log

start变量中,时间戳在当前时间之前3分钟(180秒)。

end中有当前时间。

$0 ~ start, $0 ~ end选择startend

之间的行

答案 1 :(得分:4)

date +"%F %R"为您提供当前时间。

grep '^'"$(date +"%F %R")" agent.log将从文件中选择最后一分钟

现在前两分钟它更棘手......我已经开发了一些脚本可以完成相对或绝对的时间操作,它可能比摆弄date ...

2分钟前,格式正确:date --date="@$(($(date +"%s") - 2*60))" +"%F %R"

合并所有3:

NOW=$(date +"%F %R")
M1=$(date --date="@$(($(date +"%s") - 1*60))" +"%F %R")
M2=$(date --date="@$(($(date +"%s") - 2*60))" +"%F %R")
grep '^'"$NOW\|$M1\|$M2" agent.log

答案 2 :(得分:2)

我的回答考虑了以下几点:

  1. 使用bash和UNIX / Linux命令
  2. 最后一个日志行是开始时间而不是实际服务器时间
  3. 对行的日期(分钟,日,年等)没有期望
  4. 整个脚本应该可以扩展为反向或指定的从 - 到间隔

    #!/bin/bash
    # this script expects descending dates in a log file (reverse as real life examples)!!!
    FILE=$1
    INTV=180 # sec
    
    while read LINE
    do    
        if [ -z $LAST_LOG_LINE ]
        then
            # interval stat line
            LAST_LOG_LINE=$(date --date="$( echo "$LINE" | sed -e 's/INFO.*//')" +%s)
            # mod 
            #continue 
        fi
        ACT_LOG_LINE=$(date --date="$( echo "$LINE" | sed -e 's/INFO.*//')" +%s)
        # print line if not greater than $INTV (180s)
        # else break the reading and exit
        if [ $(($LAST_LOG_LINE-$ACT_LOG_LINE)) -gt $INTV ]
        then
            break
        fi
        # actual print
        echo "$LINE"
    done < $FILE
    

    测试:

    2014-01-07 03:43:35,223 INFO ...some data
    2014-01-07 03:42:35,223 INFO ...some data
    2014-01-07 03:41:35,223 INFO ...some data
    2014-01-07 03:40:35,223 INFO ...some data
    2014-01-07 02:43:35,223 INFO ...some data
    2014-01-07 01:43:35,223 INFO ...some data
    2014-01-06 03:43:35,223 INFO ...some data
    

  5.     $ /tmp/stack.sh /tmp/log 
        2014-01-07 03:42:35,223 INFO ...some data
        2014-01-07 03:41:35,223 INFO ...some data
        2014-01-07 03:40:35,223 INFO ...some data
        $
    

答案 3 :(得分:0)

我认为在这种情况下使用Python可能会好一些。即使此脚本在3分钟前没有找到日期,它仍会在调用脚本和3分钟前之间获得任何日志条目。这比以前提供的一些解决方案更简洁,更健壮。

#!/usr/bin/env python                                                           
from datetime import datetime, timedelta                                        

with open('agent.log') as f:                                                    
    for line in f:                                                              
         logdate = datetime.strptime(line.split(',')[0], '%Y-%m-%d %H:%M:%S')                                                                      
         if logdate >= datetime.now() - timedelta(minutes=3):                   
             print(line) 

答案 4 :(得分:0)

Ruby解决方案(在ruby 1.9.3上测试)

您可以将天,小时,分钟或秒作为参数传递,它将搜索表达式和指定的文件(或目录,在这种情况下,它将附加&#39; / *&#39;名):

在你的情况下,只需调用脚本:$ 0 -m 3&#34; expression&#34; LOG_FILE

注意:如果您知道&#39; ruby​​&#39;的位置。改变shebang(脚本的第一行), 出于安全考虑。

#! /usr/bin/env ruby

require 'date'
require 'pathname'

if ARGV.length != 4
        $stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
        exit 1
end
begin
        total_amount = Integer ARGV[1]
rescue ArgumentError
        $stderr.print "error: parameter 'time' must be an Integer\n"
        $stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end

if ARGV[0] == "-m"
        gap = Rational(60, 86400)
        time_str = "%Y-%m-%d %H:%M"
elsif ARGV[0] == "-s"
        gap = Rational(1, 86400)
        time_str = "%Y-%m-%d %H:%M:%S"
elsif ARGV[0] == "-h"
        gap = Rational(3600, 86400)
        time_str = "%Y-%m-%d %H"
elsif ARGV[0] == "-d"
        time_str = "%Y-%m-%d"
        gap = 1
else
        $stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
        exit 1
end

pn = Pathname.new(ARGV[3])
if pn.exist?
        log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
        $stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
        $stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end

search_str = ARGV[2]
now = DateTime.now

total_amount.times do
        now -= gap
        system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end