create-evlog-framework-integration by hugorcd/evlog
npx skills add https://github.com/hugorcd/evlog --skill create-evlog-framework-integration向 evlog 添加一个新的框架集成。每个集成都遵循基于共享的 createMiddlewareLogger 工具构建的相同架构。本技能将贯穿所有接触点。每个接触点都是强制性的——不要跳过任何一个。
推荐的拉取请求标题格式:
feat({framework}): add {Framework} middleware integration
---|---|---
1 | packages/evlog/src/{framework}/index.ts | 创建集成源代码
2 | packages/evlog/tsdown.config.ts | 添加构建入口 + 外部依赖
3 | packages/evlog/package.json | 添加 exports + typesVersions + 对等依赖 + 关键词
4 | | 创建测试
5 | | 创建框架文档页面
6 | | 添加卡片 + 表格行
7 | | 在"选择您的框架"中添加卡片
8 | | 添加框架代码片段
9 | | 添加框架标签页
10 | | 添加框架设置部分 + 更新 frontmatter 描述
11 | | 添加框架部分 + 在框架支持表中添加行
12 | | 创建带有测试 UI 的示例应用
13 | (根目录) | 添加 脚本
14 | | 创建 changeset ()
15 | | 添加 作用域
16 | | 添加 作用域
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
packages/evlog/test/{framework}.test.tsapps/docs/content/2.frameworks/{NN}.{framework}.mdapps/docs/content/2.frameworks/00.overview.mdapps/docs/content/1.getting-started/2.installation.mdapps/docs/content/0.landing.mdapps/docs/app/components/features/FeatureFrameworks.vueskills/review-logging-patterns/SKILL.mdpackages/evlog/README.mdexamples/{framework}/package.jsonexample:{framework}.changeset/{framework}-integration.mdminor.github/workflows/semantic-pull-request.yml{framework}.github/pull_request_template.md{framework}重要:在所有 16 个接触点都处理完毕之前,不要认为任务已完成。
一致地使用这些占位符:
| 占位符 | 示例 (Hono) | 用途 |
|---|---|---|
{framework} | hono | 目录名、导入路径、文件名 |
{Framework} | Hono | 类型/接口名称中的 PascalCase |
所有集成共享相同的核心工具。切勿重新实现存在于 shared/ 中的逻辑。这些工具也作为 evlog/toolkit 公开可用,供社区构建的集成使用(参见自定义集成文档)。
| 工具 | 位置 | 用途 |
|---|---|---|
createMiddlewareLogger | ../shared/middleware | 完整生命周期:记录器创建、路由过滤、尾部采样、发出、丰富、排出 |
extractSafeHeaders | ../shared/headers | 转换 Web API Headers → 过滤后的 Record<string, string> (Hono, Elysia 等) |
extractSafeNodeHeaders | ../shared/headers | 转换 Node.js IncomingHttpHeaders → 过滤后的 Record<string, string> (Express, Fastify, NestJS) |
BaseEvlogOptions | ../shared/middleware | 面向用户的基础选项类型,包含 drain、enrich、keep、include、exclude、routes |
MiddlewareLoggerOptions | ../shared/middleware | 内部选项类型,扩展自 BaseEvlogOptions,包含 method、path、requestId、headers |
createLoggerStorage | ../shared/storage | 工厂函数,返回 { storage, useLogger },用于支持 AsyncLocalStorage 的 useLogger() |
| 工具 | 位置 | 用途 |
|---|---|---|
createPipelineSpies() | test/helpers/framework | 创建模拟的 drain/enrich/keep 回调 |
assertDrainCalledWith() | test/helpers/framework | 验证 drain 是否以预期的事件形状被调用 |
assertEnrichBeforeDrain() | test/helpers/framework | 验证 enrich 在 drain 之前运行 |
assertSensitiveHeadersFiltered() | test/helpers/framework | 验证敏感标头被排除 |
assertWideEventShape() | test/helpers/framework | 验证标准的宽事件字段 |
创建 packages/evlog/src/{framework}/index.ts。
集成文件应最小化——通常是 50-80 行框架特定的粘合代码。所有管道逻辑(enrich、drain、keep、标头过滤)都由 createMiddlewareLogger 处理。
import type { RequestLogger } from '../types'
import { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'
import { extractSafeHeaders } from '../shared/headers' // 用于 Web API Headers (Hono, Elysia)
// 或者
import { extractSafeNodeHeaders } from '../shared/headers' // 用于 Node.js 标头 (Express, Fastify)
import { createLoggerStorage } from '../shared/storage'
const { storage, useLogger } = createLoggerStorage(
'middleware context. Make sure the evlog middleware is registered before your routes.',
)
export interface Evlog{Framework}Options extends BaseEvlogOptions {}
export { useLogger }
// 用于类型化记录器访问的类型增强(框架特定)
// 对于 Express: declare module 'express-serve-static-core' { interface Request { log: RequestLogger } }
// 对于 Hono: export type EvlogVariables = { Variables: { log: RequestLogger } }
export function evlog(options: Evlog{Framework}Options = {}): FrameworkMiddleware {
return async (frameworkContext, next) => {
const { logger, finish, skipped } = createMiddlewareLogger({
method: /* 从框架上下文中提取 */,
path: /* 从框架上下文中提取 */,
requestId: /* 提取 x-request-id 或 crypto.randomUUID() */,
headers: extractSafeHeaders(/* 框架请求 Headers 对象 */),
...options,
})
if (skipped) {
await next()
return
}
// 将记录器存储在框架特定的上下文中
// 例如,对于 Hono: c.set('log', logger)
// 例如,对于 Express: req.log = logger
// 将 next() 包装在 AsyncLocalStorage.run() 中以支持 useLogger()
// Express: storage.run(logger, () => next())
// Hono: await storage.run(logger, () => next())
}
}
packages/evlog/src/hono/index.ts — Web API Headers, c.set('log', logger), 在 try/catch 中包装 next()packages/evlog/src/express/index.ts — Node.js 标头, req.log, res.on('finish'), 用于 useLogger() 的 AsyncLocalStoragepackages/evlog/src/elysia/index.ts — Web API Headers, derive() 插件, onAfterHandle/onError, 用于 useLogger() 的 AsyncLocalStoragecreateMiddlewareLogger — 切勿直接调用 createRequestLoggerHeaders 使用 extractSafeHeaders,对于 Node.js IncomingHttpHeaders 使用 extractSafeNodeHeaderscreateMiddlewareLogger中 — drain、enrich、keep 由 finish() 自动处理c.set(),Express 的 req.log,Elysia 的 .derive())useLogger() — 由 AsyncLocalStorage 支持,因此可以从调用堆栈中的任何位置访问记录器finish() — 它处理 emit + enrich + drainfinish()后重新抛出错误,以便框架的错误处理程序仍然有效EvlogVariables)callEnrichAndDrain 是 createMiddlewareLogger 的内部实现Hono : 使用 MiddlewareHandler 返回类型,c.set('log', logger),c.res.status 获取状态码,c.req.raw.headers 获取标头。
Express : 标准的 (req, res, next) 中间件,res.on('finish') 用于响应结束,storage.run(logger, () => next()) 用于 useLogger()。类型增强的目标是 express-serve-static-core(不是 express)。错误处理程序使用 ErrorRequestHandler 类型。
Elysia : 返回 new Elysia({ name: 'evlog' }) 插件,使用 .derive({ as: 'global' }) 创建记录器并将 log 附加到上下文,onAfterHandle 用于成功路径,onError 用于错误路径。在 derive 中使用 storage.enterWith(logger) 以支持 useLogger()。注意:onAfterResponse 是触发即忘的,在测试中可能无法在 app.handle() 返回前完成——请改用 onAfterHandle。
Fastify : 使用 fastify-plugin 包装器,fastify.decorateRequest('log', null),onRequest/onResponse 钩子。
NestJS : NestInterceptor 配合 intercept(),在 observable 上使用 tap()/catchError(),forRoot() 动态模块。
在 packages/evlog/tsdown.config.ts 中添加构建入口:
'{framework}/index': 'src/{framework}/index.ts',
将其放在现有的框架条目(workers, next, hono, express)之后。
同时将框架 SDK 添加到 external 数组:
external: [
// ... 现有的外部依赖
'{framework-package}', // 例如,'elysia', 'fastify', 'express'
],
在 packages/evlog/package.json 中,添加四个条目:
在exports中(在最后一个框架条目之后):
"./{framework}": {
"types": "./dist/{framework}/index.d.mts",
"import": "./dist/{framework}/index.mjs"
}
在typesVersions["*"]中:
"{framework}": [
"./dist/{framework}/index.d.mts"
]
在peerDependencies中(带有版本范围):
"{framework-package}": "^{latest-major}.0.0"
在peerDependenciesMeta中(标记为可选):
"{framework-package}": {
"optional": true
}
在keywords中 — 将框架名称添加到关键词数组。
创建 packages/evlog/test/{framework}.test.ts。
从./helpers/framework导入共享的测试辅助工具:
import {
assertDrainCalledWith,
assertEnrichBeforeDrain,
assertSensitiveHeadersFiltered,
createPipelineSpies,
} from './helpers/framework'
必需的测试类别:
c.get('log') 或 req.log 返回一个 RequestLoggerx-request-id 标头logger.set() 数据出现在发出的事件中assertDrainCalledWith() 辅助工具assertEnrichBeforeDrain() 辅助工具assertSensitiveHeadersFiltered() 辅助工具useLogger() === req.log(或框架等效项)尽可能使用框架的测试工具(例如,Hono 的 app.request(),Express 的 supertest,Fastify 的 inject())。
创建 apps/docs/content/2.frameworks/{NN}.{framework}.md,并附带一个全面、自包含的指南。
使用零填充编号({NN})以保持正确的侧边栏排序。检查现有文件以确定下一个数字。
Frontmatter:
---
title: {Framework}
description: 在 {Framework} 中使用 evlog — 在 {Framework} 应用程序中实现自动宽事件记录、结构化错误、drain 适配器、enricher 和尾部采样。
navigation:
title: {Framework}
icon: i-simple-icons-{framework}
links:
- label: 源代码
icon: i-simple-icons-github
to: https://github.com/HugoRCD/evlog/tree/main/examples/{framework}
color: neutral
variant: subtle
---
部分(参考 Express/Hono/Elysia 页面):
log.set()createError() + parseError() + 框架错误处理程序createDrainPipeline 示例keep 回调include / exclude / routesbun run example:{framework}在apps/docs/content/2.frameworks/00.overview.md中:
:::card,并设置 color: neutral在apps/docs/content/1.getting-started/2.installation.md中:
::card-group 中添加一个 :::card,并设置 color: neutral在 apps/docs/content/0.landing.md 中为框架添加一个代码片段。
找到 FeatureFrameworks MDC 组件的使用(包含 #nuxt、#nextjs、#hono、#express 等的部分)并添加一个新的插槽:
#{framework}
```ts [src/index.ts]
// 展示 evlog 用法的框架特定代码示例
将代码片段放在相对于现有框架的正确顺序中。
## 步骤 8:FeatureFrameworks 组件
更新 `apps/docs/app/components/features/FeatureFrameworks.vue`:
1. 将框架添加到 `frameworks` 数组中,包含其图标和**下一个可用的标签页索引**
2. 在模板中添加一个 `<div v-show="activeTab === {N}">`,其中包含 `<slot name="{framework}" />`
3. **递增**新框架之后任何框架的标签页索引
图标使用 Simple Icons 格式:`i-simple-icons-{name}`(例如,`i-simple-icons-express`,`i-simple-icons-hono`)。
## 步骤 9:更新 `skills/review-logging-patterns/SKILL.md`
在 `skills/review-logging-patterns/SKILL.md`(分发给用户的公共技能)中:
1. 在**"框架设置"**部分添加 `### {Framework}`,放在最后一个现有框架条目之后和"Cloudflare Workers"之前
2. 包含:
- 导入 + `initLogger` + 中间件/插件设置
- 在路由处理程序中访问记录器(`req.log`、`c.get('log')` 或 `{ log }` 解构)
- 带有简短服务函数示例的 `useLogger()` 片段
- 展示 `drain`、`enrich` 和 `keep` 选项的完整管道示例
3. 更新 YAML frontmatter 中的 `description:` 行以提及新的框架名称
## 步骤 10:更新 `packages/evlog/README.md`
在根目录的 `packages/evlog/README.md` 中:
1. 在 Elysia 部分之后(`## Browser` 之前)添加一个 `## {Framework}` 部分,包含一个最小设置片段和一个指向示例应用的链接
2. 在**"框架支持"**表中添加一行:
```markdown
| **{Framework}** | `{registration pattern}` with `import { evlog } from 'evlog/{framework}'` ([example](./examples/{framework})) |
保持片段简短——只需初始化、注册/使用中间件,以及一个展示记录器访问的路由处理程序。无需在此处重复 drain/enrich/keep。
创建 examples/{framework}/,包含一个可运行的应用程序,展示所有 evlog 功能。
应用程序必须包括:
evlog() 中间件,包含 drain (PostHog) 和 enrich 回调log.set() 用法useLogger() 在服务函数中进行用户/业务数据的上下文累积createError()parseError() + 手动 log.error()/ 提供服务,一个自包含的 HTML 页面,带有按钮以点击每个路由并显示 JSON 响应Drain 必须使用 PostHog(来自 evlog/posthog 的 createPostHogDrain())。POSTHOG_API_KEY 环境变量已在根目录的 .env 中设置。这确保每个示例都测试一个真实的外部 drain 适配器。
应启用漂亮打印,以便在本地测试时输出可读。
显式键入enrich 回调参数 — 使用来自 evlog 的 type EnrichContext 以避免隐式的 any:
import { type EnrichContext } from 'evlog'
app.use(evlog({
enrich: (ctx: EnrichContext) => {
ctx.event.runtime = 'node'
},
}))
每个示例必须在 GET / 提供一个测试 UI——一个自包含的 HTML 页面(无外部依赖),允许用户点击路由并查看响应,而无需使用 curl。
UI 必须:
.ts 文件(src/ui.ts),导出一个返回 HTML 字符串的 testUI() 函数/ 路由必须在 evlog 中间件之前注册,这样它就不会被记录参考:examples/hono/src/ui.ts 作为规范模式。为每个框架复制并调整。
| 文件 | 用途 |
|---|---|
src/index.ts | 展示所有功能的应用程序 |
src/ui.ts | 测试 UI — 返回自包含 HTML 的 testUI() |
package.json | dev 和 start 脚本 |
tsconfig.json | TypeScript 配置(如果需要) |
README.md | 如何运行 + 指向 UI 的链接 |
{
"scripts": {
"dev": "bun --watch src/index.ts",
"start": "bun src/index.ts"
}
}
在 monorepo 的 package.json 中添加一个根级别脚本:
"example:{framework}": "dotenv -- turbo run dev --filter=evlog-{framework}-example"
dotenv -- 前缀在 turbo 启动之前将根目录的 .env 文件(包含 POSTHOG_API_KEY 和其他适配器密钥)加载到进程中。Turborepo 不加载 .env 文件——dotenv-cli 在根级别处理此问题,因此各个示例无需进行环境配置。
创建 .changeset/{framework}-integration.md:
---
"evlog": minor
---
添加 {Framework} 中间件集成 (`evlog/{framework}`),支持自动宽事件记录、drain、enrich 和尾部采样
将框架名称作为有效作用域添加到两个文件中,以便 PR 标题验证通过:
.github/workflows/semantic-pull-request.yml — 将 {framework} 添加到 scopes 列表:
scopes: |
# ... 现有的作用域
{framework}
.github/pull_request_template.md — 将 {framework} 添加到作用域部分:
- {framework} ({Framework} 集成)
完成所有步骤后,从仓库根目录运行:
cd packages/evlog
bun run build # 验证构建成功,包含新条目
bun run test # 验证单元测试通过
bun run lint # 验证没有 lint 错误
然后对示例进行类型检查:
cd examples/{framework}
npx tsc --noEmit # 验证示例中没有 TS 错误
每周安装次数
223
仓库
GitHub 星标
963
首次出现
2026年3月6日
安全审计
已安装于
codex219
cursor218
gemini-cli218
amp218
cline218
github-copilot218
Add a new framework integration to evlog. Every integration follows the same architecture built on the shared createMiddlewareLogger utility. This skill walks through all touchpoints. Every single touchpoint is mandatory -- do not skip any.
Recommended format for the pull request title:
feat({framework}): add {Framework} middleware integration
---|---|---
1 | packages/evlog/src/{framework}/index.ts | Create integration source
2 | packages/evlog/tsdown.config.ts | Add build entry + external
3 | packages/evlog/package.json | Add exports + typesVersions + peer dep + keyword
4 | packages/evlog/test/{framework}.test.ts | Create tests
5 | apps/docs/content/2.frameworks/{NN}.{framework}.md | Create framework docs page
6 | apps/docs/content/2.frameworks/00.overview.md | Add card + table row
7 | apps/docs/content/1.getting-started/2.installation.md | Add card in "Choose Your Framework"
8 | apps/docs/content/0.landing.md | Add framework code snippet
9 | apps/docs/app/components/features/FeatureFrameworks.vue | Add framework tab
10 | skills/review-logging-patterns/SKILL.md | Add framework setup section + update frontmatter description
11 | packages/evlog/README.md | Add framework section + add row to Framework Support table
12 | examples/{framework}/ | Create example app with test UI
13 | package.json (root) | Add example:{framework} script
14 | .changeset/{framework}-integration.md | Create changeset (minor)
15 | .github/workflows/semantic-pull-request.yml | Add {framework} scope
16 | .github/pull_request_template.md | Add {framework} scope
Important : Do NOT consider the task complete until all 16 touchpoints have been addressed.
Use these placeholders consistently:
| Placeholder | Example (Hono) | Usage |
|---|---|---|
{framework} | hono | Directory names, import paths, file names |
{Framework} | Hono | PascalCase in type/interface names |
All integrations share the same core utilities. Never reimplement logic that exists in shared/. These are also publicly available as evlog/toolkit for community-built integrations (see Custom Integration docs).
| Utility | Location | Purpose |
|---|---|---|
createMiddlewareLogger | ../shared/middleware | Full lifecycle: logger creation, route filtering, tail sampling, emit, enrich, drain |
extractSafeHeaders | ../shared/headers | Convert Web API Headers → filtered Record<string, string> (Hono, Elysia, etc.) |
extractSafeNodeHeaders |
| Utility | Location | Purpose |
|---|---|---|
createPipelineSpies() | test/helpers/framework | Creates mock drain/enrich/keep callbacks |
assertDrainCalledWith() | test/helpers/framework | Validates drain was called with expected event shape |
assertEnrichBeforeDrain() | test/helpers/framework | Validates enrich runs before drain |
Create packages/evlog/src/{framework}/index.ts.
The integration file should be minimal — typically 50-80 lines of framework-specific glue. All pipeline logic (enrich, drain, keep, header filtering) is handled by createMiddlewareLogger.
import type { RequestLogger } from '../types'
import { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'
import { extractSafeHeaders } from '../shared/headers' // for Web API Headers (Hono, Elysia)
// OR
import { extractSafeNodeHeaders } from '../shared/headers' // for Node.js headers (Express, Fastify)
import { createLoggerStorage } from '../shared/storage'
const { storage, useLogger } = createLoggerStorage(
'middleware context. Make sure the evlog middleware is registered before your routes.',
)
export interface Evlog{Framework}Options extends BaseEvlogOptions {}
export { useLogger }
// Type augmentation for typed logger access (framework-specific)
// For Express: declare module 'express-serve-static-core' { interface Request { log: RequestLogger } }
// For Hono: export type EvlogVariables = { Variables: { log: RequestLogger } }
export function evlog(options: Evlog{Framework}Options = {}): FrameworkMiddleware {
return async (frameworkContext, next) => {
const { logger, finish, skipped } = createMiddlewareLogger({
method: /* extract from framework context */,
path: /* extract from framework context */,
requestId: /* extract x-request-id or crypto.randomUUID() */,
headers: extractSafeHeaders(/* framework request Headers object */),
...options,
})
if (skipped) {
await next()
return
}
// Store logger in framework-specific context
// e.g., c.set('log', logger) for Hono
// e.g., req.log = logger for Express
// Wrap next() in AsyncLocalStorage.run() for useLogger() support
// Express: storage.run(logger, () => next())
// Hono: await storage.run(logger, () => next())
}
}
packages/evlog/src/hono/index.ts — Web API Headers, c.set('log', logger), wraps next() in try/catchpackages/evlog/src/express/index.ts — Node.js headers, req.log, res.on('finish'), AsyncLocalStorage for useLogger()packages/evlog/src/elysia/index.ts — Web API Headers, derive() plugin, /, for createMiddlewareLogger — never call createRequestLogger directlyextractSafeHeaders for Web API Headers, extractSafeNodeHeaders for Node.js IncomingHttpHeaderscreateMiddlewareLogger — drain, enrich, keep are handled automatically by Hono : Use MiddlewareHandler return type, c.set('log', logger), c.res.status for status, c.req.raw.headers for headers.
Express : Standard (req, res, next) middleware, res.on('finish') for response end, storage.run(logger, () => next()) for useLogger(). Type augmentation targets express-serve-static-core (NOT express). Error handler uses ErrorRequestHandler type.
Elysia : Return new Elysia({ name: 'evlog' }) plugin, use .derive({ as: 'global' }) to create logger and attach log to context, onAfterHandle for success path, onError for error path. Use storage.enterWith(logger) in derive for useLogger() support. Note: onAfterResponse is fire-and-forget and may not complete before app.handle() returns in tests — use onAfterHandle instead.
Fastify : Use fastify-plugin wrapper, fastify.decorateRequest('log', null), onRequest/onResponse hooks.
NestJS : NestInterceptor with intercept(), tap()/catchError() on observable, forRoot() dynamic module.
Add a build entry in packages/evlog/tsdown.config.ts:
'{framework}/index': 'src/{framework}/index.ts',
Place it after the existing framework entries (workers, next, hono, express).
Also add the framework SDK to the external array:
external: [
// ... existing externals
'{framework-package}', // e.g., 'elysia', 'fastify', 'express'
],
In packages/evlog/package.json, add four entries:
Inexports (after the last framework entry):
"./{framework}": {
"types": "./dist/{framework}/index.d.mts",
"import": "./dist/{framework}/index.mjs"
}
IntypesVersions["*"]:
"{framework}": [
"./dist/{framework}/index.d.mts"
]
InpeerDependencies (with version range):
"{framework-package}": "^{latest-major}.0.0"
InpeerDependenciesMeta (mark as optional):
"{framework-package}": {
"optional": true
}
Inkeywords — add the framework name to the keywords array.
Create packages/evlog/test/{framework}.test.ts.
Import shared test helpers from ./helpers/framework:
import {
assertDrainCalledWith,
assertEnrichBeforeDrain,
assertSensitiveHeadersFiltered,
createPipelineSpies,
} from './helpers/framework'
Required test categories:
c.get('log') or req.log returns a RequestLoggerx-request-id header is used when presentlogger.set() data appears in emitted eventassertDrainCalledWith() helperassertEnrichBeforeDrain() helperUse the framework's test utilities when available (e.g., Hono's app.request(), Express's supertest, Fastify's inject()).
Create apps/docs/content/2.frameworks/{NN}.{framework}.md with a comprehensive, self-contained guide.
Use zero-padded numbering ({NN}) to maintain correct sidebar ordering. Check existing files to determine the next number.
Frontmatter :
---
title: {Framework}
description: Using evlog with {Framework} — automatic wide events, structured errors, drain adapters, enrichers, and tail sampling in {Framework} applications.
navigation:
title: {Framework}
icon: i-simple-icons-{framework}
links:
- label: Source Code
icon: i-simple-icons-github
to: https://github.com/HugoRCD/evlog/tree/main/examples/{framework}
color: neutral
variant: subtle
---
Sections (follow the Express/Hono/Elysia pages as reference):
log.set() usagecreateError() + parseError() + framework error handlercreateDrainPipeline examplekeep callbackinclude / exclude / routesInapps/docs/content/2.frameworks/00.overview.md:
:::card in the appropriate section (Full-Stack or Server Frameworks) with color: neutralInapps/docs/content/1.getting-started/2.installation.md:
:::card in the "Choose Your Framework" ::card-group with color: neutralAdd a code snippet in apps/docs/content/0.landing.md for the framework.
Find the FeatureFrameworks MDC component usage (the section with #nuxt, #nextjs, #hono, #express, etc.) and add a new slot:
#{framework}
```ts [src/index.ts]
// Framework-specific code example showing evlog usage
Place the snippet in the correct order relative to existing frameworks.
## Step 8: FeatureFrameworks Component
Update `apps/docs/app/components/features/FeatureFrameworks.vue`:
1. Add the framework to the `frameworks` array with its icon and the **next available tab index**
2. Add a `<div v-show="activeTab === {N}">` with `<slot name="{framework}" />` in the template
3. **Increment tab indices** for any frameworks that come after the new one
Icons use Simple Icons format: `i-simple-icons-{name}` (e.g., `i-simple-icons-express`, `i-simple-icons-hono`).
## Step 9: Update `skills/review-logging-patterns/SKILL.md`
In `skills/review-logging-patterns/SKILL.md` (the public skill distributed to users):
1. Add `### {Framework}` in the **"Framework Setup"** section, after the last existing framework entry and before "Cloudflare Workers"
2. Include:
- Import + `initLogger` + middleware/plugin setup
- Logger access in route handlers (`req.log`, `c.get('log')`, or `{ log }` destructuring)
- `useLogger()` snippet with a short service function example
- Full pipeline example showing `drain`, `enrich`, and `keep` options
3. Update the `description:` line in the YAML frontmatter to mention the new framework name
## Step 10: Update `packages/evlog/README.md`
In the root `packages/evlog/README.md`:
1. Add a `## {Framework}` section after the Elysia section (before `## Browser`), with a minimal setup snippet and a link to the example app
2. Add a row to the **"Framework Support"** table:
```markdown
| **{Framework}** | `{registration pattern}` with `import { evlog } from 'evlog/{framework}'` ([example](./examples/{framework})) |
Keep the snippet short — just init, register/use middleware, and one route handler showing logger access. No need to repeat drain/enrich/keep here.
Create examples/{framework}/ with a runnable app that demonstrates all evlog features.
The app must include:
evlog() middleware with drain (PostHog) and enrich callbackslog.set() usageuseLogger() in a service functioncreateError() with status/why/fix/linkparseError() + manual log.error()/, a self-contained HTML page with buttons to hit each route and display JSON responsesDrain must use PostHog (createPostHogDrain() from evlog/posthog). The POSTHOG_API_KEY env var is already set in the root .env. This ensures every example tests a real external drain adapter.
Pretty printing should be enabled so the output is readable when testing locally.
Type theenrich callback parameter explicitly — use type EnrichContext from evlog to avoid implicit any:
import { type EnrichContext } from 'evlog'
app.use(evlog({
enrich: (ctx: EnrichContext) => {
ctx.event.runtime = 'node'
},
}))
Every example must serve a test UI at GET / — a self-contained HTML page (no external deps) that lets the user click routes and see responses without curl.
The UI must:
.ts file (src/ui.ts) exporting a testUI() function returning an HTML string/ route must be registered before the evlog middleware so it doesn't get loggedReference: examples/hono/src/ui.ts for the canonical pattern. Copy and adapt for each framework.
| File | Purpose |
|---|---|
src/index.ts | App with all features demonstrated |
src/ui.ts | Test UI — testUI() returning self-contained HTML |
package.json | dev and start scripts |
tsconfig.json | TypeScript config (if needed) |
README.md |
{
"scripts": {
"dev": "bun --watch src/index.ts",
"start": "bun src/index.ts"
}
}
Add a root-level script in the monorepo package.json:
"example:{framework}": "dotenv -- turbo run dev --filter=evlog-{framework}-example"
The dotenv -- prefix loads the root .env file (containing POSTHOG_API_KEY and other adapter keys) into the process before turbo starts. Turborepo does not load .env files — dotenv-cli handles this at the root level so individual examples need no env configuration.
Create .changeset/{framework}-integration.md:
---
"evlog": minor
---
Add {Framework} middleware integration (`evlog/{framework}`) with automatic wide-event logging, drain, enrich, and tail sampling support
Add the framework name as a valid scope in both files so PR title validation passes:
.github/workflows/semantic-pull-request.yml — add {framework} to the scopes list:
scopes: |
# ... existing scopes
{framework}
.github/pull_request_template.md — add {framework} to the Scopes section:
- {framework} ({Framework} integration)
After completing all steps, run from the repo root:
cd packages/evlog
bun run build # Verify build succeeds with new entry
bun run test # Verify unit tests pass
bun run lint # Verify no lint errors
Then type-check the example:
cd examples/{framework}
npx tsc --noEmit # Verify no TS errors in the example
Weekly Installs
223
Repository
GitHub Stars
963
First Seen
Mar 6, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex219
cursor218
gemini-cli218
amp218
cline218
github-copilot218
Azure Data Explorer (Kusto) 查询技能:KQL数据分析、日志遥测与时间序列处理
107,900 周安装
../shared/headers |
Convert Node.js IncomingHttpHeaders → filtered Record<string, string> (Express, Fastify, NestJS) |
BaseEvlogOptions | ../shared/middleware | Base user-facing options type with drain, enrich, keep, include, exclude, routes |
MiddlewareLoggerOptions | ../shared/middleware | Internal options type extending BaseEvlogOptions with method, path, requestId, headers |
createLoggerStorage | ../shared/storage | Factory returning { storage, useLogger } for AsyncLocalStorage-backed useLogger() |
assertSensitiveHeadersFiltered()test/helpers/framework |
| Validates sensitive headers are excluded |
assertWideEventShape() | test/helpers/framework | Validates standard wide event fields |
onAfterHandleonErrorAsyncLocalStorageuseLogger()finish()c.set() for Hono, req.log for Express, .derive() for Elysia)useLogger() — backed by AsyncLocalStorage so the logger is accessible from anywhere in the call stackfinish() in both success and error paths — it handles emit + enrich + drainfinish() so framework error handlers still workEvlogVariables for Hono)callEnrichAndDrain is internal to createMiddlewareLoggerassertSensitiveHeadersFiltered() helperuseLogger() === req.log (or framework equivalent)bun run example:{framework}| How to run + link to the UI |