Skip to content

Commit

Permalink
Added ability to add custom attributes to a span
Browse files Browse the repository at this point in the history
  • Loading branch information
adamlyka authored and adamlyka committed Nov 16, 2023
1 parent 7370386 commit a1368ae
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

/// <reference types="zone.js" />

import { isWrapped, InstrumentationBase } from '@opentelemetry/instrumentation';
import { isWrapped, InstrumentationBase, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';

import * as api from '@opentelemetry/api';
import { hrTime } from '@opentelemetry/core';
import { getElementXPath } from '@opentelemetry/sdk-trace-web';
import { AttributeNames } from './enums/AttributeNames';
import {
EventName,
ShouldPreventSpanCreation,
ShouldPreventSpanCreation, UserInteractionCustomAttributeFunction,
UserInteractionInstrumentationConfig,
} from './types';
import {
Expand All @@ -35,6 +35,7 @@ import {
ZoneTypeWithPrototype,
} from './internal-types';
import { VERSION } from './version';
import { Span } from '@opentelemetry/api';

const ZONE_CONTEXT_KEY = 'OT_ZONE_CONTEXT';
const EVENT_NAVIGATION_NAME = 'Navigation:';
Expand Down Expand Up @@ -78,6 +79,10 @@ export class UserInteractionInstrumentation extends InstrumentationBase<unknown>

init() {}

private _getConfig(): UserInteractionInstrumentationConfig {
return this._config;
}

/**
* This will check if last task was timeout and will save the time to
* fix the user interaction when nothing happens
Expand Down Expand Up @@ -147,6 +152,11 @@ export class UserInteractionInstrumentation extends InstrumentationBase<unknown>
: undefined
);

this._addCustomAttributesOnSpan(
span,
this._getConfig().applyCustomAttributesOnSpan
);

if (this._shouldPreventSpanCreation(eventName, element, span) === true) {
return undefined;
}
Expand All @@ -162,6 +172,28 @@ export class UserInteractionInstrumentation extends InstrumentationBase<unknown>
return undefined;
}

/**
* adds custom attributes to root span if configured
*/
private _addCustomAttributesOnSpan(
span: Span,
applyCustomAttributesOnSpan: UserInteractionCustomAttributeFunction | undefined
) {
if (applyCustomAttributesOnSpan) {
safeExecuteInTheMiddle(
() => applyCustomAttributesOnSpan(span),
error => {
if (!error) {
return;
}

this._diag.error('addCustomAttributesOnSpan', error);
},
true
);
}
}

/**
* Decrement number of tasks that left in zone,
* This is needed to be able to end span when no more tasks left
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export type ShouldPreventSpanCreation = (
span: Span
) => boolean | void;

export interface UserInteractionCustomAttributeFunction {
(span: Span): void;
}

export interface UserInteractionInstrumentationConfig
extends InstrumentationConfig {
/**
Expand All @@ -39,4 +43,9 @@ export interface UserInteractionInstrumentationConfig
* You can also use this handler to enhance created span with extra attributes.
*/
shouldPreventSpanCreation?: ShouldPreventSpanCreation;

/**
* Function for adding custom attributes on the span
*/
applyCustomAttributesOnSpan?: UserInteractionCustomAttributeFunction;
}
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,26 @@ describe('UserInteractionInstrumentation', () => {
assertInteractionSpan(span, { name: 'play' });
});

it('should apply custom attributes to spans', () => {
const customAttributeName = 'custom_attribute';
const customAttributeValue = 'custom_attribute_value';
registerTestInstrumentations({
eventNames: ['play'],
applyCustomAttributesOnSpan: (span) => {
span.setAttribute(customAttributeName, customAttributeValue)
},
});

fakeEventInteraction('play');
assert.strictEqual(exportSpy.args.length, 1, 'should export one span');
const span = exportSpy.args[0][0][0];
assert.strictEqual(
span.attributes[customAttributeName],
customAttributeValue,
'should have custom attribute on span'
);
});

it('should not be exported not configured spans', () => {
registerTestInstrumentations({
eventNames: ['play'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,26 @@ describe('UserInteractionInstrumentation', () => {
assertInteractionSpan(span, { name: 'play' });
});

it('should apply custom attributes to spans', () => {
const customAttributeName = 'custom_attribute';
const customAttributeValue = 'custom_attribute_value';
registerTestInstrumentations({
eventNames: ['play'],
applyCustomAttributesOnSpan: (span) => {
span.setAttribute(customAttributeName, customAttributeValue)
},
});

fakeEventInteraction('play');
assert.strictEqual(exportSpy.args.length, 1, 'should export one span');
const span = exportSpy.args[0][0][0];
assert.strictEqual(
span.attributes[customAttributeName],
customAttributeValue,
'should have custom attribute on span'
);
});

it('not configured spans should not be exported', () => {
registerTestInstrumentations({
eventNames: ['play'],
Expand Down

0 comments on commit a1368ae

Please sign in to comment.