This commit is contained in:
zxr
2026-03-30 18:03:40 +08:00
parent 279021bf86
commit c152a9e573
6 changed files with 474 additions and 51 deletions

View File

@@ -0,0 +1,367 @@
# Ops Logs 前端页面设计文档Log Mgmt
## 1. 背景与目标
`Logs` 服务负责采集并归一化设备侧日志Syslog / SNMP Trap并提供规则与字典等配置能力。前端需要在统一的后台界面中完成
1. 日志查询(查看归一化后的日志事件及详情)
2. Syslog 规则配置
3. Trap 规则配置
4. Trap 字典配置
5. Trap 屏蔽/抑制规则配置
本设计以当前代码库的后端模型与前端实现为准:后端路由在 `internal/routers/register.go`,前端页面在 `front/src/views/ops/pages/log-mgmt/**/index.vue`
---
## 2. 范围(页面数量与路由)
本模块共 5 个页面,对应后端 5 组资源(列表+CRUD 或列表+详情抽屉)。
| 页面 | 菜单/路由路径 | 前端组件 |
|---|---|---|
| 日志查询 | `/log-mgmt/entries` | `front/src/views/ops/pages/log-mgmt/entries/index.vue` |
| Syslog 匹配规则 | `/log-mgmt/syslog-rules` | `front/src/views/ops/pages/log-mgmt/syslog-rules/index.vue` |
| SNMP Trap 匹配规则 | `/log-mgmt/trap-rules` | `front/src/views/ops/pages/log-mgmt/trap-rules/index.vue` |
| Trap 字典 | `/log-mgmt/trap-dictionary` | `front/src/views/ops/pages/log-mgmt/trap-dictionary/index.vue` |
| Trap 屏蔽/抑制 | `/log-mgmt/trap-suppressions` | `front/src/views/ops/pages/log-mgmt/trap-suppressions/index.vue` |
路由与菜单配置参考:
- `front/src/router/local-menu-flat.ts` / `front/src/router/local-menu-items.ts`
- `front/src/views/ops/pages/system-settings/system-logs/index.vue`(页面入口按钮)
- `front/src/views/ops/pages/monitor/log/index.vue`(嵌入 `LogMgmtEntries`
---
## 3. 数据对象与接口映射
后端认证API 路由组启用 `middleware.JwtAuth(true)`
前端请求的 API Base`front/src/api/ops/logs.ts` 中为 `/Logs/v1`
### 3.1 日志事件entries
- 接口:`GET /Logs/v1/entries`
- 返回结构(前端类型):`LogEntriesResult``total``page``page_size``items`
- 日志事件字段(前端类型 `LogEvent`
- `id`
- `created_at`
- `source_kind``syslog` / `snmp_trap`
- `remote_addr`
- `raw_payload`
- `normalized_summary`
- `normalized_detail`
- `device_name`
- `severity_code`
- `trap_oid`
- `alert_sent`
后端实现:`internal/models/log_event.go``internal/logic/controllers/crud.go``ListLogEvents`)。
### 3.2 Syslog 规则syslog-rules
- 接口:
- `GET /Logs/v1/syslog-rules`
- `POST /Logs/v1/syslog-rules`
- `PUT /Logs/v1/syslog-rules/:id`
- `DELETE /Logs/v1/syslog-rules/:id`
- 规则字段(前端类型 `SyslogRule` / 后端 `SyslogRule`
- `id``created_at``updated_at`
- `name`
- `enabled`
- `priority`
- `device_name_contains`
- `keyword_regex`
- `alert_name`
- `severity_code`
- `policy_id`
后端实现:`internal/models/syslog_rule.go``internal/logic/controllers/crud.go`
### 3.3 Trap 规则trap-rules
- 接口:
- `GET /Logs/v1/trap-rules`
- `POST /Logs/v1/trap-rules`
- `PUT /Logs/v1/trap-rules/:id`
- `DELETE /Logs/v1/trap-rules/:id`
- 规则字段(前端类型 `TrapRule` / 后端 `TrapRule`
- `name`
- `enabled`
- `priority`
- `oid_prefix`
- `varbind_match_regex`
- `alert_name`
- `severity_code`
- `policy_id`
后端实现:`internal/models/trap_rule.go``internal/logic/controllers/crud.go`
### 3.4 Trap 字典trap-dictionary
- 接口:
- `GET /Logs/v1/trap-dictionary`
- `POST /Logs/v1/trap-dictionary`
- `PUT /Logs/v1/trap-dictionary/:id`
- `DELETE /Logs/v1/trap-dictionary/:id`
- 字典条目字段(前端类型 `TrapDictionaryEntry` / 后端 `TrapDictionaryEntry`
- `oid_prefix`后端约束uniqueIndex
- `title`
- `description`
- `severity_code`
- `recovery_message`
- `enabled`
后端实现:`internal/models/trap_dictionary.go``internal/logic/controllers/crud.go`
### 3.5 Trap 屏蔽/抑制trap-suppressions
- 接口:
- `GET /Logs/v1/trap-suppressions`
- `POST /Logs/v1/trap-suppressions`
- `PUT /Logs/v1/trap-suppressions/:id`
- `DELETE /Logs/v1/trap-suppressions/:id`
- 屏蔽规则字段(前端类型 `TrapShield` / 后端 `TrapShield`
- `name`
- `enabled`
- `source_ip_cidr`
- `oid_prefix`
- `interface_hint`
- `time_windows_json`JSON 字符串)
后端实现:`internal/models/trap_shield.go``internal/logic/controllers/crud.go`
---
## 4. 页面设计详情(逐页)
### 4.1 日志查询页(`/log-mgmt/entries`
目标:以“可筛选的列表 + 详情抽屉”方式查看归一化日志事件。
#### 1顶部筛选区
- 使用 `search-table` 组件
- 筛选项:`source_kind`(下拉)
- `全部`value=''
- `Syslog`value='syslog'
- `SNMP Trap`value='snmp_trap'
筛选触发:`@search` 调用 `handleSearch`,重置则 `@reset` 调用 `handleReset`
#### 2列表表格列Columns
表格由 `columns` 定义,主要列:
- `ID`
- `来源``source_kind`,通过 `sourceKindLabel()` 显示(`syslog`->`Syslog``snmp_trap`->`SNMP Trap`
- `时间``created_at`
- `来源地址``remote_addr`
- `设备``device_name`
- `级别``severity_code`
- `OID``trap_oid`
- `原始报文``raw_payload`
- 使用 slot `raw_payload`:省略显示,保留 `tooltip`
- `已告警``alert_sent`
- 使用 slot `alert_sent``a-tag`(已转发/否)
- `操作`slot `operations`
- `详情`:打开右侧抽屉
#### 3详情抽屉a-drawer
- 打开逻辑:点击表格行操作中的 `详情`,调用 `openDetail(record)`
- 抽屉展示:`a-descriptions`1 列bordered
- 展示字段:
- 来源类型(`source_kind`
- 采集时间(`created_at`
- 来源地址(`remote_addr`,空则 `-`
- 设备名(`device_name`
- 严重级别(`severity_code`
- Trap OID`trap_oid`
- 已转发告警(`alert_sent`
- 摘要(`normalized_summary`
- 详情(`normalized_detail``pre-block` 预格式化展示)
- 原始报文(`raw_payload``pre-block` 预格式化展示)
#### 4分页策略
- 分页参数由前端 `pagination.current/pageSize` 控制,并随筛选条件一起请求后端:
- 调用 `fetchLogEntries({ page, page_size, source_kind })`
### 4.2 Syslog 规则页(`/log-mgmt/syslog-rules`
目标:规则的“列表 + 新建/编辑弹窗 + 删除确认”。
#### 1通用列表与本地过滤
- 使用 `search-table`,并在前端进行“关键词本地过滤”,过滤字段:
- `name`
- `alert_name`
- `keyword_regex`
- 搜索输入字段:
- `keyword`label`关键词`placeholder`规则名 / 告警名`
说明:该页(以及 trap-*、dictionary、suppressions 三类列表页)采用“先拉取全量 -> 本地过滤 -> 切片分页”的方式。
#### 2表格列
- `ID`
- `名称``name`
- `优先级``priority`
- `启用``enabled`slot `enabled`tag启用/禁用)
- `设备名包含``device_name_contains`
- `关键字正则``keyword_regex`
- `告警名``alert_name`
- `级别``severity_code`
- `策略ID``policy_id`
- `操作`:编辑/删除
#### 3新建/编辑弹窗a-modal
- 弹窗标题:
- 新建:`新建 Syslog 规则`
- 编辑:`编辑规则 #${editingId}`
- 表单 `a-form`(布局 `vertical`
- 表单字段:
- `name``a-input`(必填)
- `enabled``a-switch`
- `priority``a-input-number`
- `device_name_contains``a-input`
- `keyword_regex``a-input`
- `alert_name``a-input`
- `severity_code``a-input`
- `policy_id``a-input-number`min=0
提交逻辑:
- 编辑:`updateSyslogRule(editingId, { ...formData })`
- 新建:`createSyslogRule({ ...formData })`
- 成功后关闭弹窗并刷新列表 `fetchList()`
#### 4删除确认
- `Modal.confirm` 二次确认
- 删除接口:`deleteSyslogRule(id)`
### 4.3 Trap 规则页(`/log-mgmt/trap-rules`
目标TrapRule 的列表+弹窗 CRUD与 Syslog 规则页同构。
#### 1本地过滤关键词
- 字段:`keyword`
- 匹配来源:
- `name`
- `oid_prefix`
- `alert_name`
#### 2表格列
- `ID``名称``优先级``启用`
- `OID 前缀``oid_prefix`
- `Varbind 正则``varbind_match_regex`
- `告警名``alert_name`
- `级别``severity_code`
- `策略ID``policy_id`
- 操作:编辑/删除
#### 3弹窗表单字段
- `name`(必填)
- `enabled`
- `priority`
- `oid_prefix`
- `varbind_match_regex`
- `alert_name`
- `severity_code`
- `policy_id`min=0
### 4.4 Trap 字典页(`/log-mgmt/trap-dictionary`
目标TrapDictionaryEntry 的列表+弹窗 CRUD。
#### 1本地过滤关键词
- 匹配字段:
- `oid_prefix`
- `title`
- `description`
#### 2表格列
- `ID`
- `OID 前缀``oid_prefix`
- `标题``title`
- `级别``severity_code`
- `启用``enabled`
- `描述``description`
- 操作:编辑/删除
#### 3弹窗表单字段
- `oid_prefix`(必填,建议提示“唯一前缀”)
- `title`(必填)
- `description``a-textarea`rows=3
- `severity_code`
- `enabled`
- `recovery_message``a-textarea`rows=2
### 4.5 Trap 屏蔽/抑制页(`/log-mgmt/trap-suppressions`
目标TrapShield 的列表+弹窗 CRUD并对 `time_windows_json` 做前端校验。
#### 1本地过滤关键词
- 匹配字段:
- `name`
- `oid_prefix`
- `source_ip_cidr`
#### 2表格列
- `ID`
- `名称``name`
- `启用``enabled`
- `源 IP/CIDR``source_ip_cidr`
- `OID 前缀``oid_prefix`
- `接口提示``interface_hint`
- 操作:编辑/删除
#### 3弹窗表单字段
- `name`(必填)
- `enabled`
- `source_ip_cidr`
- `oid_prefix`
- `interface_hint`
- `time_windows_json``a-textarea`rows=4placeholder=`{}`
#### 4time_windows_json JSON 校验
-`time_windows_json` 非空时:
-`trim` 后尝试 `JSON.parse(tw)`
- 校验失败:`Message.warning('时间窗 JSON 格式无效')` 并阻止提交
---
## 5. 页面交互一致性要求(实现要点)
为了保证各列表页体验一致,本模块约定:
1. 列表页使用统一的 `search-table` 布局(顶部搜索、表格、分页、刷新)
2. 规则类/字典/屏蔽页采用“拉取全量 -> 本地过滤 -> 切片分页”的方式
3. 创建/编辑统一使用 `a-modal`,提交按钮触发 `formRef.validate()`
4. 删除统一使用 `Modal.confirm`,成功后刷新列表并给出 `Message.success`
5. `trap-suppressions``time_windows_json` 进行 JSON 字符串合法性校验
---
## 6. 数据流(简图)
```mermaid
flowchart LR
UI[前端页面search-table + 表格/弹窗/抽屉)] --> API[front/src/api/ops/logs.ts]
API --> BE[后端路由 internal/routers/register.go]
BE --> DB[(Postgres)]
BE --> Refresh[ingest.Global.Refresh()(规则/字典/屏蔽变更后触发)]
```

View File

@@ -2,18 +2,30 @@ package models
import "time"
// LogEvent 表示一条归一化/存储后的日志事件。
type LogEvent struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
SourceKind string `gorm:"size:16;index" json:"source_kind"`
RemoteAddr string `gorm:"size:64" json:"remote_addr"`
RawPayload string `gorm:"type:text" json:"raw_payload"`
NormalizedSummary string `gorm:"type:text" json:"normalized_summary"`
NormalizedDetail string `gorm:"type:text" json:"normalized_detail"`
DeviceName string `gorm:"size:512;index" json:"device_name"`
SeverityCode string `gorm:"size:32" json:"severity_code"`
TrapOID string `gorm:"size:512;index" json:"trap_oid"`
AlertSent bool `json:"alert_sent"`
// ID 是数据库主键。
ID uint `gorm:"primaryKey" json:"id"`
// CreatedAt 记录创建时间(写入日志事件时)。
CreatedAt time.Time `json:"created_at"`
// SourceKind 表示日志来源类型(例如 trap/syslog 等)。
SourceKind string `gorm:"size:16;index" json:"source_kind"`
// RemoteAddr 表示日志发送方地址。
RemoteAddr string `gorm:"size:64" json:"remote_addr"`
// RawPayload 保存原始负载内容。
RawPayload string `gorm:"type:text" json:"raw_payload"`
// NormalizedSummary 保存归一化后的摘要信息。
NormalizedSummary string `gorm:"type:text" json:"normalized_summary"`
// NormalizedDetail 保存归一化后的详细信息。
NormalizedDetail string `gorm:"type:text" json:"normalized_detail"`
// DeviceName 表示关联设备名称。
DeviceName string `gorm:"size:512;index" json:"device_name"`
// SeverityCode 表示告警/严重度编码。
SeverityCode string `gorm:"size:32" json:"severity_code"`
// TrapOID 表示关联的 Trap OID若来源为 trap
TrapOID string `gorm:"size:512;index" json:"trap_oid"`
// AlertSent 表示是否已将告警发送出去。
AlertSent bool `json:"alert_sent"`
}
func (LogEvent) TableName() string {

View File

@@ -2,18 +2,30 @@ package models
import "time"
// SyslogRule 表示一条 Syslog 规则,用于匹配设备日志并触发告警。
type SyslogRule struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `gorm:"size:256" json:"name"`
Enabled bool `gorm:"default:true" json:"enabled"`
Priority int `gorm:"index" json:"priority"`
DeviceNameContains string `gorm:"size:512" json:"device_name_contains"`
KeywordRegex string `gorm:"size:512" json:"keyword_regex"`
AlertName string `gorm:"size:256" json:"alert_name"`
SeverityCode string `gorm:"size:32" json:"severity_code"`
PolicyID uint `json:"policy_id"`
// ID 是数据库主键。
ID uint `gorm:"primaryKey" json:"id"`
// CreatedAt 记录创建时间GORM 自动维护)。
CreatedAt time.Time `json:"created_at"`
// UpdatedAt 记录更新时间GORM 自动维护)。
UpdatedAt time.Time `json:"updated_at"`
// Name 规则名称,用于展示/标识。
Name string `gorm:"size:256" json:"name"`
// Enabled 表示该规则是否启用。
Enabled bool `gorm:"default:true" json:"enabled"`
// Priority 表示匹配优先级(数值越高/低需以业务约定为准)。
Priority int `gorm:"index" json:"priority"`
// DeviceNameContains 表示设备名称包含条件。
DeviceNameContains string `gorm:"size:512" json:"device_name_contains"`
// KeywordRegex 表示关键字/内容匹配的正则表达式。
KeywordRegex string `gorm:"size:512" json:"keyword_regex"`
// AlertName 表示告警名称。
AlertName string `gorm:"size:256" json:"alert_name"`
// SeverityCode 表示严重级别编码。
SeverityCode string `gorm:"size:32" json:"severity_code"`
// PolicyID 表示关联的告警/处理策略 ID。
PolicyID uint `json:"policy_id"`
}
func (SyslogRule) TableName() string {

View File

@@ -2,16 +2,26 @@ package models
import "time"
// TrapDictionaryEntry 表示 Trap 字典条目,用于描述某个 OID 前缀对应的告警元信息。
type TrapDictionaryEntry struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
OIDPrefix string `gorm:"size:512;uniqueIndex" json:"oid_prefix"`
Title string `gorm:"size:512" json:"title"`
Description string `gorm:"type:text" json:"description"`
SeverityCode string `gorm:"size:32" json:"severity_code"`
RecoveryMessage string `gorm:"type:text" json:"recovery_message"`
Enabled bool `gorm:"default:true" json:"enabled"`
// ID 是数据库主键。
ID uint `gorm:"primaryKey" json:"id"`
// CreatedAt 记录创建时间GORM 自动维护)。
CreatedAt time.Time `json:"created_at"`
// UpdatedAt 记录更新时间GORM 自动维护)。
UpdatedAt time.Time `json:"updated_at"`
// OIDPrefix 表示该字典条目对应的 OID 前缀(唯一)。
OIDPrefix string `gorm:"size:512;uniqueIndex" json:"oid_prefix"`
// Title 表示字典条目的标题。
Title string `gorm:"size:512" json:"title"`
// Description 表示字典条目的说明文本。
Description string `gorm:"type:text" json:"description"`
// SeverityCode 表示默认严重级别编码。
SeverityCode string `gorm:"size:32" json:"severity_code"`
// RecoveryMessage 表示恢复/消警时的消息模板内容。
RecoveryMessage string `gorm:"type:text" json:"recovery_message"`
// Enabled 表示该字典条目是否启用。
Enabled bool `gorm:"default:true" json:"enabled"`
}
func (TrapDictionaryEntry) TableName() string {

View File

@@ -2,18 +2,30 @@ package models
import "time"
// TrapRule 表示一条 SNMP Trap 规则,用于匹配并触发告警策略。
type TrapRule struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `gorm:"size:256" json:"name"`
Enabled bool `gorm:"default:true" json:"enabled"`
Priority int `gorm:"index" json:"priority"`
OIDPrefix string `gorm:"size:512" json:"oid_prefix"`
VarbindMatchRegex string `gorm:"size:512" json:"varbind_match_regex"`
AlertName string `gorm:"size:256" json:"alert_name"`
SeverityCode string `gorm:"size:32" json:"severity_code"`
PolicyID uint `json:"policy_id"`
// ID 是数据库主键。
ID uint `gorm:"primaryKey" json:"id"`
// CreatedAt 记录创建时间GORM 自动维护)。
CreatedAt time.Time `json:"created_at"`
// UpdatedAt 记录更新时间GORM 自动维护)。
UpdatedAt time.Time `json:"updated_at"`
// Name 规则名称,用于展示/标识。
Name string `gorm:"size:256" json:"name"`
// Enabled 表示该规则是否启用。
Enabled bool `gorm:"default:true" json:"enabled"`
// Priority 表示匹配优先级(数值越高/低需以业务约定为准)。
Priority int `gorm:"index" json:"priority"`
// OIDPrefix 表示匹配的 OID 前缀。
OIDPrefix string `gorm:"size:512" json:"oid_prefix"`
// VarbindMatchRegex 表示对 varbind 内容的正则匹配条件。
VarbindMatchRegex string `gorm:"size:512" json:"varbind_match_regex"`
// AlertName 表示告警名称。
AlertName string `gorm:"size:256" json:"alert_name"`
// SeverityCode 表示严重级别编码。
SeverityCode string `gorm:"size:32" json:"severity_code"`
// PolicyID 表示关联的告警/处理策略 ID。
PolicyID uint `json:"policy_id"`
}
func (TrapRule) TableName() string {

View File

@@ -2,16 +2,26 @@ package models
import "time"
// TrapShield 表示一条针对 SNMP Trap 的“屏蔽/防护”规则。
type TrapShield struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `gorm:"size:256" json:"name"`
Enabled bool `gorm:"default:true" json:"enabled"`
SourceIPCIDR string `gorm:"size:64" json:"source_ip_cidr"`
OIDPrefix string `gorm:"size:512" json:"oid_prefix"`
InterfaceHint string `gorm:"size:256" json:"interface_hint"`
TimeWindowsJSON string `gorm:"type:text" json:"time_windows_json"`
// ID 是数据库主键。
ID uint `gorm:"primaryKey" json:"id"`
// CreatedAt 记录创建时间GORM 自动维护)。
CreatedAt time.Time `json:"created_at"`
// UpdatedAt 记录更新时间GORM 自动维护)。
UpdatedAt time.Time `json:"updated_at"`
// Name 规则名称,用于展示/标识。
Name string `gorm:"size:256" json:"name"`
// Enabled 表示该规则是否启用。
Enabled bool `gorm:"default:true" json:"enabled"`
// SourceIPCIDR 表示规则适用的源 IP 网段CIDR
SourceIPCIDR string `gorm:"size:64" json:"source_ip_cidr"`
// OIDPrefix 表示匹配的 OID 前缀。
OIDPrefix string `gorm:"size:512" json:"oid_prefix"`
// InterfaceHint 关联提示信息(例如接口/线路标识),用于定位设备来源。
InterfaceHint string `gorm:"size:256" json:"interface_hint"`
// TimeWindowsJSON 以 JSON 文本形式描述规则生效时间窗口。
TimeWindowsJSON string `gorm:"type:text" json:"time_windows_json"`
}
func (TrapShield) TableName() string {