寻找指定时间附近日志

背景

在处理分布式系统的问题时,经常需要从大量日志文件中提取特定时间段的日志进行分析。今天分享一个实用的Python工具,它能够从多个日志文件中精确提取指定时间范围的日志内容。

功能

  • 支持多时区转换(上海时间与纽约时间)
  • 处理压缩(.gz)和未压缩日志文件
  • 支持批量处理多个日志文件
  • 精确的时间范围过滤(目标时间±2分钟)

代码

import gzip
import sys
from datetime import datetime, timedelta
import pytz
from pathlib import Path
import os

def convert_shanghai_to_ny(shanghai_time_str):
    shanghai_tz = pytz.timezone('Asia/Shanghai')
    ny_tz = pytz.timezone('America/New_York')
    shanghai_time = shanghai_tz.localize(datetime.strptime(shanghai_time_str, '%Y-%m-%d %H:%M:%S'))
    ny_time = shanghai_time.astimezone(ny_tz)
    return ny_time

def get_output_filename(target_time_str):
    time_str = datetime.strptime(target_time_str, '%Y-%m-%d %H:%M:%S').strftime('%Y%m%d_%H%M%S')
    return f"logs_{time_str}.log"

def parse_log_time(line):
    try:
        log_time_str = line[:23]  # 提取时间戳部分
        log_time = datetime.strptime(log_time_str, '%Y-%m-%d %H:%M:%S.%f')
        return pytz.timezone('America/New_York').localize(log_time)
    except (ValueError, IndexError):
        return None

def process_file(file_path, time_range_start, time_range_end):
    matching_logs = []
    found_start = False
    
    # 根据文件类型选择打开方式
    open_func = gzip.open if file_path.endswith('.gz') else open
    mode = 'rt' if file_path.endswith('.gz') else 'r'
    
    try:
        with open_func(file_path, mode, encoding='utf-8') as f:
            for line in f:
                log_time = parse_log_time(line)
                if log_time is None:
                    # 如果已经开始收集日志,则继续保存
                    if found_start:
                        matching_logs.append(line)
                    continue

                # 找到开始时间点
                if not found_start and log_time >= time_range_start:
                    found_start = True
                    matching_logs.append(line)
                # 在开始和结束时间之间
                elif found_start and log_time <= time_range_end:
                    matching_logs.append(line)
                # 超过结束时间,停止收集
                elif found_start and log_time > time_range_end:
                    break
                
    except Exception as e:
        print(f"处理文件 {file_path} 时发生错误: {str(e)}")
        return []
        
    return matching_logs

def process_log_files(target_time_str, input_files):
    # 转换目标时间为纽约时间
    target_time = convert_shanghai_to_ny(target_time_str)
    time_range_start = target_time - timedelta(minutes=2)
    time_range_end = target_time + timedelta(minutes=2)
    
    output_file = get_output_filename(target_time_str)
    
    # 检查并删除已存在的输出文件
    if os.path.exists(output_file):
        try:
            os.remove(output_file)
            print(f"已删除已存在的输出文件: {output_file}")
        except Exception as e:
            print(f"删除已存在的输出文件时发生错误: {str(e)}")
            return
    
    print(f"\n搜索时间范围: ")
    print(f"上海时间: {target_time_str} ±2分钟")
    print(f"纽约时间: {target_time.strftime('%Y-%m-%d %H:%M:%S')} ±2分钟")
    
    all_matching_logs = []
    
    for input_file in input_files:
        print(f"\n处理文件: {input_file}")
        matching_logs = process_file(input_file, time_range_start, time_range_end)
        if matching_logs:
            all_matching_logs.extend(matching_logs)
            print(f"找到符合条件的日志 {len(matching_logs)} 行")
        else:
            print("未找到符合条件的日志")

    if all_matching_logs:
        try:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.writelines(all_matching_logs)
            print(f"\n所有匹配的日志已写入文件: {output_file}")
            print(f"总计: {len(all_matching_logs)} 行")
        except Exception as e:
            print(f"写入输出文件时发生错误: {str(e)}")
    else:
        print("\n未找到任何符合条件的日志")

def main():
    if len(sys.argv) < 2:
        print("使用方法: python script.py <目标时间> <日志文件1> [日志文件2 ...]")
        print("时间格式: YYYY-MM-DD HH:MM:SS")
        print("示例: python script.py \"2025-02-20 12:00:00\" app.log app.log.gz")
        return

    target_time = sys.argv[1]
    input_files = sys.argv[2:]

    if not input_files:
        print("请指定至少一个日志文件")
        return

    # 验证所有输入文件是否存在
    for input_file in input_files:
        if not Path(input_file).exists():
            print(f"文件不存在: {input_file}")
            return

    process_log_files(target_time, input_files)

if __name__ == "__main__":
    main()
~~~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值