in sdk/monitor/monitor-opentelemetry-exporter/src/platform/nodejs/baseSender.ts [71:216]
public async exportEnvelopes(envelopes: Envelope[]): Promise<ExportResult> {
diag.info(`Exporting ${envelopes.length} envelope(s)`);
if (envelopes.length < 1) {
return { code: ExportResultCode.SUCCESS };
}
try {
const startTime = new Date().getTime();
const { result, statusCode } = await this.send(envelopes);
const endTime = new Date().getTime();
const duration = endTime - startTime;
this.numConsecutiveRedirects = 0;
if (statusCode === 200) {
// Success -- @todo: start retry timer
if (!this.retryTimer) {
this.retryTimer = setTimeout(() => {
this.retryTimer = null;
this.sendFirstPersistedFile();
}, this.batchSendRetryIntervalMs);
this.retryTimer.unref();
}
// If we are not exportings statsbeat and statsbeat is not disabled -- count success
this.networkStatsbeatMetrics?.countSuccess(duration);
return { code: ExportResultCode.SUCCESS };
} else if (statusCode && isRetriable(statusCode)) {
// Failed -- persist failed data
if (statusCode === 429 || statusCode === 439) {
this.networkStatsbeatMetrics?.countThrottle(statusCode);
}
if (result) {
diag.info(result);
const breezeResponse = JSON.parse(result) as BreezeResponse;
const filteredEnvelopes: Envelope[] = [];
// If we have a partial success, count the succeeded envelopes
if (breezeResponse.itemsReceived > 0) {
this.networkStatsbeatMetrics?.countSuccess(duration);
}
// Figure out if we need to either retry or count failures
if (breezeResponse.errors) {
breezeResponse.errors.forEach((error) => {
if (error.statusCode && isRetriable(error.statusCode)) {
filteredEnvelopes.push(envelopes[error.index]);
}
});
}
if (filteredEnvelopes.length > 0) {
this.networkStatsbeatMetrics?.countRetry(statusCode);
// calls resultCallback(ExportResult) based on result of persister.push
return await this.persist(filteredEnvelopes);
}
// Failed -- not retriable
this.networkStatsbeatMetrics?.countFailure(duration, statusCode);
return {
code: ExportResultCode.FAILED,
};
} else {
// calls resultCallback(ExportResult) based on result of persister.push
this.networkStatsbeatMetrics?.countRetry(statusCode);
return await this.persist(envelopes);
}
} else {
// Failed -- not retriable
if (this.networkStatsbeatMetrics) {
if (statusCode) {
this.networkStatsbeatMetrics.countFailure(duration, statusCode);
}
} else {
// Handles all other status codes or client exceptions for Statsbeat
this.incrementStatsbeatFailure();
}
return {
code: ExportResultCode.FAILED,
};
}
} catch (error: any) {
const restError = error as RestError;
if (
restError.statusCode &&
(restError.statusCode === 307 || // Temporary redirect
restError.statusCode === 308)
) {
// Permanent redirect
this.numConsecutiveRedirects++;
// To prevent circular redirects
if (this.numConsecutiveRedirects < 10) {
if (restError.response && restError.response.headers) {
const location = restError.response.headers.get("location");
if (location) {
// Update sender URL
this.handlePermanentRedirect(location);
// Send to redirect endpoint as HTTPs library doesn't handle redirect automatically
return this.exportEnvelopes(envelopes);
}
}
} else {
const redirectError = new Error("Circular redirect");
this.networkStatsbeatMetrics?.countException(redirectError);
return { code: ExportResultCode.FAILED, error: redirectError };
}
} else if (
restError.statusCode &&
isRetriable(restError.statusCode) &&
!this.isStatsbeatSender
) {
this.networkStatsbeatMetrics?.countRetry(restError.statusCode);
return this.persist(envelopes);
} else if (
restError.statusCode === 400 &&
restError.message.includes("Invalid instrumentation key")
) {
// Invalid instrumentation key, shutdown statsbeat, fail silently
this.shutdownStatsbeat();
return { code: ExportResultCode.SUCCESS };
} else if (
restError.statusCode &&
this.isStatsbeatSender &&
isStatsbeatShutdownStatus(restError.statusCode)
) {
// If the status code is a shutdown status code for statsbeat, shutdown statsbeat and fail silently
this.incrementStatsbeatFailure();
return { code: ExportResultCode.SUCCESS };
}
if (this.isRetriableRestError(restError)) {
if (restError.statusCode) {
this.networkStatsbeatMetrics?.countRetry(restError.statusCode);
}
if (!this.isStatsbeatSender) {
diag.error(
"Retrying due to transient client side error. Error message:",
restError.message,
);
}
return this.persist(envelopes);
}
this.networkStatsbeatMetrics?.countException(restError);
if (!this.isStatsbeatSender) {
diag.error(
"Envelopes could not be exported and are not retriable. Error message:",
restError.message,
);
}
return { code: ExportResultCode.FAILED, error: restError };
}
}