复刻字节 AI 开发流:实践 Node.js 通用脚手架

复刻字节 AI 开发流:实践 Node.js 通用脚手架最近与前同事深入交流 他现为字节某组的 TL 组长 团队规模近 10 人 在讨论他们团队的 AI 工作流实践中 也得到一些八卦信息 第一个是 人才储备变化 他们团队已基本停止招聘实习生 今年仅招一人 个人解读 AI 协作模式下 新人的边际效应大幅下降 第二个是 组织预期转变 业内多位跟他同级的 Leader 私下评估 今年可能出现大规模调整 个人解读 生成式 AI

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



最近与前同事深入交流,他现为字节某组的 TL(组长),团队规模近 10 人。在讨论他们团队的 AI 工作流实践中,也得到一些八卦信息。

第一个是: 人才储备变化

第二个是:组织预期转变

第三个是:开发方法论的周期性

  • 层出不穷的新概念:Vibe Coding、SDD 规范、Harness Engineering……
  • 理性看待:这些都是过渡阶段产物,随着大模型升级,这些方法论的生命周期可能只有几个月
    个人建议: 不必投入过多精力去追赶,因为等你熟练一种方法论后,可能用不了多久就被淘汰了



第四个是:招聘标准演变
前端岗位招聘标准很多 JD 上开始冠以"全栈开发" 的名义招聘了
实际面试:侧重前端能力考察,但开始要求一些后端基础能力了
个人解读: AI 协作工具提效下,企业希望前端承担更多职能

















好了,八卦之后,关于他们的 ai 工作流的核心如下:

你得教 AI,不断沉淀并固化它的规范

具体实践方法:

  • 识别问题:第一次遇到某类问题,AI 执行效果不理想
  • 人工介入:手动处理并解决问题
  • 规则沉淀:将解决方案固化为规则或 Skill
  • 迭代积累:问题解决越多,效率提升越明显,也就是后期 ai 执行的只要不是新的场景和复杂业务,基本不会出错

本质: 通过持续的反馈循环来训练和优化 AI 的工作能力,而不是一开始就寻求完美的工作流

这个理念在字节技术专家杨晨的全软软件开发大会分享中也提出过:Prompt = 可训练资产(像模型一样优化)

让后我个人抽象了这个单 Agent 的工作流程图如下:

image

接下来我会解释每个步骤的思路和如何落地:

项目初始化是指,大多数现代框架都提供了开箱即用的脚手架工具,例如:

# Vue/React 生态 npm create vite@latest # Nest.js nest new project-name # Hono.js pnpm create hono@latest 

初始化完成后,立即在根目录创建规则文件,通常命名为 CLAUDE.md 或 AGENTS.md。

这个文件是 AI 协作的宪法,应包含例如项目定位,技术栈清单,核心哲学(例如测试先行,采用 TDD 测试方案),项目结构示例,AI 协作原则等等内容。有兴趣的同学可以找我要这个项目的全局规则。

两个关键注意事项
动态迭代
规则文件不是一成不变的。当发现 AI 写的代码不规范时,要想到如何抽离抽象的规则来约束,而不是一味手动修改










SKILL 机制(规则的模块化)
当规则内容过多时,抽象可复用的 Skill 文件。好处是 AI 按需加载,不会每次都把全局规则加入上下文,大大减少 token 用量



规则中引用 SKILL 的示例:

 3. 核心哲学:测试先行 (TDD) 参考 `.trae/skills/tdd-first/SKILL.md` 中的测试驱动开发规范。 所有新功能开发或 Bug 修复必须遵循 「红-绿-重构」 循环。严禁在没有对应测试用例的情况下提交业务逻辑代码。 --- 4. 响应格式 参考 `.trae/skills/response-standard/SKILL.md` 中的响应格式规范。 [强制] 所有接口统一返回 JSON,使用 `@/utils/response` 中的工具函数生成响应。 --- 

