330 строки
14 KiB
JavaScript
330 строки
14 KiB
JavaScript
(function (win, doc, snipConfig) {
|
|
var locn = win.location;
|
|
var helpLink = "https://go.microsoft.com/fwlink/?linkid=2128109";
|
|
var scriptText = "script";
|
|
var strInstrumentationKey = "instrumentationKey";
|
|
var strIngestionendpoint = "ingestionendpoint";
|
|
var strDisableExceptionTracking = "disableExceptionTracking";
|
|
var strAiDevice = "ai.device.";
|
|
var strAiOperationName = "ai.operation.name";
|
|
var strAiSdkVersion = "ai.internal.sdkVersion";
|
|
var strToLowerCase = "toLowerCase";
|
|
var strConStringIKey = strInstrumentationKey[strToLowerCase]();
|
|
var strEmpty = "";
|
|
var strUndefined = "undefined";
|
|
var strCrossOrigin = "crossOrigin";
|
|
|
|
var strPostMethod = "POST";
|
|
var sdkInstanceName = "appInsightsSDK"; // required for Initialization to find the current instance
|
|
var aiName = snipConfig.name || "appInsights"; // provide non default instance name through snipConfig name value
|
|
if (snipConfig.name || win[sdkInstanceName]) {
|
|
// Only set if supplied or another name is defined to avoid polluting the global namespace
|
|
win[sdkInstanceName] = aiName;
|
|
}
|
|
var aiSdk = win[aiName] || (function (aiConfig) {
|
|
var loadFailed = false;
|
|
var handled = false;
|
|
var appInsights = {
|
|
initialize: true, // initialize sdk on download
|
|
queue: [],
|
|
sv: "6", // Track the actual snippet version for reporting.
|
|
version: 2.0, // initialization version, if this is not 2.0 the previous scripts fail to initialize
|
|
config: aiConfig
|
|
};
|
|
function _parseConnectionString() {
|
|
var fields = {};
|
|
var connectionString = aiConfig.connectionString;
|
|
if (connectionString) {
|
|
var kvPairs = connectionString.split(";");
|
|
for (var lp = 0; lp < kvPairs.length; lp++) {
|
|
var kvParts = kvPairs[lp].split("=");
|
|
|
|
if (kvParts.length === 2) { // only save fields with valid formats
|
|
fields[kvParts[0][strToLowerCase]()] = kvParts[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
// apply the default endpoints
|
|
if (!fields[strIngestionendpoint]) {
|
|
// use endpoint suffix where overrides are not provided
|
|
var endpointSuffix = fields.endpointsuffix;
|
|
// Only fetch the location if a suffix was supplied
|
|
var fLocation = endpointSuffix ? fields.location : null;
|
|
fields[strIngestionendpoint] = "https://" + (fLocation ? fLocation + "." : strEmpty) + "dc." + (endpointSuffix || "services.visualstudio.com");
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
function _sendEvents(evts, endpointUrl) {
|
|
if (JSON) {
|
|
var sender = win.fetch;
|
|
if (sender && !snipConfig.useXhr) {
|
|
sender(endpointUrl, { method:strPostMethod, body: JSON.stringify(evts), mode:"cors"});
|
|
} else if (XMLHttpRequest) {
|
|
// IE doesn't support fetch and private clouds may only be using IE
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open(strPostMethod, endpointUrl);
|
|
xhr.setRequestHeader("Content-type", "application/json");
|
|
xhr.send(JSON.stringify(evts));
|
|
}
|
|
}
|
|
}
|
|
|
|
function _reportFailure(targetSrc) {
|
|
var conString = _parseConnectionString();
|
|
var iKey = conString[strConStringIKey] || aiConfig[strInstrumentationKey] || strEmpty;
|
|
var ingest = conString[strIngestionendpoint];
|
|
var endpointUrl = ingest ? ingest + "/v2/track" : aiConfig.endpointUrl; // only add /v2/track when from connectionstring
|
|
|
|
var message = "SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)";
|
|
var evts = [];
|
|
evts.push(_createException(iKey, message, targetSrc, endpointUrl));
|
|
evts.push(_createInternal(iKey, message, targetSrc, endpointUrl));
|
|
|
|
_sendEvents(evts, endpointUrl);
|
|
}
|
|
|
|
// Gets the time as an ISO date format, using a function as IE7/8 doesn't support toISOString
|
|
function _getTime() {
|
|
var date = new Date();
|
|
function pad(num) {
|
|
var r = strEmpty + num;
|
|
if (r.length === 1) {
|
|
r = "0" + r;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
return date.getUTCFullYear()
|
|
+ "-" + pad(date.getUTCMonth() + 1)
|
|
+ "-" + pad(date.getUTCDate())
|
|
+ "T" + pad(date.getUTCHours())
|
|
+ ":" + pad(date.getUTCMinutes())
|
|
+ ":" + pad(date.getUTCSeconds())
|
|
+ "." + String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
|
|
+ "Z";
|
|
}
|
|
|
|
function _createEnvelope(iKey, theType) {
|
|
var tags = {};
|
|
var type = "Browser";
|
|
tags[strAiDevice + "id"] = type[strToLowerCase]();
|
|
tags[strAiDevice + "type"] = type;
|
|
tags[strAiOperationName] = locn && locn.pathname || "_unknown_";
|
|
tags[strAiSdkVersion] = "javascript:snippet_" + (appInsights.sv || appInsights.version);
|
|
|
|
return {
|
|
time: _getTime(),
|
|
iKey: iKey,
|
|
name: "Microsoft.ApplicationInsights." + iKey.replace(/-/g, strEmpty) + "." + theType,
|
|
sampleRate: 100,
|
|
tags: tags,
|
|
data: {
|
|
baseData: {
|
|
ver: 2
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function _createInternal(iKey, message, targetSrc, endpointUrl) {
|
|
var envelope = _createEnvelope(iKey, "Message");
|
|
var data = envelope.data;
|
|
data.baseType = "MessageData";
|
|
var baseData = data.baseData;
|
|
baseData.message = "AI (Internal): 99 message:\"" + (message + " (" + targetSrc + ")").replace(/\"/g, strEmpty) + "\"";
|
|
baseData.properties = {
|
|
endpoint: endpointUrl
|
|
};
|
|
|
|
return envelope;
|
|
}
|
|
|
|
function _createException(iKey, message, targetSrc, endpointUrl) {
|
|
var envelope = _createEnvelope(iKey, "Exception");
|
|
var data = envelope.data;
|
|
data.baseType = "ExceptionData";
|
|
data.baseData.exceptions = [{
|
|
typeName: "SDKLoadFailed",
|
|
message: message.replace(/\./g, "-"), // Replacing '.' characters as it causes the portal to hide the start of the message in the summary
|
|
hasFullStack: false,
|
|
stack: message + "\nSnippet failed to load [" + targetSrc + "] -- Telemetry is disabled\nHelp Link: " + helpLink + "\nHost: " + (locn && locn.pathname || "_unknown_") + "\nEndpoint: " + endpointUrl,
|
|
parsedStack: []
|
|
}];
|
|
|
|
return envelope;
|
|
}
|
|
|
|
// Assigning these to local variables allows them to be minified to save space:
|
|
var targetSrc = aiConfig.url || snipConfig.src;
|
|
if (targetSrc) {
|
|
function _handleError(evt) {
|
|
loadFailed = true;
|
|
appInsights.queue = []; // Clear the queue
|
|
if (!handled) {
|
|
handled = true;
|
|
_reportFailure(targetSrc);
|
|
}
|
|
}
|
|
|
|
function _handleLoad(evt, isAbort) {
|
|
if (!handled) {
|
|
// IE10, Opera calls loaded before the script is processed.
|
|
// so delaying to give the script a chance to be processed
|
|
setTimeout(function() {
|
|
if (isAbort || !appInsights.core) {
|
|
_handleError();
|
|
}
|
|
}, 500);
|
|
}
|
|
}
|
|
|
|
function _createScript() {
|
|
var scriptElement = doc.createElement(scriptText);
|
|
scriptElement.src = targetSrc;
|
|
|
|
// Allocate Cross origin only if defined and available
|
|
var crossOrigin = snipConfig[strCrossOrigin];
|
|
if ((crossOrigin || crossOrigin === "") && scriptElement[strCrossOrigin] != strUndefined) {
|
|
scriptElement[strCrossOrigin] = crossOrigin;
|
|
}
|
|
|
|
scriptElement.onload = _handleLoad;
|
|
scriptElement.onerror = _handleError;
|
|
|
|
// Some browsers support onload while others onreadystatechange and others both
|
|
scriptElement.onreadystatechange = function (evt, isAbort) {
|
|
if (scriptElement.readyState === "loaded" || scriptElement.readyState === "complete") {
|
|
_handleLoad(evt, isAbort);
|
|
}
|
|
};
|
|
|
|
return scriptElement;
|
|
}
|
|
|
|
var theScript = _createScript();
|
|
if (snipConfig.ld < 0) {
|
|
// if user wants to append tag to document head, blocking page load
|
|
var headNode = doc.getElementsByTagName("head")[0];
|
|
headNode.appendChild(theScript);
|
|
} else {
|
|
setTimeout(function () {
|
|
// Attempts to place the script tag in the same location as the first script on the page
|
|
doc.getElementsByTagName(scriptText)[0].parentNode.appendChild(theScript);
|
|
}, snipConfig.ld || 0);
|
|
}
|
|
}
|
|
|
|
// capture initial cookie
|
|
try {
|
|
appInsights.cookie = doc.cookie;
|
|
} catch (e) { }
|
|
|
|
function _createMethods(methods) {
|
|
while (methods.length) {
|
|
(function (name) {
|
|
// Define a temporary method that queues-up a the real method call
|
|
appInsights[name] = function () {
|
|
// Capture the original arguments passed to the method
|
|
var originalArguments = arguments;
|
|
if (!loadFailed) { // If we have detected that the main script failed to load then stop queuing events that will never be processed
|
|
// Queue-up a call to the real method
|
|
appInsights.queue.push(function () {
|
|
// Invoke the real method with the captured original arguments
|
|
appInsights[name].apply(appInsights, originalArguments);
|
|
});
|
|
}
|
|
};
|
|
})(methods.pop());
|
|
}
|
|
}
|
|
|
|
var track = "track";
|
|
var trackPage = "TrackPage";
|
|
var trackEvent = "TrackEvent";
|
|
_createMethods([track + "Event",
|
|
track + "PageView",
|
|
track + "Exception",
|
|
track + "Trace",
|
|
track + "DependencyData",
|
|
track + "Metric",
|
|
track + "PageViewPerformance",
|
|
"start" + trackPage,
|
|
"stop" + trackPage,
|
|
"start" + trackEvent,
|
|
"stop" + trackEvent,
|
|
"addTelemetryInitializer",
|
|
"setAuthenticatedUserContext",
|
|
"clearAuthenticatedUserContext",
|
|
"flush"]);
|
|
|
|
// expose SeverityLevel enum
|
|
appInsights['SeverityLevel'] = {
|
|
Verbose : 0,
|
|
Information : 1,
|
|
Warning : 2,
|
|
Error : 3,
|
|
Critical : 4
|
|
};
|
|
|
|
// Collect global errors
|
|
// Note: ApplicationInsightsAnalytics is the extension string identifier for
|
|
// AppAnalytics. It is defined in ApplicationInsights.ts:ApplicationInsights.identifer
|
|
var analyticsCfg = ((aiConfig.extensionConfig || {}).ApplicationInsightsAnalytics ||{});
|
|
if (!(aiConfig[strDisableExceptionTracking] === true || analyticsCfg[strDisableExceptionTracking] === true)) {
|
|
var method = "onerror";
|
|
_createMethods(["_" + method]);
|
|
var originalOnError = win[method];
|
|
win[method] = function(message, url, lineNumber, columnNumber, error) {
|
|
var handled = originalOnError && originalOnError(message, url, lineNumber, columnNumber, error);
|
|
if (handled !== true) {
|
|
appInsights["_" + method]({
|
|
message: message,
|
|
url: url,
|
|
lineNumber: lineNumber,
|
|
columnNumber: columnNumber,
|
|
error: error,
|
|
evt: win.event
|
|
});
|
|
}
|
|
|
|
return handled;
|
|
};
|
|
aiConfig.autoExceptionInstrumented = true;
|
|
}
|
|
|
|
return appInsights;
|
|
})(snipConfig.cfg);
|
|
|
|
// global instance must be set in this order to mitigate issues in ie8 and lower
|
|
win[aiName] = aiSdk;
|
|
|
|
function _onInit() {
|
|
if (snipConfig.onInit) {
|
|
snipConfig.onInit(aiSdk);
|
|
}
|
|
}
|
|
|
|
// if somebody calls the snippet twice, don't report page view again
|
|
if (aiSdk.queue && aiSdk.queue.length === 0) {
|
|
aiSdk.queue.push(_onInit);
|
|
aiSdk.trackPageView({});
|
|
} else {
|
|
// Already loaded so just call the onInit
|
|
_onInit();
|
|
}
|
|
})(window, document, {
|
|
src: "https://js.monitor.azure.com/scripts/b/ai.3.gbl.min.js", // The SDK URL Source
|
|
// name: "appInsights", // Global SDK Instance name defaults to "appInsights" when not supplied
|
|
// ld: 0, // Defines the load delay (in ms) before attempting to load the sdk. -1 = block page load and add to head. (default) = 0ms load after timeout,
|
|
// useXhr: 1, // Use XHR instead of fetch to report failures (if available),
|
|
crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
|
|
// onInit: null, // Once the application insights instance has loaded and initialized this callback function will be called with 1 argument -- the sdk instance (DO NOT ADD anything to the sdk.queue -- As they won't get called)
|
|
cfg: { // Application Insights Configuration
|
|
connectionString: "YOUR_CONNECTION_STRING"
|
|
}
|
|
});
|