Skip to content

Commit

Permalink
Merging 2.1.6 code with beta branch (#828)
Browse files Browse the repository at this point in the history
* Revert "Beta version release with AAD support (#765)"

This reverts commit ea3fa66.

* WIP
  • Loading branch information
hectorhdzg authored Aug 26, 2021
1 parent 089061b commit 9258636
Show file tree
Hide file tree
Showing 39 changed files with 1,476 additions and 612 deletions.
7 changes: 3 additions & 4 deletions AutoCollection/AsyncHooksScopeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export class OpenTelemetryScopeManagerWrapper {
if (key === this._activeSymbol) {
return context;
}

return false;
},
setValue: () => { }
Expand Down Expand Up @@ -55,10 +54,10 @@ export class OpenTelemetryScopeManagerWrapper {
}

private static _spanToContext(span: Span, parentSpanId?: string, name?: string): CorrelationContext {
const _parentId = parentSpanId ? `|${span.context().traceId}.${parentSpanId}.` : span.context().traceId;
const _parentId = parentSpanId ? `|${span.spanContext().traceId}.${parentSpanId}.` : span.spanContext().traceId;
const context: SpanContext = {
...span.context(),
traceFlags: span.context().traceFlags
...span.spanContext(),
traceFlags: span.spanContext().traceFlags
};
const correlationContext = CorrelationContextManager.spanToContextObject(context, _parentId, name)
return correlationContext;
Expand Down
6 changes: 5 additions & 1 deletion AutoCollection/Exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ class AutoCollectExceptions {
// For scenarios like Promise.reject(), an error won't be passed to the handle. Create a placeholder
// error for these scenarios.
var handle = (reThrow: boolean, name: string, error: Error = new Error(AutoCollectExceptions._FALLBACK_ERROR_MESSAGE)) => {
this._client.trackException({ exception: error });
let exceptionTelemetry: Contracts.ExceptionTelemetry = { exception: error };
// Add full error in context so it could used in telemetryProcessors
exceptionTelemetry.contextObjects = {};
exceptionTelemetry.contextObjects["Error"] = error;
this._client.trackException(exceptionTelemetry);
this._client.flush({ isAppCrashing: true });
// only rethrow when we are the only listener
if (reThrow && name && (<any>process).listeners(name).length === 1) {
Expand Down
88 changes: 11 additions & 77 deletions AutoCollection/HeartBeat.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import os = require("os");
import Vm = require("../Library/AzureVirtualMachine");
import TelemetryClient = require("../Library/TelemetryClient");
import Constants = require("../Declarations/Constants");
import Util = require("../Library/Util");
import Config = require("../Library/Config");
import Context = require("../Library/Context");
import AutoCollectHttpDependencies = require("../AutoCollection/HttpDependencies");

const AIMS_URI = "http://169.254.169.254/metadata/instance/compute";
const AIMS_API_VERSION = "api-version=2017-12-01";
const AIMS_FORMAT = "format=json";
const ConnectionErrorMessage = "ENETUNREACH";

class HeartBeat {

Expand All @@ -21,16 +15,11 @@ class HeartBeat {
private _isEnabled: boolean;
private _isInitialized: boolean;
private _isVM: boolean;
private _vmData = <{[key: string]: string}>{};
private _azInst_vmId: string = "";
private _azInst_subscriptionId: string = "";
private _azInst_osType: string = "";

constructor(client: TelemetryClient) {
if (!HeartBeat.INSTANCE) {
HeartBeat.INSTANCE = this;
}

this._isInitialized = false;
this._client = client;
}
Expand All @@ -43,7 +32,7 @@ class HeartBeat {

if (isEnabled) {
if (!this._handle) {
this._handle = setInterval(() => this.trackHeartBeat(config, () => {}), this._collectionInterval);
this._handle = setInterval(() => this.trackHeartBeat(config, () => { }), this._collectionInterval);
this._handle.unref(); // Allow the app to terminate even while this loop is going on
}
} else {
Expand All @@ -64,7 +53,7 @@ class HeartBeat {

public trackHeartBeat(config: Config, callback: () => void) {
let waiting: boolean = false;
let properties: {[key: string]: string} = {};
let properties: { [key: string]: string } = {};
const sdkVersion = Context.sdkVersion; // "node" or "node-nativeperf"
properties["sdk"] = sdkVersion;
properties["osType"] = os.type();
Expand All @@ -77,26 +66,20 @@ class HeartBeat {
} else if (config) {
if (this._isVM === undefined) {
waiting = true;
this._getAzureComputeMetadata(config, () => {
if (this._isVM && Object.keys(this._vmData).length > 0) { // VM
properties["azInst_vmId"] = this._vmData["vmId"] || "";
properties["azInst_subscriptionId"] = this._vmData["subscriptionId"] || "";
properties["azInst_osType"] = this._vmData["osType"] || "";
this._azInst_vmId = this._vmData["vmId"] || "";
this._azInst_subscriptionId = this._vmData["subscriptionId"] || "";
this._azInst_osType = this._vmData["osType"] || "";
Vm.AzureVirtualMachine.getAzureComputeMetadata(config, (vmInfo) => {
this._isVM = vmInfo.isVM;
if (this._isVM) {
properties["azInst_vmId"] = vmInfo.id;
properties["azInst_subscriptionId"] = vmInfo.subscriptionId;
properties["azInst_osType"] = vmInfo.osType;
}
this._client.trackMetric({name: Constants.HeartBeatMetricName, value: 0, properties: properties});
this._client.trackMetric({ name: Constants.HeartBeatMetricName, value: 0, properties: properties });
callback();
});
} else if (this._isVM) {
properties["azInst_vmId"] = this._azInst_vmId;
properties["azInst_subscriptionId"] = this._azInst_subscriptionId;
properties["azInst_osType"] = this._azInst_osType;
}
}
if (!waiting) {
this._client.trackMetric({name: Constants.HeartBeatMetricName, value: 0, properties: properties});
this._client.trackMetric({ name: Constants.HeartBeatMetricName, value: 0, properties: properties });
callback();
}
}
Expand All @@ -106,55 +89,6 @@ class HeartBeat {
this.enable(false);
this._isInitialized = false;
}

private _getAzureComputeMetadata(config: Config, callback: () => void) {
const metadataRequestUrl = `${AIMS_URI}?${AIMS_API_VERSION}&${AIMS_FORMAT}`;
const requestOptions = {
method: 'GET',
[AutoCollectHttpDependencies.disableCollectionRequestOption]: true,
headers: {
"Metadata": "True",
}
};

const req = Util.makeRequest(config, metadataRequestUrl, requestOptions, (res) => {
if (res.statusCode === 200) {
// Success; VM
this._isVM = true;
let virtualMachineData = "";
res.on('data', (data: any) => {
virtualMachineData += data;
});
res.on('end', () => {
this._vmData = this._isJSON(virtualMachineData) ? JSON.parse(virtualMachineData) : {};
callback();
});
} else {
// else Retry on next heartbeat metrics call
callback();
}
});
if (req) {
req.on('error', (error: Error) => {
// Unable to contact endpoint.
// Do nothing for now.
if (error && error.message && error.message.indexOf(ConnectionErrorMessage) > -1) {
this._isVM = false; // confirm it's not in VM
}
// errors other than connect ENETUNREACH - retry
callback();
});
req.end();
}
}

private _isJSON(str: string): boolean {
try {
return (JSON.parse(str) && !!str);
} catch (e) {
return false;
}
}
}

export = HeartBeat;
17 changes: 14 additions & 3 deletions AutoCollection/HttpDependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,26 @@ class AutoCollectHttpDependencies {

client.trackDependency(dependencyTelemetry);
});
telemetry.request.on('error', (e: Error) => {
requestParser.onError(e);
telemetry.request.on('error', (error: Error) => {
requestParser.onError(error);

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

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

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;
dependencyTelemetry.contextObjects["Error"] = e;

client.trackDependency(dependencyTelemetry);
});
Expand Down
24 changes: 11 additions & 13 deletions AutoCollection/HttpDependencyParser.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import http = require("http");
import https = require("https");
import url = require("url");

import Contracts = require("../Declarations/Contracts");
import TelemetryClient = require("../Library/TelemetryClient");
import Logging = require("../Library/Logging");
import Util = require("../Library/Util");
import RequestResponseHeaders = require("../Library/RequestResponseHeaders");
import RequestParser = require("./RequestParser");
Expand Down Expand Up @@ -46,7 +43,7 @@ class HttpDependencyParser extends RequestParser {
* Gets a dependency data contract object for a completed ClientRequest.
*/
public getDependencyTelemetry(baseTelemetry?: Contracts.Telemetry, dependencyId?: string): Contracts.DependencyTelemetry {
let urlObject = url.parse(this.url);
let urlObject = new url.URL(this.url);
urlObject.search = undefined;
urlObject.hash = undefined;
let dependencyName = this.method.toUpperCase() + " " + urlObject.pathname;
Expand Down Expand Up @@ -116,17 +113,17 @@ class HttpDependencyParser extends RequestParser {
if (typeof options === 'string') {
if (options.indexOf("http://") === 0 || options.indexOf("https://") === 0) {
// protocol exists, parse normally
options = url.parse(options);
options = new url.URL(options);
} else {
// protocol not found, insert http/https where appropriate
const parsed = url.parse(options);
if (parsed.host === "443") {
options = url.parse("https://" + options);
const parsed = new url.URL("http://" + options);
if (parsed.port === "443") {
options = new url.URL("https://" + options);
} else {
options = url.parse("http://" + options)
options = new url.URL("http://" + options);
}
}
} else if (options && typeof (url as any).URL === 'function' && options instanceof (url as any).URL) {
} else if (options && typeof url.URL === 'function' && options instanceof url.URL) {
return url.format(options);
} else {
// Avoid modifying the original options object.
Expand All @@ -141,8 +138,9 @@ class HttpDependencyParser extends RequestParser {

// Oddly, url.format ignores path and only uses pathname and search,
// so create them from the path, if path was specified
if (options.path) {
const parsedQuery = url.parse(options.path);
if (options.path && options.host) {
// need to force a protocol to make parameter valid - base url is required when input is a relative url
const parsedQuery = new url.URL(options.path, 'http://' + options.host + options.path);
options.pathname = parsedQuery.pathname;
options.search = parsedQuery.search;
}
Expand All @@ -155,7 +153,7 @@ class HttpDependencyParser extends RequestParser {
if (options.host && options.port) {
// Force a protocol so it will parse the host as the host, not path.
// It is discarded and not used, so it doesn't matter if it doesn't match
const parsedHost = url.parse(`http://${options.host}`);
const parsedHost = new url.URL(`http://${options.host}`);
if (!parsedHost.port && options.port) {
options.hostname = options.host;
delete options.host;
Expand Down
14 changes: 7 additions & 7 deletions AutoCollection/HttpRequestParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import url = require("url");
import net = require("net");

import Contracts = require("../Declarations/Contracts");
import TelemetryClient = require("../Library/TelemetryClient");
import Logging = require("../Library/Logging");
import Util = require("../Library/Util");
import RequestResponseHeaders = require("../Library/RequestResponseHeaders");
import RequestParser = require("./RequestParser");
Expand Down Expand Up @@ -70,7 +68,7 @@ class HttpRequestParser extends RequestParser {
public getRequestTelemetry(baseTelemetry?: Contracts.Telemetry): Contracts.RequestTelemetry {
var requestTelemetry: Contracts.RequestTelemetry & Contracts.Identified = {
id: this.requestId,
name: this.method + " " + url.parse(this.url).pathname,
name: this.method + " " + new url.URL(this.url).pathname,
url: this.url,
/*
See https://github.com/microsoft/ApplicationInsights-dotnet-server/blob/25d695e6a906fbe977f67be3966d25dbf1c50a79/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs#L250
Expand Down Expand Up @@ -138,7 +136,7 @@ class HttpRequestParser extends RequestParser {
}

public getOperationName(tags: { [key: string]: string }) {
return tags[HttpRequestParser.keys.operationName] || this.method + " " + url.parse(this.url).pathname;
return tags[HttpRequestParser.keys.operationName] || this.method + " " + new url.URL(this.url).pathname;
}

public getRequestId() {
Expand Down Expand Up @@ -167,13 +165,15 @@ class HttpRequestParser extends RequestParser {
}

var encrypted = (<any>request).connection ? ((<any>request).connection as any).encrypted : null;
var requestUrl = url.parse(request.url);

var protocol = (encrypted || request.headers["x-forwarded-proto"] == "https") ? "https" : "http";

var baseUrl = protocol + '://' + request.headers.host + '/';
var requestUrl = new url.URL(request.url, baseUrl);

var pathName = requestUrl.pathname;
var search = requestUrl.search;

var protocol = (encrypted || request.headers["x-forwarded-proto"] == "https") ? "https" : "http";

var absoluteUrl = url.format({
protocol: protocol,
host: request.headers.host,
Expand Down
8 changes: 8 additions & 0 deletions AutoCollection/HttpRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ class AutoCollectHttpRequests {
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, error);
});
}

// track an aborted request if an aborted event is emitted
if (telemetry.request.on) {
telemetry.request.on("aborted", () => {
const errorMessage = "The request has been aborted and the network socket has closed.";
AutoCollectHttpRequests.endRequest(client, requestParser, telemetry, null, errorMessage);
});
}
}

/**
Expand Down
43 changes: 43 additions & 0 deletions AutoCollection/NetworkStatsbeat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export class NetworkStatsbeat {

public time: number;

public lastTime: number;

public endpoint: number;

public host: string;

public totalRequestCount: number;

public lastRequestCount: number;

public totalSuccesfulRequestCount: number;

public totalFailedRequestCount: number;

public retryCount: number;

public exceptionCount: number;

public throttleCount: number;

public intervalRequestExecutionTime: number;

public lastIntervalRequestExecutionTime: number;

constructor(endpoint: number, host: string) {
this.endpoint = endpoint;
this.host = host;
this.totalRequestCount = 0;
this.totalSuccesfulRequestCount = 0;
this.totalFailedRequestCount = 0;
this.retryCount = 0;
this.exceptionCount = 0;
this.throttleCount = 0;
this.intervalRequestExecutionTime = 0;
this.lastIntervalRequestExecutionTime = 0;
this.lastTime = +new Date;
this.lastRequestCount = 0;
}
}
Loading

0 comments on commit 9258636

Please sign in to comment.