如果你很清楚自己要做什么,可以直接下发任务。但如果只有模糊想法,建议先和 AI 一起做需求分析。

推荐提示词
你好!现在的任务是:我们要从零开始设计并实现 `hono.js boilerplate`。 你现在是资深的 Node.js 工程师。我有一个初步的想法,需要你通过向我提问,帮助我澄清需求、挖掘边缘场景,最终目标是理清我做一个通用后端功能的脚手架需要实现哪些功能。并按顺序输出一个实现这些功能的大纲。 请开始你的提问。 

效果: Claude 会像资深 PM 一样向你提问,你逐一回答这些问题后,AI 会生成一份完整的功能清单文档。


这是整个工作流的核心环节,必须让 AI 严格按照 TDD 测试方案执行代码。

执行策略
  1. 任务拆解 → 将需求拆分为最小可测试单元
  2. 红阶段 → 先编写测试用例(此时测试应当失败)
  3. 绿阶段 → 编写最小化实现代码,使测试通过
  4. 重构阶段 → 在测试通过的基础上,优化代码结构和性能
关键约束

在全局规则中强制要求 AI:

  • ✅ 任何业务代码提交前,必须有对应的单元测试覆盖
  • ✅ 测试用例需包含正常场景 + 边界场景 + 异常场景
  • ✅ 测试执行必须通过,覆盖率不低于 80%
  • ✅ 严禁为了赶进度而跳过测试环节

AI 执行代码后,进入审核阶段,分为 AI 自动审核和人工审核两部分。

AI 自动审核

AI 每次完成任务时,需要自动进行:

  • Eslint 校验
  • TypeScript 类型校验

如果报错,AI 自己修复直到通过(可以限制修复次数,避免死循环)

人工审核

前期必须进行人工审核,一旦发现问题,思考如何抽象成规则或 Skill,避免 AI 再次犯错。

核心发现: 你会发现后期 AI 执行的效果会越来越好。对于 CRUD 场景,基本不需要人审核了,大概看一下产出代码就知道没问题。


随着迭代轮次增加,形成正向循环:

迭代轮数 ↑ ↓ 规则精确度 ↑ → AI 执行准确率 ↑ ↓ 处理边界场景的能力 ↑ ↓ 人工介入频率 ↓ ↓ 开发效率 ↑ 

这就是 AI 时代的竞争力所在: 不是盲目信任 AI,而是通过不断的反馈循环来「教」AI,逐步固化和优化工作规范。


我举个自己实践中的迭代案例:

  • 例如我让 ai 实现超时中间件的时候,ai 是自己原生实现的,然后我感觉这种很常用的功能一般都有现成的库,就查了一下,果然是有 'hono/timeout' 这个库,然后就在全局规则加入了类似:”优先使用社区成熟,稳定的库解决问题“。
  • 例如我在设计后端的 url 的时候,突然想起 K8s 有一个类似的 url 设计规范,可以跟权限结合起来,例如,/api/v1/roles/{roleId},其中 roles 代表就是资源,roleId 代表的是子资源。
resources: ["roles"] # 操作的资源 verbs: ["get"] # 操作类型,增删改查 resourceNames: ["{roleId}"] # 可选(精确到某个子资源) 

简单就是说一个 url 代表对什么资源的什么操作。

HTTP 请求 RBAC GET /roles/ verbs: ["get"] GET /roles verbs: ["list"] POST /roles verbs: ["create"] DELETE /roles/ verbs: ["delete"]

然后就可以结合我们的 rbac 模型(权限模型),用来标识一个权限是什么,简单来说就是资源名 + 操作,就能标识一个权限。

然后我干脆让 ai 把这个 url 规范抽象为一个 skill,下次 ai 定义 url 的时候就会调用这个规则。

  • 还有很多例子就不一一列举了...

