Skip to content

Commit 2388847

Browse files
authored
[Monitor OpenTelemetry Exporter] Add Support for Custom Events (#33183)
### Packages impacted by this PR @azure/monitor-opentelemetry-exporter ### Describe the problem that is addressed by this PR Adds support for custom events by setting the appropriate attribute on a log record `"microsoft.custom_event.name"`. ### Are there test cases added in this PR? _(If not, why?)_ Yes, tests to ensure that log records created with the correct attribute are sent as custom events. ### Checklists - [x] Added impacted package name to the issue description - [ ] Does this PR needs any fixes in the SDK Generator?** _(If so, create an Issue in the [Autorest/typescript](https://github.com/Azure/autorest.typescript) repository and link it here)_ - [x] Added a changelog (if necessary)
1 parent 82343df commit 2388847

File tree

4 files changed

+75
-31
lines changed

4 files changed

+75
-31
lines changed

sdk/monitor/monitor-opentelemetry-exporter/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

77
- Support the AMW de-duping flag in AKS auto-attach scenarios.
8+
- Support sending custom events via specifying `microsoft.custom_event.name` on logs.
89
- Support the stable OpenTelemetry HTTP semantic conventions.
910

1011
### Other Changes

sdk/monitor/monitor-opentelemetry-exporter/src/utils/constants/applicationinsights.ts

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export enum DependencyTypes {
3333

3434
export const AzureMonitorSampleRate = "microsoft.sample_rate";
3535
export const ApplicationInsightsBaseType = "_MS.baseType";
36+
export const ApplicationInsightsCustomEventName = "microsoft.custom_event.name";
3637

3738
export const ApplicationInsightsMessageName = "Microsoft.ApplicationInsights.Message";
3839
export const ApplicationInsightsExceptionName = "Microsoft.ApplicationInsights.Exception";

sdk/monitor/monitor-opentelemetry-exporter/src/utils/logUtils.ts

+43-30
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
ApplicationInsightsAvailabilityBaseType,
2727
ApplicationInsightsAvailabilityName,
2828
ApplicationInsightsBaseType,
29+
ApplicationInsightsCustomEventName,
2930
ApplicationInsightsEventBaseType,
3031
ApplicationInsightsEventName,
3132
ApplicationInsightsExceptionBaseType,
@@ -51,36 +52,47 @@ export function logToEnvelope(log: ReadableLogRecord, ikey: string): Envelope |
5152
let baseType: string;
5253
let baseData: MonitorDomain;
5354

54-
if (!log.attributes[ApplicationInsightsBaseType]) {
55-
// Get Exception attributes if available
56-
const exceptionType = log.attributes[ATTR_EXCEPTION_TYPE];
57-
if (exceptionType) {
58-
const exceptionMessage = log.attributes[ATTR_EXCEPTION_MESSAGE];
59-
const exceptionStacktrace = log.attributes[ATTR_EXCEPTION_STACKTRACE];
60-
name = ApplicationInsightsExceptionName;
61-
baseType = ApplicationInsightsExceptionBaseType;
62-
const exceptionDetails: TelemetryExceptionDetails = {
63-
typeName: String(exceptionType),
64-
message: String(exceptionMessage),
65-
hasFullStack: exceptionStacktrace ? true : false,
66-
stack: String(exceptionStacktrace),
67-
};
68-
const exceptionData: TelemetryExceptionData = {
69-
exceptions: [exceptionDetails],
70-
severityLevel: String(getSeverity(log.severityNumber)),
71-
version: 2,
72-
};
73-
baseData = exceptionData;
74-
} else {
75-
name = ApplicationInsightsMessageName;
76-
baseType = ApplicationInsightsMessageBaseType;
77-
const messageData: MessageData = {
78-
message: String(log.body),
79-
severityLevel: String(getSeverity(log.severityNumber)),
80-
version: 2,
81-
};
82-
baseData = messageData;
83-
}
55+
const exceptionStacktrace = log.attributes[ATTR_EXCEPTION_STACKTRACE];
56+
const exceptionType = log.attributes[ATTR_EXCEPTION_TYPE];
57+
const isExceptionType: boolean = !!(exceptionType && exceptionStacktrace) || false;
58+
const isMessageType: boolean =
59+
!log.attributes[ApplicationInsightsBaseType] &&
60+
!log.attributes[ApplicationInsightsCustomEventName] &&
61+
!exceptionType;
62+
if (isExceptionType) {
63+
const exceptionMessage = log.attributes[ATTR_EXCEPTION_MESSAGE];
64+
name = ApplicationInsightsExceptionName;
65+
baseType = ApplicationInsightsExceptionBaseType;
66+
const exceptionDetails: TelemetryExceptionDetails = {
67+
typeName: String(exceptionType),
68+
message: String(exceptionMessage),
69+
hasFullStack: exceptionStacktrace ? true : false,
70+
stack: String(exceptionStacktrace),
71+
};
72+
const exceptionData: TelemetryExceptionData = {
73+
exceptions: [exceptionDetails],
74+
severityLevel: String(getSeverity(log.severityNumber)),
75+
version: 2,
76+
};
77+
baseData = exceptionData;
78+
} else if (log.attributes[ApplicationInsightsCustomEventName]) {
79+
name = ApplicationInsightsEventName;
80+
baseType = ApplicationInsightsEventBaseType;
81+
const eventData: TelemetryEventData = {
82+
name: String(log.attributes[ApplicationInsightsCustomEventName]),
83+
version: 2,
84+
};
85+
baseData = eventData;
86+
measurements = getLegacyApplicationInsightsMeasurements(log);
87+
} else if (isMessageType) {
88+
name = ApplicationInsightsMessageName;
89+
baseType = ApplicationInsightsMessageBaseType;
90+
const messageData: MessageData = {
91+
message: String(log.body),
92+
severityLevel: String(getSeverity(log.severityNumber)),
93+
version: 2,
94+
};
95+
baseData = messageData;
8496
} else {
8597
// If Legacy Application Insights Log
8698
baseType = String(log.attributes[ApplicationInsightsBaseType]);
@@ -144,6 +156,7 @@ function createPropertiesFromLog(log: ReadableLogRecord): [Properties, Measureme
144156
if (
145157
!(
146158
key.startsWith("_MS.") ||
159+
key.startsWith("microsoft") ||
147160
key === ATTR_EXCEPTION_TYPE ||
148161
key === ATTR_EXCEPTION_MESSAGE ||
149162
key === ATTR_EXCEPTION_STACKTRACE ||

sdk/monitor/monitor-opentelemetry-exporter/test/internal/logUtils.spec.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ describe("logUtils.ts", () => {
409409
);
410410
});
411411

412-
it("should create a Event Envelope", () => {
412+
it("should create an Event Envelope", () => {
413413
const data: TelemetryEventData = {
414414
name: "testName",
415415
version: 2,
@@ -444,6 +444,35 @@ describe("logUtils.ts", () => {
444444
expectedTime,
445445
);
446446
});
447+
448+
it("should create a Custom Event Envelope", () => {
449+
testLogRecord.attributes = {
450+
"microsoft.custom_event.name": "testing name",
451+
"extra.attribute": "foo",
452+
};
453+
const expectedTime = hrTimeToDate(testLogRecord.hrTime);
454+
const expectedProperties = {
455+
"extra.attribute": "foo",
456+
};
457+
const expectedBaseData: TelemetryEventData = {
458+
name: "testing name",
459+
version: 2,
460+
properties: expectedProperties,
461+
measurements: {},
462+
};
463+
464+
const envelope = logToEnvelope(testLogRecord as ReadableLogRecord, "ikey");
465+
assertEnvelope(
466+
envelope,
467+
"Microsoft.ApplicationInsights.Event",
468+
100,
469+
"EventData",
470+
expectedProperties,
471+
emptyMeasurements,
472+
expectedBaseData,
473+
expectedTime,
474+
);
475+
});
447476
});
448477

449478
it("should parse objects if passed as the message field of a legacy ApplicationInsights log", () => {

0 commit comments

Comments
 (0)