news 2026/10/17 18:29:57

Claude Code、Codex和Gemini CLI的会话日志长什么样?tokentab三大解析器实现详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Claude Code、Codex和Gemini CLI的会话日志长什么样?tokentab三大解析器实现详解

【免费下载链接】tokentab

Local-first CLI and web dashboard that reads Claude Code, Codex and Gemini CLI session logs and shows token usage and cost by model, project, day and activity. No account, no API key, nothing leaves your machine

项目地址:https://gitcode.com/gh_mirrors/toke/tokentab
点击查看免费下载

tokentab 是一个本地优先(local-first)的 Token 用量与成本统计工具:它直接读取 Claude Code、Codex 和 Gemini CLI 留在磁盘上的会话日志,按模型、项目、日期和活动类型统计 token 消耗与花费——无需账号、无需 API Key,数据全程不离开你的机器。这篇文章详解 tokentab 三大解析器的实现:这三种工具的会话日志到底长什么样、藏在哪个目录、又是如何被一行行解析成统一数据的。

会话日志藏在哪里?位置和格式一览

三个工具都会"悄悄"在本地留下会话记录,tokentab 的解析器就是围绕这些路径工作的:

工具日志位置文件形态
Claude Code~/.claude/projects/**/*.jsonl每行一个 JSON 对象(JSONL)
Codex~/.codex/sessions/**/rollout-*.jsonl事件流 JSONL
Gemini CLI~/.gemini/tmp/**/session-*.json单个 JSON 文档

没安装的工具会被自动跳过,你只会看到自己真正用过的工具。

三大解析器的共同语法:统一数据模型

阅读解析器之前,先认识 tokentab 的"公共语法"——tokentab/types.py 中定义的两组数据类:

  • TokenCounts:一次调用的 input / output / cache_read / cache_write 四类 token 数;
  • UsageRecord:一条完整记录,含 provider(哪个工具)、model、project、timestamp、activity(活动类型)、tokens 和去重用的 id。

每个解析器只需暴露一个collect()函数,返回扁平的UsageRecord列表,并在 tokentab/providers/init.py 的ALL_PROVIDERS里登记。定价、分组、仪表盘等下游代码只接触这同一形状的数据——这就是为什么新增一个工具"写完一个模块就全通了"。三个解析器共用的辅助函数(安全解析 JSON、遍历目录、从编码目录名还原项目名、时间戳容错解析)集中在 tokentab/providers/shared.py。

Claude Code 解析器:最友好的 JSONL 日志怎么读

Claude Code 每个会话对应一个~/.claude/projects/<编码路径>/<会话id>.jsonl文件,是三者中最规整的格式:每行一个 JSON 对象,assistant 回合的消息里自带model字段和一个usage块,形如:

{"input_tokens": 1200, "output_tokens": 350, "cache_read_input_tokens": 98000, "cache_creation_input_tokens": 2048}

解析流程见 claude.py 的collect(),分两轮扫描:

  1. 上下文轮:抓取第一条 user 消息的文本(截取前 500 字)和所有tool_use块的工具名,交给 tokentab/classify.py 猜测活动类型;
  2. 用量轮:逐行取出带usage的消息,按消息id去重后生成记录。

两个值得注意的细节:

  • 缓存拆分:Claude 把缓存读(cache_read)和缓存写(cache_write)分开计费,解析器原样映射到TokenCounts,下游才能按不同单价计价;
  • 项目名还原:目录里的-home-user-myapp这类编码名无法完美反转,pretty_project 取最后一段(如myapp)作为展示名;
  • 配置目录支持CLAUDE_CONFIG_DIR环境变量覆盖,目录不存在则直接返回空列表。

Codex 解析器:累计型 token_count 事件怎么破

Codex 把日志按日期分目录存放在~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl(旧数据在archived_sessions/),每行是一个"事件"对象。它的难点在于:token 用量出现在token_count事件里,而这些数字是整场会话的累计值。直接相加会把同一批 token 重复计费。

解析器(codex.py)的解法是对相邻事件做差值:记录上一次的 input / output / cached 累计值,本次减去上次(负数按 0 处理),得到的增量才是"这一次调用"的真实消耗:

d_in = max(0, tot_in - prev_in) # 累计值做差,得到单次调用量

其他信息则来自"上下文轮"扫描:

  • 项目名:取事件里的cwd字段(通常来自文件开头附近的 session-meta 事件);
  • 模型名:取model字段;
  • 工具名:来自function_call事件,同样用于活动分类;
  • 首次提问:第一条 user 消息文本用于 classify。

由于 Codex 只报告"已缓存的输入"而不区分缓存写入,cache_write恒为 0。_find_token_count还做了多层嵌套兼容——token_count可能出现在事件顶层、payload里或info.total_token_usage中,保证新旧版本格式都能解析。

Gemini CLI 解析器:缓存 token 如何避免重复计费

Gemini CLI 的日志"最文明":每个会话是~/.gemini/tmp/<项目>/chats/session-*.json里的一个完整 JSON 文档,包含一个messages列表,每条消息自带tokens块(input / output / cached)、model和timestamp。

