adoptium/log-analysis

GitHub: adoptium/log-analysis

一个 Python 日志分析工具包,将 Jenkins 及系统日志解析为结构化事件,并通过模板聚类和规则过滤帮助运维人员高效排查基础设施故障。

Stars: 1 | Forks: 2

# Eclipse-Log-Analysis ## 项目描述 本项目提议开发一个由 AI 驱动的日志分析助手,旨在自动审查 Jenkins 服务器日志、系统日志(如 syslog)和其他基础设施输出,以实时识别警告、错误和异常模式。通过利用现代机器学习和自然语言处理技术,该工具将智能解析大量非结构化日志数据,根据严重程度和历史影响确定问题的优先级,并将多个来源的相关事件进行关联,从而提供有意义的洞察,而非原始的无用信息。 ## 目标 1. 识别并收集各种服务器和系统日志,作为“自动化日志分析”助手的输入。 2. 分析基础设施日志,以检测安全问题并发出警报。 3. 为与工作流和自动化的交互创造流畅的客户体验。 4. 总结调查结果并生成有用的报告。 ## 团队 Samuel Yuan, Marcus White, Faisal Toosan, Hani Murtaza, Yuchen Zhou, Aashka Shah # Jenkins Log Analyzer — 使用指南 一个小巧的 Python 工具包,可将原始 Jenkins 日志转换为结构化、可查询的 记录,并将分析报告写入磁盘。本文档首先解释核心 概念(什么是“日志事件”及其重要性),然后说明如何运行各个 部分。 ## 心智模型:是事件,而不是行 其他一切所依赖的唯一理念是,分析的基本单位是 **日志事件**,而不是一行文本。 原始的 Jenkins 日志看起来像是一组平铺的行序列,但单个逻辑 事件通常跨越多行物理文本。警告记录在一行上,然后其异常消息和完整的堆栈跟踪在它下方的行中继续: ``` 2026-06-02 22:17:45.108+0000 [id=580770] WARNING o.j.p.workflow.job.WorkflowRun#getExecution: error in build ... #67 hudson.AbortException: Cannot resume build because FlowNode 12 ... at ...CpsFlowExecution.initializeStorage(CpsFlowExecution.java:802) at ...WorkflowRun.getExecution(WorkflowRun.java:743) ... 12 more ``` 所有这五行是**一个事件**。分析器将它们重新组合 在一起,这样您就可以将事件作为一个整体来推理,而不是作为散落的 行。只有以时间戳开头的行才会开启一个新事件; 其他所有内容都被视为上方事件的延续。 ## 事件包含的内容 每个事件由一个包含以下字段的 `LogEvent` 记录表示: | 字段 | 含义 | | --- | --- | | `line_start`, `line_end` | 该事件在文件中占用的物理行范围。 | | `timestamp` | 具有时区信息的 `datetime` 格式的事件时间。 | | `timestamp_raw` | 完全按照日志中写入的原始时间戳字符串。 | | `thread_id` | Jenkins 线程 ID (`[id=580770]`)。 | | `level` | `INFO`, `WARNING`, `SEVERE` 等。 | | `logger`, `method` | 行的来源,例如 `WorkflowRun` 和 `getExecution`。 | | `message` | 干净的单行人类可读消息。这是用于模板提取的内容。 | | `stack_trace` | 完整的延续块(异常 + 堆栈帧),单独保存。 | | `raw` | 事件的完整原始文本,原样保留。 | | `template_id`, `template` | 由 drain3 分配 —— 见下文。 | | `tags`, `ignored` | 由您的规则集设置 —— 见下文。 | 最重要的拆分是 **`message` 与 `stack_trace`**。人类可读消息 简短且适合分组;堆栈跟踪对于分组来说是噪音,但 恰好是您在排查故障时会交给人类(或 AI)的细节。 将它们保留在单独的字段中,意味着您永远不必为了获取其中 之一而重新解析。 ## 模板和 `template_id` 两个事件很少是相同的 —— URL、构建号和作业名各不相同 —— 但它们通常描述的是*同一类*事物。**模板**是 消息的通用形状,其中可变部分被替换为 占位符。例如,以下三个消息: ``` While serving https://.../job/A/2286/: anonymous is missing the Job/Build permission While serving https://.../job/B/516/: anonymous is missing the Job/Build permission While serving https://.../job/C/123/: anonymous is missing the Overall/Read permission ``` 折叠成一个模板: ``` While serving : hudson.security.AccessDeniedException3: anonymous is missing the permission ``` 聚类由 **drain3** 库完成。每个不同的模板都会获得一个 稳定的 `template_id`(一个整数),并且每个事件都会打上它所属模板的 ID 标签。这使得“20 个最频繁的错误 模板”成为一个有意义的、可计数的事物,而不是成千上万个几乎相同的 唯一字符串。 ## 规则集 **规则集**是一个有序的规则列表,用于决定如何处理匹配的 事件 —— 最常见的是*忽略*嘈杂的事件。每个规则都有匹配 条件(通过 AND 组合)和一个操作。例如,“屏蔽权限被拒绝的噪音,并将任何内存溢出错误标记为严重”: ``` rules = [ {"name": "ignore-anon-perms", "action": "ignore", "message_regex": "anonymous is missing the"}, {"name": "flag-oom", "action": "tag", "tag": "critical", "stack_regex": "OutOfMemoryError"}, ] ``` 您可以使用的匹配条件:`level`, `logger_regex`, `template_id`, `message_regex`, `stack_regex`。操作:`ignore`(设置 `ignored = True`), `tag`(追加到 `tags`,需要 `tag`),以及 `set_level`(重写 `level`, 需要 `set_level`)。所有分析函数都会跳过设置了 `ignored` 标志的事件,因此忽略一个事件会将其从每个报告中移除。 ## 要求和设置 - **Python 3.10+**(使用现代类型提示语法,如 `list[str]`)。 - **drain3** 是进行模板提取所必需的:`pip install drain3`。 如果未安装,解析器和分析功能仍可运行,但 `template_id` / `template` 将保持为空。 ## 快速开始 ``` from datetime import timedelta from jenkins_log_analyzer import ( analyze, top_templates, fatal_events, level_counts, in_window, ) # 1. 运行 pipeline:parse -> assign templates ->(可选)apply rules。 events = analyze("sample.log") # 2. 将 analytics reports 写入 output/。 top_templates(events, n=20) # -> output/top-20-messages fatal_events(events) # -> output/fatal-events # 3. level_counts 仍然 RETURNS 一个 dict(它不会写入文件)。 print(level_counts(events)) # e.g. {'INFO': 3, 'WARNING': 1, 'SEVERE': 1} # 4. 在复制的 timestamp 附近查询 time window。 in_window( events, "2026-06-02 22:17:45.108+0000", # paste straight from a report timedelta(hours=1), # 1 hour before timedelta(hours=1), # 1 hour after ) # -> output/-before-
-and--after ``` 要应用规则集,请将其传递给 `analyze`: ``` events = analyze("sample.log", rules=rules) # rules as shown above ``` 将每个事件导出为 JSON: ``` from jenkins_log_analyzer import to_json with open("events.json", "w", encoding="utf-8") as f: f.write(to_json(events)) ``` ## 函数参考 ### Pipeline `analyze(path, rules=None) -> list[LogEvent]` 读取 `path` 处的文件,将其解析为事件,分配 drain3 模板,并且 (如果给定了 `rules`)应用规则集。返回事件列表。这是 您首先调用的函数;其他所有操作都会消耗其结果。 `to_json(events, indent=2) -> str` 将事件序列化为 JSON 字符串。将其与 `open(...).write(...)` 结合使用以 保存文件。 ### 分析和查询 这些都接收由 `analyze` 返回的 `events` 列表。请注意,它们中有三个 现在**会写入文件并返回 `None`**,而 `level_counts` 返回一个值。 | 函数 | 功能 | 输出 | | --- | --- | --- | | `active(events)` | 仅返回未标记为 `ignored` 的事件。供其他函数内部使用。 | 返回 `list[LogEvent]` | | `top_templates(events, n=20)` | 活动事件中最频繁出现的前 `n` 个模板,包含计数和示例消息。 | 写入 `output/top-{n}-messages` | | `fatal_events(events)` | 级别为致命(`SEVERE`, `FATAL`, 或 `ERROR`)的活动事件,包含行号和时间戳。 | 写入 `output/fatal-events` | | `level_counts(events)` | 统计每个级别发生的活动事件数量。 | **返回**一个 `dict` | | `in_window(events, center, before, after)` | 在 `[center - before, center + after]` 时间段内的事件。 | 写入一个以时间窗口命名的文件 | | `sys_correspond(date, path, threshold)` | 打印 path 处 syslog 中 `[date - threshold, date + threshold]` 时间段内的事件,按距离排序 | `in_window` 的 `center` 参数很灵活:可以传递 `datetime`、原始的 Jenkins 时间戳字符串(`"2026-06-02 22:17:45.108+0000"`),或者在 JSON 导出中生成的 ISO 字符串。`before` 和 `after` 参数是 `datetime.timedelta` 对象,例如 `timedelta(hours=1)` 或 `timedelta(minutes=30)`。`sys_correspond` 也是如此 ## 输出文件 所有报告都存放在脚本旁边的 `output/` 目录中: - `output/top-{n}-messages` — 每个模板一行,已排序,格式为 `[#rank:template_id] x