需要注意的是,字节内部的复杂度是更高的,我们后期也会探索,例如字节内部还有:

  • 多 Agent 系统,比如主 Agent 来负责 plan 的制定,有 Coder Agent 负责编码,还有测试 Agent, test Agent 等等,这种多 Agent 协作,我个人估计字节迟早会推出一个开源库让我们使用的,所以不必着急。
  • 评测体系,会对 AI 输出质量进行打分,也就是评测 AI 的输出质量,这条我们目前这一版是靠人工来识别,但我觉得还好,前期人工介入,后期规则越来越好,模型能力越来越强,就可以进入 AI 自我评测阶段了。
  • 可观测性体系:就是对于 AI 写错的地方,是否能知道哪一步错了,然后根据这个让 AI 自动修正 Prompt,然后自动修正全局规则或者抽象为 SKILL。

上面要这么玩,目前个人还是很难的,需要大的平台支持,本文主要是先走通一个小循环,也欢迎大家一起交流(如果觉得不错,感谢点赞关注哦,欢迎入**流~)。

技术栈: Hono.js + Drizzle ORM + PostgreSQL 数据库

前置声明: 整个工作流仅使用免费版工具(Trace + GLM5/豆包模型)即可高质量完成,充分说明该方法论的实际效果令人满意,而非纸上谈兵。

源码获取: 因外链限流问题,需要的朋友可以联系我获取完整代码(github)

脚手架目前的架构图如下:

image

分享上述实战过程中,网上 Node.js 教程很少提及的企业级**实践。

无论部署在 Kubernetes、Docker Compose 还是物理机,都需要实现优雅关闭逻辑。

为什么重要?

当应用报错或升级时,容器编排系统会执行关闭流程:

应用故障/升级 → 容器启动关闭流程 ↓ 向 PID 1 进程发送 SIGTERM 信号 ↓ 开启倒计时(默认 10 秒) ↓ 如果 10 秒后进程未退出,发送 SIGKILL(强制杀死) 
问题场景
例:电商扣款业务

  1. 扣除用户余额 ✅
  2. Docker 信号来了,进程被强杀 🔥
  3. 积分增加 ❌(未执行)

结果:用户钱扣了但没到账,投诉炸裂。

问题根源: Docker 强杀是瞬间的,Node.js 无法执行完事件循环中的剩余回调。

解决方案

优雅关闭可以让你在收到信号后,停止接收新请求,但把内存中已排队的写操作执行完。同时及时释放系统资源(如数据库连接),避免占满最大连接数。


TraceId 是请求在系统中的唯一标识符,从进入系统到返回响应,始终伴随整个生命周期。

为什么需要?
场景:前端用户报错 用户说:”我提交表单后,收到错误 ID:abc123def456”

后端排查: ❌ 日志有 1000 条,怎么找到那条错误? ✅ 按 traceId = abc123def456 过滤,立即定位问题

Node.js 的特殊性

与 Java/Go 等多线程模型相比,Node.js 的单进程模型在处理 TraceId 时有本质区别:

语言 模型 上下文隔离方案 难度 Java/Go 多线程/协程 ThreadLocal ⭐ 简单 Node.js 单进程 AsyncLocalStorage ⭐⭐⭐ 复杂
错误做法

方案 1:全局变量

let traceId; // 全局变量

app.use((req, res, next) => { traceId = generateId(); // 请求 A 的 traceId next(); });

// 问题:请求 B 来了,traceId 被覆盖,日志全乱

方案 2:函数传参

// controller → service → dao,每层都要传 traceId // 代码极其丑陋,难以维护

async function getUserOrder(traceId, userId) ; }

正确方案:AsyncLocalStorage

Node.js 官方在 async_hooks 基础上,封装了更高级、性能更优的 API:

import { AsyncLocalStorage } from ‘async_hooks’;

const traceIdStorage = new AsyncLocalStorage();

// 在请求中间件中创建隔离上下文 app.use((req, res, next) => { const traceId = generateId();

// 在当前上下文中存储 traceId(自动隔离) traceIdStorage.run(traceId, () => {

next(); 

}); });

