Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: microsoft/ApplicationInsights-node.js
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.1.0
Choose a base ref
...
head repository: microsoft/ApplicationInsights-node.js
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2.1.1
Choose a head ref
  • 3 commits
  • 8 files changed
  • 2 contributors

Commits on Jun 9, 2021

  1. Handle canceled events for HttpRequest and aborted events for HttpDep…

    …endency (#767)
    
    * add request and response handle
    
    * update handler
    
    * address comments
    xiao-lix authored Jun 9, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b3e871b View commit details
  2. Adding support for temporary redirect (#768)

    * Adding support for temporary redirect
    
    * WIP
    
    * Remove unused variable
    
    * Adding nock scope restore
    
    * WIP
    
    * Adding logs in tests
    
    * Fixing tests
    hectorhdzg authored Jun 9, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    5741272 View commit details
  3. 2.1.1 release (#771)

    * 2.1.1 release
    
    * Update package-lock and reverting OT updates
    
    * Update version in bootstrap
    hectorhdzg authored Jun 9, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    73f4ff0 View commit details
11 changes: 11 additions & 0 deletions AutoCollection/HttpDependencies.ts
Original file line number Diff line number Diff line change
@@ -208,6 +208,17 @@ class AutoCollectHttpDependencies {
dependencyTelemetry.contextObjects["http.ClientRequest"] = telemetry.request;
dependencyTelemetry.contextObjects["Error"] = e;

client.trackDependency(dependencyTelemetry);
});
telemetry.request.on('abort', () => {
requestParser.onError(new Error());

var dependencyTelemetry = requestParser.getDependencyTelemetry(telemetry, uniqueRequestId);

dependencyTelemetry.contextObjects = dependencyTelemetry.contextObjects || {};
dependencyTelemetry.contextObjects["http.RequestOptions"] = telemetry.options;
dependencyTelemetry.contextObjects["http.ClientRequest"] = telemetry.request;

client.trackDependency(dependencyTelemetry);
});
}
13 changes: 13 additions & 0 deletions AutoCollection/HttpRequests.ts
Original file line number Diff line number Diff line change
@@ -224,17 +224,30 @@ class AutoCollectHttpRequests {
(<PrivateCustomProperties>correlationContext.customProperties).addHeaderData(requestParser.getCorrelationContextHeader());
}

let isRequestFinished = false;
// response listeners
if (telemetry.response.once) {
telemetry.response.once("finish", () => {
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, null);
isRequestFinished = true;
});
}

// track a failed request if an error is emitted
if (telemetry.request.on) {
telemetry.request.on("error", (error: any) => {
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, error);
isRequestFinished = true;
});
}

