zipkin-context-cls
Advanced tools
Comparing version 0.19.0 to 0.19.2-alpha.7
"use strict"; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); | ||
var _require = require('continuation-local-storage'), | ||
createNamespace = _require.createNamespace, | ||
getNamespace = _require.getNamespace; | ||
var cls = require('continuation-local-storage'); | ||
var clsHooked = require('cls-hooked'); | ||
module.exports = | ||
@@ -18,7 +18,11 @@ /*#__PURE__*/ | ||
var namespace = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'zipkin'; | ||
var supportAsyncAwait = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; | ||
(0, _classCallCheck2["default"])(this, CLSContext); | ||
_classCallCheck(this, CLSContext); | ||
if (supportAsyncAwait) { | ||
this._session = clsHooked.getNamespace(namespace) || clsHooked.createNamespace(namespace); | ||
} else { | ||
this._session = cls.getNamespace(namespace) || cls.createNamespace(namespace); | ||
} | ||
this._session = getNamespace(namespace) || createNamespace(namespace); | ||
var defaultContext = this._session.createContext(); | ||
@@ -29,3 +33,3 @@ | ||
_createClass(CLSContext, [{ | ||
(0, _createClass2["default"])(CLSContext, [{ | ||
key: "setContext", | ||
@@ -69,4 +73,3 @@ value: function setContext(ctx) { | ||
}]); | ||
return CLSContext; | ||
}(); |
{ | ||
"name": "zipkin-context-cls", | ||
"version": "0.19.0", | ||
"version": "0.19.2-alpha.7+86c4493", | ||
"description": "A Context API implementation that uses continuation-local-storage under the hood", | ||
@@ -16,5 +16,10 @@ "main": "lib/CLSContext.js", | ||
"dependencies": { | ||
"@babel/runtime": "^7.8.4", | ||
"cls-hooked": "^4.2.2", | ||
"continuation-local-storage": "^3.1.7" | ||
}, | ||
"gitHead": "579e12b642b7e0b486dd2b78193ec0a798e82a7a" | ||
"devDependencies": { | ||
"@babel/plugin-transform-runtime": "^7.8.3" | ||
}, | ||
"gitHead": "86c4493611a11ff4079419b6d2d019a8a9a7ec2c" | ||
} |
@@ -15,3 +15,3 @@ # zipkin-context-cls | ||
ctxImpl: new CLSContext('zipkin'), | ||
recorder, // typically Kafka or Scribe | ||
recorder, // typically HTTP or Kafka | ||
localServiceName: 'service-a' // name of this application | ||
@@ -28,4 +28,17 @@ }); | ||
This package is not suitable if your code inside the context uses promises. The context is then not properly propagated. There is work underway called [async_hooks](https://nodejs.org/api/async_hooks.html), but is at the time of this writing (node v10) in Experimental state. | ||
By default, this package is not suitable if your code inside the context uses promises, however you can enable an experimental feature for async/await support by using [cls_hooked](https://github.com/jeff-lewis/cls-hooked) library which underneath uses [async_hooks](https://nodejs.org/api/async_hooks.html). | ||
```javascript | ||
const CLSContext = require('zipkin-context-cls'); | ||
const tracer = new Tracer({ | ||
ctxImpl: new CLSContext('zipkin', true), | ||
recorder, | ||
localServiceName: 'service-a' | ||
}); | ||
``` | ||
At the time of this writing, `async_hooks` [have some performance implications](https://github.com/DataDog/dd-trace-js/issues/695) whose effect may vary depending on the node version. | ||
The underneath implementation for async_hooks may change, that is why we hide that with the opt-in parameter. | ||
## A note on the workings of CLS context | ||
@@ -32,0 +45,0 @@ |
@@ -1,6 +0,11 @@ | ||
const {createNamespace, getNamespace} = require('continuation-local-storage'); | ||
const cls = require('continuation-local-storage'); | ||
const clsHooked = require('cls-hooked'); | ||
module.exports = class CLSContext { | ||
constructor(namespace = 'zipkin') { | ||
this._session = getNamespace(namespace) || createNamespace(namespace); | ||
constructor(namespace = 'zipkin', supportAsyncAwait = false) { | ||
if (supportAsyncAwait) { | ||
this._session = clsHooked.getNamespace(namespace) || clsHooked.createNamespace(namespace); | ||
} else { | ||
this._session = cls.getNamespace(namespace) || cls.createNamespace(namespace); | ||
} | ||
const defaultContext = this._session.createContext(); | ||
@@ -7,0 +12,0 @@ this._session.enter(defaultContext); |
const CLSContext = require('../'); | ||
describe('CLSContext', () => { | ||
const namespace = 'mynamespace'; | ||
function CLSContextPerAsync(supportAsync) { | ||
it('should start with context null', () => { | ||
const ctx = new CLSContext(); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
expect(ctx.getContext()).to.equal(null); | ||
@@ -10,13 +12,14 @@ }); | ||
it('should set an inner context', () => { | ||
const ctx = new CLSContext(); | ||
ctx.letContext('foo', () => { | ||
expect(ctx.getContext()).to.equal('foo'); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
ctx.letContext('tres-leches', () => { | ||
expect(ctx.getContext()).to.equal('tres-leches'); | ||
}); | ||
ctx.setContext(null); | ||
}); | ||
it('should set an inner context with setContext', () => { | ||
const ctx = new CLSContext(); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
ctx.scoped(() => { | ||
ctx.setContext('bla'); | ||
expect(ctx.getContext()).to.equal('bla'); | ||
ctx.setContext('tiramisú'); | ||
expect(ctx.getContext()).to.equal('tiramisú'); | ||
}); | ||
@@ -27,4 +30,4 @@ expect(ctx.getContext()).to.equal(null); | ||
it('should return the inner value', () => { | ||
const ctx = new CLSContext(); | ||
const returnValue = ctx.letContext('foo', () => 123); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
const returnValue = ctx.letContext('cheesecake', () => 123); | ||
expect(returnValue).to.equal(123); | ||
@@ -34,4 +37,4 @@ }); | ||
it('should be reset after the callback', () => { | ||
const ctx = new CLSContext(); | ||
ctx.letContext('foo', () => { | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
ctx.letContext('combinado', () => { | ||
// do nothing | ||
@@ -43,8 +46,8 @@ }); | ||
it('should reset after error in callback', () => { | ||
const ctx = new CLSContext(); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
let error; | ||
try { | ||
ctx.letContext('buy-smoothie', () => { | ||
throw new Error('no smoothies. try our cake'); | ||
ctx.letContext('buy-red-velvet', () => { | ||
throw new Error('no red velvet. try our cake'); | ||
}); | ||
@@ -56,3 +59,3 @@ } catch (err) { | ||
// sanity check | ||
expect(error.message).to.eql('no smoothies. try our cake'); | ||
expect(error.message).to.eql('no red velvet. try our cake'); | ||
@@ -63,11 +66,11 @@ // context wasn't leaked | ||
it('support nested contexts', () => { | ||
const ctx = new CLSContext(); | ||
const finalReturnValue = ctx.letContext('foo', () => { | ||
expect(ctx.getContext()).to.equal('foo'); | ||
const innerReturnValue = ctx.letContext('bar', () => { | ||
expect(ctx.getContext()).to.equal('bar'); | ||
it('supports nested contexts', () => { | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
const finalReturnValue = ctx.letContext('lemon-pie', () => { | ||
expect(ctx.getContext()).to.equal('lemon-pie'); | ||
const innerReturnValue = ctx.letContext('pannacotta', () => { | ||
expect(ctx.getContext()).to.equal('pannacotta'); | ||
return 1; | ||
}); | ||
expect(ctx.getContext()).to.equal('foo'); | ||
expect(ctx.getContext()).to.equal('lemon-pie'); | ||
return innerReturnValue + 2; | ||
@@ -80,11 +83,51 @@ }); | ||
it('supports CLS contexts (setTimeout etc)', (done) => { | ||
const ctx = new CLSContext(); | ||
const ctx = new CLSContext(namespace, supportAsync); | ||
function callback() { | ||
expect(ctx.getContext()).to.equal('foo'); | ||
expect(ctx.getContext()).to.equal('brownie'); | ||
ctx.setContext(null); | ||
done(); | ||
} | ||
ctx.letContext('foo', () => { | ||
ctx.letContext('brownie', () => { | ||
setTimeout(callback, 10); | ||
}); | ||
}); | ||
} | ||
describe('CLSContext', () => { | ||
describe('without async-await support', () => { | ||
CLSContextPerAsync(false); | ||
}); | ||
describe('with async-await support', () => { | ||
CLSContextPerAsync(true); | ||
it('supports async-await contexts', async() => { | ||
const ctx = new CLSContext(namespace, true); | ||
ctx.setContext('arroz-con-leche'); | ||
async function stall(stallTime) { | ||
await new Promise(resolve => setTimeout(resolve, stallTime)); | ||
} | ||
async function getCtx() { | ||
const durationInMs = Math.random() + 0.1; | ||
await stall(durationInMs * 500); | ||
return ctx.getContext(); | ||
} | ||
async function callback() { | ||
const obtainedContext = await getCtx(); | ||
return obtainedContext; | ||
} | ||
async function fn() { | ||
const ctx1 = await ctx.letContext('budin', () => callback()); | ||
const ctx2 = await ctx.letContext('torta-helada', () => callback()); | ||
expect(ctx1).to.equal('budin'); | ||
expect(ctx2).to.equal('torta-helada'); | ||
} | ||
await fn(); // eslint-disable-line | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20519
8
199
49
3
1
1
+ Added@babel/runtime@^7.8.4
+ Addedcls-hooked@^4.2.2
+ Added@babel/runtime@7.26.0(transitive)
+ Addedasync-hook-jl@1.7.6(transitive)
+ Addedcls-hooked@4.2.2(transitive)
+ Addedregenerator-runtime@0.14.1(transitive)
+ Addedstack-chain@1.3.7(transitive)