Skip to content

Commit 919e856

Browse files
authored
[AzureMonitorExporter] Adding support for temporary redirect (Azure#15850)
* Adding support for temporary redirect * Lint
1 parent 4471210 commit 919e856

File tree

3 files changed

+94
-25
lines changed

3 files changed

+94
-25
lines changed

sdk/monitor/monitor-opentelemetry-exporter/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"test:browser": "npm run unit-test:browser",
2525
"unit-test:browser": "echo skipped",
2626
"unit-test:node": "nyc mocha -r esm --require ts-node/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"test/unit/**/*.test.ts\"",
27+
"unit-test:node:debug": "nyc mocha --inspect-brk -r esm --require ts-node/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"test/unit/**/*.test.ts\"",
2728
"unit-test:node:no-timeout": "echo skipped",
2829
"unit-test": "npm run unit-test:node && npm run unit-test:browser",
2930
"functional-test": "nyc mocha -r esm --require ts-node/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"test/functional/**/*.test.ts\"",

sdk/monitor/monitor-opentelemetry-exporter/src/export/trace.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export class AzureMonitorTraceExporter implements SpanExporter {
8080

8181
try {
8282
const { result, statusCode } = await this._sender.send(envelopes);
83+
this._numConsecutiveRedirects = 0;
8384
if (statusCode === 200) {
8485
// Success -- @todo: start retry timer
8586
if (!this._retryTimer) {
@@ -121,12 +122,26 @@ export class AzureMonitorTraceExporter implements SpanExporter {
121122
}
122123
} catch (error) {
123124
const restError = error as RestError;
124-
if (restError.statusCode && restError.statusCode === 308) {
125+
if (
126+
restError.statusCode &&
127+
(restError.statusCode === 307 || // Temporary redirect
128+
restError.statusCode === 308)
129+
) {
125130
// Permanent redirect
126-
if (restError.response && restError.response.headers) {
127-
let location = restError.response.headers.get("location");
128-
this._handleRedirect(location);
129-
return await this._persist(envelopes);
131+
this._numConsecutiveRedirects++;
132+
// To prevent circular redirects
133+
if (this._numConsecutiveRedirects < 10) {
134+
if (restError.response && restError.response.headers) {
135+
let location = restError.response.headers.get("location");
136+
if (location) {
137+
// Update sender URL
138+
this._sender.handlePermanentRedirect(location);
139+
// Send to redirect endpoint as HTTPs library doesn't handle redirect automatically
140+
return this.exportEnvelopes(envelopes);
141+
}
142+
}
143+
} else {
144+
return { code: ExportResultCode.FAILED, error: new Error("Circular redirect") };
130145
}
131146
} else if (restError.statusCode && isRetriable(restError.statusCode)) {
132147
return await this._persist(envelopes);
@@ -188,14 +203,4 @@ export class AzureMonitorTraceExporter implements SpanExporter {
188203
}
189204
return false;
190205
}
191-
192-
private _handleRedirect(location: string | undefined) {
193-
if (location) {
194-
this._numConsecutiveRedirects++;
195-
// To prevent circular redirects
196-
if (this._numConsecutiveRedirects < 10) {
197-
this._sender.handlePermanentRedirect(location);
198-
}
199-
}
200-
}
201206
}

sdk/monitor/monitor-opentelemetry-exporter/test/unit/export/trace.test.ts

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
partialBreezeResponse,
1111
successfulBreezeResponse
1212
} from "../breezeTestUtils";
13-
import { FileSystemPersist } from "../../../src/platform";
13+
import { FileSystemPersist, HttpSender } from "../../../src/platform";
1414
import { TelemetryItem as Envelope } from "../../../src/generated";
1515
import nock from "nock";
1616

@@ -150,9 +150,8 @@ describe("#AzureMonitorBaseExporter", () => {
150150
assert.strictEqual(exporter["_retryTimer"], "foo");
151151
});
152152

153-
it("should handle redirects in Azure Monitor", async () => {
153+
it("should handle permanent redirects in Azure Monitor", async () => {
154154
const exporter = new TestExporter();
155-
156155
let redirectHost = "https://ukwest-0.in.applicationinsights.azure.com";
157156
let redirectLocation = redirectHost + "/v2/track";
158157
// Redirect endpoint
@@ -163,17 +162,81 @@ describe("#AzureMonitorBaseExporter", () => {
163162
scope.reply(308, {}, { location: redirectLocation });
164163

165164
let result = await exporter.exportEnvelopesPrivate([envelope]);
166-
// Redirect triggered so telemetry must be persisted
165+
let persistedEnvelopes = (await exporter["_persister"].shift()) as Envelope[];
166+
assert.strictEqual(persistedEnvelopes, null);
167167
assert.strictEqual(result.code, ExportResultCode.SUCCESS);
168+
assert.strictEqual(
169+
(<HttpSender>exporter["_sender"])["_appInsightsClient"]["host"],
170+
redirectHost
171+
);
172+
});
173+
174+
it("should handle temporary redirects in Azure Monitor", async () => {
175+
const exporter = new TestExporter();
176+
let redirectHost = "https://ukwest-0.in.applicationinsights.azure.com";
177+
let redirectLocation = redirectHost + "/v2/track";
178+
// Redirect endpoint
179+
const redirectScope = nock(redirectHost).post("/v2/track", () => {
180+
return true;
181+
});
182+
redirectScope.reply(200, JSON.stringify(successfulBreezeResponse(1)));
183+
scope.reply(307, {}, { location: redirectLocation });
184+
185+
let result = await exporter.exportEnvelopesPrivate([envelope]);
168186
let persistedEnvelopes = (await exporter["_persister"].shift()) as Envelope[];
169-
assert.strictEqual(persistedEnvelopes?.length, 1);
170-
assert.deepStrictEqual(persistedEnvelopes[0], toObject(envelope));
171-
assert.strictEqual(exporter["_numConsecutiveRedirects"], 1);
172-
// After redirect return 200
187+
assert.strictEqual(persistedEnvelopes, null);
188+
assert.strictEqual(result.code, ExportResultCode.SUCCESS);
189+
assert.strictEqual(
190+
(<HttpSender>exporter["_sender"])["_appInsightsClient"]["host"],
191+
redirectHost
192+
);
193+
});
194+
195+
it("should use redirect URL for following requests", async () => {
196+
const exporter = new TestExporter();
197+
let redirectHost = "https://ukwest-0.in.applicationinsights.azure.com";
198+
let redirectLocation = redirectHost + "/v2/track";
199+
// Redirect endpoint
200+
const redirectScope = nock(redirectHost).post("/v2/track", () => {
201+
return true;
202+
});
203+
redirectScope.twice().reply(200, JSON.stringify(successfulBreezeResponse(1)));
204+
scope.reply(307, {}, { location: redirectLocation });
205+
let result = await exporter.exportEnvelopesPrivate([envelope]);
206+
assert.strictEqual(result.code, ExportResultCode.SUCCESS);
207+
assert.strictEqual(
208+
(<HttpSender>exporter["_sender"])["_appInsightsClient"]["host"],
209+
redirectHost
210+
);
173211
result = await exporter.exportEnvelopesPrivate([envelope]);
174212
assert.strictEqual(result.code, ExportResultCode.SUCCESS);
175-
persistedEnvelopes = (await exporter["_persister"].shift()) as Envelope[];
176-
assert.strictEqual(persistedEnvelopes, null);
213+
assert.strictEqual(
214+
(<HttpSender>exporter["_sender"])["_appInsightsClient"]["host"],
215+
redirectHost
216+
);
217+
});
218+
219+
it("should stop redirecting when circular redirect is triggered", async () => {
220+
const exporter = new TestExporter();
221+
let redirectHost = "https://ukwest-0.in.applicationinsights.azure.com";
222+
let redirectLocation = redirectHost + "/v2/track";
223+
// Redirect endpoint
224+
const redirectScope = nock(redirectHost).post("/v2/track", () => {
225+
return true;
226+
});
227+
// Circle redirect
228+
scope
229+
.reply(307, JSON.stringify(successfulBreezeResponse(1)), { location: redirectLocation })
230+
.persist();
231+
redirectScope
232+
.reply(307, JSON.stringify(successfulBreezeResponse(1)), {
233+
location: DEFAULT_BREEZE_ENDPOINT
234+
})
235+
.persist();
236+
237+
let result = await exporter.exportEnvelopesPrivate([envelope]);
238+
assert.strictEqual(result.code, ExportResultCode.FAILED);
239+
assert.strictEqual(result.error?.message, "Circular redirect");
177240
});
178241
});
179242
});

0 commit comments

Comments
 (0)