New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Identify whether the script is being consumed via the CDN or NPM package #1249
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,8 @@ import * as Common from "@microsoft/applicationinsights-common" | |
|
||
"use strict"; | ||
|
||
let _internalSdkSrc: string; | ||
|
||
/** | ||
* | ||
* @export | ||
|
@@ -18,6 +20,7 @@ import * as Common from "@microsoft/applicationinsights-common" | |
export interface Snippet { | ||
config: IConfiguration & Common.IConfig; | ||
queue?: Array<() => void>; | ||
sv?: string; | ||
version?: number; | ||
} | ||
|
||
|
@@ -46,10 +49,12 @@ export class Initialization implements IApplicationInsights { | |
|
||
private dependencies: DependenciesPlugin; | ||
private properties: PropertiesPlugin; | ||
private _snippetVersion: string; | ||
|
||
constructor(snippet: Snippet) { | ||
let _this = this; | ||
// initialize the queue and config in case they are undefined | ||
_this._snippetVersion = "" + (snippet.sv || snippet.version || ""); | ||
snippet.queue = snippet.queue || []; | ||
snippet.version = snippet.version || 2.0; // Default to new version | ||
let config: IConfiguration & Common.IConfig = snippet.config || ({} as any); | ||
|
@@ -269,6 +274,15 @@ export class Initialization implements IApplicationInsights { | |
|
||
function _updateSnippetProperties(snippet: Snippet) { | ||
if (snippet) { | ||
let snippetVer = ""; | ||
if (!CoreUtils.isNullOrUndefined(_this._snippetVersion)) { | ||
snippetVer += _this._snippetVersion; | ||
} | ||
if (legacyMode) { | ||
snippetVer += ".lg"; | ||
} | ||
_this.properties.context.internal.snippetVer = snippetVer || "-"; | ||
|
||
// apply updated properties to the global instance (snippet) | ||
for (const field in _this) { | ||
if (CoreUtils.isString(field) && | ||
|
@@ -296,6 +310,9 @@ export class Initialization implements IApplicationInsights { | |
// initialize core | ||
_this.core.initialize(_this.config, extensions); | ||
_this.context = _this.properties.context; | ||
if (_internalSdkSrc) { | ||
_this.context.internal.sdkSrc = _internalSdkSrc; | ||
} | ||
_updateSnippetProperties(_this.snippet); | ||
|
||
// Empty queue of all api calls logged prior to sdk download | ||
|
@@ -411,3 +428,49 @@ export class Initialization implements IApplicationInsights { | |
_this.config.diagnosticLogInterval && _this.config.diagnosticLogInterval > 0 ? _this.config.diagnosticLogInterval : 10000; | ||
} | ||
} | ||
|
||
// tslint:disable-next-line | ||
(function () { | ||
let sdkSrc = null; | ||
let isModule = false; | ||
|
||
try { | ||
// Try and determine whether the sdk is being loaded from the CDN | ||
// currentScript is only valid during initial processing | ||
let scrpt = (document ||{} as any).currentScript; | ||
if (scrpt) { | ||
sdkSrc = scrpt.src; | ||
// } else { | ||
// // We need to update to at least typescript 2.9 for this to work :-( | ||
// // Leaving as a stub for now so after we upgrade this breadcrumb is available | ||
// let meta = import.meta; | ||
// sdkSrc = (meta || {}).url; | ||
// isModule = true; | ||
} | ||
} catch (e) { | ||
} | ||
|
||
if (sdkSrc) { | ||
try { | ||
let url = sdkSrc.toLowerCase(); | ||
if (url) { | ||
let src = ""; | ||
if (url.indexOf("://az416426.vo.msecnd.net/") !== -1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only populating if this is from the standard CDN -- ignore non MS defined endpoints, and only include an anonymous name "cdn1" rather than the full domain/url There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the script is consumed from CDN via the CName will we have to update this to match those domain names? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, once we have enabled additional common names this will need to be updated and I'm planning on enumerating the known names (which is why I called the existing one cdn1) |
||
src = "cdn1"; | ||
if (url.indexOf("/scripts/") === -1) { | ||
if (url.indexOf("/next/") !== -1) { | ||
src += "-next"; | ||
} else if (url.indexOf("/beta/") !== -1) { | ||
src += "-beta"; | ||
} | ||
} | ||
} | ||
|
||
if (src) { | ||
_internalSdkSrc = src + (isModule ? ".mod" : ""); | ||
} | ||
} | ||
} catch (e) { | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When caught, does that mean NPM? Is it possible to know NPM vs CDN vs unknown? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This catch is unexpected and added purely to ensure that we don't crash, in which case this will mean that we don't know the outcome (same as what would happen with all IE and really old browsers). So it's not possible to "always" determine npm, cdn or unknown. This is also why I added the snippet property as it should always be defined in which case we could assume that snippet users are using the primary CDN (vs their own). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok so for now it will report primary CDN or (NPM + custom CDN + unknown)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will report primary CDN or nothing. |
||
} | ||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,9 @@ | |
* @copyright Microsoft 2018 | ||
*/ | ||
|
||
import { ITelemetryItem, IProcessTelemetryContext, IDiagnosticLogger, CoreUtils, hasWindow } from '@microsoft/applicationinsights-core-js'; | ||
import { ITelemetryItem, IProcessTelemetryContext, IDiagnosticLogger, CoreUtils, hasWindow, _InternalLogMessage } from '@microsoft/applicationinsights-core-js'; | ||
import { Session, _SessionManager } from './Context/Session'; | ||
import { Extensions, ITelemetryContext, IOperatingSystem, ITelemetryTrace, IWeb, SampleRate, CtxTagKeys } from '@microsoft/applicationinsights-common'; | ||
import { Extensions, ITelemetryContext, IOperatingSystem, ITelemetryTrace, IWeb, SampleRate, CtxTagKeys, PageView } from '@microsoft/applicationinsights-common'; | ||
import { Application } from './Context/Application'; | ||
import { Device } from './Context/Device'; | ||
import { Internal } from './Context/Internal'; | ||
|
@@ -29,140 +29,159 @@ export class TelemetryContext implements ITelemetryContext { | |
public appId: () => string; | ||
|
||
constructor(logger: IDiagnosticLogger, defaultConfig: ITelemetryConfig) { | ||
let _self = this; | ||
if (hasWindow()) { | ||
this.sessionManager = new _SessionManager(defaultConfig, logger); | ||
this.application = new Application(); | ||
this.device = new Device(); | ||
this.internal = new Internal(defaultConfig); | ||
this.location = new Location(); | ||
this.user = new User(defaultConfig, logger); | ||
this.telemetryTrace = new TelemetryTrace(undefined, undefined, undefined, logger); | ||
this.session = new Session(); | ||
} | ||
this.appId = () => null; | ||
_self.sessionManager = new _SessionManager(defaultConfig, logger); | ||
_self.application = new Application(); | ||
_self.device = new Device(); | ||
_self.internal = new Internal(defaultConfig); | ||
_self.location = new Location(); | ||
_self.user = new User(defaultConfig, logger); | ||
_self.telemetryTrace = new TelemetryTrace(undefined, undefined, undefined, logger); | ||
_self.session = new Session(); | ||
} | ||
_self.appId = () => null; | ||
} | ||
|
||
public applySessionContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
const sessionContext = this.session || (this.sessionManager && this.sessionManager.automaticSession); | ||
let session = this.session; | ||
let sessionManager = this.sessionManager; | ||
const sessionContext = session || (sessionManager && sessionManager.automaticSession); | ||
if (sessionContext) { | ||
if (typeof sessionContext.id === "string") { | ||
if (CoreUtils.isString(sessionContext.id)) { | ||
event.ext.app.sesId = sessionContext.id; | ||
} | ||
} | ||
|
||
if (this.session) { | ||
if (session) { | ||
// If customer set session info, apply his context; otherwise apply context automatically generated | ||
if (typeof this.session.id === "string") { | ||
event.ext.app.sesId = this.session.id; | ||
if (CoreUtils.isString(session.id)) { | ||
event.ext.app.sesId = session.id; | ||
} else { | ||
event.ext.app.sesId = this.sessionManager.automaticSession.id; | ||
event.ext.app.sesId = sessionManager.automaticSession.id; | ||
} | ||
} | ||
} | ||
|
||
public applyOperatingSystemContxt(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.os && this.os.name) { | ||
event.ext.os = this.os; | ||
let os = this.os; | ||
if (os && os.name) { | ||
event.ext.os = os; | ||
} | ||
} | ||
|
||
public applyApplicationContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.application) { | ||
let application = this.application; | ||
if (application) { | ||
|
||
if (typeof this.application.ver === "string") { | ||
event.tags[CtxTagKeys.applicationVersion] = this.application.ver; | ||
if (CoreUtils.isString(application.ver)) { | ||
event.tags[CtxTagKeys.applicationVersion] = application.ver; | ||
} | ||
if (typeof this.application.build === "string") { | ||
event.tags[CtxTagKeys.applicationBuild] = this.application.build; | ||
if (CoreUtils.isString(application.build)) { | ||
event.tags[CtxTagKeys.applicationBuild] = application.build; | ||
} | ||
} | ||
} | ||
|
||
public applyDeviceContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
|
||
if (this.device) { | ||
if (typeof this.device.id === "string") { | ||
event.ext.device.localId = this.device.id; | ||
let device = this.device; | ||
if (device) { | ||
if (CoreUtils.isString(device.id)) { | ||
event.ext.device.localId = device.id; | ||
} | ||
|
||
if (typeof this.device.ip === "string") { | ||
event.ext.device.ip = this.device.ip; | ||
if (CoreUtils.isString(device.ip)) { | ||
event.ext.device.ip = device.ip; | ||
} | ||
|
||
if (typeof this.device.model === "string") { | ||
event.ext.device.model = this.device.model; | ||
if (CoreUtils.isString(device.model)) { | ||
event.ext.device.model = device.model; | ||
} | ||
|
||
if (typeof this.device.deviceClass === "string") { | ||
event.ext.device.deviceClass = this.device.deviceClass; | ||
if (CoreUtils.isString(device.deviceClass)) { | ||
event.ext.device.deviceClass = device.deviceClass; | ||
} | ||
} | ||
} | ||
|
||
public applyInternalContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.internal) { | ||
if (typeof this.internal.agentVersion === "string") { | ||
event.tags[CtxTagKeys.internalAgentVersion] = this.internal.agentVersion; // not mapped in CS 4.0 | ||
let internal = this.internal; | ||
if (internal) { | ||
if (CoreUtils.isString(internal.agentVersion)) { | ||
event.tags[CtxTagKeys.internalAgentVersion] = internal.agentVersion; // not mapped in CS 4.0 | ||
} | ||
if (CoreUtils.isString(internal.sdkVersion)) { | ||
event.tags[CtxTagKeys.internalSdkVersion] = internal.sdkVersion; | ||
} | ||
if (typeof this.internal.sdkVersion === "string") { | ||
event.tags[CtxTagKeys.internalSdkVersion] = this.internal.sdkVersion; | ||
|
||
if (event.baseType === _InternalLogMessage.dataType || event.baseType === PageView.dataType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Limited to the Internal messages and initial page view |
||
if (CoreUtils.isString(internal.snippetVer)) { | ||
event.tags[CtxTagKeys.internalSnippet] = internal.snippetVer; | ||
} | ||
|
||
if (CoreUtils.isString(internal.sdkSrc)) { | ||
event.tags[CtxTagKeys.internalSdkSrc] = internal.sdkSrc; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public applyLocationContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.location) { | ||
if (typeof this.location.ip === "string") { | ||
event.tags[CtxTagKeys.locationIp] = this.location.ip; | ||
let location = this.location; | ||
if (location) { | ||
if (CoreUtils.isString(location.ip)) { | ||
event.tags[CtxTagKeys.locationIp] = location.ip; | ||
} | ||
} | ||
} | ||
|
||
public applyOperationContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.telemetryTrace) { | ||
let telemetryTrace = this.telemetryTrace; | ||
if (telemetryTrace) { | ||
const trace = event.ext.trace || ({traceID: undefined, parentID: undefined} as ITelemetryTrace); | ||
if (typeof this.telemetryTrace.traceID === "string") { | ||
trace.traceID = this.telemetryTrace.traceID; | ||
if (CoreUtils.isString(telemetryTrace.traceID)) { | ||
trace.traceID = telemetryTrace.traceID; | ||
} | ||
|
||
if (typeof this.telemetryTrace.name === "string") { | ||
trace.name = this.telemetryTrace.name; | ||
if (CoreUtils.isString(telemetryTrace.name)) { | ||
trace.name = telemetryTrace.name; | ||
} | ||
|
||
if (typeof this.telemetryTrace.parentID === "string") { | ||
trace.parentID = this.telemetryTrace.parentID; | ||
if (CoreUtils.isString(telemetryTrace.parentID)) { | ||
trace.parentID = telemetryTrace.parentID; | ||
} | ||
|
||
event.ext.trace = trace; | ||
} | ||
} | ||
|
||
public applyWebContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.web) { | ||
let web = this.web; | ||
if (web) { | ||
event.ext.web = event.ext.web || {}; | ||
event.ext.web = this.web; | ||
event.ext.web = web; | ||
} | ||
} | ||
|
||
public applyUserContext(event: ITelemetryItem, itemCtx?: IProcessTelemetryContext) { | ||
if (this.user) { | ||
let user = this.user; | ||
if (user) { | ||
if (!event.tags) { | ||
event.tags = []; | ||
} | ||
|
||
// stays in tags | ||
if (typeof this.user.accountId === "string") { | ||
const item = {}; | ||
event.tags[CtxTagKeys.userAccountId] = this.user.accountId; | ||
if (CoreUtils.isString(user.accountId)) { | ||
event.tags[CtxTagKeys.userAccountId] = user.accountId; | ||
} | ||
|
||
// CS 4.0 | ||
if (typeof this.user.id === "string") { | ||
event.ext.user.id = this.user.id; | ||
if (CoreUtils.isString( user.id)) { | ||
event.ext.user.id = user.id; | ||
} | ||
|
||
if (typeof this.user.authenticatedId === "string") { | ||
event.ext.user.authId = this.user.authenticatedId; | ||
if (CoreUtils.isString(user.authenticatedId)) { | ||
event.ext.user.authId = user.authenticatedId; | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried quite a few work-arounds to get this information with 2.5.3 (our current TS version), but nothing worked -- I could have done some sort of post processing (like the es3-poly), but that seems like overkill considering we should be upgrading to a later version of TS sooner rather than later.