我有一个从未轮换过的服务的日志文件。现在我想将此日志文件拆分为单独的文件,每个月一个。大多数行都以括号中的 unix 时间戳开头,但是有些日志消息跨越多行(来自 的输出dig
),需要抓取。此外,多行消息后带有时间戳的下一行不一定来自同一个月。如下例所示。
1700653509 = Wed 22 Nov 12:45:09 CET 2023
1700798246 = Fri 24 Nov 04:57:26 CET 2023
1701385200 = Fri 1 Dec 00:00:00 CET 2023
[1700653509] unbound[499:0] debug: module config: "subnetcache validator iterator"
[1700798246] unbound[1506:0] info: incoming scrubbed packet: ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0
;; flags: qr aa ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
chat.cdn.whatsapp.net. IN A
;; ANSWER SECTION:
chat.cdn.whatsapp.net. 60 IN A 157.240.252.61
;; AUTHORITY SECTION:
;; ADDITIONAL SECTION:
;; MSG SIZE rcvd: 55
[1701385200] unbound[1506:0] debug: iter_handle processing q with state QUERY RESPONSE STATE
我的第一个方法是定义最小值和最大值(一个月的第一秒和最后一秒),并检查行中的时间戳是否符合该范围。如果是,则将其写入新日志文件并继续。我需要这种方法,因为日志文件中并非存在一个月的每个第一秒或最后一秒。
像这样:
for YEAR in {2023..2024}; do
for MONTH in {1..12}; do
# Calculate first and last second of each month
FIRST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01)" "+%s")"
LAST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01) + 1 month - 1 second" "+%s")"`
awk -F'[\\[\\]]' -v MIN="${FIRST_SECOND}" -v MAX="${LAST_SECOND}" '{if($2 >= MIN && $2 <= MAX) print}' unbound.log >> "unbound-$YEAR-$MONTH.log
done;
done
然后我遇到了多行消息并遇到了障碍。
基本上,我现在需要的是某种“抓取所有匹配和不匹配的行,直到第一个值大于 MAX”。我想到获取第一个和最后一个匹配的行号,然后简单地使用它们。但是我又遇到了多行消息的相同问题。
有什么想法吗?
编辑:根据已接受的答案,我最终得到了这个。我将文件名更改为 unbound-YYYY-MM 而不是 MM-YYYY,并在关闭每个文件后对其进行 gzip 压缩。
awk '
$1 ~ /^\[[0-9]+]$/ {
f = "unbound-" strftime("%Y-%m", substr($1, 2, length($1)-2)) ".log"
if (f != prev) {
if (prev) system("gzip " prev)
close(prev)
prev = f
}
}
{
print > f
}
END {
if (prev) system("gzip " prev)
}' unbound.log