// 任何地方都可以取,不用传参 function getTraceId()

// 使用示例 async function getUserOrder(userId) ] Fetching user`, { userId });

const user = await getUser(userId); logger.info([${traceId}] User fetched, { userId: user.id });

return user; }

日志集成
const logger = createLogger((level, msg, meta) => ; console.log(JSON.stringify(logEntry)); }); 

TDD 是企业级后端项目的核心质量保障手段,在 AI 协作开发模式下更是确保代码质量的关键。

核心流程:红-绿-重构
  1. 红阶段 → 编写测试用例,预期会失败(功能未实现)
  2. 绿阶段 → 实现最小化代码,使测试通过
  3. 重构阶段 → 优化代码结构,保持测试通过
Hono.js 项目中的实践

采用 Hono 原生集成测试方案,结合 Vitest 测试框架:

// test/user.test.ts import { describe, it, expect } from ‘vitest’; import app from ‘../src/app’;

describe(‘User API’, () => { it(‘should return 404 for non-existent user’, async () => {

const res = await app.request('/api/users/9999', { method: 'GET' }); expect(res.status).toBe(404); const data = await res.json(); expect(data.code).toBe(0); expect(data.message).toBe('User not found'); 

});

it(‘should create a new user’, async () => ),

 headers: { 'Content-Type': 'application/json' } }); expect(res.status).toBe(200); const data = await res.json(); expect(data.code).toBe(1); expect(data.data.name).toBe('测试用户'); 

}); });

表格驱动测试

对于多分支逻辑和边界情况,采用表格驱动测试风格:

describe(‘User Validation’, () => { const testCases = [

{ desc: '缺少必填字段', body: { name: '测试用户' }, expectedStatus: 400, expectedMessage: 'Email is required' }, { desc: '邮箱格式错误', body: { name: '测试用户', email: 'invalid-email' }, expectedStatus: 400, expectedMessage: 'Invalid email format' }, { desc: '密码长度不足', body: { name: '测试用户', email: '', password: '123' }, expectedStatus: 400, expectedMessage: 'Password must be at least 6 characters' } 

];

test.each(testCases)(‘$desc’, async ({ body, expectedStatus, expectedMessage }) =>

}); expect(res.status).toBe(expectedStatus); const data = await res.json(); expect(data.message).toBe(expectedMessage); 

}); });


请求超时处理是后端服务稳定性的重要保障,可以防止长时间运行的请求占用系统资源。

为什么需要?
  • 保护用户体验:与其让用户等待 30 秒,不如在 5 秒内返回”请求超时”
  • 防止系统雪崩:大量超时请求堆积会导致 CPU/内存被迅速耗尽
API 接口级超时

利用 Hono 自带的 timeout 中间件:

import { timeout } from ‘hono/timeout’

// 1. 全局配置:所有请求默认 5 秒超时 app.use(‘/api/*’, timeout(5000))

// 2. 局部配置:针对耗时操作,允许更长时间 app.get(‘/api/export’, timeout(30000), async © => { // 执行耗时操作… return c.json({ success: true }) })

// 3. 自定义超时后的逻辑 const customTimeout = timeout(5000, { onTimeout: © => {

return c.json({ code: 0, message: '服务器繁忙,请稍后再试' }, 408) 

} })

数据库级超时

API 层超时只是”切断了回传给用户的路”,但数据库内部的任务可能仍在运行。需要更细粒度的控制:

// Drizzle ORM 配置:通过底层驱动设置超时 import { drizzle } from ‘drizzle-orm/postgres-js’ import postgres from ‘postgres’

const queryClient = postgres(process.env.DATABASE_URL, )

// 在业务代码中手动控制单次查询超时 async function getSlowData() { return await db.select().from(users).execute(); }