它有一个隐蔽的坑,解析器文档注释里写得直白:Gemini 报告的 input 是"包含缓存部分"的总数。如果直接按 input 计价,缓存 token 会被收两次钱。gemini.py 的处理是一行减法:

fresh_input = max(0, raw_input - cached) # input 包含缓存,先减掉再计价

这样缓存部分被单独归入cache_read按低价计费,新鲜输入按正常 input 计价。项目名直接从路径中tmp后的目录段取得;工具名来自parts中的functionCall;若消息未带模型名,则回退到gemini-2.5-pro。

两个加分细节:活动分类与价格模糊匹配

活动分类(tokentab/classify.py):刻意"笨"的设计——不调用任何模型,只看两类信号:用过哪些工具(edit/read/bash 等集合)+ 首条消息里的关键词(bug、refactor、test、commit……)。输出 testing / git / planning / debugging / refactor / feature / coding / exploring / chat 之一。确定性强、零开销,当作"提示"而非判决即可。

价格模糊匹配(tokentab/pricing/prices.py):价格是一张手工维护的"美元/百万 token"表,从不联网查询。日志里的claude-opus-4-6-20260514找不到精确 key 时,先去掉anthropic/这类厂商前缀,再按"最长 key 优先"做子串匹配。遇到完全匹配不到的模型,CLI 会明确提示而不是悄悄记成 $0.00。

快速上手:从日志到仪表盘

git clone https://gitcode.com/gh_mirrors/toke/tokentab cd tokentab pip install . python cli.py # 默认统计最近 7 天 python cli.py -web # 打开 localhost:4747 的 Web 仪表盘

解析出的记录经 collect_all 统一加价后,由 tokentab/report/aggregate.py 的build_report按工具、模型、项目、活动、日期分组——单个工具解析失败只会打印一行 warning,不会拖垮整份报告。整个 Web 仪表盘只基于 Python 标准库 HTTP 服务搭建,只绑定 localhost,甚至可以拔网线使用。

写在最后

看懂这三大解析器,你会发现 tokentab 的设计哲学很朴素:每种日志格式只在一个文件里被"翻译"一次,翻译结果就只有一个形状(UsageRecord)。想接入新的工具?照着 claude.py 这个最简单的模板写一个collect(),再加进ALL_PROVIDERS列表即可——定价、分组、图表全部自动生效。Cursor 的解析位已留好(tokentab/providers/cursor.py,数据在 SQLite 的state.vscdb里,目前返回空列表),是现成的练手入口。更多输出解读技巧(比如缓存命中率长期低于 80% 说明什么),参见 README.md 的 "Reading the output" 一节。

【免费下载链接】tokentab

Local-first CLI and web dashboard that reads Claude Code, Codex and Gemini CLI session logs and shows token usage and cost by model, project, day and activity. No account, no API key, nothing leaves your machine

项目地址:https://gitcode.com/gh_mirrors/toke/tokentab
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 18:27:19

AI辅助开发登录界面:从需求拆解到前后端联调全流程

前一阵折腾了几个小项目&#xff0c;发现用AI辅助开发这件事&#xff0c;真正难的不是写代码&#xff0c;而是怎么把一个模糊的需求描述成机器能理解的任务。这个系列写到第三篇&#xff0c;正好拿“登录界面”这个看似简单、实际坑不少的场景来聊聊。如果你正准备用AI帮忙搭一…

作者头像 李华
网站建设 2026/10/17 18:21:23

2020A题炉温曲线:热传导模型、参数反演与传送带速度优化

简介&#xff1a;这份资源是2020年全国大学生数学建模竞赛A题「炉温曲线」的讲评资料&#xff0c;面向备战数模竞赛的高校学生及指导教师&#xff0c;帮助读者系统理解该赛题的建模思路与求解方法。压缩包内仅含1个PDF文件&#xff0c;约26.94MB&#xff0c;内容围绕赛题展开完…

作者头像 李华
网站建设 2026/10/17 18:16:40

汇编优化实战:表驱动选择、条件伪指令与移位指令全解析

第一次写带功能菜单的程序时&#xff0c;我老老实实把每个按键值都判断一遍&#xff1a;CMP AL, 0、JE&#xff0c;然后CMP AL, 1、JE……也就五六个分支&#xff0c;写完连我自己都看不下去。旁边带我的前辈扫了一眼代码&#xff0c;只说了一句&#xff1a;“别让 CPU 一条一条…

作者头像 李华
网站建设 2026/10/17 18:16:04

大图切块与小目标检测:从切图到结果合并的完整实践指南

做目标检测的人&#xff0c;迟早会遇到这么一类项目&#xff1a;图特别大&#xff0c;目标特别小。你拿着一张四千乘三千的航拍图&#xff0c;里面要找的是十几个像素的车辆或屋顶&#xff0c;直接丢进检测器&#xff0c;要么显存不够跑不起来&#xff0c;要么跑起来了但漏检漏…

作者头像 李华