create-evlog-enricher

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Create evlog Enricher

创建 evlog Enricher

Add a new built-in enricher to evlog. Every enricher is built on the public toolkit primitive
defineEnricher
from
evlog/toolkit
, so a community enricher has the same shape as a built-in one.
向 evlog 添加一个新的内置 Enricher。每个 Enricher 都基于
evlog/toolkit
提供的公共 toolkit 原语
defineEnricher
构建,因此社区 Enricher 与内置 Enricher 具有相同的结构。

PR Title

PR 标题

feat(core): add the {name} enricher
Enrichers live in the core package surface (
evlog/enrichers
), so use the
core
scope unless a dedicated scope exists.
feat(core): add the {name} enricher
Enricher 位于 core 包的公开接口(
evlog/enrichers
)中,因此除非存在专用 scope,否则使用
core
scope。

Touchpoints Checklist

涉及文件检查清单

#FileAction
1
packages/evlog/src/enrichers/index.ts
Add enricher source (one
defineEnricher
call)
2Same file:
createDefaultEnrichers()
Decide whether the enricher belongs in the default composition (see below)
3
packages/evlog/test/toolkit/enrichers.test.ts
Add tests (one
describe
block per enricher)
4
apps/docs/content/5.use-cases/5.enrichers.md
Add a section for the enricher + update the import list and, if applicable, the "All built-in enrichers" default composition text
5
skills/review-logging-patterns/SKILL.md
Add the enricher to the
Built-in:
line in the Enrichers section
6
packages/evlog/README.md
Add the enricher to the Built-in Enrichers section (root
README.md
is a symlink to it)
7
.changeset/{name}-enricher.md
Create changeset (
minor
)
Important: Do NOT consider the task complete until all 7 touchpoints have been addressed.
#文件操作
1
packages/evlog/src/enrichers/index.ts
添加 Enricher 源代码(一次
defineEnricher
调用)
2同一文件中的
createDefaultEnrichers()
判断该 Enricher 是否应加入默认组合(见下文)
3
packages/evlog/test/toolkit/enrichers.test.ts
添加测试(每个 Enricher 使用一个
describe
块)
4
apps/docs/content/5.use-cases/5.enrichers.md
为该 Enricher 添加章节,并更新导入列表;如适用,还要更新 "All built-in enrichers" 的默认组合文本
5
skills/review-logging-patterns/SKILL.md
在 Enrichers 部分的
Built-in:
行中添加该 Enricher
6
packages/evlog/README.md
在 Built-in Enrichers 部分添加该 Enricher(根目录的
README.md
是它的符号链接)
7
.changeset/{name}-enricher.md
创建 changeset(
minor
)
重要:在处理完全部 7 个涉及文件之前,不要认为此任务已完成。

Should it join
createDefaultEnrichers()
?

是否应加入
createDefaultEnrichers()
?

createDefaultEnrichers()
composes user agent, geo, request size, and trace context via
composeEnrichers
(from
../shared/compose
). Add the new enricher to the composition only if it is universally applicable and reads nothing but the request (headers/env). Anything requiring service-specific setup or extra cost stays opt-in. Changing the default composition is a behavior change for every existing
createDefaultEnrichers()
user: call it out explicitly in the changeset.
createDefaultEnrichers()
通过
composeEnrichers
(来自
../shared/compose
)组合 user agent、geo、request size 和 trace context。仅当新 Enricher 普遍适用且只读取 request(headers/env)时,才应将其加入组合。任何需要特定服务配置或会产生额外成本的功能都应保持 opt-in。修改默认组合会改变每个现有
createDefaultEnrichers()
用户的行为:请在 changeset 中明确说明这一变化。

Naming Conventions

命名约定

PlaceholderExample (UserAgent)Usage
{name}
userAgent
camelCase for event field key
{Name}
UserAgent
PascalCase in function/interface names
{DISPLAY}
User Agent
Human-readable display name
占位符示例(UserAgent)用途
{name}
userAgent
事件字段键使用 camelCase
{Name}
UserAgent
函数和接口名称使用 PascalCase
{DISPLAY}
User Agent
人类可读的显示名称

