trace-hook
v0.2.17
Published
一个轻量化的全链路追踪中间件, 可生成TraceID, 并将TraceID注入到各种请求中, 以便于在日志中查看请求的完整链路, 目前支持logger koa-logger axios mq A lightweight, full-link tracking middleware that generates traceIds and injects traceIds into various requests so that the full link of the request can be v
Downloads
14
Maintainers
Readme
trace-hook
还在开发中, 有任何问题和bug欢迎发给邮箱: [email protected]
Description
一个轻量化的全链路追踪中间件, 可生成TraceID, 并将TraceID注入到各种请求中, 以便于在日志中查看请求的完整链路
配置逻辑简介
这个模块, 用于生成traceId, 以及解析traceId
必须有生产TraceID的模块才能使用其余所有功能\
产生TraceID的模块有:
- koaTrace
- amqplibTrace
- transByAmqplib
- 自定义模块
简介
- koaTrace 用于koa框架
- amqplibTrace 用于amqplib框架 一般不单独使用
- transByAmqplib 用于amqplib框架 (集成了amqplibTrace 所以也属于生产者)
- 自定义模块(todo)
使用ID的模块有:
- logger
- loggerTrace
- koaLogger
- transByAxios
简介
- logger, loggerTrace 用于记录日志
- koaLogger 用于请求信息记录日志
- transByAxios 用于axios请求传递traceId (解析traceId的是由koaTrace处理的)
- transByAmqplib 用于amqplib生成和解析以及请求传递traceId (生成traceId的是由amqplibTrace处理的)
KOA配置
最小配置
1. 在KOA中配置中间件
const Koa = require('koa');
const {koaHookMiddleware} = require('server/middleware/koa-hook');
let koa = new Koa();
koa.use(koaHookMiddleware()); // call ruanchuhao 全链路hook
2. 使用框架提供的日志方法, 或者在自己的日志中添加traceID
2.1. 使用自定义的方法
// 引入核心包
const {hookCore} = require('trace-hook');
// 获取当前请求的TraceID
const traceId = hookCore.getRootIdx();
// 在日志中添加TraceID
...你的核心logger逻辑
return `[traceID-${traceId}] ${level}:${module}${category} ${info.message ? info.message : JSON.stringify(info)}`;
2.2. 使用框架提供的方法
const logger = require("trace-hook").logger.logger(config).child({ module: "server:router:basic" });
logger.info(`[${process.env.NODE_ENV}]MeetingPadService works! start at ${_now} [1]`);
2.1或2.2可以得到日志
[traceID-3002] info: [Token] path [/api] token [undefined] state [{}]
[traceID-3002] info:server:router:basic [development]MeetingPadService works! start at Thu Aug 17 2023 15:27:43 GMT+0800 (China Standard Time) [1]
更多配置
1. 为KOA请求官方的KOA-logger中间件添加traceID
const { koaLogger } = require('trace-hook');
let koa = new Koa();
koa.use(koaLogger()); // 这样就可以生效了
可以得到日志
[traceID-3002] <-- GET /api
.....
[traceID-3002] --> GET /api 200 1,018ms 137b
2. axios请求中添加traceID
const axios = require('axios');
const {transByAxios} = require("trace-hook");
transByAxios(axios);// 初始化axios, 使得axios可以自动注入traceID 全局只需执行一次 请勿执行多次
// 使用axios 正常使用即可
const axios = require('axios');
axios.get('http://localhost:3000/api')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
可以得到日志
# 调用方日志 传出traceID
[traceID-6002] <-- GET /api
......
# 背调方日志 获得traceID
[traceID-T-6002] --> GET /api 200 1,004ms 137b
......
3. amqplib 添加日志
目前支持三个方法的日志
- publish
- sendToQueue
- addSetup中的channel.consume
// amqp 依赖包
const amqp = require('amqp-connection-manager');
// 连接MQ配置
const connection = amqp.connect(['amqp://localhost:5672']);
// 使用初始化方法令amqp支持traceID
const {transByAmqplib} = require('trace-hook');
transByAmqplib(this.connection);
配置完成后正常使用amqp即可(可以不看下面的例子)
// 正常使用amqp即可
const channelWrapper = this.connection.createChannel({
json: true, setup: function (channel) {
return channel.assertQueue('rxQueueName', {durable: true});
},
});
// sendToQueue
channelWrapper.sendToQueue('rxQueueName', {hello: 'world'});
// publish
await channelWrapper.assertExchange('any', 'direct', {durable: false});
await channelWrapper.publish('any', '', {hello: 'world'}).then(() => {
logger.info('publish success');
});
// addSetup中的channel.consume
await channelWrapper.addSetup(function (channel) {
return channel.consume('rxQueueName', function (msg) {
logger.info('Rx msg' + msg.content.toString());
setTimeout(() => {
logger.info('2Rx msg' + msg.content.toString());
}, 1000);
});
});
可以得到日志
# 调用方日志 传出traceID
[traceID-1409] info:infra:rabbitmq publish success
# 消费方日志 获得traceID
[traceID-T-1409] info:infra:rabbitmq 2Rx msg{"hello":"world","traceId":"T-1409"}
# 若生产者没有传入traceID, 则消费者日志会生成自己的traceID
[traceID-1037] info:infra:rabbitmq 2Rx msg{"hello":"world"}
4. mqtt
目前支持mqtt包中的两个方法
- on('message', ....)
- publish
使用方法
// mqtt 依赖包
const mqtt = require('mqtt');
// 连接MQ配置
this.client = mqtt.connect(...);
// 使用初始化方法令mqtt支持traceID
traceByMqtt(this.client);
// === 配置完成 以下为正常使用mqtt ===
// 使用mqtt
this.client.on('message', function (topic, message) {
// message is Buffer
logger.info(message.toString());
});
this.client.publish('presence', {msg: 'Hello mqtt'});
可以得到日志
# 生产者日志
[traceID-65582] info:infra:mqtt send ...
# 消费者日志
[traceID-T-65582] info:infra:mqtt {"msg": "Hello mqtt","traceId":"T-65582"}
5. 自定义模块
可以自定义模块, 用于生成traceID, 以及解析traceID
// 引入核心包 创建自己的模块
let mqttTraceHook = new CustomTraceHook();
// [重要] 使用入口函数, 只有入口函数及其子函数可以获得traceID
mqttTraceHook.entrance(
msg.traceId, // 外部传入的traceID 可以指定rootId(根traceID) 也可以不指定, 不指定则自动生成
(_outerTraceId, _innerTraceId)=>{ `...`}, // 传入的traceID, 以及生成的traceID 可以自定义上下文记录
()=>{return callback(topic, Buffer.from(JSON.stringify(msg)));} // 子函数(callback\ next) 在这里执行你的业务逻辑 可以使用traceID的全部能力
);
还有一些附加能力
mqttTraceHook.getRootIdx() // 获取当前的根节点 (traceId)
mqttTraceHook.getCurrentIdx() // 获取当前的 async id 在没有根节点的情况下充当TraceId
未完待续...