UNPKG

lightstep-tracer

Version:

> ❗ **This instrumentation is no longer recommended**. Please review [documentation on setting up and configuring the OpenTelemetry Node.js Launcher](https://github.com/lightstep/otel-launcher-node) or [OpenTelemetry JS (Browser)](https://github.com/open-

160 lines (136 loc) 4.89 kB
// eslint-disable-next-line import/no-import-module-exports import _each from '../_each'; class InstrumentPageLoad { constructor() { this._inited = false; this._span = null; } name() { return 'instrument_page_load'; } addOptions(tracerImp) { tracerImp.addOption('instrument_page_load', { type : 'bool', defaultValue : false }); } start(tracerImp) { if (this._inited) { return; } this._inited = true; if (typeof window !== 'object' || typeof document !== 'object') { return; } const currentOptions = tracerImp.options(); if (currentOptions.instrument_page_load) { this._ensureSpanStarted(tracerImp); document.addEventListener('readystatechange', this._handleReadyStateChange.bind(this)); } } stop() { } _ensureSpanStarted(tracerImp) { if (!this._span) { this._span = tracerImp.startSpan('document/load'); tracerImp.addActiveRootSpan(this._span); } } _handleReadyStateChange() { if (!this._span) { return; } let span = this._span; let state = document.readyState; let payload; if (state === 'complete') { payload = {}; if (window.performance && performance.timing) { this._addTimingSpans(span, performance.timing); payload['window.performance.timing'] = performance.timing; } } span.logEvent(`document.readystatechange ${state}`, payload); if (state === 'complete') { if (span.tracer()) { span.tracer().removeActiveRootSpan(span.tracer()); } span.finish(); } } _copyNavigatorProperties(nav) { let dst = {}; for (let key in nav) { // eslint-disable-line guard-for-in, no-restricted-syntax try { let value = nav[key]; switch (key) { case 'plugins': { let p = []; for (let i = 0; i < value.length; i++) { let item = value.item(i); p.push({ name : item.name, description : item.description, }); } dst[key] = p; } break; case 'mimeTypes': { let p = []; for (let i = 0; i < value.length; i++) { let item = value.item(i); p.push({ type : item.type, description : item.description, suffixes : item.suffixes, }); } dst[key] = p; } break; default: dst[key] = value; break; } } catch (e) { // Skip, just in case } } return dst; } // Retroactively create the appropriate spans and logs _addTimingSpans(parentImp, timing) { // NOTE: this currently relies on LightStep-specific APIs if (!parentImp) { return; } parentImp.setTag('user_agent', navigator.userAgent); _each(timing, (value, key) => { // e.g. secureConnectionStart is not always set if (typeof value !== 'number' || value === 0) { return; } let payload; if (key === 'navigationStart' && typeof navigator === 'object') { payload = { navigator : this._copyNavigatorProperties(navigator), }; } parentImp.log({ message : `document ${key}`, payload : payload, }, value); }); parentImp.setBeginMicros(timing.navigationStart * 1000.0); parentImp.tracer().startSpan('document/time_to_first_byte', { childOf : parentImp }) .setBeginMicros(timing.requestStart * 1000.0) .setEndMicros(timing.responseStart * 1000.0) .finish(); parentImp.tracer() .startSpan('document/response_transfer', { childOf : parentImp }) .setBeginMicros(timing.responseStart * 1000.0) .setEndMicros(timing.responseEnd * 1000.0) .finish(); parentImp.tracer().startSpan('document/dom_load', { childOf : parentImp }) .setBeginMicros(timing.domLoading * 1000.0) .setEndMicros(timing.domInteractive * 1000.0) .finish(); } } module.exports = new InstrumentPageLoad();