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 `。
- `output/fatal-events` — 每个致命事件一行:
`line at ,: `。
- `output/-before--and--after` — 时间窗口内的每个事件一行,格式与致命报告相同。文件名是根据
时间窗口边界构建的,因此它准确编码了是哪个查询生成了它。
### 关于文件名的说明
`in_window` 的输出文件名包含时间戳和 `timedelta`
字符串,这些字符串包含空格和冒号(例如
`1:00:00-before-2026-06-02 22:17:45.108000+00:00-and-1:00:00-after`)。这在
Linux/macOS 上没问题,但**在 Windows 上文件名中包含冒号和空格是无效的**,因此如果此工具需要在那运行,请在构建名称时对这些字符进行清理
(替换 `:` 和空格)。所有报告文件都没有
扩展名;如果您希望通过双击在编辑器中打开它们,请添加 `.txt`。
## 端到端示例
```
from datetime import timedelta
from jenkins_log_analyzer import analyze, top_templates, fatal_events, level_counts, in_window
rules = [
{"name": "ignore-anon-perms", "action": "ignore",
"message_regex": "anonymous is missing the"},
]
events = analyze("sample.log", rules=rules)
print(level_counts(events)) # quick console summary
top_templates(events, n=20) # output/top-20-messages
fatal_events(events) # output/fatal-events
in_window(events, "2026-06-02 22:17:45.108+0000",
timedelta(hours=1), timedelta(hours=1))
```
运行此命令后,您将得到一个包含这三份
报告的 `output/` 文件夹,并且权限被拒绝的噪音已经通过规则集过滤掉了。
标签:Jenkins, 人体姿态估计, 人工智能, 用户模式Hook绕过, 资源优化, 运维监控, 逆向工具