diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts index 2ee5253fb..669db5617 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts @@ -1530,5 +1530,49 @@ export class SenderTests extends AITestClass { QUnit.assert.equal(SendRequestReason.MaxBatchSize, sendNotifications[0].sendReason); } }); + + this.testCase({ + name: 'Envelope: operation.name is correctly truncated if required', + test: () => { + const excessiveName = new Array(1234).join("a"); // exceeds max of 1024 + + const bd = new Exception( + null, + new Error(), + {"property1": "val1", "property2": "val2" }, + {"measurement1": 50.0, "measurement2": 1.3 } + ); + const inputEnvelope: ITelemetryItem = { + name: "test", + time: new Date("2018-06-12").toISOString(), + iKey: "iKey", + baseType: Exception.dataType, + baseData: bd, + data: { + "property3": "val3", + "measurement3": 3.0 + }, + ext: { + "trace": { + "traceID": "1528B5FF-6455-4657-BE77-E6664CAC72DC", + "parentID": "1528B5FF-6455-4657-BE77-E6664CACEEEE", + "name": excessiveName + } + }, + tags: [ + {"user.accountId": "TestAccountId"}, + ], + }; + + // Act + const appInsightsEnvelope = Sender.constructEnvelope(inputEnvelope, this._instrumentationKey, null); + const baseData = appInsightsEnvelope.data.baseData; + + QUnit.assert.equal("val3", baseData.properties["property3"], "ExceptionData: customProperties (item.data) are added to the properties of the envelope and not included in the item.data") + QUnit.assert.equal("val1", baseData.properties["property1"], "ExceptionData: properties (item.baseData.properties) are added to telemetry envelope"); + QUnit.assert.equal(50.0, baseData.measurements["measurement1"], "ExceptionData: measurements (item.baseData.measurements) are added to telemetry envelope"); + QUnit.assert.equal(1024, appInsightsEnvelope.tags["ai.operation.name"].length, "The ai.operation.name should have been truncated to the maximum"); + } + }); } } \ No newline at end of file diff --git a/channels/applicationinsights-channel-js/src/EnvelopeCreator.ts b/channels/applicationinsights-channel-js/src/EnvelopeCreator.ts index 8802bdaba..6d35a281b 100644 --- a/channels/applicationinsights-channel-js/src/EnvelopeCreator.ts +++ b/channels/applicationinsights-channel-js/src/EnvelopeCreator.ts @@ -5,7 +5,8 @@ import { IPageViewPerformanceTelemetry, CtxTagKeys, HttpMethod, IPageViewTelemetryInternal, IWeb, IExceptionInternal, - SampleRate + SampleRate, + dataSanitizeString } from "@microsoft/applicationinsights-common"; import { ITelemetryItem, IDiagnosticLogger, LoggingSeverity, _InternalMessageId, hasJSON, getJSON, objForEachKey, @@ -25,7 +26,7 @@ function _setValueIf(target:T, field:keyof T, value:any) { /* * Maps Part A data from CS 4.0 */ -function _extractPartAExtensions(item: ITelemetryItem, env: IEnvelope) { +function _extractPartAExtensions(logger: IDiagnosticLogger, item: ITelemetryItem, env: IEnvelope) { // todo: switch to keys from common in this method let envTags = env.tags = env.tags || {}; let itmExt = item.ext = item.ext || {}; @@ -77,7 +78,7 @@ function _extractPartAExtensions(item: ITelemetryItem, env: IEnvelope) { let extTrace = itmExt.trace; if (extTrace) { _setValueIf(envTags, CtxTagKeys.operationParentId, extTrace.parentID); - _setValueIf(envTags, CtxTagKeys.operationName, extTrace.name); + _setValueIf(envTags, CtxTagKeys.operationName, dataSanitizeString(logger, extTrace.name)); _setValueIf(envTags, CtxTagKeys.operationId, extTrace.traceID); } @@ -157,7 +158,7 @@ function _createEnvelope(logger: IDiagnosticLogger, envelopeType: string, tel envelope.name = envelope.name.replace("{0}", iKeyNoDashes); // extract all extensions from ctx - _extractPartAExtensions(telemetryItem, envelope); + _extractPartAExtensions(logger, telemetryItem, envelope); // loop through the envelope tags (extension of Part A) and pick out the ones that should go in outgoing envelope tags telemetryItem.tags = telemetryItem.tags || []; diff --git a/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/ApplicationInsights.ts b/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/ApplicationInsights.ts index 9fb6d966b..5b47eccac 100644 --- a/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/ApplicationInsights.ts +++ b/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/ApplicationInsights.ts @@ -9,7 +9,7 @@ import { IExceptionTelemetry, ITraceTelemetry, IMetricTelemetry, IAutoExceptionTelemetry, IPageViewTelemetryInternal, IPageViewTelemetry, IPageViewPerformanceTelemetry, IPageViewPerformanceTelemetryInternal, dateTimeUtilsDuration, IExceptionInternal, PropertiesPluginIdentifier, AnalyticsPluginIdentifier, stringToBoolOrDefault, createDomEvent, - strNotSpecified, isCrossOriginError, utlDisableStorage + strNotSpecified, isCrossOriginError, utlDisableStorage, dataSanitizeString } from "@microsoft/applicationinsights-common"; import { @@ -684,7 +684,8 @@ export class ApplicationInsights extends BaseTelemetryPlugin implements IAppInsi traceLocationName = _location.pathname + (_location.hash || ""); } - _properties.context.telemetryTrace.name = traceLocationName; + // This populates the ai.operation.name which has a maximum size of 1024 so we need to sanitize it + _properties.context.telemetryTrace.name = dataSanitizeString(_self.diagLog(), traceLocationName); } if (_currUri) { _prevUri = _currUri; diff --git a/shared/AppInsightsCommon/src/Telemetry/Common/DataSanitizer.ts b/shared/AppInsightsCommon/src/Telemetry/Common/DataSanitizer.ts index 11c4eec59..b2bbd3502 100644 --- a/shared/AppInsightsCommon/src/Telemetry/Common/DataSanitizer.ts +++ b/shared/AppInsightsCommon/src/Telemetry/Common/DataSanitizer.ts @@ -60,13 +60,13 @@ export function dataSanitizeKeyAndAddUniqueness(logger: IDiagnosticLogger, key: export function dataSanitizeKey(logger: IDiagnosticLogger, name: any) { let nameTrunc: String; if (name) { - // Remove any leading or trailing whitepace + // Remove any leading or trailing whitespace name = strTrim(name.toString()); // truncate the string to 150 chars if (name.length > DataSanitizerValues.MAX_NAME_LENGTH) { nameTrunc = name.substring(0, DataSanitizerValues.MAX_NAME_LENGTH); - logger.throwInternal( + logger && logger.throwInternal( LoggingSeverity.WARNING, _InternalMessageId.NameTooLong, "name is too long. It has been truncated to " + DataSanitizerValues.MAX_NAME_LENGTH + " characters.", @@ -84,7 +84,7 @@ export function dataSanitizeString(logger: IDiagnosticLogger, value: any, maxLen value = strTrim(value); if (value.toString().length > maxLength) { valueTrunc = value.toString().substring(0, maxLength); - logger.throwInternal( + logger && logger.throwInternal( LoggingSeverity.WARNING, _InternalMessageId.StringValueTooLong, "string value is too long. It has been truncated to " + maxLength + " characters.", @@ -104,7 +104,7 @@ export function dataSanitizeMessage(logger: IDiagnosticLogger, message: any) { if (message) { if (message.length > DataSanitizerValues.MAX_MESSAGE_LENGTH) { messageTrunc = message.substring(0, DataSanitizerValues.MAX_MESSAGE_LENGTH); - logger.throwInternal( + logger && logger.throwInternal( LoggingSeverity.WARNING, _InternalMessageId.MessageTruncated, "message is too long, it has been truncated to " + DataSanitizerValues.MAX_MESSAGE_LENGTH + " characters.", { message }, @@ -122,7 +122,7 @@ export function dataSanitizeException(logger: IDiagnosticLogger, exception: any) let value:string = "" + exception; if (value.length > DataSanitizerValues.MAX_EXCEPTION_LENGTH) { exceptionTrunc = value.substring(0, DataSanitizerValues.MAX_EXCEPTION_LENGTH); - logger.throwInternal( + logger && logger.throwInternal( LoggingSeverity.WARNING, _InternalMessageId.ExceptionTruncated, "exception is too long, it has been truncated to " + DataSanitizerValues.MAX_EXCEPTION_LENGTH + " characters.", { exception }, true); } @@ -140,7 +140,7 @@ export function dataSanitizeProperties(logger: IDiagnosticLogger, properties: an try { value = getJSON().stringify(value); } catch (e) { - logger.throwInternal(LoggingSeverity.WARNING, _InternalMessageId.CannotSerializeObjectNonSerializable, "custom property is not valid", { exception: e}, true); + logger && logger.throwInternal(LoggingSeverity.WARNING, _InternalMessageId.CannotSerializeObjectNonSerializable, "custom property is not valid", { exception: e}, true); } } value = dataSanitizeString(logger, value, DataSanitizerValues.MAX_PROPERTY_LENGTH); @@ -177,7 +177,7 @@ export function dataSanitizeInput(logger: IDiagnosticLogger, input: any, maxLeng input = strTrim(input); if (input.length > maxLength) { inputTrunc = input.substring(0, maxLength); - logger.throwInternal( + logger && logger.throwInternal( LoggingSeverity.WARNING, _msgId, "input is too long, it has been truncated to " + maxLength + " characters.",