@chankamlam/express-jaeger
Version:
Jaeger middleware to request tracing for express application
301 lines (260 loc) • 9.26 kB
Markdown
# Express-Jaeger
```
_
_____ ___ __ _ __ ___ ___ ___ (_) __ _ ___ __ _ ___ _ __
/ _ \ \/ / '_ \| '__/ _ \/ __/ __|_____| |/ _` |/ _ \/ _` |/ _ \ '__|
| __/> <| |_) | | | __/\__ \__ \_____| | (_| | __/ (_| | __/ |
\___/_/\_\ .__/|_| \___||___/___/ _/ |\__,_|\___|\__, |\___|_|
|_| |__/ |___/
```
**Jaeger middleware to request tracing for express application**
# Required Reading
#### _Opentracing_
_To fully understand Opentracing, it's helpful to be familiar with the [OpenTracing project](http://opentracing.io) and
[terminology](http://opentracing.io/documentation/pages/spec.html) more specifically._
#### _Jaeger(One Of Request Tracing System implement Opentracing)_
_To fully understand Jaeger, it's helpful to be familiar with the [Jaeger project](https://www.jaegertracing.io) and [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)_
# Simple Concept

> #### _One request map to one trace_
> #### _One trace atleast has one span which is master span_
> #### _Master span can have many children spans_
# Installation
```
npm i /express-jaeger -S
```
## Architecture of Jaeger Server
> ### _for development_

> ### _for prodution_

> ### _Build up Jaeger Server Infra locally(development env)_
```
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
```
# Quick Start
```
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');
});
```
# Usage
## _normallyUsingSpan2Log_
```
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...');
});
```
## _usingSpan2LogWithError_
```
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"});
});
```
## _remoteCallingAndlogResult_
```
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"});
});
```
## _remoteCallingAndlogResultInTwoSpan_
```
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"});
});
```
# Lookup Request Tracing
> open url http://localhost:16686 , remember to build up the Jager Server locally first


# Object Detail
## _Config_
> for detail, pls look up to [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)
```
{
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"
}
}
```
## _options_
> for detail, pls look up to [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)
```
{
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_
> 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) // create a new span un der 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
}
```
### _log_
```
req.jaeger.log("info","..........")
```
### _setTag_
```
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)
```
### _setTracingTag_
```
const jaeger = req.jaeger
const tags = jaeger
jaeger.setTracingTag("waybill","wb-123456")
```
### _addTags_
```
const jaeger = req.jaeger
const tags = jaeger
// add mutiple tag one time
jaeger.addTags({"error":true,"info":true})
```
### _createSpan_
```
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();
```
### _tags_
predefined tag, some come from [OpenTracing project](http://opentracing.io)
### _axios_
jaeger.axios wrap axios with tracing header, for usage detail pls look up to [axios](https://www.npmjs.com/package/axios)
## license
MIT