aws-xray-sdk-core
Advanced tools
Comparing version 3.0.0-alpha.2 to 3.0.0
# Changelog for AWS X-Ray Core SDK for JavaScript | ||
<!--LATEST=3.0.0-alpha.2--> | ||
<!--LATEST=3.0.0--> | ||
<!--ENTRYINSERT--> | ||
## 3.0.0 | ||
* **BREAKING** change: Releasing all changes in 3.0.0-alpha.1 and 3.0.0-alpha.2 as stable. See below changelog entries. [#ISSUE157](https://github.com/aws/aws-xray-sdk-node/issues/157) | ||
* improvement: Deprecated support for Node 8 [#PR 273](https://github.com/aws/aws-xray-sdk-node/pull/273) | ||
* bugfix: Catch errors on requests to daemon [#ISSUE267](https://github.com/aws/aws-xray-sdk-node/issues/267) | ||
* bugfix: Correct AWS patcher TS defitnitions [#ISSUE276](https://github.com/aws/aws-xray-sdk-node/issues/276) | ||
## 3.0.0-alpha.2 | ||
@@ -5,0 +11,0 @@ * **BREAKING** change: Removed dependency on the aws-sdk, including all dependent TS definitions [PR #255](https://github.com/aws/aws-xray-sdk-node/pull/255) |
@@ -52,3 +52,3 @@ var logger = require('../../logger'); | ||
if (err) { | ||
logger.getLogger().warn('Failed to call GetSamplingRules API: ' + err); | ||
logger.getLogger().warn('Failed to retrieve sampling rules from X-Ray service:', err); | ||
} else if(newRules.length !== 0) { | ||
@@ -55,0 +55,0 @@ ruleCache.loadRules(newRules); |
@@ -21,2 +21,3 @@ var crypto = require('crypto'); | ||
samplingTargetsPath: '/SamplingTargets', | ||
logger: logger, | ||
httpClient: http, | ||
@@ -26,4 +27,5 @@ | ||
const body = '{}'; // Payload needed for GetSamplingRules POST request | ||
const options = getOptions(this.samplingRulesPath, body.length); | ||
const req = this.httpClient.request(getOptions(this.samplingRulesPath, body.length), res => { | ||
const req = this.httpClient.request(options, res => { | ||
var data = ''; | ||
@@ -43,3 +45,3 @@ res.on('data', d => { | ||
} catch (err) { | ||
callback(error); | ||
callback(err); | ||
} | ||
@@ -51,2 +53,7 @@ | ||
}); | ||
req.on('error', (err) => { | ||
this.logger.getLogger().error(`Failed to connect to X-Ray daemon at ${options.hostname}:${options.port} to get sampling rules.`); | ||
callback(err); | ||
}); | ||
@@ -59,4 +66,5 @@ req.write(body); | ||
const body = JSON.stringify(constructStatisticsDocs(rules)); | ||
const options = getOptions(this.samplingTargetsPath, body.length); | ||
const req = this.httpClient.request(getOptions(this.samplingTargetsPath, body.length), res => { | ||
const req = this.httpClient.request(options, res => { | ||
var data = ''; | ||
@@ -84,2 +92,7 @@ res.on('data', d => { | ||
}); | ||
req.on('error', (err) => { | ||
this.logger.getLogger().error(`Failed to connect to X-Ray daemon at ${options.hostname}:${options.port} to get sampling targets.`); | ||
callback(err); | ||
}); | ||
@@ -86,0 +99,0 @@ req.write(body); |
@@ -33,9 +33,6 @@ var rulePoller = require('./rule_poller'); | ||
var candidates = getCandidates(); | ||
if(!candidates || candidates.length === 0) | ||
logger.getLogger().debug('There is no sampling rule statistics to report.'); | ||
else { | ||
logger.getLogger().debug('Reporting rule statistics to get new quota.'); | ||
if(candidates && candidates.length > 0) { | ||
serviceConnector.fetchTargets(candidates, function(err, targetsMapping, ruleFreshness) { | ||
if (err) { | ||
logger.getLogger().debug('Failed to call GetSamplingTargets API: ' + err); | ||
logger.getLogger().warn('Failed to retrieve sampling targets from X-Ray service:', err); | ||
return; | ||
@@ -49,2 +46,4 @@ } | ||
} | ||
logger.getLogger().info('Successfully reported rule statistics to get new sampling quota.'); | ||
}); | ||
@@ -51,0 +50,0 @@ } |
@@ -1,13 +0,9 @@ | ||
/* The types returned from patching AWS clients is left as any because using types defined | ||
* by the aws-sdk would require us to depend on that package, which would make our bundle size unreasonable. | ||
* Instead, it is recommended to cast patched AWS clients back to their original types. | ||
/* The type accepted and returned from patching AWS clients is generic because using types defined | ||
* by the aws-sdk would require us to depend on it, which would make our bundle size too large. | ||
* | ||
* See: https://github.com/aws/aws-xray-sdk-node/issues/113 | ||
* See: https://github.com/aws/aws-xray-sdk-node/pull/255 | ||
*/ | ||
export type PatchedAWS = any; | ||
export type PatchedAWSClient = any; | ||
export function captureAWS<T>(awssdk: T): T; | ||
export function captureAWS(awssdk: any): PatchedAWS; | ||
export function captureAWSClient(service: any): PatchedAWSClient; | ||
export function captureAWSClient<T>(service: T): T; |
@@ -26,3 +26,3 @@ /** | ||
* @alias module:aws_p.captureAWS | ||
* @returns {any} - Typed as any to avoid dependency on AWS SDK. Otherwise would be AWS. | ||
* @returns {AWS} | ||
* @see https://github.com/aws/aws-sdk-js | ||
@@ -51,3 +51,3 @@ */ | ||
* @alias module:aws_p.captureAWSClient | ||
* @returns {any} - Typed as any to avoid dependency on AWS SDK. Otherwise would be AWS.Service. | ||
* @returns {AWS.Service} | ||
* @see https://github.com/aws/aws-sdk-js | ||
@@ -54,0 +54,0 @@ */ |
{ | ||
"name": "aws-xray-sdk-core", | ||
"version": "3.0.0-alpha.2", | ||
"version": "3.0.0", | ||
"description": "AWS X-Ray SDK for Javascript", | ||
@@ -12,3 +12,3 @@ "author": "Amazon Web Services", | ||
"engines": { | ||
"node": ">= 4.x" | ||
"node": ">= 10.x" | ||
}, | ||
@@ -55,3 +55,3 @@ "directories": { | ||
"repository": "https://github.com/aws/aws-xray-sdk-node/tree/master/packages/core", | ||
"gitHead": "77a4358f9e40e4666b764e2753ec55a929e09297" | ||
"gitHead": "bfbc97d88f8452a288dc6396c9cc0f9cffcf45fd" | ||
} |
358
README.md
@@ -8,28 +8,12 @@ | ||
The AWS X-Ray SDK (the SDK) automatically records information for incoming and outgoing | ||
requests and responses (via middleware). It also automatically records local data | ||
The AWS X-Ray SDK (the SDK) allows developers to instrument their web applications | ||
to automatically record information for incoming and outgoing | ||
requests and responses. It can also record local data | ||
such as function calls, time, variables (via metadata and annotations), and Amazon | ||
EC2 instance data (via plugins). Currently, only Express | ||
applications are supported for automatic capturing. See the | ||
[aws-xray-sdk-express](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) package for additional information. | ||
EC2, ECS, and Elastic Beanstalk metadata (via plugins). Currently, [Express](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) and [Restify](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/restify) | ||
applications are supported for automatic capturing via middleware. AWS Lambda functions can also be instrumented. | ||
The SDK exposes the Segment and Subsegment objects so you can create your own capturing | ||
mechanisms, but a few are supplied. | ||
These keep the current subsegment up to date in automatic mode, or propagate the current subsegment in manual mode. | ||
mechanisms, but a few are supplied. See Capturing Function Calls below. | ||
`AWSXRay.captureFunc` - Takes a function that takes a single subsegment argument. This creates a new nested subsegment and exposes it. The segment | ||
closes automatically when the function finishes executing and returns the result if any. This does not correctly | ||
time functions with asynchronous calls. Instead, use | ||
captureAsyncFunc. | ||
`AWSXRay.captureAsyncFunc` - Takes an async function that takes a single subsegment argument and returns the promise by executing the function. | ||
This creates a new nested subsegment and exposes it. | ||
The segment must be closed using subsegment.close() the asynchronous function completes successfully. | ||
`AWSXRay.captureCallbackFunc` - Takes a function to be used as a callback. Useful | ||
for capturing callback information and directly associating it to the call | ||
that generated it. This creates a new nested subsegment and exposes it by appending it onto the arguments used to call the callback. For this reason, | ||
always call your captured callbacks with the full parameter list. The subsegment closes | ||
automatically when the function finishes executing. | ||
## Setup | ||
@@ -48,15 +32,8 @@ | ||
Automatic mode is for use with the `aws-xray-sdk-express` module to support Express | ||
applications, but can be used outside of Express applications. | ||
The `aws-xray-sdk-express` module captures incoming request/response information via middleware and creates the base segment object automatically. | ||
If your application isn't using the Express middleware, you have to create a | ||
new segment, and set this on the SDK when in automatic mode. | ||
Automatic mode is designed for use with Express, Restify, and Lambda | ||
applications, but can be used outside of such applications. | ||
For more information about developing your own middleware or using automatic mode without middleware, see the [developing custom solutions | ||
using automatic mode](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/core#developing-custom-solutions-using-automatic-mode) section below. | ||
var segment = new AWSXRay.Segment(name, [optional root ID], [optional parent ID]); | ||
AWSXRay.setSegment(segment); | ||
For more information about developing your own middleware or using automatic mode without middleware, see the `developing custom solutions | ||
using automatic mode` section below. | ||
Automatic mode uses the Continuation Local Storage package and automatically tracks | ||
Automatic mode uses the `cls-hooked` package and automatically tracks | ||
the current segment or subsegment when using the built-in capture functions or any | ||
@@ -74,3 +51,3 @@ of the aws-xray-sdk modules. Using the built-in capture functions or other aws-xray-sdk modules automatically creates | ||
Manual mode requires that you pass around the segment reference. See the examples | ||
below for the different usages. | ||
in the [express package](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) for the different usages. | ||
@@ -135,3 +112,3 @@ ### Environment variables | ||
By default, when the X-Ray SDK is operating in automatic mode and attempts to find a segment in the `cls` context but | ||
By default, when the X-Ray SDK is operating in automatic mode and attempts to find a segment in the `cls-hooked` context but | ||
cannot find one, it throws a runtime error. This behavior can be undesirable when unit testing or doing experimentation. | ||
@@ -284,7 +261,44 @@ It can be changed to instead log an error either by using the `AWS_XRAY_CONTEXT_MISSING` environment variable documented above, or programatically by calling | ||
### Capturing Function Calls | ||
```ts | ||
AWSXRay.captureFunc<T>( | ||
name: string, | ||
fcn: (subsegment?: Subsegment) => T, | ||
parent?: Segment | Subsegment | ||
): T | ||
``` | ||
`AWSXRay.captureFunc` - Takes a function that takes a single subsegment argument. This creates a new nested subsegment and exposes it. The segment | ||
closes automatically when the function finishes executing and returns the result if any. This does not correctly | ||
time functions with asynchronous calls. Instead, use | ||
`captureAsyncFunc`. | ||
```ts | ||
captureAsyncFunc<T>( | ||
name: string, | ||
fcn: (subsegment?: Subsegment) => T, | ||
parent?: Segment | Subsegment | ||
): T | ||
``` | ||
`AWSXRay.captureAsyncFunc` - Takes an async function that takes a single subsegment argument and returns the promise by executing the function. | ||
This creates a new nested subsegment and exposes it. | ||
The segment must be closed using subsegment.close() the asynchronous function completes successfully. | ||
```ts | ||
captureCallbackFunc<S extends any[], T>( | ||
name: string, | ||
fcn: (...args: S) => T, | ||
parent?: Segment | Subsegment | ||
): (...args: S) => T | ||
``` | ||
`AWSXRay.captureCallbackFunc` - Takes a function to be used as a callback. Useful | ||
for capturing callback information and directly associating it to the call | ||
that generated it. This creates a new nested subsegment and exposes it by appending it onto the arguments used to call the callback. For this reason, | ||
always call your captured callbacks with the full parameter list. The subsegment closes | ||
automatically when the function finishes executing. | ||
### Developing custom solutions using automatic mode | ||
Automatic mode is for use with the aws-xray-sdk-express module to support Express | ||
applications, however it can be used outside of Express applications. | ||
If your application isn't using the Express middleware, you have to create the | ||
If your application isn't using a supported framework, you have to create the | ||
new segment and set this on the SDK. | ||
@@ -320,30 +334,16 @@ You need to create a new level of CLS, and you can do so by using the CLS namespace object. We expose this via the following. | ||
## Example code | ||
## Usage in AWS Lambda | ||
### Version capturing | ||
To understand X-Ray's integration with Lambda functions, please read the [Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html). Lambda functions are unique environments because a segment is automatically provided in function code once `Active Tracing` is enabled for a function. That segment is immutable, however all subsegment operations described below are permitted. | ||
Use the 'npm start' script to enable. | ||
By default in Lambda, the streaming threshold is set to 0 (immediate subsegment streaming), centralized sampling is disabled, automatic mode is enabled, and the daemon address is set by the Lambda runtime. | ||
### Capture all incoming HTTP requests to '/' | ||
For an example function, see [tracing node.js functions](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-tracing.html). | ||
var app = express(); | ||
## Example code | ||
//... | ||
### Version capturing | ||
var AWSXRay = require('aws-xray-sdk'); | ||
Use the 'npm start' script to enable. | ||
app.use(AWSXRay.express.openSegment('defaultName')); //required at the start of your routes | ||
app.get('/', function (req, res) { | ||
res.render('index'); | ||
}); | ||
app.use(AWSXRay.express.closeSegment()); //Required at the end of your routes / first in error handling routes | ||
### Capture all outgoing AWS requests | ||
var AWS = captureAWS(require('aws-sdk')); | ||
// Create new AWS clients as usual. | ||
### Configure AWSXRay to automatically capture EC2 instance data | ||
@@ -380,61 +380,27 @@ | ||
var newSubseg = subsegment.addNewSubsegment(name); | ||
... | ||
newSubseg.close(); | ||
// Or | ||
var subsegment = new Subsegment(name); | ||
var newSubseg = new Subsegment(name); | ||
subsegment.addSubsegment(newSubseg); | ||
... | ||
newSubseg.close(); | ||
## Automatic mode examples | ||
Automatic mode is for use with the aws-xray-sdk-express module to support Express | ||
applications, however it can be used outside of Express applications. | ||
If the Express middleware isn't being used, you have to create a root segment and | ||
set on the SDK using the following. | ||
var segment = new AWSXRay.Segment(name, [optional root ID], [optional parent ID]); | ||
AWSXRay.setSegment(segment); | ||
Only then will the segment be available for use in automatic mode and be able to be picked up by the capture functions and other aws-xray-sdk modules. | ||
### Capture all incoming HTTP requests to '/' | ||
var app = express(); | ||
//... | ||
var AWSXRay = require('aws-xray-sdk'); | ||
app.use(AWSXRay.express.openSegment('defaultName')); | ||
app.get('/', function (req, res) { | ||
res.render('index'); | ||
}); | ||
app.use(AWSXRay.express.closeSegment()); | ||
### Capture through function calls | ||
var AWSXRay = require('aws-xray-sdk'); | ||
This creates 5 nested subsegments on the root segment and captures timing data individually for each subsegment. This example assumes an automatic mode environment. | ||
app.use(AWSXRay.express.openSegment('defaultName')); | ||
captureFunc('1', function(subsegment1) { | ||
//Exposing the subsegment in the function is optional, and is listed here as an example | ||
//You can also use: | ||
//var subsegment1 = AWSXRay.getSegment(); | ||
//... | ||
//The root segment is created by the Express middleware | ||
//This creates 5 nested subsegments on the root segment | ||
//and captures timing data individually for each subsegment | ||
app.get('/', function (req, res) { | ||
captureFunc('1', function(subsegment1) { | ||
//Exposing the subsegment in the function is optional, and is listed here | ||
as an example | ||
//You can also use | ||
//var subsegment1 = AWSXRay.getSegment(); | ||
captureFunc('2', function(subsegment2) { | ||
captureFunc('3', function(subsegment3) { | ||
captureFunc('4', function(subsegment4) { | ||
captureFunc('5', function() { | ||
//exposing the subsegment is optional | ||
res.render('index'); | ||
}); | ||
captureFunc('2', function(subsegment2) { | ||
captureFunc('3', function(subsegment3) { | ||
captureFunc('4', function(subsegment4) { | ||
captureFunc('5', function() { | ||
//exposing the subsegment is optional | ||
res.render('index'); | ||
}); | ||
@@ -446,29 +412,16 @@ }); | ||
app.use(AWSXRay.express.closeSegment()); | ||
### Capture through async function calls | ||
var AWSXRay = require('aws-xray-sdk'); | ||
var host = 'samplego-env.us-east-1.elasticbeanstalk.com'; | ||
//... | ||
AWSXRay.captureAsyncFunc('send', function(subsegment) { | ||
//'subsegment' here is the newly created and exposed subsegment for the async | ||
//request, and must be closed manually (this ensures timing data is correct) | ||
app.use(AWSXRay.express.openSegment('defaultName')); | ||
app.get('/', function (req, res) { | ||
var host = 'samplego-env.us-east-1.elasticbeanstalk.com'; | ||
AWSXRay.captureAsyncFunc('send', function(subsegment) { | ||
//'subsegment' here is the newly created and exposed subsegment for the async | ||
//request, and must be closed manually (this ensures timing data is correct) | ||
sendRequest(host, function() { | ||
console.log("rendering!"); | ||
res.render('index'); | ||
subsegment.close(); | ||
}); | ||
sendRequest(host, function() { | ||
console.log("Request sent!"); | ||
subsegment.close(); | ||
}); | ||
}); | ||
app.use(AWSXRay.express.closeSegment()); | ||
function sendRequest(host, cb) { | ||
@@ -495,2 +448,8 @@ var options = { | ||
### Capture all outgoing AWS requests | ||
var AWS = captureAWS(require('aws-sdk')); | ||
// Create new AWS clients as usual. | ||
### Capture outgoing AWS requests on a single client | ||
@@ -504,13 +463,15 @@ | ||
### Capture outgoing AWS requests on every AWS SDK client | ||
### Capture all outgoing HTTP and HTTPS requests | ||
var aws = AWSXRay.captureAWS(require('aws-sdk')); | ||
AWSXRay.captureHTTPsGlobal(require('http')); | ||
AWSXRay.captureHTTPsGlobal(require('https')); | ||
//Create new clients as usual | ||
//Be sure any outgoing calls that are dependent on another async | ||
//function are wrapped with captureAsyncFunc, or duplicate segments might leak | ||
// Requests with this http client, and any other http/https client including | ||
// those used by third party modules, will now be traced | ||
var http = require('http'); | ||
### Capture all outgoing HTTP/S requests | ||
### Capture outgoing HTTP/S requests with a traced client | ||
var tracedHttp = AWSXRay.captureHTTPs(require('http')); //returns a copy of the http module that is patched, can patch https as well. | ||
//returns a copy of the http module that is patched, can patch https as well | ||
var tracedHttp = AWSXRay.captureHTTPs(require('http')); | ||
@@ -535,122 +496,1 @@ var options = { | ||
const AxiosWithXray = require('axios'); | ||
## Manual mode examples | ||
Enable manual mode: | ||
AWSXRay.enableManualMode(); | ||
### Capture through function calls | ||
var AWSXRay = require('aws-xray-sdk'); | ||
app.use(AWSXRay.express.openSegment('defaultName')); | ||
//... | ||
//The root segment is created by the Express middleware | ||
//This creates 5 nested subsegments on the root segment | ||
//and captures timing data individually for each subsegment | ||
app.get('/', function (req, res) { | ||
var segment = req.segment; | ||
captureFunc('1', function(subsegment1) { | ||
captureFunc('2', function(subsegment2) { | ||
captureFunc('3', function(subsegment3) { | ||
captureFunc('4', function(subsegment4) { | ||
captureFunc('5', function() { | ||
//subsegment need not be exposed here since we're not doing anything with it | ||
res.render('index'); | ||
}, subsegment4); | ||
}, subsegment3); | ||
}, subsegment2); | ||
}, subsegment1); | ||
}, segment); | ||
}); | ||
app.use(AWSXRay.express.closeSegment()); | ||
### Capture through async function calls | ||
var AWSXRay = require('aws-xray-sdk'); | ||
AWSXRay.enableManualMode(); | ||
app.use(AWSXRay.express.openSegment('defaultName')); | ||
app.get('/', function (req, res) { | ||
var segment = req.segment; | ||
var host = 'samplego-env.us-east-1.elasticbeanstalk.com'; | ||
AWSXRay.captureAsyncFunc('send', function(subsegment) { | ||
sendRequest(host, function() { | ||
console.log("rendering!"); | ||
res.render('index'); | ||
subsegment.close(); | ||
}, subsegment); | ||
}, segment); | ||
}); | ||
app.use(AWSXRay.express.closeSegment()); | ||
function sendRequest(host, cb, subsegment) { | ||
var options = { | ||
host: host, | ||
path: '/', | ||
XRaySegment: subsegment //required 'XRaySegment' param | ||
}; | ||
var callback = function(response) { | ||
var str = ''; | ||
//The whole response has been received, so we just print it out here | ||
//Another chunk of data has been received, so append it to `str` | ||
response.on('data', function (chunk) { | ||
str += chunk; | ||
}); | ||
response.on('end', function () { | ||
cb(); | ||
}); | ||
} | ||
http.request(options, callback).end(); | ||
}; | ||
### Capture outgoing AWS requests on a single client | ||
var s3 = AWSXRay.captureAWSClient(new AWS.S3()); | ||
var params = { | ||
Bucket: bucketName, | ||
Key: keyName, | ||
Body: 'Hello!', | ||
XRaySegment: subsegment //required 'XRaySegment' param | ||
}; | ||
s3.putObject(params, function(err, data) { | ||
... | ||
}); | ||
### Capture all outgoing AWS requests | ||
var AWS = captureAWS(require('aws-sdk')); | ||
//Create new clients as usual | ||
//Be sure any outgoing calls that are dependent on another async | ||
//function are wrapped, or duplicate segments might leak | ||
### Capture all outgoing HTTP/S requests | ||
var tracedHttp = AWSXRay.captureHTTPs(require('http')); //returns a copy of the http module that is patched, can patch https as well. | ||
... | ||
//Include sub/segment reference in options as 'XRaySegment' | ||
var options = { | ||
... | ||
XRaySegment: subsegment //required 'XRaySegment' param | ||
} | ||
tracedHttp.request(options, callback).end(); |
var assert = require('chai').assert; | ||
var expect = require('chai').expect; | ||
var chai = require('chai'); | ||
@@ -36,7 +37,10 @@ var sinon = require('sinon'); | ||
function generateMockClient(samplingRules) { | ||
var res = buildFakeResponse(); | ||
var req = buildFakeRequest(res, samplingRules); | ||
return buildFakeHttpClient(req, res); | ||
}; | ||
function buildFakeHttpClient(req, res) { | ||
return { | ||
request: function(options, callback) { | ||
var res = buildFakeResponse(); | ||
var req = buildFakeRequest(res, samplingRules); | ||
callback(res); | ||
@@ -191,3 +195,4 @@ return req; | ||
write: () => {}, | ||
end: () => {} | ||
end: () => {}, | ||
on: (event, func) => {} | ||
}); | ||
@@ -227,2 +232,24 @@ }); | ||
}); | ||
describe('HttpException', function() { | ||
var logging; | ||
beforeEach(function() { | ||
var path = '../../../lib/logger'; | ||
delete require.cache[require.resolve(path)]; | ||
logging = require(path); | ||
}); | ||
it('should log an error when the HTTP request fails', function() { | ||
let response = buildFakeResponse(); | ||
let request = buildFakeRequest(response, []); | ||
sandbox.spy(ServiceConnector.logger, 'getLogger'); | ||
sandbox.stub(ServiceConnector, 'httpClient') | ||
.value(buildFakeHttpClient(request, response)); | ||
ServiceConnector.fetchSamplingRules(function() {}); | ||
request.emit('error', new Error('Fake ECONNREFUSED error')); | ||
expect(ServiceConnector.logger.getLogger).to.be.calledOnce; | ||
}); | ||
}); | ||
}); |
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
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
9071
1
382880
486
70