@loongsuite/cms_trace
v1.0.0
Published
## 简介
Downloads
15
Readme
@loongsuite/cms_trace
简介
CMS Trace 是 CMS 可观测性 SDK 的核心追踪实现包,提供完整的分布式追踪功能。包括追踪器管理器、追踪器、Span、采样器、Span 处理器等核心组件,是实现分布式追踪的基础设施。
特性
- 🎯 完整追踪: 提供完整的分布式追踪实现
- 📊 多种采样器: 支持多种采样策略
- 🔄 批量处理: 高效的 Span 批量处理
- ⚡ 高性能: 优化的追踪性能
- 🔧 灵活配置: 可配置的追踪参数
- 📈 资源检测: 自动资源信息检测
安装
# 使用 anpm (推荐)
anpm add @loongsuite/cms_trace
# 或使用 npm
npm install @loongsuite/cms_trace核心概念
追踪器管理器 (TracerManager)
追踪器管理器是追踪系统的核心,负责管理追踪器实例和 Span 处理。
追踪器 (Tracer)
追踪器用于创建和管理 Span,是追踪数据的主要入口。
Span
Span 表示追踪中的一个操作单元,包含操作名称、时间戳、属性等信息。
采样器 (Sampler)
采样器决定哪些 Span 需要被记录和导出。
Span 处理器 (SpanProcessor)
Span 处理器负责处理 Span 的生命周期事件。
主要导出
import {
TracerManager,
Tracer,
Span,
SpanProcessor,
BatchSpanProcessor,
SimpleSpanProcessor,
Sampler,
TraceIdRatioBasedSampler,
AlwaysOnSampler,
AlwaysOffSampler,
ParentBasedSampler,
ResourceDetector,
EnvResourceDetector,
ProcessResourceDetector,
HostResourceDetector
} from '@loongsuite/cms_trace';使用示例
基础追踪
import { TracerManager, BatchSpanProcessor } from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
// 创建追踪器管理器
const tracerManager = new TracerManager({
spanProcessors: [
new BatchSpanProcessor(new ConsoleSpanExporter(), {
scheduledDelayMillis: 200,
maxExportBatchSize: 100,
maxQueueSize: 1000
})
]
});
// 获取追踪器
const tracer = tracerManager.getTracer('my-service', '1.0.0');
// 创建 Span
const span = tracer.startSpan('user-operation', {
kind: 1, // SERVER
attributes: {
'user.id': '12345',
'operation.type': 'login'
}
});
// 执行业务逻辑
try {
// 模拟业务操作
await new Promise(resolve => setTimeout(resolve, 100));
// 添加事件
span.addEvent('user-authenticated', {
'auth.method': 'password',
'auth.success': true
});
// 设置状态
span.setStatus({ code: 1, message: 'Success' });
} catch (error) {
// 记录错误
span.setStatus({ code: 2, message: error.message });
span.recordException(error);
} finally {
// 结束 Span
span.end();
}
// 关闭追踪器管理器
await tracerManager.shutdown();嵌套 Span
import { TracerManager, BatchSpanProcessor } from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
const tracerManager = new TracerManager({
spanProcessors: [new BatchSpanProcessor(new ConsoleSpanExporter())]
});
const tracer = tracerManager.getTracer('nested-service');
// 创建父 Span
const parentSpan = tracer.startSpan('http-request', {
kind: 1, // SERVER
attributes: {
'http.method': 'POST',
'http.url': '/api/users',
'http.status_code': 200
}
});
// 在父 Span 上下文中创建子 Span
const childSpan = tracer.startSpan('database-query', {
kind: 2, // CLIENT
attributes: {
'db.system': 'postgresql',
'db.operation': 'INSERT',
'db.table': 'users'
}
});
// 模拟数据库操作
setTimeout(() => {
childSpan.setStatus({ code: 1 });
childSpan.end();
// 创建另一个子 Span
const anotherChildSpan = tracer.startSpan('cache-update', {
kind: 2, // CLIENT
attributes: {
'cache.operation': 'SET',
'cache.key': 'user:12345'
}
});
setTimeout(() => {
anotherChildSpan.setStatus({ code: 1 });
anotherChildSpan.end();
parentSpan.setStatus({ code: 1 });
parentSpan.end();
}, 50);
}, 100);采样器配置
import {
TracerManager,
BatchSpanProcessor,
TraceIdRatioBasedSampler,
AlwaysOnSampler,
AlwaysOffSampler,
ParentBasedSampler
} from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
// 1. 基于比例的采样器(采样 50% 的请求)
const ratioSampler = new TraceIdRatioBasedSampler(0.5);
// 2. 总是采样
const alwaysOnSampler = new AlwaysOnSampler();
// 3. 从不采样
const alwaysOffSampler = new AlwaysOffSampler();
// 4. 基于父 Span 的采样器
const parentBasedSampler = new ParentBasedSampler({
root: new TraceIdRatioBasedSampler(0.1), // 根 Span 采样 10%
remoteParentSampled: new AlwaysOnSampler(), // 远程父 Span 已采样则采样
remoteParentNotSampled: new AlwaysOffSampler(), // 远程父 Span 未采样则不采样
localParentSampled: new AlwaysOnSampler(), // 本地父 Span 已采样则采样
localParentNotSampled: new AlwaysOffSampler() // 本地父 Span 未采样则不采样
});
const tracerManager = new TracerManager({
sampler: parentBasedSampler,
spanProcessors: [new BatchSpanProcessor(new ConsoleSpanExporter())]
});
const tracer = tracerManager.getTracer('sampled-service');
// 创建 Span(会根据采样器决定是否记录)
const span = tracer.startSpan('sampled-operation');
span.end();资源检测
import {
TracerManager,
BatchSpanProcessor,
EnvResourceDetector,
ProcessResourceDetector,
HostResourceDetector
} from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
// 创建资源检测器
const resourceDetectors = [
new EnvResourceDetector(), // 环境变量检测
new ProcessResourceDetector(), // 进程信息检测
new HostResourceDetector() // 主机信息检测
];
const tracerManager = new TracerManager({
resourceDetectors,
spanProcessors: [new BatchSpanProcessor(new ConsoleSpanExporter())]
});
const tracer = tracerManager.getTracer('resource-service');
// 创建 Span(会自动包含资源信息)
const span = tracer.startSpan('resource-operation');
span.end();自定义 Span 处理器
import { SpanProcessor, ReadableSpan } from '@loongsuite/cms_trace';
class CustomSpanProcessor implements SpanProcessor {
onStart(span: ReadableSpan): void {
console.log('Span started:', span.name);
// 添加自定义属性
span.setAttributes({
'custom.processor': 'custom-span-processor',
'custom.timestamp': Date.now()
});
}
onEnd(span: ReadableSpan): void {
console.log('Span ended:', span.name, 'Duration:', span.duration);
// 自定义处理逻辑
if (span.duration > 1000) {
console.warn('Slow operation detected:', span.name);
}
}
shutdown(): Promise<void> {
console.log('Custom span processor shutting down');
return Promise.resolve();
}
forceFlush(): Promise<void> {
console.log('Custom span processor force flush');
return Promise.resolve();
}
}
const tracerManager = new TracerManager({
spanProcessors: [
new CustomSpanProcessor(),
new BatchSpanProcessor(new ConsoleSpanExporter())
]
});错误处理和异常记录
import { TracerManager, BatchSpanProcessor } from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
const tracerManager = new TracerManager({
spanProcessors: [new BatchSpanProcessor(new ConsoleSpanExporter())]
});
const tracer = tracerManager.getTracer('error-service');
async function riskyOperation() {
const span = tracer.startSpan('risky-operation');
try {
// 可能失败的操作
await new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
reject(new Error('Random failure'));
} else {
resolve('Success');
}
}, 100);
});
span.setStatus({ code: 1, message: 'Success' });
} catch (error) {
// 记录异常
span.recordException(error);
span.setStatus({
code: 2,
message: error.message
});
// 添加错误相关属性
span.setAttributes({
'error.type': error.constructor.name,
'error.message': error.message,
'error.stack': error.stack
});
throw error;
} finally {
span.end();
}
}
// 使用示例
riskyOperation().catch(error => {
console.error('Operation failed:', error.message);
});与上下文管理器集成
import { TracerManager, BatchSpanProcessor } from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
import { AsyncLocalStorageContextManager } from '@loongsuite/cms_context';
const contextManager = new AsyncLocalStorageContextManager();
const tracerManager = new TracerManager({
contextManager,
spanProcessors: [new BatchSpanProcessor(new ConsoleSpanExporter())]
});
const tracer = tracerManager.getTracer('context-service');
// 在上下文中创建 Span
const span = tracer.startSpan('contextual-operation');
const contextWithSpan = tracerManager.setSpan(contextManager.active(), span);
contextManager.with(contextWithSpan, () => {
// 在此上下文中,可以获取当前 Span
const currentSpan = tracerManager.getActiveSpan(contextManager.active());
console.log('Current span:', currentSpan?.name);
// 异步操作也会保持上下文
setTimeout(() => {
const asyncSpan = tracerManager.getActiveSpan(contextManager.active());
console.log('Async span:', asyncSpan?.name); // 仍然是同一个 span
}, 100);
});
span.end();配置选项
TracerManager 配置
interface TracerManagerConfig {
contextManager?: IContextManager;
sampler?: Sampler;
spanProcessors?: SpanProcessor[];
resourceDetectors?: ResourceDetector[];
resource?: Resource;
}BatchSpanProcessor 配置
interface BatchSpanProcessorConfig {
scheduledDelayMillis?: number; // 批量导出间隔,默认 5000
maxExportBatchSize?: number; // 每批最大数量,默认 512
maxQueueSize?: number; // 队列最大大小,默认 2048
exportTimeoutMillis?: number; // 导出超时时间,默认 30000
}性能优化
采样策略
// 生产环境:低采样率
const productionSampler = new TraceIdRatioBasedSampler(0.01); // 1%
// 开发环境:高采样率
const developmentSampler = new TraceIdRatioBasedSampler(1.0); // 100%
// 根据环境动态配置
const sampler = process.env.NODE_ENV === 'production'
? productionSampler
: developmentSampler;批量处理优化
const batchProcessor = new BatchSpanProcessor(exporter, {
scheduledDelayMillis: 1000, // 更频繁的导出
maxExportBatchSize: 256, // 更小的批次
maxQueueSize: 1024, // 更小的队列
exportTimeoutMillis: 5000 // 更短的超时
});与 NodeSDK 集成
import { NodeSDK } from '@loongsuite/cms_node_sdk';
import { BatchSpanProcessor, TraceIdRatioBasedSampler } from '@loongsuite/cms_trace';
import { ConsoleSpanExporter } from '@loongsuite/cms_exporters';
const sdk = new NodeSDK({
serviceName: 'my-service',
spanProcessors: [
new BatchSpanProcessor(new ConsoleSpanExporter())
],
// 其他配置会自动使用默认的 TracerManager
});
sdk.start();
// 获取追踪器管理器
const tracerManager = sdk.getTracerManager();
const tracer = tracerManager.getTracer('my-service');故障排除
常见问题
- Span 未导出: 检查 Span 是否正确结束
- 性能问题: 调整采样率和批量处理参数
- 内存泄漏: 确保正确关闭追踪器管理器
调试技巧
// 启用详细日志
const tracerManager = new TracerManager({
spanProcessors: [
new BatchSpanProcessor(new ConsoleSpanExporter(), {
scheduledDelayMillis: 100 // 更频繁的导出用于调试
})
]
});
// 添加调试信息
const span = tracer.startSpan('debug-operation');
span.setAttributes({
'debug.timestamp': Date.now(),
'debug.process.pid': process.pid,
'debug.memory.usage': process.memoryUsage().heapUsed
});
span.end();依赖
@loongsuite/cms_core: 核心类型和接口定义@loongsuite/cms_context: 上下文管理器实现
许可证
MIT License
