日志插件(usage_log)业务说明
文档地图(usage_log 相关)
| 文档 | 读它当你需要… |
|---|---|
| 本文 | 业务:目标、流程、环境变量、附件、API、前端展示、限制。 |
| 插件开发.md | 机制:ext 包、目录树、新建插件、表初始化、联调、附录。 |
| usage_log与上游合并-源码入侵.md | 合并:主仓库非 ext 须保留的代码与 i18n。 |
| 与上游-Gitee-手动合并步骤.md | Git:与 Gitee 无共同祖先时的合并命令。 |
本文定位: ext/usage_log 做什么、怎么配(以本文为准);不写合并用的逐文件代码块(见上表第三列)。
概述
ext/usage_log 在网关中的主要作用,是把与单次中继请求相关的可读摘要写入独立表 usage_log_content,并通过 request_id 与主库 logs 关联,供管理端查询「使用日志」。
落库字段通常包括:系统提示词摘要、用户问题、模型回答摘要(具体解析与截断见下文)。不修改上游 logs / model.Log 等已有表结构;计费与主日志仍走原有链路。
本文档结构(与后文编号小节对应)
| # | 主题 | 说明 |
|---|---|---|
| 1 | 目标与边界 | 维护扩展日志、不改变主库表结构。 |
| 2 | 接入顺序(与 Gin 行为相关) | Gin 中间件注册顺序及对 capture 路径的影响。 |
| 3 | 业务主流程(一次请求) | 从读 body 到写扩展表、关联附件的端到端步骤。 |
| 4–5 | 请求侧逻辑 / 响应侧逻辑 | 捕获路径、request_id、解析规则与流式/非流式响应提取。 |
| 6 | 落库规则 | 以 request_id 为键的 upsert 等行为。 |
| 7 | 长度与截断(业务语义) | 落库前按配置截断长文本。 |
| 8 | 配置项汇总(环境变量) | 环境变量与业务含义对照。 |
| 9 | 附件(消息内链接 + 预上传文件) | 消息内链接、multipart 预上传与注入等;9.6 说明 Excel 表格与主仓 go.mod 中 excelize 的作用。 |
| 10 | 只读 API | 扩展提供的查询接口。 |
| 11 | 前端(可选扩展) | 管理端 Web 展示(扩展组件)。 |
| 12 | 限制与已知情况 | 使用边界与已知问题。 |
| 13 | 源码索引 | 关键源码路径速查。 |
| 14 | 四份文档怎样配合 | 与 插件开发、源码侵入、Gitee 合并 的分工。 |
本文旨在细化 usage_log 的用途与实现细节,并与《插件开发.md》形成互补。
1. 目标与边界
| 项目 | 说明 |
|---|---|
| 目标 | 在独立表 usage_log_content 中,按 request_id 与主库 logs 关联,额外保存 system 提示词摘要、用户问题、模型回答摘要,供管理端「使用日志」展示或接口查询。 |
| 不修改 | 不改动上游 model.Log / logs 表结构;计费、主日志写入逻辑仍由网关原有链路完成。 |
| 数据库 | 读写使用 model.LOG_DB(与主日志库一致);表由注册时 AutoMigrate 或 ext/table_init 脚本初始化。 |
2. 接入顺序(与 Gin 行为相关)
要点:ext.MustRegister 须在 router.SetRouter 之前;ext.RegisterRelayMiddleware 须在 relay 侧解压之后、第一个 /v1 等子路由 Group 之前——否则捕获链进不了聊天接口。Session 须在 MustRegister 之前挂载(详见 插件开发 · 第 9.1 节)。
可复制的代码块(含 middleware/auth.go 的 EnforceUserAuth、go.mod 等)见 usage_log与上游合并-源码入侵 · 后端 Go 与 非 ext 文件一览;合并冲突时以该文 〔合并段〕 为准。
3. 业务主流程(一次请求)
请求进入 CaptureMiddleware
→ 总开关关闭? → 直接 Next()
→ 非 POST 或非 capture 路径? → 直接 Next()
→ 无 request_id(common.RequestIdKey)? → 直接 Next()
→ 读请求体,解析 system / prompt / stream(见第 4 节)
→ 还原 BodyStorage,与 common.KeyBodyStorage 对齐,供下游 relay 复用
→ 包装 ResponseWriter,执行 c.Next()(relay 处理)
→ c.Next() 后:若存在「有效 system」(KeyEffectiveSystemPrompt),覆盖 system 文本(见第 4.4 节)
→ 非流式:从完整响应 JSON 提取回答;流式:从缓冲的 SSE 拼接回答(见第 5 节)
→ 按 MaxPromptLen / MaxCompletionLen 截断(见第 7 节)
→ SaveContent:按 request_id upsert 到 usage_log_content
→ processAttachmentsFromBody:关联 usage_log_attachment_tokens、写入消息内 URL 附件4. 请求侧逻辑
4.1 捕获路径(仅 POST)
当前固定为以下路径(与 IsCapturePath 一致):
/v1/chat/completions/v1/completions/v1/messages/pg/chat/completions
4.2 依赖 request_id
中间件从 Gin Context 读取 common.RequestIdKey(与响应头 X-Oneapi-Request-Id、使用日志表 logs.request_id 一致)。若为空则不捕获、不写扩展表。
4.3 请求体解析
| 字段 | 含义 | 说明 |
|---|---|---|
| system | messages 中 role=system 的 content 拼接 | 多段 system 合并为多行文本;与 MaxPromptLen 截断后落 system_prompt_text。 |
| prompt / 问题 | 非 system 的 messages 的 content,或旧版 prompt 字段 | 支持字符串与多模态数组中的 type:text;截断后落 prompt_text。 |
| stream | 是否流式 | 除标准 true/false 外,兼容字符串 "true"/"false"、"1"/"0" 等,避免误判分支。 |
4.4 有效 system 提示词(渠道注入)
Relay 可能在处理过程中写入实际生效的 system 文本。中间件在 c.Next() 之后 若读到 KeyEffectiveSystemPrompt(定义在 ext/usage_log/keys.go),则用其替换此前从请求体解析的 system 摘要,再截断落库。
5. 响应侧逻辑
5.1 非流式(stream 为 false)
- 使用
responseCaptureWriter缓存Write/WriteString输出,并转发Flush(保证 SSE 类实现不丢流)。 - 响应体按 OpenAI 风格 JSON 解析回答,支持:
- Chat:
choices[0].message的content,以及reasoning_content/reasoning(与content合并); - 旧版补全:
choices[0].text。
- Chat:
5.2 流式(stream 为 true)
- 同样缓存完整 SSE 字节流,结束后按
data:行解析 JSON。 - 从每条
choices[0].delta中拼接文本,字段包括reasoning_content、reasoning、content、text(兼容推理模型与旧补全流)。 RecordStreamCompletion为 false 时:仍写 system / 问题,不写completion_text(见配置表)。
5.3 与上游失败的关系
若 relay 未返回 200 或 body 非预期,则可能得到空回答;扩展仍可能写入 prompt 侧,completion 为空。
6. 落库规则
| 规则 | 说明 |
|---|---|
| 表 | usage_log_content |
| 唯一键 | request_id |
| 写入方式 | SaveContent:单条 upsert(冲突则更新正文与时间戳);CreatedAt 在更新时也会刷新。 |
| 字段 | system_prompt_text、prompt_text、completion_text、created_at |
7. 长度与截断(业务语义)
配置在 ext/usage_log/config.go 中加载,落库前在 TruncateUTF8 中执行(按 Unicode 码点 / rune,不是字节)。
| 配置项 | 环境变量 | 默认 | 说明 |
|---|---|---|---|
| 问题侧上限 | LOG_EXT_MAX_PROMPT_LEN | 2000 | system 提示词与用户问题各自分别截断到该长度 |
| 回答上限 | LOG_EXT_MAX_COMPLETION_LEN | 1000 | 合并后的回答截断到该长度 |
特殊值:
LOG_EXT_*_LEN=0:与TruncateUTF8约定maxLen <= 0不截断(该维度不设上限)。- 未设置、解析失败或负数:回退到上表默认值(2000 / 1000)。
8. 配置项汇总(环境变量)
| 环境变量 | 默认 | 业务含义 |
|---|---|---|
LOG_EXT_RECORD_PROMPT_COMPLETION | true | 总开关;false 时不写扩展表;但若 LOG_EXT_ATTACHMENT_ENABLED=true 且仍开启 LOG_EXT_ATTACHMENT_INJECT_TO_MESSAGES 或 LOG_EXT_FILE_URL_FETCH_ENABLED,中间件仍会读 body 并做附件注入 / file_url 展开后再转发。 |
LOG_EXT_MAX_PROMPT_LEN | 2000 | 问题侧(system 与 user 各自)最大记录长度(rune)。 |
LOG_EXT_MAX_COMPLETION_LEN | 1000 | 回答最大记录长度(rune)。 |
LOG_EXT_RECORD_STREAM_COMPLETION | 未单独设置时,见下一行 | 流式是否写入回答;false 时流式只记 system/问题。 |
LOG_EXT_STREAM_ONLY | true(在未设置上一项时生效) | 旧名,与 LOG_EXT_RECORD_STREAM_COMPLETION 同义;若同时设置了 LOG_EXT_RECORD_STREAM_COMPLETION,以该新变量为准。 |
.env 需在主程序加载后再执行 LoadConfig(见 Register 时机),否则进程启动时读不到变量。
9. 附件(消息内链接 + 预上传文件)
在 LOG_EXT_RECORD_PROMPT_COMPLETION=true 且 LOG_EXT_ATTACHMENT_ENABLED=true(默认) 时生效;附件元数据表 usage_log_attachment,文件体落在 LOG_EXT_ATTACHMENT_ROOT(默认 ./data/usage_log_attachments)。
9.1 消息内的链接(无需上传)
中间件在 SaveContent 之后 解析请求 JSON 的 messages:对 content 为数组时,收集
type: "image_url"→image_url.urltype: "file"→file.file_url(若存在)
同一请求内 URL 去重 后写入表,kind=url,source_url 存完整链接;下载接口对 url 类型返回 302 到该地址(仅 http/https)。
说明:若启用了下文 9.1.1 的 file_url 展开,附件采集仍使用展开前的 JSON,因此 file.file_url 仍会写入附件表。
9.1.1 file_url 网关侧拉取(无需本地上传)
在 LOG_EXT_FILE_URL_FETCH_ENABLED=true(默认) 且 LOG_EXT_ATTACHMENT_ENABLED=true 时,在转发给上游 relay 之前,若 messages[].content 中存在 type: "file",且 file.file_url 为 http/https 绝对地址,且未设置 file.file_id(或为空),网关会:
- 服务端
GET该 URL(响应体积 ≤LOG_EXT_ATTACHMENT_MAX_BYTES,并做内网/回环等 SSRF 限制); - 按
Content-Type与内容:将 UTF-8 文本、HTML(抽取可见文本)、JSON 等转为一段{"type":"text","text":"..."},替换原file段再交给下游(行为上接近「外链图用 URL」:由网关侧代为取内容,客户端不必先上传文件); - PDF(
Content-Type: application/pdf或%PDF魔数)当前不做服务端抽字,请求会 400,提示改用 文本/Markdown 公链或先上传取得file_id。
关闭本行为:LOG_EXT_FILE_URL_FETCH_ENABLED=false,则 file_url 不展开,原样进入 relay(直连要求 file_id 的上游时仍可能报错)。
9.2 预上传文件(本地文件)
调用
POST /api/ext/attachment/upload,鉴权与/v1一致:TokenOrUserAuth—— 管理端会话 或Authorization: Bearer sk-...(与调用 chat 时同一密钥即可)。multipart支持:- 字段名
files:一次选多个文件;或 - 字段名
file:可重复多个 part(与 HTML<input type="file" multiple name="file">一致); - 仍兼容仅一个
file的旧用法。
- 字段名
响应:
data.items:数组,每项含pending_token、filename、size;data.pending_tokens:全部 token 的字符串数组;- 若本次仅 1 个文件,仍返回
data.pending_token/data.filename/data.size(与旧版一致)。
调用 Relay
POST /v1/chat/completions时,将预上传 token 交给网关的方式二选一(或同时提供,会去重合并):- 推荐:请求头
X-Usage-Log-Attachment-Tokens,值为 逗号分隔 的 token,或 JSON 数组字符串["t1","t2"]—— 无需在 JSON body 顶层写usage_log_attachment_tokens; - 兼容:JSON 顶层
usage_log_attachment_tokens:["token1","token2"]。
- 推荐:请求头
转发前注入消息(默认):在
LOG_EXT_ATTACHMENT_INJECT_TO_MESSAGES=true(默认) 时,中间件在交给 relay 之前会根据 token 读取待定文件,向messages中最后一条role=user的content追加 OpenAI 兼容段:- PDF(默认):
LOG_EXT_ATTACHMENT_PDF_INJECT_MODE=file(默认) 时,PDF 以type:file+file_data: data:application/pdf;base64,...注入最后一条 user 消息(不依赖系统pdftotext)。须上游在 Chat 路径上支持messages内该形态;若上游忽略未知段,模型会看不到 PDF。 LOG_EXT_ATTACHMENT_PDF_INJECT_MODE=text时,网关调用pdftotext(需 poppler-utils)将 PDF 抽成纯文本,以type:text注入——适合只接受纯文本、或不接受type:file的上游。- 非 PDF:仍使用
type:file+ Data URL。
须与预上传使用同一鉴权(Authorization: Bearer sk-...或管理端会话),否则返回 400。若LOG_EXT_ATTACHMENT_INJECT_TO_MESSAGES=false,则 token 仅用于下文第 5 步关联数据库,不会把文件塞进messages(旧行为)。
- PDF(默认):
中间件在
c.Next()之后 根据logs.request_id,将待定行中pending_token匹配、且user_id等于该日志用户或为 0(历史匿名数据) 的记录写入request_id,并把user_id更新为日志所属用户,完成关联。
约束:每个文件大小 ≤ LOG_EXT_ATTACHMENT_MAX_BYTES(默认 20MiB);单次请求最多 20 个文件。
9.2.1 单次请求内联上传(与对话同发,无需先调 /api/ext/attachment/upload)
在 POST /v1/chat/completions(以及 /v1/completions、/v1/messages、/pg/chat/completions 等捕获路径)使用 Content-Type: multipart/form-data:
| 表单字段 | 说明 |
|---|---|
request 或 json | 必填,值为与原先 application/json body 完全相同的 JSON;可为纯文本字段,也可用 curl -F request=@chat.json 上传文件(服务端会从 multipart 文件部件读取)。 |
files 或 file(可多个) | 可选,本地文件;网关会写入待定附件并自动合并到本次请求的 usage_log_attachment_tokens。 |
鉴权需 Authorization: Bearer sk-...(与纯 JSON 聊天相同)或管理端会话;带文件时必须能解析出用户。
# 1)准备 chat.json(与原来 JSON body 一致,不要写 usage_log_attachment_tokens)
# 2)一次请求带上文件
curl -N -sS -X POST 'http://127.0.0.1:3000/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'request=@chat.json' \
-F 'files=@/path/to/report.pdf' \
-F 'files=@/path/to/notes.docx'网关内部会把 body 还原为 application/json 再交给下游 relay,行为与「先预上传 + 头里带 token」等价。
9.3 配置(附件)
| 环境变量 | 默认 | 说明 |
|---|---|---|
LOG_EXT_ATTACHMENT_ENABLED | true | 关闭则不上传、不解析链接、不写入附件表。 |
LOG_EXT_ATTACHMENT_ROOT | ./data/usage_log_attachments | 本地存储根目录(自动 mkdir)。 |
LOG_EXT_ATTACHMENT_MAX_BYTES | 20971520 | 单次上传最大字节数。 |
LOG_EXT_FILE_URL_FETCH_ENABLED | true | 是否将无 file_id 的 file.file_url 拉取并替换为 type:text(见 9.1.1)。 |
LOG_EXT_FILE_URL_MAX_TEXT_RUNES | 200000 | 单条 URL 展开后的文本最大 rune 数;0 表示该条不截断(与 TruncateUTF8 约定一致)。 |
LOG_EXT_ATTACHMENT_INJECT_TO_MESSAGES | true | 是否将预上传 token 对应内容注入最后一条 user 消息后再转发(见 9.2 第 4 点)。 |
LOG_EXT_ATTACHMENT_PDF_INJECT_MODE | file | PDF:file(默认)= type:file + Data URL,无需 pdftotext;text= pdftotext 抽字后以 type:text 注入(需安装 poppler-utils)。 |
9.3.1 预上传 PDF 后模型像「没读到文档」
- 现象:
upload成功、请求头已带X-Usage-Log-Attachment-Tokens,回复却与 PDF 无关。 - 常见原因(默认
file直传):下游 Chat Completions 实现未实现或丢弃messages里的type:file,模型只看到文字指令。 - 处理:换用支持该字段的渠道/上游;或改为
LOG_EXT_ATTACHMENT_PDF_INJECT_MODE=text并在网关机安装 poppler-utils(将 PDF 抽成type:text,兼容性更好,但依赖系统命令)。
9.4 下载与权限
GET /api/ext/attachment/download?id=<附件主键>(需登录):校验附件的request_id对应logs归属当前用户或管理员。kind=upload:读磁盘文件并Content-Disposition下载。kind=url:302 重定向到source_url。
9.5 联调示例(curl:预上传 + 流式聊天)
本机上的 PDF / Word / Excel 等:OpenAI 风格 messages[].content 里没有「直接塞本地文件二进制」的标准字段;网关侧 file.file_url 只解析 http(s) 外链。因此 本地文档 须:
POST /api/ext/attachment/upload用multipart上传(可多文件);- 聊天请求用请求头
X-Usage-Log-Attachment-Tokens带上返回的pending_token(与Authorization: Bearer sk-...同一密钥),才会记入 **usage_log_attachment**并与本次request_id关联。
与外链、内嵌图的区别(摘要):
| 内容 | 怎么交给网关 / 日志 |
|---|---|
| 外链图片 / 外链 PDF | image_url.url 或 file.file_url |
| 本地小图(给模型看) | 常用 data:image/...;base64,... 写在 image_url.url |
| 本机 pdf / doc(x) / xlsx 等 | 预上传 + X-Usage-Log-Attachment-Tokens(不能只靠 JSON 里一段 base64 文件名) |
1)预上传本地文件(与 chat 使用同一 Authorization: Bearer sk-... 密钥)。示例同时上传图片与多种办公文档:
curl -sS -X POST 'http://127.0.0.1:3000/api/ext/attachment/upload' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'files=@/path/to/photo.png' \
-F 'files=@/path/to/report.pdf' \
-F 'files=@/path/to/notes.docx' \
-F 'files=@/path/to/data.xlsx'从响应 data.pending_tokens(或 data.items[].pending_token)复制全部 token。
2)调用聊天接口:在 X-Usage-Log-Attachment-Tokens 中填入上一步 token(逗号分隔);messages 里仍可写外链图、外链 PDF、base64 图等。
curl -N -sS -X POST 'http://127.0.0.1:3000/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'X-Usage-Log-Attachment-Tokens: TOKEN_FROM_PNG,TOKEN_FROM_PDF,TOKEN_FROM_DOCX,TOKEN_FROM_XLSX' \
-H 'Content-Type: application/json' \
-d @- <<'EOF'
{
"model": "gpt-4o",
"stream": true,
"messages": [
{
"role": "system",
"content": "你是专业助手,回答简洁。"
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "请结合:外链图、外链 PDF、base64 本地小图;本机的 pdf/docx/xlsx 已通过预上传并在请求头关联 token。"
},
{
"type": "image_url",
"image_url": {
"url": "https://img-s.msn.cn/tenant/amp/entityid/AA1Z6SrD.img?w=600&h=466&m=6"
}
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}
}
]
}
]
}
EOF说明:OpenAI 官方等上游若要在 content 里带文档,通常要求 file.file_id(先走 Files API),不会把任意 file.file_url 当可下载文档交给模型。若开启 9.1.1(默认),本网关会先把 file_url(且无 file_id) 拉成 纯文本再转发,则下游收到的是 type:text,一般不再出现「缺少 file_id」。若关闭 LOG_EXT_FILE_URL_FETCH_ENABLED,则 file_url 仍可能原样进入上游,此时仅便于 usage_log 从消息里收集 URL 记库,联调直连 OpenAI 时可能报 missing_required_parameter。模型是否真的能「读」本地 pdf/doc 仍取决于渠道;usage_log 侧 token 关联成功即可在管理端看到附件。
(若仍使用 JSON 顶层的 usage_log_attachment_tokens,可与请求头合并,重复 token 会去重。)
9.6 主仓库 Go 依赖:github.com/xuri/excelize/v2
作用(业务)
预上传或内联上传的 .xlsx / .xlsm(OpenXML 电子表格)在需要注入到 messages 时,扩展不会把整个二进制当 PDF/图片处理,而是由 ext/usage_log/attachment_xlsx.go 调用 excelize 打开工作簿,按工作表读出单元格,拼成分段纯文本(制表符分列、多表带标题、并限制单表行数/工作表数量以防爆内存),再按与其它办公附件类似的逻辑转为可注入内容(例如以 type:text 等形式参与转发,具体与同路径下 attachment_process.go 等一致)。
作用(工程)
该文件 import github.com/xuri/excelize/v2,因此主仓库的 go.mod / go.sum 必须包含该模块(及 go mod tidy 写入的间接依赖)。否则 go build 报错:no required module provides package github.com/xuri/excelize/v2。
是否「整个日志插件都必须」
- 编译当前源码:必须保留该依赖,否则无法完成构建。
- 功能上:仅在与 Excel 类附件的解析/注入路径相关;不涉及 PDF、纯链接、图片等其它附件逻辑。若将来删除
attachment_xlsx.go及相关调用链,可再通过go mod tidy尝试移除 excelize(本文不展开)。
合并上游后若依赖丢失,补全方式见 usage_log与上游合并-源码入侵.md 中的 go.mod / go.sum 一节。
10. 只读 API
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/ext/log-content?request_id=xxx | 需登录;校验 request_id;返回 system_prompt_text、prompt_text、completion_text、attachments 列表(含 download_url)。无文本记录时仍可能返回仅 attachments。 |
| POST | /api/ext/attachment/upload | 预上传,见第 9.2 节。 |
| GET | /api/ext/attachment/download?id= | 下载或跳转,见第 9.4 节。 |
11. 前端(可选扩展)
管理端「使用日志」通过 web/src/ext/usage-logs/ 展示「问题 / 对话详情」列;详情内为 提示词、问题(正文与关联附件同属提问区)、回答。VITE_EXT_USAGE_LOG_CONTENT=false 可关闭扩展表。
入口替换、locales 所需 key 见 usage_log与上游合并-源码入侵 · 前端;组件职责见 插件开发 · 第 2.7.5 节。
12. 限制与已知情况
- 流式:依赖完整 SSE 缓冲;客户端中断、网关超时可能导致回答不完整。
- 超长:受
LOG_EXT_MAX_*截断。 - 路径:仅覆盖第 4.1 节所列;未列出的 relay 路径不会写入扩展表。
- 附件:依赖
logs已写入 后才能按user_id关联预上传令牌;若极端情况下日志滞后,关联可能失败(见服务端日志)。
13. 源码索引
| 模块 | 路径 |
|---|---|
| 配置与加载 | ext/usage_log/config.go |
| 捕获中间件与解析 | ext/usage_log/middleware.go、file_url_expand.go、attachment_inject.go |
| 落库 | ext/usage_log/store.go |
| 附件存储与解析 | ext/usage_log/attachment_store.go、attachment_parse.go、attachment_process.go、attachment_handler.go |
| 表格(xlsx/xlsm)纯文本抽取 | ext/usage_log/attachment_xlsx.go(依赖主仓 go.mod 中的 github.com/xuri/excelize/v2,见 第 9.6 节) |
| 模型与迁移 | ext/usage_log/model_ext.go |
| 路由 | ext/usage_log/router_ext.go |
| Context 键 | ext/usage_log/keys.go |
| 注册 | ext/usage_log/register.go |
| Relay 单点接入 | ext/relay.go |
| 表初始化脚本 | ext/table_init/usage_log_attachment_*.sql |
| 主仓库侵入点(合并上游用) | usage_log与上游合并-源码入侵.md(仅非 ext/ 源码) |
14. 四份文档怎样配合
| 文档 | 职责 |
|---|---|
| 本文(日志插件) | 业务:目标、流程、环境变量、附件、API、前端语义、限制;Excel / excelize 见 第 9.6 节。 |
| 插件开发.md | 机制:ext 包、目录、新建插件、表初始化、源码摘录、附录;业务数字以本文为准。 |
| usage_log与上游合并-源码入侵.md | 合并:主仓库须保留的 Go / 前端 / i18n / go.mod;〔合并段〕 与源码注释 // 开始 对应。 |
| 与上游-Gitee-手动合并步骤.md | Git:仅当与 Gitee 无共同祖先时的 merge、stash、-X theirs;不包含业务与侵入代码块。 |
典型路径: 日常查配置 → 本文;写 ext/ 或联调 → 插件开发;拉上游代码 → Gitee 步骤(若需要)→ 源码侵入 逐项恢复 → go build。
