重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
workers-observability by secondsky/claude-skills
npx skills add https://github.com/secondsky/claude-skills --skill workers-observability为 Cloudflare Workers 提供生产级可观测性:日志记录、指标、追踪和告警。
// 带上下文的结构化日志记录
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const requestId = crypto.randomUUID();
const logger = createLogger(requestId, env);
try {
logger.info('Request received', { method: request.method, url: request.url });
const result = await handleRequest(request, env);
logger.info('Request completed', { status: result.status });
return result;
} catch (error) {
logger.error('Request failed', { error: error.message, stack: error.stack });
throw error;
}
}
};
// 简单的日志记录器工厂函数
function createLogger(requestId: string, env: Env) {
return {
info: (msg: string, data?: object) => console.log(JSON.stringify({ level: 'info', requestId, msg, ...data, timestamp: Date.now() })),
error: (msg: string, data?: object) => console.error(JSON.stringify({ level: 'error', requestId, msg, ...data, timestamp: Date.now() })),
warn: (msg: string, data?: object) => console.warn(JSON.stringify({ level: 'warn', requestId, msg, ...data, timestamp: Date.now() })),
};
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 组件 | 用途 | 使用时机 |
|---|---|---|
console.log | 基础日志记录 | 开发、调试 |
| Tail Workers | 实时日志流 | 生产环境日志聚合 |
| Analytics Engine | 自定义指标/分析 | 业务指标、性能追踪 |
| Logpush | 日志导出到外部服务 | 长期存储、合规性 |
| Workers Trace Events | 分布式追踪 | 请求流调试 |
| 错误 | 症状 | 预防措施 |
|---|---|---|
| 日志未显示 | 仪表板中无输出 | 在 wrangler.jsonc 中启用 "Standard" 日志记录 |
| 日志截断 | 消息在 128KB 处被截断 | 对大负载进行分块,使用采样 |
| Tail Worker 未接收 | 无事件被处理 | 检查绑定名称是否与 wrangler.jsonc 匹配 |
| Analytics Engine 写入失败 | 数据未记录 | 验证 AE 绑定,检查 blobs 格式 |
| 日志中包含个人身份信息 | 安全/合规性违规 | 实施数据脱敏中间件 |
| 缺少请求上下文 | 无法关联日志 | 为所有日志条目添加 requestId |
| 日志量激增 | 成本高、噪音大 | 对高频事件实施采样 |
| 告警缺失 | 未检测到事件 | 为错误率阈值配置监控器 |
wrangler.jsonc :
{
"name": "my-worker",
"observability": {
"enabled": true,
"head_sampling_rate": 1 // 0-1, 1 = 100% 的请求
},
"tail_consumers": [
{
"service": "log-aggregator", // Tail Worker 名称
"environment": "production"
}
],
"analytics_engine_datasets": [
{
"binding": "ANALYTICS",
"dataset": "my_worker_metrics"
}
]
}
interface LogEntry {
level: 'debug' | 'info' | 'warn' | 'error';
message: string;
requestId: string;
timestamp: number;
// 上下文数据
method?: string;
path?: string;
status?: number;
duration?: number;
// 错误详情
error?: {
name: string;
message: string;
stack?: string;
};
// 自定义字段
[key: string]: unknown;
}
class Logger {
constructor(private requestId: string, private baseContext: object = {}) {}
private log(level: LogEntry['level'], message: string, data?: object) {
const entry: LogEntry = {
level,
message,
requestId: this.requestId,
timestamp: Date.now(),
...this.baseContext,
...data,
};
// 脱敏敏感字段
const sanitized = this.redact(entry);
const output = JSON.stringify(sanitized);
level === 'error' ? console.error(output) : console.log(output);
}
private redact(entry: LogEntry): LogEntry {
const sensitiveKeys = ['password', 'token', 'secret', 'authorization', 'cookie'];
const redacted = { ...entry };
for (const key of Object.keys(redacted)) {
if (sensitiveKeys.some(s => key.toLowerCase().includes(s))) {
redacted[key] = '[REDACTED]';
}
}
return redacted;
}
info(message: string, data?: object) { this.log('info', message, data); }
warn(message: string, data?: object) { this.log('warn', message, data); }
error(message: string, data?: object) { this.log('error', message, data); }
debug(message: string, data?: object) { this.log('debug', message, data); }
}
interface Env {
ANALYTICS: AnalyticsEngineDataset;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const start = Date.now();
const url = new URL(request.url);
try {
const response = await handleRequest(request, env);
// 写入成功指标
env.ANALYTICS.writeDataPoint({
blobs: [request.method, url.pathname, String(response.status)],
doubles: [Date.now() - start], // 响应时间(毫秒)
indexes: [url.pathname.split('/')[1] || 'root'], // 用于快速查询的索引
});
return response;
} catch (error) {
// 写入错误指标
env.ANALYTICS.writeDataPoint({
blobs: [request.method, url.pathname, 'error', error.message],
doubles: [Date.now() - start],
indexes: ['error'],
});
throw error;
}
}
};
// tail-worker.ts - 接收来自其他 worker 的日志
interface TailEvent {
scriptName: string;
event: {
request?: { method: string; url: string };
response?: { status: number };
};
logs: Array<{
level: string;
message: unknown[];
timestamp: number;
}>;
exceptions: Array<{
name: string;
message: string;
timestamp: number;
}>;
outcome: 'ok' | 'exception' | 'exceededCpu' | 'exceededMemory' | 'canceled';
eventTimestamp: number;
}
export default {
async tail(events: TailEvent[], env: Env): Promise<void> {
for (const event of events) {
// 筛选并转发日志
const errorLogs = event.logs.filter(l => l.level === 'error');
const exceptions = event.exceptions;
if (errorLogs.length > 0 || exceptions.length > 0) {
// 发送到外部日志服务
await fetch(env.LOGGING_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
scriptName: event.scriptName,
timestamp: event.eventTimestamp,
errors: errorLogs,
exceptions,
outcome: event.outcome,
}),
});
}
}
}
};
根据任务加载特定参考资料:
references/logging.md 获取结构化日志记录模式、日志级别、数据脱敏references/analytics-engine.md 获取 Analytics Engine SQL 查询、数据建模references/tail-workers.md 获取 Tail Worker 模式、外部服务集成references/custom-metrics.md 获取业务指标、性能追踪references/alerting.md 获取错误率监控、PagerDuty/Slack 集成| 模板 | 用途 | 使用时机 |
|---|---|---|
templates/logging-setup.ts | 生产环境日志记录类 | 为新的 worker 设置日志记录 |
templates/analytics-worker.ts | Analytics Engine 集成 | 添加自定义指标 |
templates/tail-worker.ts | 完整的 Tail Worker | 构建日志聚合管道 |
| 脚本 | 用途 | 命令 |
|---|---|---|
scripts/setup-logging.sh | 配置日志记录设置 | ./setup-logging.sh |
scripts/analyze-logs.sh | 查询和分析日志 | ./analyze-logs.sh --errors --last 1h |
每周安装次数
67
代码仓库
GitHub 星标数
90
首次出现时间
2026年1月25日
安全审计
已安装于
claude-code60
codex53
cursor53
opencode52
gemini-cli52
github-copilot49
Production-grade observability for Cloudflare Workers: logging, metrics, tracing, and alerting.
// Structured logging with context
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const requestId = crypto.randomUUID();
const logger = createLogger(requestId, env);
try {
logger.info('Request received', { method: request.method, url: request.url });
const result = await handleRequest(request, env);
logger.info('Request completed', { status: result.status });
return result;
} catch (error) {
logger.error('Request failed', { error: error.message, stack: error.stack });
throw error;
}
}
};
// Simple logger factory
function createLogger(requestId: string, env: Env) {
return {
info: (msg: string, data?: object) => console.log(JSON.stringify({ level: 'info', requestId, msg, ...data, timestamp: Date.now() })),
error: (msg: string, data?: object) => console.error(JSON.stringify({ level: 'error', requestId, msg, ...data, timestamp: Date.now() })),
warn: (msg: string, data?: object) => console.warn(JSON.stringify({ level: 'warn', requestId, msg, ...data, timestamp: Date.now() })),
};
}
| Component | Purpose | When to Use |
|---|---|---|
console.log | Basic logging | Development, debugging |
| Tail Workers | Real-time log streaming | Production log aggregation |
| Analytics Engine | Custom metrics/analytics | Business metrics, performance tracking |
| Logpush | Log export to external services | Long-term storage, compliance |
| Workers Trace Events | Distributed tracing | Request flow debugging |
| Error | Symptom | Prevention |
|---|---|---|
| Logs not appearing | No output in dashboard | Enable "Standard" logging in wrangler.jsonc |
| Log truncation | Messages cut off at 128KB | Chunk large payloads, use sampling |
| Tail Worker not receiving | No events processed | Check binding name matches wrangler.jsonc |
| Analytics Engine write fails | Data not recorded | Verify AE binding, check blobs format |
| PII in logs | Security/compliance violation | Implement redaction middleware |
| Missing request context | Can't correlate logs | Add requestId to all log entries |
| Log volume explosion | High costs, noise | Implement sampling for high-frequency events |
| Alerting gaps | Incidents not detected | Configure monitors for error rate thresholds |
wrangler.jsonc :
{
"name": "my-worker",
"observability": {
"enabled": true,
"head_sampling_rate": 1 // 0-1, 1 = 100% of requests
},
"tail_consumers": [
{
"service": "log-aggregator", // Tail Worker name
"environment": "production"
}
],
"analytics_engine_datasets": [
{
"binding": "ANALYTICS",
"dataset": "my_worker_metrics"
}
]
}
interface LogEntry {
level: 'debug' | 'info' | 'warn' | 'error';
message: string;
requestId: string;
timestamp: number;
// Contextual data
method?: string;
path?: string;
status?: number;
duration?: number;
// Error details
error?: {
name: string;
message: string;
stack?: string;
};
// Custom fields
[key: string]: unknown;
}
class Logger {
constructor(private requestId: string, private baseContext: object = {}) {}
private log(level: LogEntry['level'], message: string, data?: object) {
const entry: LogEntry = {
level,
message,
requestId: this.requestId,
timestamp: Date.now(),
...this.baseContext,
...data,
};
// Redact sensitive fields
const sanitized = this.redact(entry);
const output = JSON.stringify(sanitized);
level === 'error' ? console.error(output) : console.log(output);
}
private redact(entry: LogEntry): LogEntry {
const sensitiveKeys = ['password', 'token', 'secret', 'authorization', 'cookie'];
const redacted = { ...entry };
for (const key of Object.keys(redacted)) {
if (sensitiveKeys.some(s => key.toLowerCase().includes(s))) {
redacted[key] = '[REDACTED]';
}
}
return redacted;
}
info(message: string, data?: object) { this.log('info', message, data); }
warn(message: string, data?: object) { this.log('warn', message, data); }
error(message: string, data?: object) { this.log('error', message, data); }
debug(message: string, data?: object) { this.log('debug', message, data); }
}
interface Env {
ANALYTICS: AnalyticsEngineDataset;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const start = Date.now();
const url = new URL(request.url);
try {
const response = await handleRequest(request, env);
// Write success metric
env.ANALYTICS.writeDataPoint({
blobs: [request.method, url.pathname, String(response.status)],
doubles: [Date.now() - start], // Response time in ms
indexes: [url.pathname.split('/')[1] || 'root'], // Index for fast queries
});
return response;
} catch (error) {
// Write error metric
env.ANALYTICS.writeDataPoint({
blobs: [request.method, url.pathname, 'error', error.message],
doubles: [Date.now() - start],
indexes: ['error'],
});
throw error;
}
}
};
// tail-worker.ts - Receives logs from other workers
interface TailEvent {
scriptName: string;
event: {
request?: { method: string; url: string };
response?: { status: number };
};
logs: Array<{
level: string;
message: unknown[];
timestamp: number;
}>;
exceptions: Array<{
name: string;
message: string;
timestamp: number;
}>;
outcome: 'ok' | 'exception' | 'exceededCpu' | 'exceededMemory' | 'canceled';
eventTimestamp: number;
}
export default {
async tail(events: TailEvent[], env: Env): Promise<void> {
for (const event of events) {
// Filter and forward logs
const errorLogs = event.logs.filter(l => l.level === 'error');
const exceptions = event.exceptions;
if (errorLogs.length > 0 || exceptions.length > 0) {
// Send to external logging service
await fetch(env.LOGGING_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
scriptName: event.scriptName,
timestamp: event.eventTimestamp,
errors: errorLogs,
exceptions,
outcome: event.outcome,
}),
});
}
}
}
};
Load specific references based on the task:
references/logging.md for structured logging patterns, log levels, redactionreferences/analytics-engine.md for Analytics Engine SQL queries, data modelingreferences/tail-workers.md for Tail Worker patterns, external service integrationreferences/custom-metrics.md for business metrics, performance trackingreferences/alerting.md for error rate monitoring, PagerDuty/Slack integration| Template | Purpose | Use When |
|---|---|---|
templates/logging-setup.ts | Production logging class | Setting up new worker with logging |
templates/analytics-worker.ts | Analytics Engine integration | Adding custom metrics |
templates/tail-worker.ts | Complete Tail Worker | Building log aggregation pipeline |
| Script | Purpose | Command |
|---|---|---|
scripts/setup-logging.sh | Configure logging settings | ./setup-logging.sh |
scripts/analyze-logs.sh | Query and analyze logs | ./analyze-logs.sh --errors --last 1h |
Weekly Installs
67
Repository
GitHub Stars
90
First Seen
Jan 25, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykWarn
Installed on
claude-code60
codex53
cursor53
opencode52
gemini-cli52
github-copilot49