mcpField
C
create-evlog-adapter

create-evlog-adapter

github.com/evloghq开发1.9k836 次安装2 天前更新
代码仓库

关于 create-evlog-adapter

这款仓库 Skill 指导贡献者为 evlog 添加内置 drain 适配器,说明适配器架构与配置方式。它提供涵盖实现、测试、包导出、文档和发布工作的清单。

主要功能

  1. 01使用 defineHttpDrain 实现适配器
  2. 02标准配置解析
  3. 03请求编码与发送辅助函数
  4. 04单元及端到端测试要求
  5. 05构建、导出和文档清单

适用场景

  1. 01添加新的日志服务适配器
  2. 02提交拉取请求前检查适配器改动
  3. 03规划包与文档更新

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/evloghq/evlog --skill create-evlog-adapter

安装后在 Claude Code 中输入/create-evlog-adapter确认已加载。

详细介绍

创建 evlog 适配器

为 evlog 添加一个新的内置适配器。所有适配器都遵循相同的架构,并基于 evlog/toolkit 中的公共工具包原语构建,因此社区适配器与内置适配器具有相同的结构。

PR 标题

feat({name}): add the {Name} drain adapter

近期示例:feat(loki): add the Grafana Loki drain adapter、feat(clickhouse): add the ClickHouse drain adapter。将适配器名称用作 Conventional Commits 的作用域,并注册该作用域(见接触点 11)。

作用域时间注意事项:语义化 PR 检查会从基分支读取作用域列表,因此全新作用域无法通过引入它的 PR 的验证。可以先通过一个小型 PR 注册作用域(Loki/ClickHouse 的做法),或者在引入作用域的 PR 中使用不带作用域的标题(feat: add the {Name} drain adapter)。

接触点检查清单

#文件操作
1packages/evlog/src/adapters/{name}.ts创建适配器源码(基于 ../shared/drain 中的 defineHttpDrain 构建)
2packages/evlog/tsdown.config.ts添加构建入口
3packages/evlog/package.json添加 exports 和 typesVersions 条目
4packages/evlog/test/adapters/{name}.test.ts创建单元测试(使用 test/helpers/fetch.ts)
5packages/evlog/test/e2e/{name}.e2e.ts创建由环境变量控制的端到端测试;如果支持自托管,则扩展 Docker 沙箱
6packages/evlog/test/toolkit/__snapshots__/api-surface.test.ts.snap构建后运行测试即可重新生成(先运行 pnpm run build,再运行 pnpm test)
7apps/docs/content/4.integrate/adapters/{category}/{NN}.{name}.md在相应分类下创建适配器文档页面
8apps/docs/content/4.integrate/adapters/01.overview.md在概览中添加适配器(frontmatter 链接和卡片)
9skills/review-logging-patterns/SKILL.md在 Drain Adapters 表格中添加适配器行,并更新 frontmatter 描述
10.changeset/{name}-adapter.md创建 changeset(minor),描述该适配器
11.github/workflows/semantic-pull-request.yml + .github/pull_request_template.md在两个文件中注册 {name} 作为 PR 作用域
12.agents/skills/create-adapter/references/upstream-alignment.md添加适配器对应行:接收文档 URL、官方客户端仓库和包、构建请求的文件、客户端为提供商的其他功能(例如问题、指标或用户资料)提供数据的文件(如果提供商只存储我们发送的内容,则写 none),以及将 Aligned to 设为编写适配器时查阅的客户端版本

重要:必须完成全部 12 个接触点,才能认为任务已完成。

命名约定

请一致使用以下占位符:

占位符示例(Loki)用途
{name}loki文件名、导入路径、环境变量后缀、PR 作用域
{Name}Loki函数/接口名称中的 PascalCase
{NAME}LOKI环境变量前缀中的 SCREAMING_CASE

标准选项命名(请使用以下确切名称):

概念标准选项名称
Bearer 类型 API 密钥apiKey
接收 API 的基础 URLendpoint
服务标识符serviceName
请求超时时间(ms)timeout
瞬态故障时的重试次数retries

如果服务沿用了不同名称(token、sourceToken 等),请通过 applyDeprecatedAlias 将其保留为已弃用的别名。Axiom 和 Better Stack 中有相应示例。

步骤 1:适配器源码:基于 defineHttpDrain