在复杂的后端系统中,错误可能来自业务逻辑、数据库约束、第三方 API 失败或语法错误。没有统一处理的话,返回给前端的可能是难看的堆栈信息。

设计原则
  1. 收口原则 → 业务代码通过 throw 抛出错误,由顶层中间件统一拦截处理
  2. 分类分级 → 区分”预期内错误”和”预期外错误”
  3. 安全性 → 生产环境下严禁将详细 Stack 返回给客户端
实现方案

步骤 1:定义标准错误类

// src/utils/errors.ts export class AppError extends Error { constructor(

public statusCode: number, public message: string, public code: number = 0 // 自定义业务状态码 

) {

super(message); this.name = 'AppError'; 

} }

步骤 2:配置全局捕获钩子

import { Hono } from ‘hono’; import { AppError } from ‘./utils/errors’;

const app = new Hono();

app.onError((err, c) => , err.statusCode as any); }

// 2. 处理参数校验错误 if (err.name === ‘ZodError’) {

return c.json({ code: 400, message: '参数验证失败', details: err, traceId }, 400); 

}

// 3. 处理未知错误 console.error([Fatal Error] [${traceId}]:, err);

return c.json({

code: 500, message: process.env.NODE_ENV === 'production' ? '服务器内部错误' : err.message, traceId 

}, 500); });

步骤 3:业务层使用

export async function deleteUser(id: string)

return db.delete(id); }


RBAC(基于角色的访问控制)是中后台系统最通用的权限模型。通过”用户-角色-权限”的关联,实现权限的解耦。

为什么不直接判断角色?

如果代码里写 if (user.role === ‘admin’),当新增一个”超级编辑”角色也需要此权限时,得修改所有代码。判断权限点(Permission)而非角色名,才是系统扩展性的关键。

核心概念
  • 用户 (User) → 拥有一个或多个角色
  • 角色 (Role) → 如 Admin、Editor、Viewer
  • 权限 (Permission) → 如 user:create、order:delete
实现方案

步骤 1:定义数据模型

// 简化版 schema export const users = pgTable(‘users’, { id: serial(‘id’).primaryKey(), role: text(‘role’).default(‘viewer’), });

// 权限映射表 const ROLE_PERMISSIONS = { admin: [‘user:all’, ‘post:all’], editor: [‘post:edit’, ‘post:create’], viewer: [‘post:read’], } as const;

步骤 2:实现 RBAC 中间件

// middleware/rbac.ts import { createMiddleware } from ‘hono/factory’; import { AppError } from ‘../utils/errors’;

export const checkPermission = (requiredPermission: string) =>

const userPermissions = ROLE_PERMISSIONS[user.role] || []; // 支持通配符或精确匹配 const hasPermission = userPermissions.some(p => p === requiredPermission || p === `${requiredPermission.split(':')[0]}:all` ); if (!hasPermission) { throw new AppError(403, '权限不足,无法执行此操作'); } await next(); 

}); };

步骤 3:在路由层应用

const api = new Hono();

// 只有拥有 post:create 权限的角色才能访问 api.post(‘/posts’, checkPermission(‘post:create’), async © => { return c.json({ message: ‘发布成功’ }); });

// 管理员专属接口 api.get(‘/admin/stats’, checkPermission(‘user:all’), async © => { return c.json({ stats: ‘…’ }); });


在生产环境中,如果所有日志都无限制地写入同一个文件,最终会导致磁盘爆满和日志文件难以打开。

核心目的
  1. 防止单个文件过大(难以检索、占用磁盘空间)
  2. 自动化归档(按日期分类)
  3. 过期清理(例如只保留最近 14 天的日志)
实现方案:Winston + Daily Rotate File
import winston from ‘winston’; import ‘winston-daily-rotate-file’;

