合并具有不同时间戳格式的日志文件

合并具有不同时间戳格式的日志文件

我有两种类型的日志文件

标准系统日志格式

时间戳如下所示

5:2015 Dec 21 07:35:06:ABC:foo1:1559: common.c:946:Enabling filter
6:2015 Dec 21 07:35:08:ABC:bar1:1461: api.c:124:Trigger activated
6:2015 Dec 21 07:35:16:BMC:kernel:-:<6>drivers/usb1_1.c:598:Error processing request on endpoint 0

自定义日志格式

日期时间在文件的第一行给出。以下几行与第一行“相对”。示例如下:

Timestamp H:M:S 15:4:1 D:M:Y 16:1:2015
Firmware Version: 121020150140
[04:01]------------[ Logs ]------------
[04:03]Device Data: -> Supported Attributes -> 0x8033B
[04:01]Device Cleanup

[04:19]SendClearMsg ...
[04:23]Param:GetData failed
[04:51]Current Update Count:7
[05:01]MODECHK:Normal mode

时间戳 4:01 是自 15:4:1 起 4 分 1 秒,应翻译为 15:08:2。

有什么建议来实现这一目标吗?

  • 将相对时间转化为绝对时间
  • 与syslog合并成一个大文件,按时间排序

答案1

此解决方案使用 awk 脚本将第一个文件中的日期转换为自纪元以来的秒数,并将该数字预先添加到输出中。我们用来做艰苦的工作,并通过调用 awk函数date +%s --date将命令的输出捕获到 awk 变量中。 (awk 语法是:secsgetline命令 | getline 多变的)。

awk <log1 >log1.new '
{ y = substr($0,3,4); m = $2; d = $3; hms = substr($0,15,8)
  "date \"+%s\" --date \"" d " " m " " y " " hms "\"" | getline secs
  print secs " " $0
}'

第二个 awk 脚本对第二个文件执行相同的操作,但仅针对带有时间戳的第一行,该时间戳保存在 awk 变量中base。在其他行中,我们只需将分钟和秒偏移量添加到该基数中,并使用date第一个文件的格式将自纪元以来的秒数转换为真实日期。

awk <log2 >log2.new '
/^Timestamp/{ split($5,x,":"); dmy = sprintf("%04d/%02d/%02d",x[3],x[2],x[1])
              split($3,x,":"); hms = sprintf("%02d:%02d:%02d",x[1],x[2],x[3])
              "date \"+%s\" --date \"" dmy " " hms "\"" | getline base
}
/^\[/ { mins = substr($0,2,2); secs = substr($0,5,2);
        tot = base + mins*60+secs
        "date \"+%Y %b %d %H:%M:%S\" --date @" tot | getline date
        print tot " -:" date " " substr($0,8)
}'

然后通过对数字字段进行排序来合并两个文件,最后通过 sed 删除数字。

sort -m -n -k1,1 log1.new log2.new |
sed 's/^[^ ]* //'

答案2

这会将自定义日志文件生成的相对数字添加到原始基数并更新所有行

#!/usr/bin/env bash

f=$(head -n 1 custom_log_format.log)
base=$(sed 's/.*H:M:S \(.*\) D:M:Y.*/\1/' <<<$f)

OLDIFS=$IFS
IFS=$'n' 
readarray lines < custom_log_format.log
IFS=$OLDIFS
for i in ${!lines[@]}
do
    b="${lines[$i]}"
    if [[ $b == "["* ]]
    then
        rel_time=$(sed 's/^\[\(.*[^ ]\)\].*/\1/' <<<$b)
        time=$(echo $rel_time | awk -F: '{ print ($1 * 60) + $2 * 60 }')
        # convert base to seconds
        base_seconds=$(date -d"$base" +"%s")
        new_time_seconds=$(( base_seconds + time ))

        new_time=$(date -d"@$new_time_seconds" +"%H:%M:%S")
    fi
    echo ${b/$rel_time/$new_time}
done

输出

Timestamp H:M:S 15:4:1 D:M:Y 16:1:2015
Firmware Version: 121020150140
[15:09:01]------------[ Logs ]------------
[15:11:01]Device Data: -> Supported Attributes -> 0x8033B
[15:09:01]Device Cleanup

[15:27:01]SendClearMsg ...
[15:31:01]Param:GetData failed
[15:59:01]Current Update Count:7
[15:10:01]MODECHK:Normal mode

答案3

尝试基于 Rust 的工具超快速系统日志搜索器

(假设你有已安装铁锈

cargo install super_speedy_syslog_searcher

然后

s4 log1 log2

超快速系统日志搜索器将按解释的日期时间对不同的日志消息日期时间格式进行排序。

相关内容