diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/FastTrackFscmTelemetrySamples.sln b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/FastTrackFscmTelemetrySamples.sln index 0502a9a..0480e88 100644 --- a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/FastTrackFscmTelemetrySamples.sln +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/FastTrackFscmTelemetrySamples.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.8.34322.80 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FC65038C-1B2F-41E1-A629-BED71D161FFF}") = "Order2Cash (USR) [FTApplicationInsightsTelemetry]", "Order2Cash\Order2Cash.rnrproj", "{A24B055C-A29A-4198-AA06-F62C9471F635}" EndProject +Project("{FC65038C-1B2F-41E1-A629-BED71D161FFF}") = "TelemetryExtensionExample (SYS) [Application Suite]", "TelemetryExtensionExample\TelemetryExtensionExample.rnrproj", "{7A2363FB-28BD-4203-BDDC-661CC58FBC68}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,6 +14,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {A24B055C-A29A-4198-AA06-F62C9471F635}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A24B055C-A29A-4198-AA06-F62C9471F635}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A2363FB-28BD-4203-BDDC-661CC58FBC68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A2363FB-28BD-4203-BDDC-661CC58FBC68}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ApplicationInsights.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ApplicationInsights.png new file mode 100644 index 0000000..64d4473 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ApplicationInsights.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ConcreteTelemetryClass.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ConcreteTelemetryClass.png new file mode 100644 index 0000000..a3bf239 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ConcreteTelemetryClass.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/FineGrainedControlwithinTheTelemetryClass.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/FineGrainedControlwithinTheTelemetryClass.png new file mode 100644 index 0000000..1d17f4a Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/FineGrainedControlwithinTheTelemetryClass.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/HowToDisableParticularTelemetry.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/HowToDisableParticularTelemetry.png new file mode 100644 index 0000000..1069a1c Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/HowToDisableParticularTelemetry.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/LoggingTelemetry.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/LoggingTelemetry.png new file mode 100644 index 0000000..a3ee249 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/LoggingTelemetry.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/MyTelemetryBase.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/MyTelemetryBase.png new file mode 100644 index 0000000..2c6b6c7 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/MyTelemetryBase.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ProjectStructure.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ProjectStructure.png new file mode 100644 index 0000000..83f22a9 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/ProjectStructure.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/RefreshAOT.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/RefreshAOT.png new file mode 100644 index 0000000..9c6753a Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/RefreshAOT.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/TelemetryLogSettings.png b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/TelemetryLogSettings.png new file mode 100644 index 0000000..3236758 Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/ScreenShots/TelemetryLogSettings.png differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/TelemetryExtensionExample.rnrproj b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/TelemetryExtensionExample.rnrproj new file mode 100644 index 0000000..6bb0b6a --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/TelemetryExtensionExample.rnrproj @@ -0,0 +1,119 @@ + + + + Debug + AnyCPU + $(MSBuildProgramFiles32)\MSBuild\Microsoft\Dynamics\AX + Foundation + v4.6 + bin + 2.0 + True + False + False + False + {7a2363fb-28bd-4203-bddc-661cc58fbc68} + TelemetryExtensionExample + TelemetryExtensionExample + Class + + + Debug + False + False + + + initial + AnyCPU + False + False + + + true + false + + + + Content + DMFDefinitionGroupExecutionHistory_Extension + DMFDefinitionGroupExecutionHistory_Extension + + + Content + MyApplicationInsightsEventIds + MyApplicationInsightsEventIds + + + Content + MyApplicationInsightsEventNames + MyApplicationInsightsEventNames + + + Content + MyApplicationInsightsEventProperties + MyApplicationInsightsEventProperties + + + Content + MyApplicationInsightsProperty + MyApplicationInsightsProperty + + + Content + MySysIntParametersFormEventHandler + MySysIntParametersFormEventHandler + + + Content + MyTelemetryBase + MyTelemetryBase + + + Content + TelemetryDataManagementImport + TelemetryDataManagementImport + + + Content + TelemetryPurchaseOrderConfirm + TelemetryPurchaseOrderConfirm + + + Content + TelemetrySalesOrderConfirm + TelemetrySalesOrderConfirm + + + Content + TelemetryShipConfirm + TelemetryShipConfirm + + + Content + WhsShipConfirm_Extension + WhsShipConfirm_Extension + + + Content + MyTelemetryClass + MyTelemetryClass + + + Content + MyTelemetrySeverityLevel + MyTelemetrySeverityLevel + + + Content + SysIntParameters.MyExtension + SysIntParameters.MyExtension + + + Content + MyTelemetryParameters + MyTelemetryParameters + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/DMFDefinitionGroupExecutionHistory_Extension.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/DMFDefinitionGroupExecutionHistory_Extension.xml new file mode 100644 index 0000000..99483eb --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/DMFDefinitionGroupExecutionHistory_Extension.xml @@ -0,0 +1,41 @@ + + + DMFDefinitionGroupExecutionHistory_Extension + + +/// DMFDefinitionGroupExecutionHistory_Extension Table extension +/// +[ExtensionOf(tableStr(DMFDefinitionGroupExecutionHistory))] +final class DMFDefinitionGroupExecutionHistory_Extension +{ +} +]]> + + + insertExecutionHistory + + /// Insert execution history + /// + /// DMFDefinitionGroupExecution record + public void insertExecutionHistory(DMFDefinitionGroupExecution _definitionGroupExecution) + { + next insertExecutionHistory(_definitionGroupExecution); + + DMFDefinitionGroupExecution dmfDefinitionGroupExecution = DMFDefinitionGroupExecution::find(_definitionGroupExecution.DefinitionGroup,_definitionGroupExecution.Entity,_definitionGroupExecution.ExecutionId); + DMFDefinitionGroupExecutionHistory dmfDefinitionGroupExecutionHistory = DMFDefinitionGroupExecutionHistory::find(dmfDefinitionGroupExecution.DefinitionGroup, dmfDefinitionGroupExecution.Entity, + dmfDefinitionGroupExecution.ExecutionId, dmfDefinitionGroupExecution.WriteStartDateTime, true); + + // Add any other conditions to log only for the entities you want here. + if (dmfDefinitionGroupExecutionHistory.RecId) + { + new TelemetryDataManagementImport(dmfDefinitionGroupExecutionHistory.WriteStartDateTime, dmfDefinitionGroupExecutionHistory.WriteEndDateTime, dmfDefinitionGroupExecutionHistory).processEvent(MyApplicationInsightsEventNames::DMFDefinitionGroupExecutionHistory); + } + } + +]]> + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventIds.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventIds.xml new file mode 100644 index 0000000..8d72f4c --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventIds.xml @@ -0,0 +1,14 @@ + + + MyApplicationInsightsEventIds + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventNames.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventNames.xml new file mode 100644 index 0000000..6caf09e --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventNames.xml @@ -0,0 +1,14 @@ + + + MyApplicationInsightsEventNames + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventProperties.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventProperties.xml new file mode 100644 index 0000000..28c25bf --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsEventProperties.xml @@ -0,0 +1,38 @@ + + + MyApplicationInsightsEventProperties + + +/// The MyApplicationInsightsEventProperties class contains all available event properties that can be used in the Application Insights telemetry. +/// +/// +/// The names must be unique. +/// Please keep the list sorted alphabetically in ascending order. +/// +internal static final class MyApplicationInsightsEventProperties +{ + internal static const str InventLocationId = 'inventLocationId'; + internal static const str LoadId = 'loadId'; + internal static const str LoadStatus = 'loadStatus'; + internal static const str NumOfLines = 'numOfLines'; + internal static const str SalesId = 'salesId'; + internal static const str CustAccount = 'custAccount'; + internal static const str SalesStatus = 'salesStatus'; + internal static const str DeliveryDate = 'deliveryDate'; + internal static const str PurchId = 'PurchId'; + internal static const str VendorName = 'vendorName'; + internal static const str PurchStatus = 'PurchStatus'; + internal static const str ElapsedMilliseconds = 'ElapsedMilliseconds'; + internal static const str DefinitionGroup = 'DefinitionGroup'; + internal static const str Entity = 'Entity'; + internal static const str ExecutionId = 'ExecutionId'; + internal static const str NoOfRecords = 'NoOfRecords'; + internal static const str NumOfTargetNew = 'NumOfTargetNew'; + internal static const str NumOfTargetUpdated = 'NumOfTargetUpdated'; + +} +]]> + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsProperty.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsProperty.xml new file mode 100644 index 0000000..2829035 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyApplicationInsightsProperty.xml @@ -0,0 +1,42 @@ + + + MyApplicationInsightsProperty + + +/// Concrete class for Application Insights message payload properties. +/// +public final class MyApplicationInsightsProperty extends SysApplicationInsightsProperty +{ + private str key; + private SysApplicationInsightsComplianceDataType dataType; + +} +]]> + + + new + + + + initialize + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MySysIntParametersFormEventHandler.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MySysIntParametersFormEventHandler.xml new file mode 100644 index 0000000..c076b4d --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MySysIntParametersFormEventHandler.xml @@ -0,0 +1,78 @@ + + + MySysIntParametersFormEventHandler + + + + + SysIntParameters_OnInitializing + +/// +/// +/// +/// +[FormEventHandler(formStr(SysIntParameters), FormEventType::Initializing)] +public static void SysIntParameters_OnInitializing(xFormRun sender, FormEventArgs e) + { + + #define.ClassPath(@"\Classes\%1") + + SysDictClass dictClass; + List extendedClassList; + ListEnumerator listEnumerator; + ClassName className; + // MethodName methodName; + ClassId childClass; + TreeNode childClassNode; + TreeNode methodNode; + int numberofMethods; + MyTelemetryParameters param; + + //set parent class and method you want to investigate + className = classStr(MyTelemetryBase); + //methodName = "DefaultDimension"; + + dictClass = new SysDictClass(className2Id(classname)); + extendedClassList = dictClass.extendedBy(); + + //loop through all child classes + if (extendedClassList.elements()) + { + listEnumerator = extendedClassList.getEnumerator(); + + setprefix(strfmt("Class %1 extended by %2 classes.", className, int2str(extendedClassList.elements()))); + + while (listEnumerator.moveNext()) + { + childClass = listEnumerator.current(); + childClassNode = TreeNode::findNode(strFmt(#ClassPath, classId2Name(childClass))); + + param = MyTelemetryParameters::find(childClassNode.AOTname()); + + if(!param) + { + ttsbegin; + param.clear(); + param.TelemetryClass = childClassNode.AOTname(); + param.IsEnabled = NoYes::Yes; + param.SeverityLevel = MyTelemetrySeverityLevel::Information; + param.insert(); + ttscommit; + } + + } + + } + +} + +]]> + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyTelemetryBase.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyTelemetryBase.xml new file mode 100644 index 0000000..da9fefa --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/MyTelemetryBase.xml @@ -0,0 +1,461 @@ + + + MyTelemetryBase + + +/// MyTelemetryBase class +/// +/// + + using DataContracts = Microsoft.ApplicationInsights.DataContracts; + +abstract class MyTelemetryBase +{ + protected Map basePropertyMap = new Map(Types::String, Types::string); + protected Map runtimePropertyMap = new Map(Types::String, Types::string); + + System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); + + protected MyTelemetryParameters telemetryLoggingParams; + //you can fill this field or not, if you dont fill it, it will be set to 0 + protected str eventId = "0"; +} +]]> + + + new + + + + telemetryName + + /// Class telemetryName + /// + /// Telemetry + protected ClassName telemetryName() + { + return classId2Name(classIdGet(this)); + } + +]]> + + + setElapsedMilliseconds + + + + addBaseProperty + + + + addRuntimeProperty + + + + clearRuntimeProperties + + + + shouldSkipLogging + + + + shouldSkipOnSeverityLevel + severity) + return true; + + return false; + } + +]]> + + + processMetric + + /// Method ProcessMetric + /// + public final void processMetric(real _value) + { + try + { + this.logMetric(_value); + } + catch + { + warning(strFmt("Telemetry Metric Processing Error - className : %1",classId2Name(classIdGet(this)))); + } + } + +]]> + + + processEvent + + /// Method processEvent + /// + public final void processEvent(str _name) + { + try + { + + if(this.shouldSkipLogging()) + return; + + if(!_name) + _name = this.telemetryName(); + + this.populateProperties(); + this.logEvent(this.eventId, _name); + } + catch + { + warning(strFmt("Telemetry Event Processing Error: className : %1 - EventName: %2", classId2Name(classIdGet(this)), _name)); + } + } + +]]> + + + processTrace + + /// Method processTrace + /// + public final void processTrace(str traceMessage, MyTelemetrySeverityLevel severity = MyTelemetrySeverityLevel::Information) + { + try + { + if(this.shouldSkipLogging()) + return; + + if(this.shouldSkipOnSeverityLevel(severity)) + return; + + this.populateProperties(); + this.logTrace(traceMessage, severity); + } + catch + { + warning(strFmt("Telemetry Trace Processing Error: className : %1 - TraceMessage: %2", classId2Name(classIdGet(this)), traceMessage)); + } + } + +]]> + + + populateProperties + + /// Method Populate properties. This housld be implemented by the concrete class that extends this base. + /// + protected abstract void populateProperties() + { + } + +]]> + + + metricName + + /// Class metricName + /// + /// Telemetry + protected ClassName metricName() + { + return classId2Name(classIdGet(this)); + } + +]]> + + + logMetric + + /// + protected void logMetric(real _value) + { + SysApplicationInsightsTelemetryLogger::instance().trackMetric(this.metricName(), _value); + } + +]]> + + + logMetricWithDimensions + + /// + protected void logMetricWithDimensions(real _value, str _dimension1Name, str _dimension1Value, str _dimension2Name = "", str _dimension2Value = '', str _dimension3Name = '', str _dimension3Value = '') + { + SysApplicationInsightsTelemetryLogger::instance().trackMetricWithDimensions(this.metricName(), _value, _dimension1Name, _dimension1Value, _dimension2Name, _dimension2Value, _dimension3Name, _dimension3Value); + } + +]]> + + + logEvent + + /// Method Log + /// + protected void logEvent(str _eventId, str _name) + { + SysApplicationInsightsEventTelemetry eventTelemetry = SysApplicationInsightsEventTelemetry::newFromEventIdName(_eventId, _name); + + MapIterator iterator; + str key, value; + + // Get an iterator for the map + iterator = new MapIterator(basePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + eventTelemetry.addProperty(property); + iterator.next(); + } + + //add runtime properties: + iterator = new MapIterator(runtimePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + eventTelemetry.addProperty(property); + iterator.next(); + } + + SysApplicationInsightsTelemetryLogger::instance().trackEvent(eventTelemetry); + } + +]]> + + + shouldLogEvent + + + + logTrace + + /// Method Log + /// + protected void logTrace(str traceMessage, MyTelemetrySeverityLevel severity = MyTelemetrySeverityLevel::Information) + { + DataContracts.SeverityLevel dotNetSeverity; + switch(severity) + { + case MyTelemetrySeverityLevel::Critical: + dotNetSeverity = DataContracts.SeverityLevel::Critical; + break; + case MyTelemetrySeverityLevel::Error: + dotNetSeverity = DataContracts.SeverityLevel::Error; + break; + case MyTelemetrySeverityLevel::Warning: + dotNetSeverity = DataContracts.SeverityLevel::Warning; + break; + case MyTelemetrySeverityLevel::Information: + dotNetSeverity = DataContracts.SeverityLevel::Information; + break; + case MyTelemetrySeverityLevel::Verbose: + dotNetSeverity = DataContracts.SeverityLevel::Verbose; + break; + default: + dotNetSeverity = DataContracts.SeverityLevel::Information; + break; + } + SysApplicationInsightsTraceTelemetry traceTelemetry = SysApplicationInsightsTraceTelemetry::newFromEventIdName(traceMessage, dotNetSeverity); + + MapIterator iterator; + str key, value; + + // Get an iterator for the map + iterator = new MapIterator(basePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + traceTelemetry.addProperty(property); + iterator.next(); + } + + //add runtime properties: + iterator = new MapIterator(runtimePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + traceTelemetry.addProperty(property); + iterator.next(); + } + + SysApplicationInsightsTelemetryLogger::instance().trackTrace(traceTelemetry); + } + +]]> + + + logException + + /// Method Log + /// + protected void logException(str message) + { + SysApplicationInsightsExceptionTelemetry exceptionTelemetry = SysApplicationInsightsExceptionTelemetry::newFromExceptionMessage(message); + + MapIterator iterator; + str key, value; + + // Get an iterator for the map + iterator = new MapIterator(basePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + exceptionTelemetry.addProperty(property); + iterator.next(); + } + + //add runtime properties: + iterator = new MapIterator(runtimePropertyMap); + + // Loop through the map & add base properties + while (iterator.more()) + { + key = iterator.key(); + value = iterator.value(); + + var property = new MyApplicationInsightsProperty(key, value, SysApplicationInsightsComplianceDataType::CustomerContent); + exceptionTelemetry.addProperty(property); + iterator.next(); + } + + SysApplicationInsightsTelemetryLogger::instance().trackException(exceptionTelemetry); + } + +]]> + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryDataManagementImport.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryDataManagementImport.xml new file mode 100644 index 0000000..1dd6ef6 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryDataManagementImport.xml @@ -0,0 +1,63 @@ + + + TelemetryDataManagementImport + + +/// TelemetryDataManagementImport class log monitoring and telemetry custom events/metrics +/// +internal final class TelemetryDataManagementImport extends MyTelemetryBase +{ + private DMFDefinitionGroupExecutionHistory dmfDefinitionGroupExecutionHistory; + private TransDateTime executionStartTime; + private TransDateTime executionEndTime; +} +]]> + + + new + + + + shouldLogEvent + + + + populateProperties + + /// populate telemetry entries to a map + /// + protected void populateProperties() + { + // We don't have to call the SetElapsedMilliSeconds() because we are getting the execution time from the table entry + // this.setElapsedMilliseconds(); + this.addBaseProperty(MyApplicationInsightsEventProperties::ElapsedMilliseconds, int642Str(DateTimeUtil::getDifference(executionEndTime, executionStartTime))); + this.addBaseProperty(MyApplicationInsightsEventProperties::DefinitionGroup, dmfDefinitionGroupExecutionHistory.DefinitionGroup); + this.addBaseProperty(MyApplicationInsightsEventProperties::Entity, dmfDefinitionGroupExecutionHistory.Entity); + this.addBaseProperty(MyApplicationInsightsEventProperties::ExecutionId,dmfDefinitionGroupExecutionHistory.ExecutionId); + this.addBaseProperty(MyApplicationInsightsEventProperties::NoOfRecords, int2Str(dmfDefinitionGroupExecutionHistory.NoOfRecords)); + this.addBaseProperty(MyApplicationInsightsEventProperties::NumOfTargetNew,int2Str(dmfDefinitionGroupExecutionHistory.NumOfTargetNew)); + this.addBaseProperty(MyApplicationInsightsEventProperties::NumOfTargetUpdated, int2Str(dmfDefinitionGroupExecutionHistory.NumOfTargetUpdated)); + } + +]]> + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryPurchaseOrderConfirm.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryPurchaseOrderConfirm.xml new file mode 100644 index 0000000..83962f1 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryPurchaseOrderConfirm.xml @@ -0,0 +1,53 @@ + + + TelemetryPurchaseOrderConfirm + + +/// TelemetryPurchaseOrderConfirm class extending methods of MyTelemetryBase class +/// +final class TelemetryPurchaseOrderConfirm extends MyTelemetryBase +{ + private PurchTable purchTable; + +} +]]> + + + new + + + + shouldLogEvent + + + + populateProperties + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetrySalesOrderConfirm.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetrySalesOrderConfirm.xml new file mode 100644 index 0000000..eb39de2 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetrySalesOrderConfirm.xml @@ -0,0 +1,61 @@ + + + TelemetrySalesOrderConfirm + + +/// TelemetrySalesOrderConfirm class extending methods of MyTelemetryBase class +/// +final class TelemetrySalesOrderConfirm extends MyTelemetryBase +{ + private SalesTable salesTable; + private str error; +} +]]> + + + new + + + + shouldLogEvent + MyTelemetrySeverityLevel::Information) + { + return false; + } + + return true; + } + +]]> + + + populateProperties + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryShipConfirm.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryShipConfirm.xml new file mode 100644 index 0000000..2bf09b9 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/TelemetryShipConfirm.xml @@ -0,0 +1,59 @@ + + + TelemetryShipConfirm + + +/// TelemetryShipConfirm class extending methods of MyTelemetryBase class +/// +final class TelemetryShipConfirm extends MyTelemetryBase +{ + private WHSLoadTable load; + +} +]]> + + + new + + + + shouldLogEvent + + + + populateProperties + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/WhsShipConfirm_Extension.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/WhsShipConfirm_Extension.xml new file mode 100644 index 0000000..dfffce8 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxClass/WhsShipConfirm_Extension.xml @@ -0,0 +1,69 @@ + + + WhsShipConfirm_Extension + + +/// Extension for the class WhsShipConfirm. +/// +[ExtensionOf(classStr(WhsShipConfirm))] +final class WhsShipConfirm_Extension +{ +} +]]> + + + shipConfirm + + /// Wrapper to WhsShipConfirm.shipConfirm(WHSLoadId loadId). Insert your logic around shipConfirm here. + /// + /// loadId value + public void shipConfirm(WHSLoadId loadId) + { + // Generate telemetry after the shipConfirm operation + WHSLoadTable loadTable = WHSLoadTable::find(loadId); + var telemetry = new TelemetryShipConfirm(loadTable); + + try + { + // Call the original shipConfirm method + next shipConfirm(loadId); + } + catch (Exception::Deadlock) + { + retry; + } + catch (Exception::UpdateConflict) + { + if (appl.ttsLevel() == 0) + { + // Define the retry count globally. + var retryCount = 3; + if (xSession::currentRetryCount() >= retryCount) + { + throw Exception::UpdateConflictNotRecovered; + } + else + { + retry; + } + } + else + { + throw Exception::UpdateConflict; + } + } + catch (Exception::Error) + { + throw Exception::Error; + } + + telemetry.processEvent(MyApplicationInsightsEventNames::WHSShipConfirm); + } + +]]> + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEdt/MyTelemetryClass.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEdt/MyTelemetryClass.xml new file mode 100644 index 0000000..6c5874e --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEdt/MyTelemetryClass.xml @@ -0,0 +1,12 @@ + + + MyTelemetryClass + + + + + 100 + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEnum/MyTelemetrySeverityLevel.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEnum/MyTelemetrySeverityLevel.xml new file mode 100644 index 0000000..5986d9a --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxEnum/MyTelemetrySeverityLevel.xml @@ -0,0 +1,47 @@ + + + MyTelemetrySeverityLevel + + MyTelemetrySeverityLevelHelp + + + + + Verbose + + 1 + + + Information + + 2 + + + Warning + + 3 + + + Error + + 4 + + + Critical + + 5 + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxFormExtension/SysIntParameters.MyExtension.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxFormExtension/SysIntParameters.MyExtension.xml new file mode 100644 index 0000000..e7f8986 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxFormExtension/SysIntParameters.MyExtension.xml @@ -0,0 +1,140 @@ + + + SysIntParameters.MyExtension + + + + FormExtensionControl + + MySettings + TabPage + + + + MyTelemetryTitleGroup + Yes + Group + SizeToAvailable + + + + MyTelemetryLogSettingsText + Yes + StaticText + SizeToAvailable + + + + MyTelemetryLogSettings + + + + No + None + + + + MyTelemetryGrid + SizeToAvailable + ToolbarList + 1.2 + Group + SizeToAvailable + + + + MyTelemetryLogParam + Grid + + + + MyTelemetryLogParam_TelemetryClass + No + String + + TelemetryClass + MyTelemetryParameters + + + MyTelemetryLogParam_IsEnabled + CheckBox + + IsEnabled + MyTelemetryParameters + + + MyTelemetryLogParam_SeverityLevel + ComboBox + + SeverityLevel + MyTelemetryParameters + + + + TelemetryFields + MyTelemetryParameters + + + None + + + + MyTelemetryLogSettings + + + TableOfContents + + + + + + + MyTelemetryParameters + MyTelemetryParameters
+ + + DataAreaId + + + IsEnabled + + + Partition + + + RecId + + + SeverityLevel + + + TableId + + + TelemetryClass + + + + + +
+
+ + +
\ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxTable/MyTelemetryParameters.xml b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxTable/MyTelemetryParameters.xml new file mode 100644 index 0000000..95936f9 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/bin/AxTable/MyTelemetryParameters.xml @@ -0,0 +1,119 @@ + + + MyTelemetryParameters + + + + + + + find + + + + + + + + + Allow + + TelemetryClass + Yes + FoundAndEmpty + + + + AutoReport + + + + AutoLookup + + + + AutoIdentification + Yes + + + + AutoSummary + + + + AutoBrowse + + + + TelemetryFields + + + TelemetryClass + + + IsEnabled + + + SeverityLevel + + + + + + + TelemetryClass + MyTelemetryClass + Yes + + + IsEnabled + NoYes + + + SeverityLevel + MyTelemetrySeverityLevel + + + + + + TelemetryClass + + + TelemetryClass + + + + + + + + \ No newline at end of file diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/obj/Debug/TelemetryExtensionExample.rnrproj.AssemblyReference.cache b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/obj/Debug/TelemetryExtensionExample.rnrproj.AssemblyReference.cache new file mode 100644 index 0000000..04557dc Binary files /dev/null and b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/obj/Debug/TelemetryExtensionExample.rnrproj.AssemblyReference.cache differ diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/obj/Debug/TelemetryExtensionExample.rnrproj.FileListAbsolute.txt b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/obj/Debug/TelemetryExtensionExample.rnrproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/readme.md b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/readme.md new file mode 100644 index 0000000..75847a0 --- /dev/null +++ b/SampleXppExtensions/Projects/FastTrackFscmTelemetrySamples/TelemetryExtensionExample/readme.md @@ -0,0 +1,82 @@ +# Dynamics 365 FastTrack FSCM Telemetry Samples - TelemetryExtensionExample + +This folder contains sample code and guidelines for implementing telemetry in Dynamics 365 Finance and Supply Chain Management (FSCM). The samples are intended to help customers utilize telemetry to monitor and optimize their D365 applications. The code is provided As-is to customer usage. No gaurentees are provided + +## Table of Contents + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Usage](#usage) +- [Contributing](#contributing) +- [License](#license) + +## Introduction + +This project provides sample implementations of telemetry in D365 FSCM. It includes creation of a telemetry Base class to demonstrate how to utilize SysApplicationInsightsTelemetryLogger to log Events/metrics/traces with properties to ApplicationInsights. It also includes an extension to the MonitoringAndTelemetry module to control the granularity of logging to Application Insights. + +## Prerequisites + +- Dynamics 365 Finance and Supply Chain Management environment +- Visual Studio 2019 or later +- .NET Framework 4.7.2 or later +- Access to Azure Application Insights + +## Installation + +1. Clone the repository: + + ```bash + git clone https://github.com/microsoft/Dynamics-365-FastTrack-FSCM-Telemetry-Samples.git + cd Dynamics-365-FastTrack-FSCM-Telemetry-Samples\SampleXppExtensions\Projects\FastTrackFscmTelemetrySamples + ``` + +2. Open the solution in Visual Studio in adminstrator mode and open FastTrackFscmTelemetrySamples.sln: + + Create the classes, enums, tables for the code under "\TelemetryExtensionExample\bin" + The project structure will look like + ![My project structure](ScreenShots/ProjectStructure.png) + +3. Once you create all the dependencies of the project, build the project and refresh AOT +![My project structure](ScreenShots/RefreshAOT.png) + +if all the classes are built fine, you should see the Cost control configuration ('My Telemetry Log Settings' feel free to rename it as appropriate in your project)in Monitoring and Telemetry settings in your D365 F&O +![Cost control settings](ScreenShots/TelemetryLogSettings.png) + +## Usage + +1. `MyTelemetryBase` class is the base class which provides structured access to SysApplicationInsightsTelemetryLogger. In this class you can aggregare Properties as your product code is executing and call the ProcessEvent, ProcessTrace, ProcessException etc methods at appropriate points to send those events to ApplicationInsights + + ![MyTelemetryBase Class](ScreenShots/MyTelemetryBase.png) + +2. For each different event/metric/Trace you want to log to AppInsights create a concrete class extending from MyTelemetryBase. Here's an example +![My copncrete telemetry Class](ScreenShots/ConcreteTelemetryClass.png) + +3. Use the telemetry class to log telemetry. + ![My copncrete telemetry Class](ScreenShots/LoggingTelemetry.png) + +4. Monitor the telemetry data in Azure Application Insights. Depending on whether you have logged an event, trace or exception etc, your data will be available in that respective table + + ![Azure Application Insights](ScreenShots/ApplicationInsights.png) + +5. As you implement telemetry classes and log data into AppInsights, you can control the which events and which severity levels are logged in AppInsights by 2 different ways. +a> You can disable particular kind of event sall together in the Extension UI + ![How to disable particular events](ScreenShots/HowToDisableParticularTelemetry.png) + +b> within the event class itself you can set a particular condition for the event to be logged. For example, in this class I have set only severity level above Information to be logged +![fine grained control within the telemetry class](ScreenShots/FineGrainedControlwithinTheTelemetryClass.png) + +## Contributing + +We welcome contributions to this project. To contribute: + +1. Fork the repository. +2. Create a new branch for your feature or bugfix. +3. Make your changes and commit them. +4. Push your changes to your fork. +5. Open a pull request to the main repository. + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. +