创建 packages/evlog/src/adapters/{name}.ts。完整的注释模板请参阅 references/adapter-template.md。loki.ts 和 clickhouse.ts 是最新的参考实现。

契约为 defineHttpDrain<TConfig>({ name, label, resolve, encode })。你只需实现两部分逻辑:

  1. resolve():生成完全解析的配置;如果应跳过,则返回 null。标准优先级(overrides → runtimeConfig.evlog.{name} → runtimeConfig.{name} → env vars)请使用 resolveAdapterConfig。在 ConfigField.env 中,先列出 NUXT_{NAME}_*,再列出 {NAME}_*,以静默兼容 Nuxt;面向用户的消息中只显示 {NAME}_*,并使用 formatPublicEnvKeys。
  2. encode(events, config):一个私有函数 encode{Name}Request(events, config): HttpDrainRequest,用于批量返回 { url, headers, body }。HTTP 传输、身份标头、重试、超时和错误日志由 defineHttpDrain(通过 httpPost)处理。

关键规则:

  • 单一工厂函数。 导出一个 create{Name}Drain(overrides?: Partial<{Name}Config>)。不要创建双 API 工厂函数:如果某个服务支持多种摄取模式(日志与事件),请通过 mode 选项提供(参见 PostHog)。
  • 适配器中不得包含 HTTP 代码。 切勿直接调用 fetch。如果服务确实需要自定义传输(如二进制封装、非 HTTP),请改用 ../shared/drain 中的 defineDrain,参见 fs.ts 和 memory.ts。
  • 编码保持一致。 独立的 sendTo{Name} / sendBatchTo{Name} 辅助函数必须复用同一个私有函数 encode{Name}Request(),并通过 sendEncodedDrainRequest(request, { label, source, timeout, retries }) 发送请求,不得使用单独的 fetch 路径。test/adapters/encode-parity.test.ts 对部分适配器进行了验证;请将新适配器也加入其中(目前尚未注册所有现有适配器,这是一个缺口,而不是跳过的理由)。
  • 不得自行实现配置解析。 始终使用 resolveAdapterConfig。已弃用的别名(token → apiKey)通过 applyDeprecatedAlias 处理。
  • 导出转换器。 如果服务需要特定的事件格式,请导出 to{Name}Event() / build{Name}Payload() 辅助函数,以便单独测试。
  • 兼容边缘运行时。 适配器运行于 Cloudflare Workers:不要使用 Buffer(请使用 TextEncoder + btoa,参见 loki.ts),也不要使用仅限 Node 的 API。如果某个运行时确实无法支持,请参照 fs.ts 中的 isEdgeRuntime() 防护模式。

步骤 2:构建配置

在 packages/evlog/tsdown.config.ts 中与现有适配器并列添加构建入口:

'adapters/{name}': 'src/adapters/{name}.ts',

遵循该文件中现有的排序方式。

步骤 3:包导出

在 packages/evlog/package.json 中添加两项(放在最后一个适配器之后,并检查当前列表,不要想当然):

在 exports 中:

"./{name}": {
  "types": "./dist/adapters/{name}.d.mts",
  "import": "./dist/adapters/{name}.mjs",
  "default": "./dist/adapters/{name}.mjs"
}

在 typesVersions["*"] 中:

"{name}": [
  "./dist/adapters/{name}.d.mts"
]

test/toolkit/entrypoint-registry.test.ts 会相互检查这三处注册,并且无需构建即可运行。如果 typesVersions["*"] 或 tsdown.config.ts 中缺少子路径,或者 import 和 default 未指向与 types 同目录下的 .mjs 文件,测试就会失败。没有导出项的 tsdown 入口不会被报告,因为内部代码块也会以这种方式构建。

第 4 步:单元测试

创建 packages/evlog/test/adapters/{name}.test.ts。阅读 references/test-template.md 查看完整的注释模板,并阅读 packages/evlog/test/README.md 了解整个仓库的约定。

测试 README 中的硬性要求:

  • 使用 test/helpers/fetch.ts 中的 mockFetch() / getFetchCall / getFetchJson / getFetchHeaders,绝不要手动编写 vi.spyOn(globalThis, 'fetch') 样板代码。
  • 在 afterEach 中清理适配器读取的任何环境变量。
  • 直接测试导出的纯函数辅助方法(to{Name}Event、build{Name}Payload、URL 解析器),每个辅助方法各用一个 describe。

