aws-xray-sdk-core
Advanced tools
Comparing version 3.0.0-alpha.1 to 3.0.0-alpha.2
# Changelog for AWS X-Ray Core SDK for JavaScript | ||
<!--LATEST=3.0.0-alpha.1--> | ||
<!--LATEST=3.0.0-alpha.2--> | ||
<!--ENTRYINSERT--> | ||
## 3.0.0-alpha.2 | ||
* **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) | ||
* improvement: Support Node 10 syntax for `http.request` [PR #247](https://github.com/aws/aws-xray-sdk-node/pull/247) | ||
* bugfix: Disable centralized sampling in Lambda [#ISSUE217](https://github.com/aws/aws-xray-sdk-node/issues/217) | ||
* bugfix: Allow lerna to bump version number of top-level package.json [PR #254](https://github.com/aws/aws-xray-sdk-node/pull/254) | ||
* bugfix: Add missing subsegment fields [PR #249](https://github.com/aws/aws-xray-sdk-node/pull/249) | ||
* bugfix: Remove query string from URL field [#ISSUE246](https://github.com/aws/aws-xray-sdk-node/issues/246) | ||
* bugfix: `unref` sockets in `segment_emitter.js` [#ISSUE241](https://github.com/aws/aws-xray-sdk-node/issues/241) | ||
* bugfix: Swap out `continuation-local-storage` types for `cls-hooked` types [PR #242](https://github.com/aws/aws-xray-sdk-node/pull/242) | ||
* bugfix: Stopped throwing context missing errors for Centralized sampling with `captureHTTPsGlobal` [#ISSUE161](https://github.com/aws/aws-xray-sdk-node/issues/161) | ||
* bugfix: Fixed `.setDaemonAddress` API not propagating address to `service_connector` [#ISSUE233](https://github.com/aws/aws-xray-sdk-node/issues/233) | ||
* bugfix: Removed TS race condition involving AWS SDK type definition [#ISSUE253](https://github.com/aws/aws-xray-sdk-node/issues/253) | ||
## 3.0.0-alpha.1 | ||
@@ -5,0 +19,0 @@ * **BREAKING** change: Merged `2.x` branch into `master`, breaking node v4 [PR #226](https://github.com/aws/aws-xray-sdk-node/pull/226) |
@@ -1,2 +0,2 @@ | ||
import { Namespace } from 'continuation-local-storage'; | ||
import { Namespace } from 'cls-hooked'; | ||
import Segment = require('./segments/segment'); | ||
@@ -3,0 +3,0 @@ import Subsegment = require('./segments/attributes/subsegment'); |
var contextUtils = require('../context_utils'); | ||
var mwUtils = require('../middleware/mw_utils'); | ||
var LambdaUtils = require('../utils').LambdaUtils; | ||
@@ -28,2 +29,11 @@ var Segment = require('../segments/segment'); | ||
/** | ||
* Disabling all centralized sampling in Lambda environments. The sampling decisions would be | ||
* uselessly applied to the facade segment, and the sampling pollers were causing errors. | ||
* | ||
* See: https://github.com/aws/aws-xray-sdk-node/issues/217 | ||
*/ | ||
logger.getLogger().info('Disabling centralized sampling in Lambda environment.'); | ||
mwUtils.disableCentralizedSampling(); | ||
var namespace = contextUtils.getNamespace(); | ||
@@ -30,0 +40,0 @@ namespace.enter(namespace.createContext()); |
@@ -40,11 +40,11 @@ var validLogLevels = [ 'debug', 'info', 'warn', 'error', 'silent' ]; | ||
var tzo = -date.getTimezoneOffset(), // Negate to make this tzo = local - UTC | ||
dif = tzo >= 0 ? '+' : '-', | ||
pad = function(num) { | ||
var norm = Math.floor(Math.abs(num)); | ||
return (norm < 10 ? '0' : '') + norm; | ||
}; | ||
dif = tzo >= 0 ? '+' : '-', | ||
pad = function(num) { | ||
var norm = Math.floor(Math.abs(num)); | ||
return (norm < 10 ? '0' : '') + norm; | ||
}; | ||
return new Date(date.getTime() + (tzo * 60 * 1000)).toISOString() | ||
.replace(/T/, ' ') | ||
.replace(/Z/, ' ') + | ||
.replace(/T/, ' ') | ||
.replace(/Z/, ' ') + | ||
dif + pad(tzo / 60) + | ||
@@ -51,0 +51,0 @@ ':' + pad(tzo % 60); |
@@ -39,3 +39,3 @@ var logger = require('../../logger'); | ||
} catch (e) { | ||
logger.getLogger().debug('Encountered unexpected exception when fetching sampling rules: ' + e); | ||
logger.getLogger().warn('Encountered unexpected exception when fetching sampling rules: ' + e); | ||
} | ||
@@ -51,4 +51,6 @@ }; | ||
// successfully fetched. | ||
ServiceConnector.fetchSamplingRules(function(newRules) { | ||
if(newRules.length !== 0) { | ||
ServiceConnector.fetchSamplingRules(function(err, newRules) { | ||
if (err) { | ||
logger.getLogger().warn('Failed to call GetSamplingRules API: ' + err); | ||
} else if(newRules.length !== 0) { | ||
ruleCache.loadRules(newRules); | ||
@@ -55,0 +57,0 @@ ruleCache.timestamp(now); |
var crypto = require('crypto'); | ||
var AWS = require('aws-sdk/global'); | ||
var Xray = require('aws-sdk/clients/xray'); | ||
var logger = require('../../logger'); | ||
@@ -8,2 +6,3 @@ var SamplingRule = require('./sampling_rule'); | ||
const util = require('util'); | ||
const http = require('http'); | ||
@@ -21,29 +20,65 @@ | ||
clientId: crypto.randomBytes(12).toString('hex'), | ||
client: new Xray({endpoint: util.format('http://%s:%d', DaemonConfig.tcp_ip, DaemonConfig.tcp_port)}), | ||
samplingRulesPath: '/GetSamplingRules', | ||
samplingTargetsPath: '/SamplingTargets', | ||
httpClient: http, | ||
fetchSamplingRules: function fetchSamplingRules(callback) { | ||
const body = '{}'; // Payload needed for GetSamplingRules POST request | ||
const req = this.httpClient.request(getOptions(this.samplingRulesPath, body.length), res => { | ||
var data = ''; | ||
res.on('data', d => { | ||
data += d; | ||
}); | ||
res.on('error', error => { | ||
callback(error); | ||
}); | ||
res.on('end', () => { | ||
var dataObj; | ||
try { | ||
dataObj = JSON.parse(data); | ||
} catch (err) { | ||
callback(error); | ||
} | ||
this.client.makeUnauthenticatedRequest('getSamplingRules', null, function(err, data) { | ||
if(err) | ||
logger.getLogger().warn(err.stack); | ||
else { | ||
var newRules = assembleRules(data); | ||
callback(newRules); | ||
} | ||
var newRules = assembleRules(dataObj); | ||
callback(null, newRules); | ||
}); | ||
}); | ||
req.write(body); | ||
req.end(); | ||
}, | ||
fetchTargets: function fetchTargets(rules, callback) { | ||
var params = constructStatisticsDocs(rules); | ||
const body = JSON.stringify(constructStatisticsDocs(rules)); | ||
const req = this.httpClient.request(getOptions(this.samplingTargetsPath, body.length), res => { | ||
var data = ''; | ||
res.on('data', d => { | ||
data += d; | ||
}); | ||
res.on('error', error => { | ||
callback(error) | ||
}); | ||
res.on('end', () => { | ||
var dataObj; | ||
try { | ||
dataObj = JSON.parse(data); | ||
} catch (err) { | ||
callback(err); | ||
} | ||
this.client.makeUnauthenticatedRequest('getSamplingTargets', params, function(err, data) { | ||
if(err) { | ||
logger.getLogger().warn(err.stack); | ||
} | ||
else{ | ||
var targetsMapping = assembleTargets(data); | ||
var ruleFreshness = dateToEpoch(data['LastRuleModification']); | ||
callback(targetsMapping, ruleFreshness); | ||
} | ||
var targetsMapping = assembleTargets(dataObj); | ||
var ruleFreshness = dateToEpoch(dataObj['LastRuleModification']); | ||
callback(null, targetsMapping, ruleFreshness); | ||
}); | ||
}); | ||
req.write(body); | ||
req.end(); | ||
} | ||
@@ -128,6 +163,18 @@ }; | ||
ServiceConnector.client.setupRequestListeners = function setupRequestListeners(request) { | ||
request.removeListener('validate', AWS.EventListeners.Core.VALIDATE_REGION); | ||
var getOptions = function getOptions(path, contentLength) { | ||
const options = { | ||
hostname: DaemonConfig.tcp_ip, | ||
port: DaemonConfig.tcp_port, | ||
method: 'POST', | ||
path: path, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Content-Length': contentLength, | ||
'Host': util.format('%s:%d', DaemonConfig.tcp_ip, DaemonConfig.tcp_port) | ||
} | ||
}; | ||
return options; | ||
}; | ||
module.exports = ServiceConnector; |
@@ -27,3 +27,3 @@ var rulePoller = require('./rule_poller'); | ||
} catch (e) { | ||
logger.getLogger().debug('Encountered unexpected exception when fetching sampling targets: ' + e); | ||
logger.getLogger().warn('Encountered unexpected exception when fetching sampling targets: ' + e); | ||
} | ||
@@ -38,3 +38,8 @@ }; | ||
logger.getLogger().debug('Reporting rule statistics to get new quota.'); | ||
serviceConnector.fetchTargets(candidates, function(targetsMapping, ruleFreshness) { | ||
serviceConnector.fetchTargets(candidates, function(err, targetsMapping, ruleFreshness) { | ||
if (err) { | ||
logger.getLogger().debug('Failed to call GetSamplingTargets API: ' + err); | ||
return; | ||
} | ||
ruleCache.loadTargets(targetsMapping); | ||
@@ -41,0 +46,0 @@ if(ruleFreshness > ruleCache.getLastUpdated()) { |
@@ -1,38 +0,13 @@ | ||
import * as AWS from 'aws-sdk'; | ||
import Segment = require('../segments/segment'); | ||
import Subsegment = require('../segments/attributes/subsegment'); | ||
/* 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. | ||
* | ||
* See: https://github.com/aws/aws-xray-sdk-node/issues/113 | ||
*/ | ||
export type Callback<D> = (err: AWS.AWSError | undefined, data: D) => void; | ||
export type PatchedAWS = any; | ||
export type PatchedAWSClient = any; | ||
export interface AWSRequestMethod<P, D> { | ||
(params: P, callback?: Callback<D>): AWS.Request<D, AWS.AWSError>; | ||
(callback?: Callback<D>): AWS.Request<D, AWS.AWSError>; | ||
} | ||
export function captureAWS(awssdk: any): PatchedAWS; | ||
export type PatchedAWSRequestMethod<P, D> = AWSRequestMethod<P & { XRaySegment?: Segment | Subsegment }, D>; | ||
export type PatchedAWSClient<T extends AWS.Service> = { | ||
[K in keyof T]: T[K] extends AWSRequestMethod<infer P, infer D> | ||
? PatchedAWSRequestMethod<P, D> | ||
: T[K] | ||
}; | ||
export interface AWSClientConstructor<P, T extends typeof AWS.Service> { | ||
new(params?: P): InstanceType<T>; | ||
} | ||
export interface PatchedAWSClientConstructor<P, T extends typeof AWS.Service> { | ||
new(params?: P): PatchedAWSClient<InstanceType<T>>; | ||
} | ||
export type PatchedAWS<T = typeof AWS> = { | ||
[K in keyof T]: T[K] extends typeof AWS.Service | ||
? (T[K] extends AWSClientConstructor<infer P, T[K]> | ||
? PatchedAWSClientConstructor<P, T[K]> | ||
: T[K]) | ||
: T[K]; | ||
}; | ||
export function captureAWS(awssdk: typeof AWS): PatchedAWS; | ||
export function captureAWSClient<T extends AWS.Service>(service: T): PatchedAWSClient<T>; | ||
export function captureAWSClient(service: any): PatchedAWSClient; |
@@ -13,3 +13,2 @@ /** | ||
var logger = require('../logger'); | ||
var ServiceConnector = require('../middleware/sampling/service_connector'); | ||
@@ -28,3 +27,3 @@ var minVersion = '2.7.15'; | ||
* @alias module:aws_p.captureAWS | ||
* @returns {AWS} | ||
* @returns {any} - Typed as any to avoid dependency on AWS SDK. Otherwise would be AWS. | ||
* @see https://github.com/aws/aws-sdk-js | ||
@@ -53,3 +52,3 @@ */ | ||
* @alias module:aws_p.captureAWSClient | ||
* @returns {AWS.Service} | ||
* @returns {any} - Typed as any to avoid dependency on AWS SDK. Otherwise would be AWS.Service. | ||
* @see https://github.com/aws/aws-sdk-js | ||
@@ -64,7 +63,2 @@ */ | ||
function captureAWSRequest(req) { | ||
// short-circuit if the client is the sampling poller | ||
if (req.service === ServiceConnector.client) { | ||
return req; | ||
} | ||
var parent = contextUtils.resolveSegment(contextUtils.resolveManualSegmentParams(req.params)); | ||
@@ -71,0 +65,0 @@ |
@@ -12,2 +12,4 @@ /** | ||
var contextUtils = require('../context_utils'); | ||
var DaemonConfig = require('../daemon_config'); | ||
var ServiceConnector = require('../middleware/sampling/service_connector'); | ||
var Utils = require('../utils'); | ||
@@ -58,7 +60,32 @@ | ||
function enableCapture(module, downstreamXRayEnabled) { | ||
function captureOutgoingHTTPs(baseFunc, options, callback) { | ||
if (!options || (options.headers && (options.headers['X-Amzn-Trace-Id']))) { | ||
return baseFunc(options, callback); | ||
function captureOutgoingHTTPs(baseFunc, ...args) { | ||
let options; | ||
let callback; | ||
let hasUrl; | ||
let urlObj; | ||
let arg0 = args[0]; | ||
if (typeof args[1] === 'object') { | ||
hasUrl = true; | ||
urlObj = typeof arg0 === 'string' ? url.parse(arg0) : arg0; | ||
options = args[1], | ||
callback = args[2]; | ||
} else { | ||
hasUrl = false; | ||
options = arg0; | ||
callback = args[1]; | ||
} | ||
// Short circuit if the HTTP request has no options, is already being captured, | ||
// or represents a centralized sampling request to the daemon | ||
if (!options || | ||
(options.headers && (options.headers['X-Amzn-Trace-Id'])) || | ||
(options.hostname == DaemonConfig.tcp_ip && | ||
options.port == DaemonConfig.tcp_port && | ||
(options.path == ServiceConnector.samplingRulesPath || | ||
options.path == ServiceConnector.samplingTargetsPath))) | ||
{ | ||
return baseFunc(...args); | ||
} | ||
if (typeof options === 'string') { | ||
@@ -68,4 +95,8 @@ options = url.parse(options); | ||
if (!hasUrl) { | ||
urlObj = options; | ||
} | ||
var parent = contextUtils.resolveSegment(contextUtils.resolveManualSegmentParams(options)); | ||
var hostname = options.hostname || options.host || 'Unknown host'; | ||
var hostname = options.hostname || options.host || urlObj.hostname || urlObj.host || 'Unknown host'; | ||
@@ -75,3 +106,3 @@ if (!parent) { | ||
output = options.method ? (output + ', method: ' + options.method) : output; | ||
output += ', path: ' + options.path + ' ]'; | ||
output += ', path: ' + Utils.stripQueryStringFromPath(options.path || urlObj.path) + ' ]'; | ||
@@ -86,3 +117,4 @@ if (!contextUtils.isAutomaticMode()) { | ||
return baseFunc(options, callback); | ||
// Options are not modified, only parsed for logging. We can pass in the original arguments. | ||
return baseFunc(...args); | ||
} | ||
@@ -121,3 +153,3 @@ | ||
var req = baseFunc(optionsCopy, function(res) { | ||
var req = baseFunc(...(hasUrl ? [arg0, optionsCopy] : [options]), function(res) { | ||
res.on('end', function() { | ||
@@ -158,9 +190,9 @@ if (res.statusCode === 429) | ||
module.__request = module.request; | ||
module.request = function captureHTTPsRequest(options, callback) { | ||
return captureOutgoingHTTPs(module.__request, options, callback); | ||
module.request = function captureHTTPsRequest(...args) { | ||
return captureOutgoingHTTPs(module.__request, ...args); | ||
}; | ||
module.__get = module.get; | ||
module.get = function captureHTTPsGet(options, callback) { | ||
return captureOutgoingHTTPs(module.__get, options, callback); | ||
module.get = function captureHTTPsGet(...args) { | ||
return captureOutgoingHTTPs(module.__get, ...args); | ||
}; | ||
@@ -167,0 +199,0 @@ } |
@@ -125,3 +125,3 @@ var dgram = require('dgram'); | ||
} else { | ||
this.socket = dgram.createSocket('udp4'); | ||
this.socket = dgram.createSocket('udp4').unref(); | ||
} | ||
@@ -192,5 +192,2 @@ } | ||
if (SegmentEmitter.socket && (typeof SegmentEmitter.socket.unref === 'function')) | ||
SegmentEmitter.socket.unref(); | ||
module.exports = SegmentEmitter; |
@@ -1,5 +0,3 @@ | ||
import * as AWS from 'aws-sdk'; | ||
declare class Aws { | ||
constructor(res: AWS.Response<any, any>, serviceName: string); | ||
constructor(res: any, serviceName: string); | ||
@@ -6,0 +4,0 @@ addData(data: any): void; |
@@ -10,3 +10,3 @@ var CallCapturer = require('../../patchers/call_capturer.js'); | ||
* @constructor | ||
* @param {AWS.Response} res - The response object from the AWS call. | ||
* @param {any} res - The response object from the AWS call. Typed as any to avoid AWS SDK dependency. Otherwise would be AWS.Response. | ||
* @param {string} serviceName - The service name of the AWS client. | ||
@@ -13,0 +13,0 @@ * @see https://github.com/aws/aws-sdk-js/blob/master/lib/response.js |
@@ -0,1 +1,3 @@ | ||
var { stripQueryStringFromPath } = require('../../utils'); | ||
/** | ||
@@ -15,3 +17,3 @@ * Represents an outgoing HTTP/HTTPS call. | ||
this.request = { | ||
url: (req.agent.protocol + '//' + req.getHeader('host') + req.path) || '', | ||
url: (req.agent.protocol + '//' + req.getHeader('host') + stripQueryStringFromPath(req.path)) || '', | ||
method: req.method || '', | ||
@@ -18,0 +20,0 @@ }; |
@@ -8,2 +8,3 @@ import * as http from 'http'; | ||
in_progress?: boolean; | ||
subsegments?: Array<Subsegment>; | ||
@@ -10,0 +11,0 @@ constructor(name: string); |
@@ -12,2 +12,3 @@ import Subsegment = require('./attributes/subsegment'); | ||
origin?: string; | ||
subsegments?: Array<Subsegment>; | ||
@@ -14,0 +15,0 @@ constructor(name: string, rootId?: string | null, parentId?: string | null); |
@@ -95,3 +95,3 @@ var crypto = require('crypto'); | ||
this.user = user; | ||
} | ||
}; | ||
@@ -98,0 +98,0 @@ /** |
@@ -5,2 +5,4 @@ import Segment = require('./segments/segment'); | ||
export function stripQueryStringFromPath(path: string): string; | ||
export function wildcardMatch(pattern: string, text: string): boolean; | ||
@@ -7,0 +9,0 @@ |
@@ -25,2 +25,19 @@ /** | ||
/** | ||
* Removes the query string parameters from a given http request path | ||
* as it may contain sensitive information | ||
* | ||
* Related issue: https://github.com/aws/aws-xray-sdk-node/issues/246 | ||
* | ||
* Node documentation: https://nodejs.org/api/http.html#http_http_request_url_options_callback | ||
* | ||
* @param {string} path - options.path in a http.request callback | ||
* @returns [string] - removes query string element from path | ||
* @alias module:utils.stripQueryStringFromPath | ||
*/ | ||
stripQueryStringFromPath: function stripQueryStringFromPath(path) { | ||
return path.split('?')[0]; | ||
}, | ||
/** | ||
* Performs a case-insensitive wildcard match against two strings. This method works with pseduo-regex chars; specifically ? and * are supported. | ||
@@ -27,0 +44,0 @@ * An asterisk (*) represents any combination of characters |
{ | ||
"name": "aws-xray-sdk-core", | ||
"version": "3.0.0-alpha.1", | ||
"version": "3.0.0-alpha.2", | ||
"description": "AWS X-Ray SDK for Javascript", | ||
@@ -18,5 +18,4 @@ "author": "Amazon Web Services", | ||
"dependencies": { | ||
"@types/continuation-local-storage": "*", | ||
"@types/cls-hooked": "*", | ||
"atomic-batcher": "^1.0.2", | ||
"aws-sdk": "^2.304.0", | ||
"cls-hooked": "^4.2.2", | ||
@@ -56,3 +55,3 @@ "pkginfo": "^0.4.0", | ||
"repository": "https://github.com/aws/aws-xray-sdk-node/tree/master/packages/core", | ||
"gitHead": "f6e7c2e311dda848aa3915b9c0e0ad2d714745fa" | ||
"gitHead": "77a4358f9e40e4666b764e2753ec55a929e09297" | ||
} |
@@ -307,3 +307,3 @@ | ||
### Capture subsegmenets within chained native Promise using automatic mode | ||
### Capture subsegments within chained native Promise using automatic mode | ||
@@ -314,3 +314,3 @@ If you have chained native Promise and you have subsegments generated within those promises, you should consider to run the following code to patch the behavior of CLS on binding X-Ray context to Promise. | ||
This will solve the issue where the subsegments within a Promise chain are attached to wrong segments or nested instead of being siblings. For more details on the discussion please see this [PR](https://github.com/aws/aws-xray-sdk-node/pull/11). | ||
This will solve the issue where the subsegments within a Promise chain are attached to wrong segments or nested instead of being siblings. For more details on the discussion please see this [PR](https://github.com/aws/aws-xray-sdk-node/pull/11). See the "Capture all outgoing Axios requests" section for full sample code. | ||
@@ -519,2 +519,11 @@ ## Example code | ||
### Capture all outgoing Axios requests | ||
This sample code works with any promise-based HTTP client. | ||
const AWSXRay = require('aws-xray-sdk'); | ||
AWSXRay.captureHTTPsGlobal(require('http')); | ||
AWSXRay.capturePromise(); | ||
const AxiosWithXray = require('axios'); | ||
## Manual mode examples | ||
@@ -521,0 +530,0 @@ |
@@ -1,4 +0,2 @@ | ||
import * as AWS from 'aws-sdk'; | ||
import { AWSError } from 'aws-sdk'; | ||
import { PromiseResult } from 'aws-sdk/lib/request'; | ||
import { Namespace } from 'cls-hooked'; | ||
import * as http from 'http'; | ||
@@ -69,20 +67,2 @@ import * as https from 'https'; | ||
const aws = AWSXRay.captureAWS(AWS); | ||
const sqs = new aws.SQS(); | ||
const queues = sqs.listQueues({ | ||
QueueNamePrefix: 'test', | ||
XRaySegment: segment | ||
}); | ||
expectType<AWS.Request<AWS.SQS.ListQueuesResult, AWSError>>(queues); | ||
const s3 = AWSXRay.captureAWSClient(new AWS.S3()); | ||
async function main() { | ||
const objects = await s3.listObjectsV2({ | ||
Bucket: 'test', | ||
XRaySegment: segment | ||
}).promise(); | ||
expectType<PromiseResult<AWS.S3.ListObjectsV2Output, AWSError>>(objects); | ||
} | ||
expectType<typeof http>(AWSXRay.captureHTTPs(http, true)); | ||
@@ -152,3 +132,3 @@ expectType<typeof https>(AWSXRay.captureHTTPs(https, true)); | ||
expectType<string>(AWSXRay.getNamespace().name); | ||
expectType<Namespace>(AWSXRay.getNamespace()); | ||
expectType<AWSXRay.Segment | AWSXRay.Subsegment | undefined>(AWSXRay.resolveSegment(segment)); | ||
@@ -155,0 +135,0 @@ expectType<AWSXRay.Segment | AWSXRay.Subsegment | undefined>(AWSXRay.resolveSegment(undefined)); |
@@ -9,2 +9,3 @@ var assert = require('chai').assert; | ||
var contextUtils = require('../../../lib/context_utils'); | ||
var mwUtils = require('../../../lib/middleware/mw_utils'); | ||
var Lambda = require('../../../lib/env/aws_lambda'); | ||
@@ -48,2 +49,3 @@ var LambdaUtils = require('../../../lib/utils').LambdaUtils; | ||
disableReusableSocketStub = sandbox.stub(SegmentEmitter, 'disableReusableSocket'); | ||
disableCentralizedSamplingStub = sandbox.stub(mwUtils, 'disableCentralizedSampling'); | ||
validateStub = sandbox.stub(LambdaUtils, 'validTraceData').returns(true); | ||
@@ -63,2 +65,7 @@ populateStub = sandbox.stub(LambdaUtils, 'populateTraceData').returns(true); | ||
it('should disable centralized sampling', function() { | ||
Lambda.init(); | ||
disableCentralizedSamplingStub.should.have.been.calledOnce; | ||
}); | ||
it('should override the default streaming threshold', function() { | ||
@@ -65,0 +72,0 @@ Lambda.init(); |
@@ -81,2 +81,4 @@ var assert = require('chai').assert; | ||
var traceId = '1-57fbe041-2c7ad569f5d6ff149137be86'; | ||
const DEFAULT_DAEMON_ADDRESS = '127.0.0.1'; | ||
const DEFAULT_DAEMON_PORT = 2000; | ||
@@ -116,3 +118,4 @@ beforeEach(function() { | ||
httpClient = { request: function(options, callback) { | ||
httpClient = { request: function(...args) { | ||
const callback = args[typeof args[1] === 'object' ? 2 : 1]; | ||
callback(fakeResponse); | ||
@@ -185,2 +188,13 @@ return fakeRequest; | ||
if (process.version.startsWith('v') && process.version >= 'v10') { | ||
it('should inject the tracing headers into the options if a URL is also provided', function() { | ||
capturedHttp.request(`http://${httpOptions.host}${httpOptions.path}`, httpOptions); | ||
// example: 'Root=1-59138384-82ff54d5ba9282f0c680adb3;Parent=53af362e4e4efeb8;Sampled=1' | ||
var xAmznTraceId = new RegExp('^Root=' + traceId + ';Parent=([a-f0-9]{16});Sampled=1$'); | ||
var options = requestSpy.firstCall.args[1]; | ||
assert.match(options.headers['X-Amzn-Trace-Id'], xAmznTraceId); | ||
}); | ||
} | ||
it('should return the request object', function() { | ||
@@ -190,2 +204,26 @@ var request = capturedHttp.request(httpOptions); | ||
}); | ||
it('should not add header to get sampling rules calls', function() { | ||
var options = { | ||
hostname: DEFAULT_DAEMON_ADDRESS, | ||
port: DEFAULT_DAEMON_PORT, | ||
path: '/GetSamplingRules' | ||
}; | ||
capturedHttp.request(options, (res) => {}); | ||
sinon.assert.notCalled(newSubsegmentStub); | ||
}); | ||
it('should not create subsegment for sampling targets calls', function() { | ||
var options = { | ||
hostname: DEFAULT_DAEMON_ADDRESS, | ||
port: DEFAULT_DAEMON_PORT, | ||
path: '/SamplingTargets' | ||
}; | ||
capturedHttp.request(options, (res) => {}); | ||
sinon.assert.notCalled(newSubsegmentStub); | ||
}); | ||
}); | ||
@@ -192,0 +230,0 @@ |
@@ -5,3 +5,5 @@ var assert = require('chai').assert; | ||
var DaemonConfig = require('../../../lib/daemon_config'); | ||
var ServiceConnector = require('../../../lib/middleware/sampling/service_connector'); | ||
var TestEmitter = require('../test_utils').TestEmitter; | ||
@@ -11,12 +13,36 @@ chai.should(); | ||
function buildFakeResponse() { | ||
var response = new TestEmitter(); | ||
return response; | ||
}; | ||
function buildFakeRequest(res, rules) { | ||
var rulesObj = { | ||
'SamplingRuleRecords': rules, | ||
'NextToken': null | ||
}; | ||
var request = new TestEmitter(); | ||
request.method = 'GET'; | ||
request.url = '/'; | ||
request.connection = { remoteAddress: 'myhost' }; | ||
request.write = () => {}; | ||
request.end = () => { | ||
res.emit('data', JSON.stringify(rulesObj)); | ||
res.emit('end'); | ||
}; | ||
return request; | ||
}; | ||
function generateMockClient(samplingRules) { | ||
return { | ||
makeUnauthenticatedRequest: function(_, _, callback) { | ||
callback(null, { | ||
'SamplingRuleRecords': samplingRules, | ||
'NextToken': null | ||
}); | ||
request: function(options, callback) { | ||
var res = buildFakeResponse(); | ||
var req = buildFakeRequest(res, samplingRules); | ||
callback(res); | ||
return req; | ||
} | ||
}; | ||
} | ||
}; | ||
@@ -94,3 +120,3 @@ describe('ServiceConnector', function() { | ||
it('filters invalid rules', function(done) { | ||
sandbox.stub(ServiceConnector, 'client').value(generateMockClient([ | ||
sandbox.stub(ServiceConnector, 'httpClient').value(generateMockClient([ | ||
noSamplingRule, | ||
@@ -101,3 +127,3 @@ invalidRule, | ||
ServiceConnector.fetchSamplingRules(function(rules) { | ||
ServiceConnector.fetchSamplingRules(function(_, rules) { | ||
// should contain 2 rules | ||
@@ -134,3 +160,3 @@ assert.include(rules[0], { | ||
it('respects a fixed rate of 0', function(done) { | ||
sandbox.stub(ServiceConnector, 'client').value(generateMockClient([ | ||
sandbox.stub(ServiceConnector, 'httpClient').value(generateMockClient([ | ||
noSamplingRule, | ||
@@ -140,3 +166,3 @@ defaultSamplingRule | ||
ServiceConnector.fetchSamplingRules(function(rules) { | ||
ServiceConnector.fetchSamplingRules(function(_, rules) { | ||
assert.deepEqual(rules.length, 2); | ||
@@ -159,2 +185,48 @@ assert.include(rules[0], { | ||
}); | ||
describe('DaemonConfig', function() { | ||
const DEFAULT_DAEMON_ADDRESS = '127.0.0.1'; | ||
const DEFAULT_DAEMON_PORT = 2000; | ||
var requestSpy; | ||
beforeEach(function() { | ||
delete process.env.AWS_XRAY_DAEMON_ADDRESS; | ||
DaemonConfig.setDaemonAddress(`${DEFAULT_DAEMON_ADDRESS}:${DEFAULT_DAEMON_PORT}`); | ||
requestSpy = sandbox.stub(ServiceConnector.httpClient, 'request').returns({ | ||
write: () => {}, | ||
end: () => {} | ||
}); | ||
}); | ||
afterEach(function() { | ||
sandbox.restore(); | ||
}); | ||
it('Should call the daemon at its default address', function() { | ||
ServiceConnector.fetchSamplingRules(function() {}); | ||
ServiceConnector.fetchTargets([], function() {}); | ||
assert.equal(DEFAULT_DAEMON_ADDRESS, requestSpy.getCall(0).args[0].hostname); | ||
assert.equal(DEFAULT_DAEMON_PORT, requestSpy.getCall(0).args[0].port); | ||
assert.equal(DEFAULT_DAEMON_ADDRESS, requestSpy.getCall(1).args[0].hostname); | ||
assert.equal(DEFAULT_DAEMON_PORT, requestSpy.getCall(1).args[0].port); | ||
}); | ||
it('Should call the daemon at new address when updated', function() { | ||
const new_address = '1.1.1.1'; | ||
const new_port = '1999'; | ||
DaemonConfig.setDaemonAddress(`${new_address}:${new_port}`); | ||
ServiceConnector.fetchSamplingRules(function() {}); | ||
ServiceConnector.fetchTargets([], function() {}); | ||
assert.equal(new_address, requestSpy.getCall(0).args[0].hostname); | ||
assert.equal(new_port, requestSpy.getCall(0).args[0].port); | ||
assert.equal(new_address, requestSpy.getCall(1).args[0].hostname); | ||
assert.equal(new_port, requestSpy.getCall(1).args[0].port); | ||
}); | ||
}); | ||
}); |
@@ -241,3 +241,4 @@ var assert = require('chai').assert; | ||
sandbox.stub(dgram, 'createSocket').returns({ | ||
send: emitStub | ||
send: emitStub, | ||
unref: sinon.stub().returnsThis() | ||
}); | ||
@@ -244,0 +245,0 @@ |
@@ -22,2 +22,12 @@ var assert = require('chai').assert; | ||
describe('#stripQueryStringFromPath', function() { | ||
it('should remove query string for simple path', function() { | ||
assert.equal(Utils.stripQueryStringFromPath('/index.html?page=12'), '/index.html'); | ||
}); | ||
it('should remove query string for complex path', function() { | ||
assert.equal(Utils.stripQueryStringFromPath('/really/long/path/to/content.html?page=12'), '/really/long/path/to/content.html'); | ||
}); | ||
}); | ||
describe('#processTraceData', function() { | ||
@@ -24,0 +34,0 @@ it('should parse X-Amzn-Trace-Id with spaces', function() { |
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
385462
5
9042
646
68
7
+ Added@types/cls-hooked@*
+ Added@types/cls-hooked@4.3.9(transitive)
- Removed@types/continuation-local-storage@*
- Removedaws-sdk@^2.304.0
- Removed@types/continuation-local-storage@3.2.7(transitive)
- Removedavailable-typed-arrays@1.0.7(transitive)
- Removedaws-sdk@2.1692.0(transitive)
- Removedbase64-js@1.5.1(transitive)
- Removedbuffer@4.9.2(transitive)
- Removedcall-bind@1.0.8(transitive)
- Removedcall-bind-apply-helpers@1.0.1(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removeddunder-proto@1.0.0(transitive)
- Removedes-define-property@1.0.1(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedes-object-atoms@1.0.0(transitive)
- Removedevents@1.1.1(transitive)
- Removedfor-each@0.3.3(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.6(transitive)
- Removedgopd@1.2.0(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-symbols@1.1.0(transitive)
- Removedhas-tostringtag@1.0.2(transitive)
- Removedhasown@2.0.2(transitive)
- Removedieee754@1.1.13(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-arguments@1.1.1(transitive)
- Removedis-callable@1.2.7(transitive)
- Removedis-generator-function@1.0.10(transitive)
- Removedis-typed-array@1.1.13(transitive)
- Removedisarray@1.0.0(transitive)
- Removedjmespath@0.16.0(transitive)
- Removedmath-intrinsics@1.0.0(transitive)
- Removedpossible-typed-array-names@1.0.0(transitive)
- Removedpunycode@1.3.2(transitive)
- Removedquerystring@0.2.0(transitive)
- Removedsax@1.2.1(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedurl@0.10.3(transitive)
- Removedutil@0.12.5(transitive)
- Removeduuid@8.0.0(transitive)
- Removedwhich-typed-array@1.1.16(transitive)
- Removedxml2js@0.6.2(transitive)
- Removedxmlbuilder@11.0.1(transitive)