はじめに
1時間ごとに実行する監視ツールを作ったときに、次のような課題と遭遇しました。
- ログファイルからエラーの有無を確認したいが、ローテーションが頻繁な環境のため、1時間の中で複数のファイルに分かれてしまっている。
- 1時間以上前の古いファイルが大量にあるため、1時間以内に生成されたログファイルだけをチェック対象にしたい。
関数
ファイルのタイムスタンプが1時間以内かどうかをチェックするために次のような関数を作りました。
以下では例としてファイルの文字列を直接変数定義していますが、実際の使用の中では、subprocessやparamikoでlsコマンドを実行して結果を変数に格納するようにしています。
import datetime
import calendar
import re
def is_within_last_hour(log_string):
current_datetime = datetime.datetime.now()
# ログから月、日、時刻を抽出
match = re.search(r"(\w{3}) (\d{2}) (\d{2}:\d{2})", log_string)
if match:
month_str, day_str, time_str = match.groups()
month = list(calendar.month_abbr).index(month_str)
day = int(day_str)
hour, minute = map(int, time_str.split(':'))
# print(month_str)
# print(list(calendar.month_abbr).index(month_str))
# ログの日時を作成(年は一致すると仮定)
log_datetime = datetime.datetime(current_datetime.year, month, day, hour, minute)
else:
return False
# 現在時刻とログの時間差が1時間以内であるかどうかを判断
delta = current_datetime - log_datetime
return delta.total_seconds() < 3600
log_str1 = "-rw------- 1 root root 16102602 Jan 15 12:03 /var/log/example.log"
log_str2 = "-rw------- 1 root root 16104860 Jan 12 02:08 /var/log/example.log"
print(f"Jan 15 12:03 {is_within_last_hour(log_str1)}")
print(f"Jan 12 02:08 {is_within_last_hour(log_str2)}")
実行例
1/15の12:41に実行したので、1/15 12:03のファイルはTrueで返ってきます。
1時間以上古いファイルはFalseで返ってきます。
[user1@server1 ~]$ python3 check_log_time.py
Jan 15 12:03 True
Jan 12 02:08 False
解説
calendar.month_abbr
以下ではJanのような月の文字列を数字に変換しています。
# コード
month = list(calendar.month_abbr).index(month_str) # month_str: Jan
print(f"calendar.month_abbr: {calendar.month_abbr}")
print(f"list(calendar.month_abbr): {list(calendar.month_abbr)}")
print(f"month: {month}")
# 標準出力
calendar.month_abbr: <calendar._localized_month object at 0x7fec48c42d68>
list(calendar.month_abbr): ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
month: 1
calendar.month_abbrをリストオブジェクトに変換すると、13個の要素(1つ目は空文字)を取得できます。
indexメソッドで対象の月の要素番号を取得することで、Jan→1の形で変換します。
delta.total_seconds()
現在時刻とファイルのタイムスタンプの時間差を秒換算して、3600秒以内ならばTrueを返す
# 現在時刻とログの時間差が1時間以内であるかどうかを判断
delta = current_datetime - log_datetime
print(f"current_datetime: {current_datetime}")
print(f"log_datetime: {log_datetime}")
print(f"delta: {delta}")
print(f"delta.total_seconds: {delta.total_seconds()}")
return delta.total_seconds() < 3600
# 標準出力
## Jan 15 12:03 → True
current_datetime: 2024-01-15 12:41:53.496180
log_datetime: 2024-01-15 12:03:00
delta: 0:38:53.496180
delta.total_seconds: 2333.49618
## Jan 12 02:08 → False
current_datetime: 2024-01-15 12:41:53.496689
log_datetime: 2024-01-12 02:08:00
delta: 3 days, 10:33:53.496689
delta.total_seconds: 297233.496689