Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(instrumentation-document-load): add custom root span to document page load instrumentation #1092

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ import {
getPerformanceNavigationEntries, getPerformanceNavigationEntries,
} from './utils'; } from './utils';


/**
* DocumentLoadInstrumentationConfig Config
*/
export interface DocumentLoadInstrumentationConfig
extends InstrumentationConfig {
// Custom root span
rootSpan?: Span;
}

/** /**
* This class represents a document load plugin * This class represents a document load plugin
*/ */
Expand All @@ -53,12 +62,16 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<unknown> {
* *
* @param config * @param config
*/ */
constructor(config: InstrumentationConfig = {}) { constructor(config: DocumentLoadInstrumentationConfig = {}) {
super('@opentelemetry/instrumentation-document-load', VERSION, config); super('@opentelemetry/instrumentation-document-load', VERSION, config);
} }


init() {} init() {}


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

/** /**
* callback to be executed when page is loaded * callback to be executed when page is loaded
*/ */
Expand Down Expand Up @@ -89,20 +102,37 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<unknown> {
* Collects information about performance and creates appropriate spans * Collects information about performance and creates appropriate spans
*/ */
private _collectPerformance() { private _collectPerformance() {
const metaElement = Array.from(document.getElementsByTagName('meta')).find(
e => e.getAttribute('name') === TRACE_PARENT_HEADER
);
const entries = getPerformanceNavigationEntries(); const entries = getPerformanceNavigationEntries();
let rootSpan = this._getConfig().rootSpan;

if (rootSpan) {
this._instrumentRootSpan(rootSpan, entries);
} else {
const metaElement = Array.from(
document.getElementsByTagName('meta')
).find(e => e.getAttribute('name') === TRACE_PARENT_HEADER);
const traceparent = (metaElement && metaElement.content) || ''; const traceparent = (metaElement && metaElement.content) || '';
context.with(propagation.extract(ROOT_CONTEXT, { traceparent }), () => { context.with(propagation.extract(ROOT_CONTEXT, { traceparent }), () => {
const rootSpan = this._startSpan( rootSpan = this._startSpan(
AttributeNames.DOCUMENT_LOAD, AttributeNames.DOCUMENT_LOAD,
PTN.FETCH_START, PTN.FETCH_START,
entries entries
); );
});

if (!rootSpan) { if (!rootSpan) {
return; return;
} }

this._instrumentRootSpan(rootSpan, entries);
this._endSpan(rootSpan, PTN.LOAD_EVENT_END, entries);
}
}

/**
* Adds child spans and tags to the root span
*/
private _instrumentRootSpan(rootSpan: Span, entries: PerformanceEntries) {
context.with(trace.setSpan(context.active(), rootSpan), () => { context.with(trace.setSpan(context.active(), rootSpan), () => {
const fetchSpan = this._startSpan( const fetchSpan = this._startSpan(
AttributeNames.DOCUMENT_FETCH, AttributeNames.DOCUMENT_FETCH,
Expand Down Expand Up @@ -130,20 +160,13 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<unknown> {
addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries); addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries);
addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries); addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries);
addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries); addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries);
addSpanNetworkEvent( addSpanNetworkEvent(rootSpan, PTN.DOM_CONTENT_LOADED_EVENT_START, entries);
rootSpan,
PTN.DOM_CONTENT_LOADED_EVENT_START,
entries
);
addSpanNetworkEvent(rootSpan, PTN.DOM_CONTENT_LOADED_EVENT_END, entries); addSpanNetworkEvent(rootSpan, PTN.DOM_CONTENT_LOADED_EVENT_END, entries);
addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries); addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries);
addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries); addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries);
addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries);


addSpanPerformancePaintEvents(rootSpan); addSpanPerformancePaintEvents(rootSpan);

this._endSpan(rootSpan, PTN.LOAD_EVENT_END, entries);
});
} }


/** /**
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { EventNames } from '../src/enums/EventNames';
const exporter = new InMemorySpanExporter(); const exporter = new InMemorySpanExporter();
const provider = new BasicTracerProvider(); const provider = new BasicTracerProvider();
const spanProcessor = new SimpleSpanProcessor(exporter); const spanProcessor = new SimpleSpanProcessor(exporter);
const tracer = provider.getTracer('default');


provider.addSpanProcessor(spanProcessor); provider.addSpanProcessor(spanProcessor);
provider.register(); provider.register();
Expand Down Expand Up @@ -653,6 +654,60 @@ describe('DocumentLoad Instrumentation', () => {
}); });
shouldExportCorrectSpan(); shouldExportCorrectSpan();
}); });

describe('when custom root span is passed', () => {
let spyEntries: any;
beforeEach(() => {
spyEntries = sandbox.stub(window.performance, 'getEntriesByType');
spyEntries.withArgs('navigation').returns([entries]);
spyEntries.withArgs('resource').returns(resources);
spyEntries.withArgs('paint').returns([]);
});
afterEach(() => {
spyEntries.restore();
});

it('should add child spans to the custom root span', done => {
const customRootSpan = tracer.startSpan('customRootSpan');
plugin = new DocumentLoadInstrumentation({
enabled: false,
rootSpan: customRootSpan,
});
plugin.setTracerProvider(provider);
plugin.enable();
setTimeout(() => {
const spanResource1 = exporter.getFinishedSpans()[1] as ReadableSpan;
const spanResource2 = exporter.getFinishedSpans()[2] as ReadableSpan;

const srEvents1 = spanResource1.events;
const srEvents2 = spanResource2.events;

assert.strictEqual(
spanResource1.parentSpanId,
customRootSpan.spanContext().spanId
);
assert.strictEqual(
spanResource2.parentSpanId,
customRootSpan.spanContext().spanId
);

assert.strictEqual(
spanResource1.attributes[SemanticAttributes.HTTP_URL],
'http://localhost:8090/bundle.js'
);
assert.strictEqual(
spanResource2.attributes[SemanticAttributes.HTTP_URL],
'http://localhost:8090/sockjs-node/info?t=1572620894466'
);

ensureNetworkEventsExists(srEvents1);
ensureNetworkEventsExists(srEvents2);

assert.strictEqual(exporter.getFinishedSpans().length, 3);
done();
});
});
});
}); });


/** /**
Expand Down