必测类别:

  1. URL 构造(默认端点 + 自定义端点,兼容末尾斜杠)
  2. 请求头(身份验证、内容类型、服务专用请求头)
  3. 请求正文格式(JSON 结构与服务 API 匹配)
  4. 缺少 apiKey(或必填字段)时的跳过行为
  5. 批量操作(一次请求发送多个事件,空批次跳过 fetch)
  6. 已弃用的别名仍可用(如适用)
  7. 将适配器添加到 test/adapters/encode-parity.test.ts

第 5 步:端到端测试 + 沙盒

创建 packages/evlog/test/e2e/{name}.e2e.ts,并设置为仅在适配器环境变量存在时运行(缺失时跳过)。使用 pnpm test:e2e 运行。

如果该服务可自托管,请扩展本地沙盒,使适配器无需云凭据即可进行测试:

  • packages/evlog/test/e2e/docker-compose.yml:添加该服务
  • packages/evlog/test/e2e/seed.mjs:让数据播种器也将数据写入新的后端
  • packages/evlog/test/e2e/README.md:添加相关说明
  • 根目录 package.json 中的 sandbox:e2e 脚本:如有需要,添加本地环境变量

请参考 Loki 和 ClickHouse 的配置。

第 6 步:适配器文档页面

修改 apps/docs/ 下的内容之前(第 6 至第 8 步),请先阅读 apps/docs/AGENTS.md。

适配器文档分为三类,位于 apps/docs/content/4.integrate/adapters/ 下:

类别目录示例
云端(仅 SaaS)cloud/Axiom、PostHog、Sentry、Better Stack、Datadog
云端或自托管hybrid/Loki、ClickHouse、OTLP、HyperDX
自托管(仅本地)self-hosted/FS、NuxtHub、Memory

在相应类别中创建 {NN}.{name}.md,使用下一个可用编号。参考 Loki 页面(hybrid/01.loki.md)的 frontmatter、语气和章节结构。关键章节包括:简介、快速设置、配置(环境变量表 + 优先级)、高级用法、在目标服务中查询、故障排除、直接 API 用法、后续步骤。

重要:多框架示例。“快速开始”部分必须包含一个 ::framework-tabs 组,每个受支持的框架各有一个代码围栏(Nuxt、Nitro、Next.js、SvelteKit、TanStack Start、React Router、Hono、Express、Fastify、Elysia、NestJS、oRPC、Cloudflare Workers、Standalone),并在方括号标签中标明框架。复制 Axiom 页面中的组,并替换为对应的 drain 工厂。不要只展示 Nitro 示例,且组内只能包含代码围栏。

第 7 步:更新适配器概览页面

在 两 处编辑 apps/docs/content/4.integrate/adapters/01.overview.md(遵循现有适配器的模式):

  1. Frontmatter links 数组:添加包含图标和 /integrate/adapters/{category}/{name} 路径的链接条目,并按类别排序
  2. ::card-group 部分:在对应位置添加卡片块

第 8 步:更新公开 Skill

在 skills/review-logging-patterns/SKILL.md(通过 /.well-known/skills/ 发布于 evlog.dev)中:

  1. 在 Drain Adapters 表格中添加一行:| {Name} | evlog/{name} | {NAME}_API_KEY, ... |
  2. 将适配器名称添加到 YAML frontmatter 中的 description: 行

第 9 步:Changeset

创建 .changeset/{name}-adapter.md,并设置 minor 版本升级。将其写成发布说明:说明适配器的功能、支持的部署模式、关键选项、环境变量和直接发送辅助方法。请参考 Loki/ClickHouse PR 中 .changeset 目录下的条目,了解所需的详细程度。

步骤 10:PR 范围

按字母顺序将 {name} 添加到 .github/workflows/semantic-pull-request.yml 中的 scopes 列表以及 .github/pull_request_template.md 的 Scopes 部分。请记住 PR 标题部分提到的时机注意事项:只有当 PR 的目标分支已包含此注册项时,该注册项才会对 PR 生效。

验证

完成全新安装后,先从仓库根目录生成工作区类型,然后运行软件包检查:

pnpm run dev:prepare
cd packages/evlog
pnpm run lint
pnpm run typecheck
pnpm run build    # required before test — api-surface snapshot is gated on dist/
pnpm run test

评论

支持 Markdown