Step 1: Enricher Source: built on
defineEnricher

第 1 步:Enricher 源代码:基于
defineEnricher

Add the enricher to
packages/evlog/src/enrichers/index.ts
. Read references/enricher-template.md for the full annotated template.
The contract is
defineEnricher<T>({ name, field, compute }, options?)
. You only ship one piece of logic:
  • compute(ctx)
    : return the computed value (typed as
    T
    ) or
    undefined
    to skip.
defineEnricher
handles the rest:
  • merging via
    mergeEventField
    (respecting
    options.overwrite
    , default
    false
    )
  • error isolation (throws are caught and logged, never propagated)
  • skipping when
    compute
    returns
    undefined
Key rules:
  • Use the toolkit helpers:
    getHeader()
    for case-insensitive header lookup,
    normalizeNumber()
    for numeric strings. Both from
    ../shared/headers
    (re-exported by
    evlog/toolkit
    ).
  • Single event field: each enricher writes one top-level field on
    ctx.event
    . If the enricher must additionally pin top-level fields (like
    createTraceContextEnricher
    does for
    event.traceId
    /
    event.parentSpanId
    ), wrap the
    defineEnricher
    result in a closure, see that enricher for the pattern.
  • Factory pattern:
    create{Name}Enricher(options: EnricherOptions = {})
    returns the result of
    defineEnricher(...)
    , directly in the normal case, or through the thin closure wrapper when the enricher also pins top-level fields (see the single-event-field rule above).
  • No side effects: never throw, never log; rely on
    defineEnricher
    's built-in error handling if something goes wrong.
  • Export the Info type:
    {Name}Info
    describing the field shape, exported alongside the factory.
将 Enricher 添加到
packages/evlog/src/enrichers/index.ts
。阅读 references/enricher-template.md,了解完整的带注释模板。
defineEnricher<T>({ name, field, compute }, options?)
的契约如下。你只需实现一段逻辑:
  • compute(ctx)
    :返回计算后的值(类型为
    T
    ),或返回
    undefined
    以跳过。
defineEnricher
负责其余工作:
  • 通过
    mergeEventField
    合并(遵循
    options.overwrite
    ,默认值为
    false
    )
  • 错误隔离(捕获并记录抛出的错误,绝不向上传播)
  • 当
    compute
    返回
    undefined
    时跳过
关键规则:
  • 使用 toolkit helpers:使用
    getHeader()
    进行不区分大小写的 header 查找,使用
    normalizeNumber()
    转换数字字符串。两者均来自
    ../shared/headers
    (由
    evlog/toolkit
    重新导出)。
  • 单一事件字段:每个 Enricher 向
    ctx.event
    写入一个顶层字段。如果该 Enricher 还必须固定顶层字段(例如
    createTraceContextEnricher
    会为
    event.traceId
    /
    event.parentSpanId
    固定字段),则将
    defineEnricher
    的结果包裹在闭包中;有关该模式,请参阅那个 Enricher。
  • 工厂模式:
    create{Name}Enricher(options: EnricherOptions = {})
    返回
    defineEnricher(...)
    的结果。在常规情况下直接返回;如果该 Enricher 还会固定顶层字段,则通过一个轻量闭包包装器返回(参见上面的单一事件字段规则)。
  • 无副作用:绝不抛出错误,绝不记录日志;如果出现异常,依赖
    defineEnricher
    的内置错误处理。
  • 导出 Info 类型:导出一个描述字段结构的
    {Name}Info
    类型,并与工厂函数一起导出。

Step 2: Tests

第 2 步:测试

Add tests to
packages/evlog/test/toolkit/enrichers.test.ts
, following the existing structure (one
describe
block per enricher) and
packages/evlog/test/README.md
conventions.
Required test categories:
  1. Sets the field from its source: verify the enricher populates the event field correctly, reading whatever it actually reads (
    ctx.request
    ,
    ctx.response
    ,
    process.env
    ,
    ctx.event
    , or headers)
  2. Skips when source data missing: verify no field is set when the required input is absent
  3. Preserves existing data: verify
    overwrite: false
    (default) doesn't replace user-provided fields
  4. Overwrites when requested: verify
    overwrite: true
    replaces existing fields
  5. Handles edge cases: empty strings and malformed values, plus case-insensitive lookup for a header-based enricher
  6. Default composition: if the enricher joined
    createDefaultEnrichers()
    , extend that composition's tests