// track a canceled request if an close is emitted
if (telemetry.request.on) {
telemetry.request.on("close", () => {
if (!isRequestFinished ) {
const errorMessage = "Request is canceled.";
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, errorMessage);
}
});
}
}
2 changes: 1 addition & 1 deletion Bootstrap/DiagnosticLogger.ts
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ export class DiagnosticLogger {
siteName: process.env.WEBSITE_SITE_NAME,
ikey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY,
extensionVersion: process.env.ApplicationInsightsAgent_EXTENSION_VERSION,
sdkVersion: "2.1.0",
sdkVersion: "2.1.1",
subscriptionId: process.env.WEBSITE_OWNER_NAME ? process.env.WEBSITE_OWNER_NAME.split("+")[0] : null,
}
}
48 changes: 25 additions & 23 deletions Library/Sender.ts
Original file line number Diff line number Diff line change
@@ -190,24 +190,35 @@ class Sender {
}
}
// Redirect handling
if (res.statusCode === 308) { // Permanent Redirect
// Try to get redirect header
const locationHeader = res.headers["location"] ? res.headers["location"].toString() : null;
if (locationHeader) {
this._handleRedirect(locationHeader);
if (res.statusCode === 307 || // Temporary Redirect
res.statusCode === 308) { // Permanent Redirect
this._numConsecutiveRedirects++;
// To prevent circular redirects
if (this._numConsecutiveRedirects < 10) {
// Try to get redirect header
const locationHeader = res.headers["location"] ? res.headers["location"].toString() : null;
if (locationHeader) {
this._redirectedHost = locationHeader;
// Send to redirect endpoint as HTTPs library doesn't handle redirect automatically
this.send(envelopes, callback);
}
}
else {
if (typeof callback === "function") {
callback("Error sending telemetry because of circular redirects.");
}
}

}
else {
this._numConsecutiveRedirects = 0;
}

Logging.info(Sender.TAG, responseString);
if (typeof this._onSuccess === "function") {
this._onSuccess(responseString);
}

if (typeof callback === "function") {
callback(responseString);
if (typeof callback === "function") {
callback(responseString);
}
Logging.info(Sender.TAG, responseString);
if (typeof this._onSuccess === "function") {
this._onSuccess(responseString);
}
}
});
};
@@ -260,7 +271,6 @@ class Sender {
private _isRetriable(statusCode: number) {
return (
statusCode === 206 || // Retriable
statusCode === 308 || // Permanent Redirect
statusCode === 408 || // Timeout
statusCode === 429 || // Throttle
statusCode === 439 || // Quota
@@ -269,14 +279,6 @@ class Sender {
);
}

private _handleRedirect(location: string) {
this._numConsecutiveRedirects++;
// To prevent circular redirects
if (this._numConsecutiveRedirects < 10) {
this._redirectedHost = location;
}
}

private _runICACLS(args: string[], callback: (err: Error) => void) {
var aclProc = child_process.spawn(Sender.ICACLS_PATH, args, <any>{ windowsHide: true });
aclProc.on("error", (e: Error) => callback(e));
11 changes: 11 additions & 0 deletions Tests/AutoCollection/HttpDependencyParser.tests.ts
Original file line number Diff line number Diff line change
@@ -208,5 +208,16 @@ describe("AutoCollection/HttpDependencyParser", () => {
assert.equal(dependencyTelemetry.dependencyTypeName, Contracts.RemoteDependencyDataConstants.TYPE_HTTP);
assert.equal(dependencyTelemetry.success, false);
});

it("should return non-success for a request abort", () => {
(<any>request)["method"] = "GET";
let parser = new HttpDependencyParser("http://bing.com/search", request);
parser.onError(new Error());

let dependencyTelemetry = parser.getDependencyTelemetry();
assert.equal(dependencyTelemetry.dependencyTypeName, Contracts.RemoteDependencyDataConstants.TYPE_HTTP);
assert.equal(dependencyTelemetry.success, false);
assert.ok(dependencyTelemetry.properties);
});
});
});
93 changes: 76 additions & 17 deletions Tests/Library/Sender.tests.ts
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ describe("Library/Sender", () => {
var testEnvelope = new Contracts.Envelope();
var sandbox: sinon.SinonSandbox;
let interceptor: nock.Interceptor;
let nockScope: nock.Scope;

before(() => {
interceptor = nock(Constants.DEFAULT_BREEZE_ENDPOINT)
@@ -36,6 +37,9 @@ describe("Library/Sender", () => {

afterEach(() => {
sandbox.restore();
if (nockScope && nockScope.restore) {
nockScope.restore();
}
});

after(() => {
@@ -75,7 +79,8 @@ describe("Library/Sender", () => {
diskEnvelope.name = "DiskEnvelope";
sender["_storeToDisk"]([diskEnvelope]);
var sendSpy = sandbox.spy(sender, "send");
interceptor.reply(200, breezeResponse).persist();
nockScope = interceptor.reply(200, breezeResponse);
nockScope.persist();
sender["_resendInterval"] = 100;
sender.send([testEnvelope], (responseText) => {
// Wait for resend timer
@@ -91,7 +96,7 @@ describe("Library/Sender", () => {
it("should put telemetry in disk when retryable code is returned", (done) => {
var envelope = new Contracts.Envelope();
envelope.name = "TestRetryable";
interceptor.reply(408, null);
nockScope = interceptor.reply(408, null);
var storeStub = sandbox.stub(sender, "_storeToDisk");
sender.send([envelope], (responseText) => {
assert.ok(storeStub.calledOnce);
@@ -120,7 +125,7 @@ describe("Library/Sender", () => {
newEnvelope.name = "TestPartial" + i;
envelopes.push(newEnvelope);
}
interceptor.reply(206, breezeResponse);
nockScope = interceptor.reply(206, breezeResponse);
var storeStub = sandbox.stub(sender, "_storeToDisk");
sender.send(envelopes, () => {
assert.ok(storeStub.calledOnce);
@@ -137,7 +142,7 @@ describe("Library/Sender", () => {
sender = new SenderMock(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
});

after(()=>{
after(() => {
sender.setDiskRetryMode(false);
});

@@ -165,19 +170,47 @@ describe("Library/Sender", () => {

describe("#endpoint redirect", () => {
it("should change ingestion endpoint when redirect response code is returned (308)", (done) => {
interceptor.reply(308, {}, { "Location": "testLocation" });
let redirectHost = "https://test";
let redirectLocation = redirectHost + "/v2.1/track";
// Fake redirect endpoint
let redirectInterceptor = nock(redirectHost)
.post("/v2.1/track", (body: string) => {
return true;
});
redirectInterceptor.reply(200, {});

nockScope = interceptor.reply(308, {}, { "Location": redirectLocation });
var testSender = new Sender(new Config("2bb22222-bbbb-1ccc-8ddd-eeeeffff3333"));
testSender.setDiskRetryMode(true);
var storeStub = sandbox.stub(testSender, "_storeToDisk");
var sendSpy = sandbox.spy(testSender, "send");
testSender.send([testEnvelope], (responseText) => {
assert.equal(testSender["_redirectedHost"], "testLocation");
assert.ok(storeStub.calledOnce);
assert.equal(testSender["_redirectedHost"], redirectLocation);
assert.ok(sendSpy.callCount === 2); // Original and redirect calls
done();
});
});

it("should change ingestion endpoint when temporary redirect response code is returned (307)", (done) => {
let redirectHost = "https://test";
let redirectLocation = redirectHost + "/v2.1/track";
// Fake redirect endpoint
let redirectInterceptor = nock(redirectHost)
.post("/v2.1/track", (body: string) => {
return true;
});
redirectInterceptor.reply(200, {});

nockScope = interceptor.reply(307, {}, { "Location": redirectLocation });
var testSender = new Sender(new Config("2bb22222-bbbb-1ccc-8ddd-eeeeffff3333"));
var sendSpy = sandbox.spy(testSender, "send");
testSender.send([testEnvelope], (responseText) => {
assert.equal(testSender["_redirectedHost"], redirectLocation);
assert.ok(sendSpy.callCount === 2); // Original and redirect calls
done();
});
});

it("should not change ingestion endpoint if redirect is not triggered", (done) => {
interceptor.reply(200, {}, { "Location": "testLocation" });
nockScope = interceptor.reply(200, {}, { "Location": "testLocation" });
var testSender = new Sender(new Config("2bb22222-bbbb-1ccc-8ddd-eeeeffff3333"));
testSender.send([testEnvelope], (responseText) => {
assert.equal(testSender["_redirectedHost"], null);
@@ -186,24 +219,50 @@ describe("Library/Sender", () => {
});

it("should use redirect URL for following requests", (done) => {
let redirectHost = "https://testLocation";
let redirectHost = "https://testlocation";
let redirectLocation = redirectHost + "/v2.1/track";
// Fake redirect endpoint
nock(redirectHost)
let redirectInterceptor = nock(redirectHost)
.post("/v2.1/track", (body: string) => {
return true;
}).reply(200, { "redirectProperty": true });
interceptor.reply(308, {}, { "Location": redirectLocation });
});

redirectInterceptor.reply(200, { "redirectProperty": true }).persist();

nockScope = interceptor.reply(308, {}, { "Location": redirectLocation });
var testSender = new Sender(new Config("2bb22222-bbbb-1ccc-8ddd-eeeeffff3333"));
testSender.send([testEnvelope], () => {
var sendSpy = sandbox.spy(testSender, "send");
testSender.send([testEnvelope], (resposneText) => {
assert.equal(testSender["_redirectedHost"], redirectLocation);
testSender.send([testEnvelope], (responseText) => {
assert.equal(responseText, '{"redirectProperty":true}');
assert.equal(resposneText, '{"redirectProperty":true}');
assert.ok(sendSpy.calledTwice);
testSender.send([testEnvelope], (secondResponseText) => {
assert.equal(secondResponseText, '{"redirectProperty":true}');
assert.ok(sendSpy.calledThrice);
done();
});
});
});

it("should stop redirecting when circular redirect is triggered", (done) => {
let redirectHost = "https://circularredirect";
// Fake redirect endpoint
let redirectInterceptor = nock(redirectHost)
.post("/v2.1/track", (body: string) => {
return true;
});
redirectInterceptor.reply(307, {}, { "Location": Constants.DEFAULT_BREEZE_ENDPOINT + "/v2.1/track" }).persist();

nockScope = interceptor.reply(307, {}, { "Location": redirectHost + "/v2.1/track" });
var testSender = new Sender(new Config("2bb22222-bbbb-1ccc-8ddd-eeeeffff3333"));
var sendSpy = sandbox.spy(testSender, "send");
testSender.send([testEnvelope], (responseText) => {
assert.equal(responseText, "Error sending telemetry because of circular redirects.");
assert.equal(sendSpy.callCount, 10);
done();
});
});

});

describe("#fileCleanupTask", () => {
22 changes: 11 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
"author": "Microsoft Application Insights Team",
"license": "MIT",
"bugs": "https://github.com/microsoft/ApplicationInsights-node.js/issues",
"version": "2.1.0",
"version": "2.1.1",
"description": "Microsoft Application Insights module for Node.js",
"repository": {
"type": "git",
@@ -55,7 +55,7 @@
"typescript": "4.1.2"
},
"dependencies": {
"@azure/core-http": "^1.2.4",
"@azure/core-http": "^1.2.5",
"@opentelemetry/api": "^0.18.1",
"@opentelemetry/tracing": "^0.19.0",
"cls-hooked": "^4.2.2",