{"id":50869690,"url":"https://github.com/shaominngqing/flog","last_synced_at":"2026-06-15T04:01:23.745Z","repository":{"id":349978051,"uuid":"1204741934","full_name":"shaominngqing/flog","owner":"shaominngqing","description":"Terminal log viewer + network inspector for Flutter. Auto-connects, HTTP/SSE/WS debugging, collapsible JSON, Flipper-style UI. 给 Flutter 开发者的终端日志查看器 + 网络调试器。","archived":false,"fork":false,"pushed_at":"2026-06-03T10:58:49.000Z","size":10158,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-03T12:21:40.042Z","etag":null,"topics":["adb","android","dart","debugging","devtools","dio","flipper","flutter","flutter-debug","flutter-tools","http","ios","log-viewer","network-inspector","ratatui","rust","sse","terminal","tui","websocket"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shaominngqing.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-08T09:36:34.000Z","updated_at":"2026-06-03T10:58:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shaominngqing/flog","commit_stats":null,"previous_names":["shaominngqing/flog"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/shaominngqing/flog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaominngqing%2Fflog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaominngqing%2Fflog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaominngqing%2Fflog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaominngqing%2Fflog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shaominngqing","download_url":"https://codeload.github.com/shaominngqing/flog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaominngqing%2Fflog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34346870,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adb","android","dart","debugging","devtools","dio","flipper","flutter","flutter-debug","flutter-tools","http","ios","log-viewer","network-inspector","ratatui","rust","sse","terminal","tui","websocket"],"created_at":"2026-06-15T04:01:05.673Z","updated_at":"2026-06-15T04:01:23.738Z","avatar_url":"https://github.com/shaominngqing.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flog\n\n```\n███████╗██╗      ██████╗  ██████╗\n██╔════╝██║     ██╔═══██╗██╔════╝\n█████╗  ██║     ██║   ██║██║  ███╗\n██╔══╝  ██║     ██║   ██║██║   ██║\n██║     ███████╗╚██████╔╝╚██████╔╝\n╚═╝     ╚══════╝ ╚═════╝  ╚═════╝\n```\n\n**给 Flutter 开发者的终端日志查看器 + 网络调试器。**\n\n![Logs 主界面](docs/screenshots/logs-main.png)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/shaominngqing/flog/master/install.sh | bash\n```\n\n## 解决什么问题\n\nFlutter 开发日志查看和网络调试一直有明显短板：\n\n**日志方面**\n- `flutter run` 输出里业务日志和系统日志（`I/flutter`、`W/1.raster`、`D/TrafficStats`）混在一起，没有级别颜色、没法过滤、没有搜索\n- JSON 被挤在一行，可读性差\n- Android `logcat` 噪音大、过滤繁琐，单条日志 1KB 长度限制会把长 JSON 截断\n- iOS 端通过 Xcode / Console 看日志，看不到 Flutter 框架层（`debugPrint`、framework error）的完整系统日志\n\n**网络方面**\n- 看请求详情要么加 `print`，要么开 DevTools，每次重启都要重连\n- DevTools 网络面板功能有限\n- 抓包工具（Charles、Proxyman、Reqable）需设置代理、装证书，调移动端还要处理网络环境\n- SSE、WebSocket 等流式请求缺少专门的可视化支持\n\n其他平台都有对应成熟工具（Flipper / Proxyman / Chrome DevTools 等），**Flutter 生态在这一方向长期空缺**。flog 就是为填补这个空缺而生。\n\n## 产品优势\n\n### 零代理、零网络依赖\n\n这是 flog 与通用抓包工具最本质的区别：\n\n- 无需设置 `HTTP_PROXY`、无需装 CA 证书\n- 无需设备与电脑在同一网络\n- 仅需 USB 连接：Android 走 `adb forward`，iOS 真机走 usbmuxd，模拟器直通\n- 自动设备发现：`flutter devices` 能识别的都自动接入\n\n### 缓存不丢\n\n- Dart 端作为唯一数据源，App 启动即开始记录\n- `FlogStore` 环形缓冲：10 万条日志 + 1 万条请求\n- 不依赖 flog 连接状态：即使 flog 没开，数据也在 Dart 端缓冲\n- flog 启动或重连后，Dart 端自动把历史数据回放给 TUI\n- 问题发生时即使没连电脑、没开 flog，事后仍可完整回溯，对偶发问题复现至关重要\n\n### 多设备、多 App 自动发现\n\n- 自动识别所有已连接设备及其上接入 flog 的 App\n- 底部设备选择器一键切换\n- 切换后即时重建历史记录，支持模拟器 + 真机无缝调试\n\n![设备选择器](docs/screenshots/device-picker.png)\n\n### 终端优先、轻量无负担\n\n选择 TUI 而非 Web 面板：进程开关无心理负担，Rust 实现响应迅速，二进制产物仅几 MB，一键安装一键卸载，不依赖运行时。\n\nTUI 不意味着门槛高：完整支持鼠标操作（点击、滚轮、右键菜单）与键盘快捷键，`?` 一键打开完整快捷键说明。\n\n### Release 零开销\n\n- `flogEnabled` 在 release 模式为 `false`，AOT 编译时移除所有 flog 代码\n- 运行时零开销\n- 系统日志（`debugPrint` / `FlutterError.onError` / `PlatformDispatcher.onError`）自动捕获，无需手动转发\n\n---\n\n## 功能介绍\n\n### ▤ Logs — 实时日志流\n\n![日志详情面板](docs/screenshots/logs-detail.png)\n\n**过滤与搜索**\n- 级别过滤：Verbose / Debug / Info / Warning / Error\n- Tag 过滤：支持逗号分隔、`-tag` 排除、正则表达式\n- 全文搜索：`/` 触发，支持 `/正则/i` 语法，`n/N` 跳转匹配\n- 重复日志自动折叠\n- 统计视图：级别分布、Tag 排名\n\n**详情面板**\n- JSON 自动格式化，语法高亮，按深度着色\n- JSON 树可折叠展开至任意层级\n- 不仅 JSON，Dart 对象 `toString` 输出也能识别并格式化\n- 一键复制、书签标记、日志导出\n\n**其他**\n- Jump to Bottom 浮层：暂停滚动后显示新日志计数\n- 10 万条环形缓冲，启动后不丢失\n\n---\n\n### ⇄ Network — 网络请求检查器\n\n![网络请求列表](docs/screenshots/network-main.png)\n\n**协议支持**\n- HTTP / SSE / WebSocket 统一列表展示\n- 列表字段：Protocol、Method、URL、Status、Duration、Size\n- 过滤器行内 pill 切换（Protocol / Method / Status）\n- URL 搜索\n\n**请求详情**\n- General：URL、Method、Status、Duration、Size\n- Query Parameters 自动解析\n- Request / Response Headers\n- Request / Response Body：JSON 语法高亮 + 可折叠树\n\n**Mock 规则**\n\n从当前请求一键创建 mock 规则，从 TUI 编辑响应体，通过 Direct Socket 下发给 App：\n\n![Mock 编辑器](docs/screenshots/mock-editor.png)\n\n匹配的请求会被 `FlogMockInterceptor` 拦截，返回预设响应，在列表中以 `[Mock]` 标记：\n\n![Network 详情带 Mock 标记](docs/screenshots/network-detail-mock.png)\n\n**核心操作**\n- **Copy as cURL** — 一键复制为 curl 命令\n- **Copy Response** — 一键复制响应体\n- **Replay** — 从 TUI 重放请求\n- **Mock** — 创建 mock 规则拦截指定请求\n\n**SSE Merged View**\n\n按指定 JSON 字段自动拼接多个 chunk 为完整文本。默认 `Events` 视图展示每个 chunk：\n\n![SSE Events 原始列表](docs/screenshots/sse-events.png)\n\n切到 `Merged` 视图（会自动识别 OpenAI / Claude 等 LLM streaming 格式，同一 URL 后续请求自动继承设置）：\n\n![SSE Merged View](docs/screenshots/sse-merged.png)\n\n**WebSocket Chat View**\n\n对话流视图：send 靠左（绿色 →），recv 靠右（蓝色 ←）。`*.delta` 类消息自动合并拼接，base64 音频数据折叠为 `[binary N KB]`：\n\n![WS Chat View](docs/screenshots/ws-chat.png)\n\n可切换到 `Raw` 视图查看原始 JSON 树：\n\n![WS Raw View](docs/screenshots/ws-raw.png)\n\n对调试 AI 相关功能（LLM streaming、语音实时会话等）帮助显著，无需借助浏览器 DevTools。\n\n**扩展功能**\n- **Performance Stats** — 延迟百分位、Top 5 慢请求、状态码分布、按域名统计\n- **Mock 规则管理面板**（`Ctrl+M`）— 统一管理所有 mock 规则\n\n---\n\n## AI inspection\n\n`flog ai` 提供面向 AI agent 的 headless JSON 接口：\n\n```bash\nflog ai snapshot --format json --last 20 --net-last 20\nflog ai logs --level error --last 20\nflog ai net --failed --last 20\nflog ai get net#42 --detail\nflog ai curl net#42\nflog ai snapshot --format json --screenshot\nflog ai doctor --format json\n```\n\n输出只读、默认脱敏，并使用 `log#12`、`net#42` 这类稳定 id，方便 AI\n引用证据，不需要从 TUI 手动复制。默认快照只返回最近少量日志和网络摘要；\n需要大字段时再用 `get --detail` 精确获取。\n\n把 AI 使用说明安装到当前项目：\n\n```bash\ncd path/to/your/flutter-app\nflog install-skill\n```\n\n这会写入项目级说明文件：`AGENTS.md` 作为主入口，`CLAUDE.md` 通过\n`@AGENTS.md` 复用它，`.cursor/rules/flog-inspect.mdc` 作为 Cursor 适配层，\n完整 workflow 放在 `.flog/skills/flog-inspect/SKILL.md`。不同 AI 工具目前\n没有统一的公共 skill 目录，所以 flog 默认安装这些适配文件；可用\n`--agent codex|claude|cursor` 只安装某一种。\n\n---\n\n## 通信架构\n\nflog 采用 **Direct Socket + Data Source** 架构：\n\n**Dart 端 = 数据源** — `FlogStore` 环形缓冲区（50K 条 FIFO）存储所有日志和网络消息。App 启动后即开始记录，不依赖 flog 是否连接。\n\n**flog TUI = 纯渲染器** — 连接时 Dart 自动回放全部历史数据，之后无缝接收实时消息。断连不丢数据，切换 Session 即时重建。\n\n**系统日志自动捕获** — `Flog.init()` 自动注册 `debugPrint` / `FlutterError.onError` / `PlatformDispatcher.onError` 三个 hook，框架异常、渲染溢出等系统输出自动进入 FlogStore，无需 `flutter logs`。\n\n- 不依赖 VM Service — 日志不再通过 print/developer.log 传输\n- 不污染终端输出 — Flutter 控制台里不会有 flog_net 日志\n- 自动设备发现 — 通过 `flutter devices` 检测已连接设备\n- 全平台支持：\n  - **macOS / iOS 模拟器** — localhost 直通\n  - **Android** — 自动 `adb forward` 端口转发\n  - **iOS 真机** — usbmuxd USB 端口转发\n\n## 用法\n\n```bash\n# 启动 flog（默认端口 9753）\nflog\n\n# 指定端口\nflog --port 9754\n\n# 启动时指定过滤\nflog --level w\nflog --tag Network\n```\n\n## 搭配 flog_dart\n\nflog 能识别任何 Flutter 日志输出。搭配 [flog_dart](https://pub.dev/packages/flog_dart) 可以获得精确的级别和 Tag 解析 + Network Inspector：\n\n```bash\n# pubspec.yaml\ndependencies:\n  flog_dart: ^0.10.0\n```\n\n### 初始化\n\n在 App 启动时尽早调用一次 `Flog.init()`，同步执行、零阻塞：\n\n```dart\nimport 'package:flog_dart/flog_dart.dart';\n\nvoid main() {\n  WidgetsFlutterBinding.ensureInitialized();\n  Flog.init();  // 自动注册 hook + 启动 server + 后台获取 app info\n  runApp(MyApp());\n}\n```\n\n### 快速接入 Network Inspector（推荐）\n\n用 `FlogDio` 替换 `Dio`，零配置自动接入 Network Inspector + Mock：\n\n```dart\nimport 'package:flog_dart/flog_dart.dart';\n\n// 替换 Dio() → FlogDio()，自动注入 HTTP 日志 + Mock 拦截器\nfinal dio = FlogDio(baseUrl: 'https://api.example.com');\n\n// 正常使用，所有请求自动出现在 flog Network 面板\nfinal response = await dio.get('/users');\n\n// SSE 流式请求也内置支持\nfinal sse = await dio.sse('/chat/completions',\n  method: 'POST',\n  data: {'prompt': 'hello'},\n);\nawait for (final event in sse.stream) {\n  print(event);\n}\n```\n\n\u003e Release 构建自动 tree-shake：`flogEnabled` 在 release 模式为 `false`，所有 flog 代码被 AOT 移除，零开销。\n\n### 日志\n\n```dart\nimport 'package:flog_dart/flog_dart.dart';\n\nfinal log = FlogLogger('Network');\nlog.i('-\u003e GET /api/users');\nlog.e('Connection failed: $e');\n```\n\n### 手动接入 Network Inspector\n\n如果不想用 `FlogDio`，可以手动添加拦截器：\n\n```dart\nfinal dio = Dio();\ndio.interceptors.addAll([\n  FlogHttpInterceptor(),        // ← 必须放在最前面\n  ApiResponseInterceptor(),     // 业务逻辑拦截器\n  LoggingInterceptor(),\n]);\n```\n\n\u003e **注意：** `FlogHttpInterceptor` 必须添加在其他会修改或拦截响应的 interceptor **之前**。如果放在后面，当其他 interceptor 调用 `handler.reject()` 时，flog 看不到原始响应，请求会一直显示为 Pending 状态。\n\n### SSE 流式请求\n\n```dart\nawait for (final data in FlogSseParser.wrap(\n  response.data!.stream,\n  url: '/api/chat/completions',\n  method: 'POST',\n)) {\n  final json = jsonDecode(data);\n  // ...\n}\n```\n\n### WebSocket\n\n```dart\nfinal ws = await FlogWebSocket.connect('wss://example.com/ws');\nws.send(jsonEncode({'type': 'hello'}));\nws.stream.listen((data) =\u003e print(data));\nawait ws.close();\n```\n\n## 快捷键\n\n按 `?` 可在 flog 内查看完整帮助。\n\n### Logs\n\n| 按键 | 功能 |\n|------|------|\n| `1` / `2` | 切换 Logs / Network 标签页 |\n| `/` | 聚焦搜索框（支持 `a|b`、`/正则/`、`/正则/i`） |\n| `\\` | 聚焦排除框 |\n| `t` | 聚焦 Tag 过滤（如 `+network|-flog_net`） |\n| `n` / `N` | 下一个/上一个匹配 |\n| `j/k` 或方向键 | 移动选择 |\n| `PgUp` / `PgDn` | 翻页 |\n| `Home` / `End` | 顶部 / 底部 |\n| `G` | 跳回底部（恢复 LIVE） |\n| `Enter` | 打开/关闭详情面板 |\n| 右键 | 书签切换 |\n| `c` | 复制选中日志 |\n| `e` | 导出过滤后的日志到文件 |\n| `S` | 统计视图 |\n| `s` | 选择模式（终端文字选择） |\n| 点击底栏 `⇅ AppName …` | 打开设备选择器切换 App |\n| `?` | 帮助 |\n| `Esc` | 清除过滤 / 关闭浮层 |\n| `q` | 退出 |\n\n### Network\n\n| 按键 | 功能 |\n|------|------|\n| `/` | URL 搜索 |\n| `\\` | 排除搜索 |\n| `c` | Copy as cURL（仅 HTTP） |\n| `y` | Copy Response（SSE Merged / WS Chat 模式下复制拼接文本） |\n| `r` | Replay 重放请求（仅 HTTP） |\n| `M` | 从当前请求创建 Mock 规则（仅 HTTP） |\n| `Ctrl+M` | 打开 Mock 规则管理面板 |\n| `S` | 统计面板 |\n| `E` / `C` | 展开 / 折叠全部 JSON |\n| `Enter` | 打开/关闭详情面板 |\n| `j/k` | SSE Merged 模式下切换字段；其他情况移动选择 |\n| `G` / `End` | 跳回请求列表底部 |\n| `Esc` | SSE Merged 模式下退出；其他情况清除过滤 |\n| `s` | 选择模式 |\n\n## 安装\n\n```bash\n# 一键安装\ncurl -fsSL https://raw.githubusercontent.com/shaominngqing/flog/master/install.sh | bash\n\n# 或通过 Cargo\ncargo install --path .\n```\n\n支持 macOS (Intel / Apple Silicon)、Linux (x86_64 / aarch64)、Windows。\n\n### 维护命令\n\n```bash\nflog update      # 从最新 GitHub Release 更新 flog，替换前会确认\nflog uninstall   # 删除 flog 二进制和本地配置，用户导出的 flog_*.log 不会删除\nflog doctor      # 检查更新网络、adb、usbmuxd 和 9753..9762 端口状态\nflog devices     # 列出发现的设备和 flog_dart App\n```\n\n这些命令不进入 TUI，适合安装维护和排障。`doctor` 会尝试区分端口是\n`free`、`flog_dart \u003capp\u003e`，还是 `open, not flog_dart`；`devices` 会短扫\n设备和 App，发现可连接的 `flog_dart` 后尽快返回。\n\n## 贡献者文档\n\n- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — 分层架构总览。\n- [`docs/MODULES.md`](docs/MODULES.md) — 各模块索引。\n- [`docs/PROTOCOL.md`](docs/PROTOCOL.md) — flog ↔ flog_dart 线协议规范。\n- [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) — 审计分类 / 测试规约 / commit 约定。\n\n当前版本 **0.8.1** —— 修复移动端恢复前台时的重复重连和 iOS USB 多接口 DeviceID 切换问题，并保留 Network Timing 采集、终端时间线和渐进式 `flog ai` 检查命令。\n`flog install-skill` 项目级 AI 使用说明，覆盖 Codex、Claude Code、Cursor，\n同时保持 AI 输出默认精简和脱敏。完整审计线索见 `docs/superpowers/`。\n\n## License\n\nMIT\n\n---\n\n[English](README_EN.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaominngqing%2Fflog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshaominngqing%2Fflog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaominngqing%2Fflog/lists"}