按照现有结构(每个 Enricher 使用一个
describe
块)以及
packages/evlog/test/README.md
的约定,将测试添加到
packages/evlog/test/toolkit/enrichers.test.ts
。
必需的测试类别:
  1. 从来源设置字段:验证 Enricher 能正确填充事件字段,并读取其实际读取的数据(
    ctx.request
    、
    ctx.response
    、
    process.env
    、
    ctx.event
    或 headers)
  2. 来源数据缺失时跳过:验证缺少必需输入时不会设置字段
  3. 保留已有数据:验证默认的
    overwrite: false
    不会替换用户提供的字段
  4. 按请求覆盖:验证
    overwrite: true
    会替换已有字段
  5. 处理边界情况:测试空字符串和格式错误的值;对于基于 header 的 Enricher,还要测试不区分大小写的查找
  6. 默认组合:如果该 Enricher 已加入
    createDefaultEnrichers()
    ,则扩展该组合的测试

Step 3: Update the Enrichers Docs Page

第 3 步:更新 Enrichers 文档页面

Edit
apps/docs/content/5.use-cases/5.enrichers.md
:
  1. Add the enricher to the import list at the top
  2. Add a
    ## {DISPLAY}
    section following the structure of the existing ones:
markdown
undefined
编辑
apps/docs/content/5.use-cases/5.enrichers.md
:
  1. 将该 Enricher 添加到顶部的导入列表
  2. 按照现有章节的结构,添加一个
    ## {DISPLAY}
    章节:
markdown
undefined

{DISPLAY}

{DISPLAY}

[One-sentence description of what the enricher does.]
Sets:
event.{name}
```typescript const enrich = create{Name}Enricher() ```
Output shape:
```typescript interface {Name}Info { // fields } ```
Example output:
```json { "{name}": { // example values } } ```

3. If the enricher joined the default composition, update the "All built-in enrichers" section text listing what `createDefaultEnrichers()` composes.

Custom-enricher authoring docs live separately at `apps/docs/content/6.extend/5.custom-enrichers.md`, with no change needed there unless the toolkit contract itself changed.
[One-sentence description of what the enricher does.]
Sets:
event.{name}
```typescript const enrich = create{Name}Enricher() ```
Output shape:
```typescript interface {Name}Info { // fields } ```
Example output:
```json { "{name}": { // example values } } ```

3. 如果该 Enricher 已加入默认组合,请更新 "All built-in enrichers" 章节中列举 `createDefaultEnrichers()` 所组合内容的文本。

自定义 Enricher 的编写文档单独位于 `apps/docs/content/6.extend/5.custom-enrichers.md`;除非 toolkit 契约本身发生变化,否则无需修改该文档。

Step 4: Update the Public Skill

第 4 步:更新公共 Skill

In
skills/review-logging-patterns/SKILL.md
(published on evlog.dev), find the Enrichers section and add the new enricher to the
Built-in:
line.
在
skills/review-logging-patterns/SKILL.md
(发布于 evlog.dev)中找到 Enrichers 部分,将新 Enricher 添加到
Built-in:
行。

Step 5: Update README

第 5 步:更新 README

Add the enricher to the Built-in Enrichers section in
packages/evlog/README.md
(the root
README.md
is a symlink to it).
在
packages/evlog/README.md
的 Built-in Enrichers 部分添加该 Enricher(根目录的
README.md
是它的符号链接)。

Step 6: Changeset

第 6 步:Changeset

Create
.changeset/{name}-enricher.md
with a
minor
bump describing what the enricher sets and when to use it. Mention explicitly if the default composition changed.
创建
.changeset/{name}-enricher.md
,使用
minor
版本增量,并描述该 Enricher 设置的内容及其适用场景。如果默认组合发生变化,请明确说明。

Verification

验证

bash
cd packages/evlog
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run build
bash
cd packages/evlog
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run build