-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/log #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
+1,243
−287
Merged
Feat/log #7
Changes from 8 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
52e6976
Feat/log command improvements: add support for line count, follow mod…
kooksee 2a7c413
Feat/log command improvements: remove grep filtering support and upda…
kooksee a571a52
Feat: add GitHub Actions workflow for ziginit release process
kooksee aca5d93
Feat: 修复 sleepNs 函数中的类型转换问题
kooksee 0d3a726
Feat/log: 保留空行并增强行计数参数的错误处理
kooksee 07d0bac
Feat/log: 实现 follow 模式的跨 chunk 行拼接,增强日志输出完整性
kooksee e8af566
Feat/log: 添加路径长度检查,防止越界写入
kooksee ff42f6f
Feat/log: 优化路径构建,增加路径长度检查并改进文件跟踪逻辑
kooksee 37bc55f
Feat/log: 增强 sockaddrUn 和 sendCommand 函数的路径长度检查,防止缓冲区溢出
kooksee 856374c
Feat/log: 增强命令处理和响应格式,确保 CLI 命令失败时正确退出并记录错误信息
kooksee 91d88f1
Feat/log: 增强 CLI 错误处理,确保命令失败时返回详细错误信息并正确退出
kooksee 990d9a7
更新 README.md,修正服务日志托管描述,调整模块行数信息,优化命令启动说明
kooksee 9a453aa
Feat/log: 添加日志轮转功能,支持备份文件管理和流式复制
kooksee 6852115
Feat/log: 将多个函数参数类型从 [*:0]const u8 修改为 c.CStr,以增强 C 字符串处理的安全性和一致性
kooksee 67e22f5
Feat/log: 添加 gzip 可用性检查,确保日志轮转时备份安全有效
kooksee 2920e6a
Feat/log: 优化日志输出处理,确保数据完整性并提升性能
kooksee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| name: Release ziginit | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - "ziginit/v*" | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| release: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Install Zig | ||
| uses: mlugg/setup-zig@v2 | ||
| with: | ||
| version: 0.16.0 | ||
|
|
||
| - name: Cache Zig build artifacts | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.cache/zig | ||
| tools/ziginit/.zig-cache | ||
| key: ziginit-${{ runner.os }}-zig-${{ hashFiles('tools/ziginit/main.zig', 'tools/ziginit/build.zig') }} | ||
| restore-keys: | | ||
| ziginit-${{ runner.os }}-zig- | ||
|
|
||
| - name: Parse version and channel from tag | ||
| id: version | ||
| run: | | ||
| version="${GITHUB_REF#refs/tags/ziginit/}" | ||
| echo "version=${version}" >> "$GITHUB_OUTPUT" | ||
| if [[ "$version" =~ -alpha ]]; then | ||
| echo "channel=dev" >> "$GITHUB_OUTPUT" | ||
| elif [[ "$version" =~ -beta ]]; then | ||
| echo "channel=beta" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "channel=prod" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Install UPX (production only) | ||
| if: steps.version.outputs.channel == 'prod' | ||
| run: sudo apt-get update && sudo apt-get install -y upx | ||
|
|
||
| - name: Cross-compile ziginit | ||
| run: | | ||
| cd tools/ziginit | ||
| channel="${{ steps.version.outputs.channel }}" | ||
| if [[ "$channel" == "prod" ]]; then | ||
| optimize="ReleaseSmall" | ||
| else | ||
| optimize="ReleaseSafe" | ||
| fi | ||
| echo "Channel: ${channel}, Optimize: ${optimize}" | ||
|
|
||
| declare -A targets=( | ||
| ["x86_64-linux"]="linux_amd64" | ||
| ["aarch64-linux"]="linux_arm64" | ||
| ["arm-linux"]="linux_armv7" | ||
| ["x86_64-macos"]="darwin_amd64" | ||
| ["aarch64-macos"]="darwin_arm64" | ||
| ) | ||
| mkdir -p ../../release-artifacts | ||
| for zig_target in "${!targets[@]}"; do | ||
| label="${targets[$zig_target]}" | ||
| echo "=== Building ziginit for ${zig_target} (${optimize}) ===" | ||
| zig build -Doptimize="${optimize}" -Dtarget="${zig_target}" | ||
| if [[ "$channel" == "prod" && "$zig_target" == *-linux ]]; then | ||
| upx --best --lzma zig-out/bin/ziginit || true | ||
| fi | ||
| archive="ziginit_${{ steps.version.outputs.version }}_${label}.tar.gz" | ||
| tar -czf "../../release-artifacts/${archive}" -C zig-out/bin ziginit | ||
| rm -rf zig-out | ||
| done | ||
|
|
||
| - name: Generate checksums | ||
| run: | | ||
| cd release-artifacts | ||
| sha256sum *.tar.gz > checksums.txt | ||
| cat checksums.txt | ||
|
|
||
| - name: Generate changelog (production only) | ||
| if: steps.version.outputs.channel == 'prod' | ||
| uses: orhun/git-cliff-action@v4 | ||
| with: | ||
| config: cliff.toml | ||
| args: --latest --strip header | ||
| env: | ||
| OUTPUT: CHANGES.md | ||
|
|
||
| - name: Create GitHub Release | ||
| env: | ||
| GH_TOKEN: ${{ secrets.RELEASER_TOKEN }} | ||
| run: | | ||
| prerelease="" | ||
| notes_arg="--generate-notes" | ||
| if [[ "${{ steps.version.outputs.channel }}" != "prod" ]]; then | ||
| prerelease="--prerelease" | ||
| else | ||
| notes_arg="--notes-file CHANGES.md" | ||
| fi | ||
| gh release create "${{ github.ref_name }}" \ | ||
| --title "ziginit ${{ steps.version.outputs.version }}" \ | ||
| $notes_arg \ | ||
| $prerelease \ | ||
| release-artifacts/* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # Log 子命令改进 | ||
|
|
||
| ## 1. 动机 | ||
|
|
||
| 原有 `log` 命令通过 Unix Socket 向 daemon 请求日志数据,daemon 读取日志文件后流式写回客户端 socket。这种架构存在以下限制: | ||
|
|
||
| - **无法 follow**:socket 是请求-响应模型,无法持续推送新数据 | ||
| - **增加延迟**:CLI → daemon → 读文件 → 回传 socket → CLI,多一跳中转 | ||
| - **daemon 耦合**:daemon 停机时无法查看日志 | ||
| - **按字节截断**:尾部读 64KB 字节,不保证从完整行开始 | ||
|
|
||
| ## 2. 新架构 | ||
|
|
||
| CLI 直接读取日志文件,绕过 daemon socket。 | ||
|
|
||
| ```mermaid | ||
| graph LR | ||
| subgraph "旧架构" | ||
| A1[CLI] -->|socket| B1[daemon] | ||
| B1 -->|read| C1[log files] | ||
| B1 -->|stream| A1 | ||
| end | ||
|
|
||
| subgraph "新架构" | ||
| A2[CLI] -->|direct read| C2[log files] | ||
| end | ||
|
|
||
| style A1 fill:#fee2e2,stroke:#dc2626 | ||
| style A2 fill:#dcfce7,stroke:#16a34a | ||
| ``` | ||
|
|
||
| 日志文件位于 `{workdir}/{service}.log` 和 `{workdir}/daemon.log`,由 daemon 进程通过 `O_APPEND` 模式写入。CLI 直读不会与 daemon 写入冲突。 | ||
|
|
||
| ## 3. CLI 用法 | ||
|
|
||
| ``` | ||
| ziginit log <name> # 显示最近 100 行 | ||
| ziginit log -n <N> <name> # 显示最近 N 行 | ||
| ziginit log -f <name> # 实时跟踪(类似 tail -f) | ||
| ziginit log daemon # 查看 daemon 日志 | ||
| ziginit log --all # 所有服务 + daemon 日志(带 [name] 前缀) | ||
| ziginit log -f --all # follow 所有服务 | ||
| ``` | ||
|
|
||
| 过滤日志使用 Unix 管道:`ziginit log -f svc | grep error` | ||
|
|
||
| ### 参数说明 | ||
|
|
||
| | 参数 | 默认值 | 说明 | | ||
| | -------- | ------ | ------------------------------------- | | ||
| | `-n <N>` | 100 | 显示尾部 N 行 | | ||
| | `-f` | off | follow 模式,持续输出新行直到 Ctrl-C | | ||
| | `--all` | off | 显示所有服务 + daemon 日志 | | ||
| | `daemon` | — | 伪服务名,指向 `{workdir}/daemon.log` | | ||
|
|
||
| ### `--all` 输出格式 | ||
|
|
||
| 每行加 `[name] ` 前缀(去掉了旧版的读取时间戳,因为它不是写入时间,会产生误导): | ||
|
|
||
| ``` | ||
| [daemon] daemon started, 2 services | ||
| [svc-a] svc-a-out | ||
| [svc-a] svc-a-err | ||
| [svc-b] listening on :8080 | ||
| ``` | ||
|
|
||
| ## 4. 实现细节 | ||
|
|
||
| ### 核心函数(journal.zig) | ||
|
|
||
| | 函数 | 职责 | | ||
| | -------------------------------- | ---------------------------------------------------------------------- | | ||
| | `tailLastLines(path, n, prefix)` | 从文件尾部读取,反向扫描定位最后 N 行,应用 prefix 后输出到 stdout | | ||
| | `followFiles(targets)` | 轮询文件变化(200ms 间隔),输出新增行,检测 `sigpending` 实现优雅退出 | | ||
| | `outputLines(data, prefix)` | 逐行处理:前缀添加 + stdout 写入(过滤交给外部 `grep` 管道) | | ||
|
|
||
| ### FollowTarget 结构 | ||
|
|
||
| ```zig | ||
| pub const FollowTarget = struct { | ||
| path_buf: [MAX_PATH + 1]u8, // 自持路径数据,避免悬空指针 | ||
| path_len: usize, | ||
| offset: usize, // 当前读取位置(= tailLastLines 返回的文件大小) | ||
| prefix: [MAX_NAME + 4]u8, // "[name] " 前缀 | ||
| prefix_len: usize, | ||
| }; | ||
| ``` | ||
|
|
||
| > **设计决策**:`FollowTarget` 拷贝路径到内部缓冲区而非存储外部指针。原因是 `ServicePaths` 是栈上临时值,循环迭代结束后失效。存裸指针会导致 Release 模式悬空指针崩溃(与 `ConfigDtoBuild` 同类问题)。 | ||
|
|
||
| ### Follow 模式实现 | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| A[tailLastLines 初始输出] --> B[blockTermInt 阻塞信号] | ||
| B --> C{sleep 200ms} | ||
| C --> D{sigpending?} | ||
| D -->|是| E[恢复信号 & 退出] | ||
| D -->|否| F[遍历 targets] | ||
| F --> G{fstat: 文件增长?} | ||
| G -->|否| C | ||
| G -->|文件缩小| H[offset = 0 重置] | ||
| H --> C | ||
| G -->|增长| I[seekTo + read 新数据] | ||
| I --> J[outputLines 过滤输出] | ||
| J --> K[更新 offset] | ||
| K --> C | ||
| ``` | ||
|
|
||
| - 使用 `fstat` 检测文件大小变化,而非 `poll()`(`poll` 对普通文件总是立即返回 `POLLIN`) | ||
| - 文件大小减小时判定为日志轮转,重置 offset 到 0 重新读取 | ||
| - 信号检查使用 `sigpending`,不依赖信号 handler 全局状态 | ||
|
|
||
| ## 5. 删除的代码 | ||
|
|
||
| | 位置 | 删除内容 | | ||
| | -------------- | -------------------------------------------------------------------- | | ||
| | `journal.zig` | `readServiceLogTail`、`readServiceLogTailPrefixed`(旧 socket 模式) | | ||
| | `server.zig` | `ACTION_LOG` 流式转发逻辑(serverLoop + handleCommand) | | ||
| | `protocol.zig` | `ACTION_LOG` 常量、`sendCommand` 中的 log 流式读取 | | ||
|
|
||
| ## 6. 配置常量(config.zig) | ||
|
|
||
| ```zig | ||
| pub const DEFAULT_LOG_LINES: u32 = 100; // -n 默认值 | ||
| pub const LOG_FOLLOW_POLL_NS: i64 = 200_000_000; // follow 轮询间隔 200ms | ||
| ``` | ||
|
|
||
| 沿用现有环境变量: | ||
| - `ZIGINIT_LOG_TAIL_KB`:控制 tail 读取的最大字节数(默认 64KB,上限 4MB) | ||
| - `ZIGINIT_LOG_MAX_KB`:控制日志轮转阈值(默认 10MB) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.