Two years ago, I wrote a blog post Monitoring and telemetry in F&O where, among other things, I showed how to add a custom trace message and even include a custom property:
Map properties = new Map(Types::String, Types::String); properties.add('Feature', 'My feature 1'); properties.add('MyCorrelationId', '123456'); SysGlobalTelemetry::logTraceWithCustomProperties('Custom message from X++', properties)
Microsoft keep evolving this area by adding more things that are logged automatically and the API has evolved as well. What I showed before is now deprecated and the new way looks like this:
SysApplicationInsightsTraceTelemetry telemetryData = SysApplicationInsightsTraceTelemetry::newFromMessageAndSeverity( 'Credit note created for XYZ.', Microsoft.ApplicationInsights.DataContracts.SeverityLevel::Information); telemetryData.addProperty(MyBusinessProcessProperty::newFromValue("Sales invoice")); SysApplicationInsightsTelemetryLogger::instance().trackTrace(telemetryData);
The biggest difference is that the property isn’t identified merely by its name anymore; we use a class. I think that Microsoft decided to do it this way because the class now includes an extra piece of information: compliance data type. It’s also possible to add more data or logic to these classes in future without changing the method of adding properties.
The example above uses MyBusinessProcessProperty class; this is how I’ve implemented it:
internal final class MyBusinessProcessProperty extends SysApplicationInsightsProperty { private const str PropertyName = 'BusinessProcess'; internal static MyBusinessProcessProperty newFromValue(str _value) { return new MyBusinessProcessProperty(_value); } protected container initialize() { return [PropertyName, SysApplicationInsightsComplianceDataType::SystemMetadata]; } }
By the way, I don’t like the new API too much. Ideally, adding trace message should be as simple as possible, so we can add tracing easily and we can focus on the actual business logic, not a big pile of code just for tracing.
For instance, the decision to expose the CLR enum (Microsoft.ApplicationInsights.DataContracts.SeverityLevel) doesn’t make a good sense to me. You either need use the full long name, or you need to interrupt your work, go to the top of the file, add a using statement and then continue. There should be a native X++ enum or a simply an appropriate method.
There are many ways how it could be redesigned. Let me show you a very simple extension making quite a difference.
Original code for adding a trace message (with a custom property):
SysApplicationInsightsTraceTelemetry telemetryData = SysApplicationInsightsTraceTelemetry::newFromMessageAndSeverity( 'Credit note created for XYZ.', Microsoft.ApplicationInsights.DataContracts.SeverityLevel::Information); telemetryData.addProperty(MyBusinessProcessProperty::newFromValue("Sales invoice")); SysApplicationInsightsTelemetryLogger::instance().trackTrace(telemetryData);
A new way:
SysApplicationInsightsTraceTelemetry::newInfo('Credit note created for XYZ.') .addProperty(MyBusinessProcessProperty::newFromValue("Sales invoice")) .send();
In this case, I’ve just added two methods to SysApplicationInsightsTraceTelemetry class:
using Microsoft.ApplicationInsights.DataContracts; [ExtensionOf(classStr(SysApplicationInsightsTraceTelemetry))] final class SysApplicationInsightsTraceTelemetry_My_Extension { public static SysApplicationInsightsTraceTelemetry newInfo(str _traceMessage) { return SysApplicationInsightsTraceTelemetry::newFromMessageAndSeverity(_traceMessage, SeverityLevel::Information); } public void send() { SysApplicationInsightsTelemetryLogger::instance().trackTrace(this); } }