_
_____ ___ __ _ __ ___ ___ ___ (_) __ _ ___ __ _ ___ _ __
/ _ \ \/ / '_ \| '__/ _ \/ __/ __|_____| |/ _` |/ _ \/ _` |/ _ \ '__|
| __/> <| |_) | | | __/\__ \__ \_____| | (_| | __/ (_| | __/ |
\___/_/\_\ .__/|_| \___||___/___/ _/ |\__,_|\___|\__, |\___|_|
|_| |__/ |___/
Jaeger middleware to request tracing for express application
To fully understand Opentracing, it's helpful to be familiar with the OpenTracing project and terminology more specifically.
To fully understand Jaeger, it's helpful to be familiar with the Jaeger project and Jaeger Client for Node
npm i @chankamlam/express-jaeger -S
docker run -d -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p5775:5775/udp -p6831:6831/udp -p6832:6832/udp \
-p5778:5778 -p16686:16686 -p14268:14268 -p9411:9411 jaegertracing/all-in-one:latest
const express = require("express");
const jaeger = require("@chankamlam/express-jaeger");
const app = express();
const config = {
serviceName: 'service1-express',
sampler: {
type: "const",
param: 1
},
reporter: {
collectorEndpoint: "http://localhost:14268/api/traces"
},
}; // required
const options = {
baggagePrefix: "-Johua-", // optional,you can let options={}
excludePath:["/api/v1/health","/api/v1/metric"] // exclude path
};
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/
x-www-form-urlencoded
app.use(jaeger(config,options,(req,res)=>{
// here to write your code
// which is showing here is to auto record query/body/path for every request
const jaeger = req.jaeger
jaeger.setTag("route",req.path)
jaeger.setTag("body",req.body)
jaeger.setTag("query",req.query)
}));
app.all("/abc", async function (req, res) {
res.send({code: 200, msg: result});
});
app.listen(3000, '127.0.0.1', function () {
console.log('start');
});
const express = require("express");
const jaeger = require("@chankamlam/express-jaeger")
const app = express();
// setup config, atleast need this param
const config = {
serviceName: 'aservice-express', // your service name
sampler: { // setup sampler
type: "const",
param: 1
},
reporter: {
collectorEndpoint: "http://localhost:14268/api/traces" // your jaeger server endpoint
},
};
// setup options, defaut is {}
const options = {
baggagePrefix: "-Johua-",
excludePath:["/api/v1/health","/api/v1/metric"] // exclude path
};
/*
* using jager,after this it will has one object which called jaeger,
* with four properties(span,tracer,request,tags) binding in req
*/
app.use(jaeger(config,options));
app.get("/normallyUsingSpan2Log", async function (req, res) {
const jaeger = req.jaeger;
jaeger.log("timestamp",Date.now());
res.send({code: 200, msg: "success"});
});
app.listen(3000, '127.0.0.1', function () {
console.log('start server...');
});
app.get("/errorUsingSpan2Log", async function (req, res) {
const jaeger = req.jaeger;
const tags = req.jaeger.tags;
try {
throw Error("err"); // create exception to test
} catch (err) {
jaeger.setTag(tags.ERROR, true); // diaplay to JaegerUI when you mark tag as "error"
jaeger.log("errorMsg", err.message);
}
res.send({code: 200, msg: "success"});
});
app.get("/remoteCallingAndlogResult", async function (req, res) {
const jaeger = req.jaeger
// for remote request, you have to use jaeger.axios which wrap axios by tracing
const result = await jaeger
.axios({url:"http://localhost:3001/bc"})
.then(r=>r.data);
jaeger.log("result",result)
res.send({code: 200, msg: "success"});
});
app.get("/remoteCallingAndlogResultInTwoSpan", async function (req, res) {
const jaeger = req.jaeger
// default under master span (auto create by every request)
const span1 = jaeger.createSpan("resut1")
const result1 = await jaeger
.axios({url:"http://localhost:3001/a"})
.then(r=>r.data);
span1.log("result1",result1)
span1.finish();
// default under master span (auto create by every request)
const span2 = jaeger.createSpan("resut2")
const result2 = await jaeger
.axios({url:"http://localhost:3001/b",method:"post",data:{}})
.then(r=>r.data);
span2.log("result2",result2)
span2.finish();
jaeger.log("resultOfMasterSpan","here is master span")
res.send({code: 200, msg: "success"});
});
open url http://localhost:16686 , remember to build up the Jager Server locally first
for detail, pls look up to Jaeger Client for Node
{
serviceName: "string", // required
disable: "boolean",
sampler: {
type: "string", // required
param: "number", // required
hostPort: "string",
host: "string",
port: "number",
refreshIntervalMs: "number"
},
reporter: {
logSpans: "boolean",
agentHost: "string",
agentPort: "number",
collectorEndpoint: "string", // required
username: "string",
password: "string",
flushIntervalMs: "number"
},
throttler: {
host: "string",
port: "number",
refreshIntervalMs: "number"
}
}
for detail, pls look up to Jaeger Client for Node
{
contextKey: "string",
baggagePrefix: "string",
metrics: "object", // a metrics
logger: "object", // a logger
tags: "object", // set of key-value pairs which will be set as process-level tags on the Tracer itself.
traceId128bit: "boolean",
shareRpcSpan: "boolean",
debugThrottler: "boolean",
excludePath:"array" // array of parttern for excluding record the access
}
jaeger object will bind in req when you do "app.use(jaeger(config,options))"
{
log : function(name,content) // write the log to master span
setTag : function(name,value) // setup tag to master span
setTracingTag : function(name,value) // setup tag to master span and children span
addTags : function({k1:v1,k2:v2}) // setup mutiple tags to master span
createSpan : function(name,parentSpan) // create a new span under parent span,if parentSpan is undefine will under master span
tags : object // all defined tags of opentracing which can be used
axios : function(url,options) // using it to remote call service if not it will be broken the tracing to next service
}
req.jaeger.log("info","..........")
const jaeger = req.jaeger
const tags = jaeger
// using defined tags by opentracing
jaeger.setTag(tags.ERROR,true)
// using your customize tag
jaeger.setTag("warning",true)
const jaeger = req.jaeger
const tags = jaeger
jaeger.setTracingTag("waybill","wb-123456")
const jaeger = req.jaeger
const tags = jaeger
// add mutiple tag one time
jaeger.addTags({"error":true,"info":true})
const span = jaeger.createSpan("subSpanName") // create a sub span under master span
// you also can call method of span
span.log("info","info......")
span.setTag("info",true)
// remember to call finish() if not there is no record send to jaeger
span.finish();
predefined tag, some come from OpenTracing project
jaeger.axios wrap axios with tracing header, for usage detail pls look up to axios
MIT