UNPKG

@chankamlam/express-jaeger

Version:

Jaeger middleware to request tracing for express application

301 lines (260 loc) 9.26 kB
# 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 ![avatar](https://www.jaegertracing.io/img/spans-traces.png) > #### _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 @chankamlam/express-jaeger -S ``` ## Architecture of Jaeger Server > ### _for development_ ![avatar](https://www.jaegertracing.io/img/architecture-v1.png) > ### _for prodution_ ![avatar](https://www.jaegertracing.io/img/architecture-v2.png) > ### _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 ![avatar](https://raw.githubusercontent.com/chankamlam/express-jaeger/master/pic/1.png) ![avatar](https://raw.githubusercontent.com/chankamlam/express-jaeger/master/pic/2.png) # 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