const transport = new winston.transports.DailyRotateFile({ filename: ‘logs/application-%DATE%.log’, datePattern: ‘YYYY-MM-DD’, zippedArchive: true, // 历史日志压缩 maxSize: ‘20m’, // 单个文件超过 20MB 也会切分 maxFiles: ‘14d’, // 只保留最近 14 天的日志 level: ‘info’, });

const logger = winston.createLogger({ transports: [

transport, new winston.transports.Console() 

] });


DDoS 攻击的本质是发大量垃圾请求,导致带宽占满、CPU/内存耗尽、连接数耗尽。

现实: 普通企业很难防住大规模 DDoS,目的是提高攻击成本。

限流

在接入层(Nginx)—— 粗筛

性能极高,在流量进入 Node.js 之前就拦截:

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; limit_req zone=api burst=20; 

在应用层(Middleware)—— 精滤

灵活度高,根据业务维度限流:

// 限制某个登录用户每分钟只能发 5 条评论 app.use(rateLimit()); 
限制请求体大小

防止内存溢出 (OOM):

// 攻击场景:发送 2GB 垃圾字符的 JSON POST 请求 // 后果:Node.js 进程尝试分配 2GB 内存,很快就 Out of Memory

// 解决:在 Nginx 层配置 client_max_body_size 1m;


Helmet 通过设置各种 HTTP 响应头,自动防御常见的 Web 漏洞(XSS、点击劫持、MIME 类型嗅探等)。

性价比最高的安全加固方案。

Hono.js 官方支持 hono/helmet 中间件,在入口文件 src/app.ts 中引入即可:

import { helmet } from ‘hono/helmet’;

app.use(helmet());


告警机制是”及时发现问题”的关键,通过监控关键指标,在异常情况下主动通知相关人员。

告警规则设计

根据应用的 SLA,定义不同严重等级:

export const alertRules = [ {

name: 'High Error Rate', condition: 'error_rate > 5%', severity: 'critical', duration: '5m', action: 'page_oncall', // 立即电话/Slack 通知 

}, {

name: 'High Response Latency', condition: 'p95_latency > 1000ms', severity: 'warning', duration: '10m', action: 'send_to_slack', 

}, {

name: 'Database Connection Pool Exhausted', condition: 'db_connections > 90%', severity: 'critical', duration: '1m', action: 'page_oncall', 

} ];

与监控系统集成

使用 Prometheus + Alertmanager:

# prometheus.yml global: scrape_interval: 15s

scrape_configs:

  • job_name: ‘hono-app’ static_configs:
     - targets: ['localhost:3000'] 
    metrics_path: ‘/metrics’

alerting: alertmanagers:

- static_configs: - targets: ['localhost:9093'] 

多渠道通知
export async function sendAlert( title: string, message: string, severity: ‘critical’ | ‘warning’ | ‘info’ ) ] ${title}`,

 attachments: [], }); 

}

// 2. 邮件通知(仅限 critical) if (severity === ‘critical’) {

await sendEmail({
  to: process.env.ALERT_EMAIL,
  subject: `🚨 CRITICAL: ${title}`,
  html: `

${title}

${message}

${timestamp}

`, });

}

// 3. 记录到数据库 await db.insert(alerts).values({

title, message, severity, createdAt: new Date(), 

}); }


性能测试是确保应用在生产环境中稳定运行的最后一道防线。

基准测试(Benchmarking)

使用 Autocannon 进行简单的吞吐量和延迟测试:

# 安装 Autocannon npm install -g autocannon

基准测试:100 并发,持续 30 秒

autocannon -c 100 -d 30 http://localhost:3000/api/users

输出示例

Req/Sec: 1234

Latency: { mean: 45.2, p50: 42, p95: 78, p99: 120 }

压力测试(Load Testing)

使用 K6 模拟真实用户行为:

// load-test.js import http from ‘k6/http’; import { check, sleep, group } from ‘k6’;

export const options = ,

, , , , 

], };

export default function () );

// 测试创建用户 let createRes = http.post('http://localhost:3000/api/users', { name: `user-${__VU}-${__ITER}`, email: `user-${__VU}-${__ITER}@example.com`, password: 'password123', }); check(createRes, { 'create status is 200': (r) => r.status === 200, }); sleep(1); 

}); }

运行压力测试:

# 安装 K6 npm install -g k6

执行测试

k6 run load-test.js

数据库性能测试
// src/tests/db-performance.test.ts import { describe, it, expect } from ‘vitest’; import { db } from ‘../db’;

describe(‘Database Performance’, () => { it(‘should query 10k users in < 500ms’, async () => {

const start = performance.now(); const users = await db.query.users.findMany({ limit: 10000 }); const duration = performance.now() - start; expect(users.length).toBe(10000); expect(duration).toBeLessThan(500); 

});

it(‘should create 1k users in batch < 2s’, async () => {

const data = Array.from({ length: 1000 }, (_, i) => ({ name: `user-${i}`, email: `user-${i}@example.com`, password: 'hashed-password', })); const start = performance.now(); await db.insert(users).values(data); const duration = performance.now() - start; expect(duration).toBeLessThan(2000); 

}); });


数据持久化本质上解决的是:当系统崩溃、误操作、甚至被攻击时,数据还能不能恢复?

重要认知: 数据库 ≠ 数据安全。数据库只是”存储”,而备份 + 恢复能力才是安全的核心。

备份脚本示例
#!/bin/bash set -o pipefail # 核心:捕获管道中任何一步的错误

DB_NAME=“your_db” BACKUPFILE=“/data/backups/db$(date +%Y%m%d).sql.gz”

执行备份

pg_dump -U admin -d \(DB_NAME | gzip -1 > \)BACKUP_FILE

检查备份是否成功

if [ $? -ne 0 ]; then

echo "❌ 备份失败!清理空文件..." rm -f $BACKUP_FILE # 调用告警机制 # sendAlert "Database Backup Failed" "pg_dump connection error" "critical" exit 1 

else

echo "✅ 备份成功" 

fi


可观测性与监控的区别:

  • 监控 → 告诉你”系统出了问题”(基于预定义的指标和阈值)
  • 可观测性 → 告诉你”系统为什么出了问题”(通过日志、指标、链路追踪)
可观测性的三大支柱

支柱 1:结构化日志

// src/utils/logger.ts import winston from ‘winston’;

const logger = winston.createLogger({ format: winston.format.combine(

winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), // 自定义格式化,确保输出为结构化 JSON winston.format.printf(({ timestamp, level, message, ...meta }) => ); }) 

), transports: [

new winston.transports.Console(), new winston.transports.File({ filename: 'logs/error.log', level: 'error' }), new winston.transports.File({ filename: 'logs/combined.log' }), 

], });

支柱 2:指标收集(Metrics)

使用 Prometheus 收集性能指标:

// src/utils/metrics.ts import promClient from ‘prom-client’;

// 创建指标 export const httpRequestDuration = new promClient.Histogram({ name: ‘http_request_duration_seconds’, help: ‘HTTP request latency’, labelNames: [‘method’, ‘route’, ‘status_code’], buckets: [0.1, 0.5, 1, 2, 5], });

export const dbQueryDuration = new promClient.Histogram({ name: ‘db_query_duration_seconds’, help: ‘Database query latency’, labelNames: [‘operation’, ‘table’], buckets: [0.01, 0.05, 0.1, 0.5, 1], });

// 暴露 Prometheus 指标端点 export function registerMetricsRoute(app: Hono) ); }

支柱 3:链路追踪(Traces)

已在前面的 TraceId 部分详细说明。


这套工作流的核心理念就是 持续反馈、不断优化。感谢您的阅读,建议点赞收藏,我们下期再见!

小讯
上一篇 2026-04-11 08:02
下一篇 2026-04-11 08:00

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/254682.html