UNPKG

@embrace-io/web-sdk

Version:
1 lines 11.2 kB
{"version":3,"file":"LoafInstrumentation.cjs","names":["EmbraceInstrumentationBase","isEntryTypeSupported","createPerformanceObserver","MAX_SCRIPT_URL_LENGTH","KEY_EMB_TYPE","generateWebVitalID","ATTR_TBD_LOAF_TOTAL_DURATION","ATTR_TBD_LOAF_WORK_DURATION","ATTR_TBD_LOAF_STYLE_AND_LAYOUT_DURATION","ATTR_TBD_LOAF_COUNT","ATTR_TBD_LOAF_LONGEST_DURATION","ATTR_TBD_LOAF_LONGEST_DURATION_EXCLUDING_FIRST","LOAF_EVENT_NAME","SeverityNumber","LOAF_SCRIPTS_EVENT_NAME"],"sources":["../../../../src/instrumentations/loaf/LoafInstrumentation/LoafInstrumentation.ts"],"sourcesContent":["/* eslint-disable baseline-js/use-baseline */\nimport { SeverityNumber } from '@opentelemetry/api-logs';\nimport type { Metric } from 'web-vitals';\nimport { EMB_TYPES, KEY_EMB_TYPE } from '../../../constants/index.ts';\nimport { generateWebVitalID } from '../../../utils/generateWebVitalID.ts';\nimport {\n createPerformanceObserver,\n isEntryTypeSupported,\n} from '../../../utils/index.ts';\nimport { EmbraceInstrumentationBase } from '../../EmbraceInstrumentationBase/index.ts';\nimport {\n ATTR_TBD_LOAF_COUNT,\n ATTR_TBD_LOAF_LONGEST_DURATION,\n ATTR_TBD_LOAF_LONGEST_DURATION_EXCLUDING_FIRST,\n ATTR_TBD_LOAF_STYLE_AND_LAYOUT_DURATION,\n ATTR_TBD_LOAF_TOTAL_DURATION,\n ATTR_TBD_LOAF_WORK_DURATION,\n BLOCKING_DURATION_GOOD_THRESHOLD,\n BLOCKING_DURATION_POOR_THRESHOLD,\n LOAF_EVENT_NAME,\n LOAF_SCRIPTS_EVENT_NAME,\n MAX_SCRIPT_ENTRIES,\n MAX_SCRIPT_URL_LENGTH,\n} from './constants.ts';\nimport type { LoafInstrumentationArgs } from './types.ts';\n\ntype ScriptSummaryValue = {\n totalDuration: number;\n styleAndLayoutDuration: number;\n count: number;\n};\n\ntype ScriptSummaries = Map<string, ScriptSummaryValue>;\n\nexport class LoafInstrumentation extends EmbraceInstrumentationBase {\n private _observer: PerformanceObserver | null = null;\n private _isFirstEntry = true;\n\n private _totalDuration = 0;\n private _workDuration = 0;\n private _styleLayoutDuration = 0;\n private _count = 0;\n private _longestDuration = 0;\n private _longestDurationExcludingFirst = 0;\n private _totalBlockingDuration = 0;\n private _scriptSummaries: ScriptSummaries = new Map();\n\n public constructor({ diag, perf }: LoafInstrumentationArgs = {}) {\n super({\n instrumentationName: 'LoafInstrumentation',\n instrumentationVersion: '1.0.0',\n diag,\n perf,\n config: {},\n });\n\n if (this._config.enabled) {\n this.enable();\n }\n }\n\n public override enable(): void {\n if (isEntryTypeSupported('long-animation-frame')) {\n super.enable();\n } else {\n this._diag.debug('long-animation-frame not supported, skipping');\n }\n }\n\n public onEnable(): void {\n if (this._observer) {\n this._observer.disconnect();\n }\n\n this._observer =\n createPerformanceObserver<PerformanceLongAnimationFrameTiming>(\n 'long-animation-frame',\n (entry) => this._processEntry(entry),\n { diag: this._diag },\n );\n\n if (!this._observer) {\n this._isEnabled = false;\n this._diag.error('failed to enable');\n return;\n }\n\n this.setSessionPartListeners({\n end: () => {\n try {\n this._flushReport();\n } catch (e) {\n this._diag.error('error flushing report', e);\n }\n },\n });\n }\n\n public onDisable(): void {\n this._resetAccumulators();\n\n if (this._observer) {\n this._observer.disconnect();\n this._observer = null;\n }\n }\n\n private _processEntry(entry: PerformanceLongAnimationFrameTiming): void {\n if (!this._isEnabled) {\n return;\n }\n\n this._count++;\n this._totalDuration += entry.duration;\n this._workDuration += entry.renderStart\n ? entry.renderStart - entry.startTime\n : entry.duration;\n\n if (entry.styleAndLayoutStart) {\n this._styleLayoutDuration += Math.max(\n 0,\n entry.startTime + entry.duration - entry.styleAndLayoutStart,\n );\n }\n\n this._longestDuration = Math.max(this._longestDuration, entry.duration);\n\n if (this._isFirstEntry && this._count === 1) {\n this._isFirstEntry = false;\n } else {\n this._longestDurationExcludingFirst = Math.max(\n this._longestDurationExcludingFirst,\n entry.duration,\n );\n if (entry.firstUIEventTimestamp === 0) {\n this._totalBlockingDuration += entry.blockingDuration;\n }\n }\n\n try {\n for (const script of entry.scripts) {\n // sourceURL is an empty string for inline scripts\n let url = script.sourceURL || '(inline)';\n if (url.length > MAX_SCRIPT_URL_LENGTH) {\n url = `${url.substring(0, MAX_SCRIPT_URL_LENGTH)}...`;\n }\n\n const existing = this._scriptSummaries.get(url);\n if (existing) {\n existing.totalDuration += script.duration;\n existing.styleAndLayoutDuration +=\n script.forcedStyleAndLayoutDuration;\n existing.count++;\n } else {\n this._scriptSummaries.set(url, {\n totalDuration: script.duration,\n styleAndLayoutDuration: script.forcedStyleAndLayoutDuration,\n count: 1,\n });\n }\n }\n } catch (e) {\n this._diag.error('error processing scripts for entry', e);\n }\n }\n\n private _flushReport(): void {\n if (this._count === 0) {\n return;\n }\n\n // use web-vitals Metric type for rating\n let rating: Metric['rating'];\n if (this._totalBlockingDuration <= BLOCKING_DURATION_GOOD_THRESHOLD) {\n rating = 'good';\n } else if (\n this._totalBlockingDuration <= BLOCKING_DURATION_POOR_THRESHOLD\n ) {\n rating = 'needs-improvement';\n } else {\n rating = 'poor';\n }\n\n const attrs: Record<string, string | number> = {\n [KEY_EMB_TYPE]: EMB_TYPES.WebVital,\n ['browser.web_vital.id']: generateWebVitalID(),\n ['browser.web_vital.name']: 'tbd',\n ['browser.web_vital.value']: Math.round(this._totalBlockingDuration),\n ['browser.web_vital.rating']: rating,\n [ATTR_TBD_LOAF_TOTAL_DURATION]: Math.round(this._totalDuration),\n [ATTR_TBD_LOAF_WORK_DURATION]: Math.round(this._workDuration),\n [ATTR_TBD_LOAF_STYLE_AND_LAYOUT_DURATION]: Math.round(\n this._styleLayoutDuration,\n ),\n [ATTR_TBD_LOAF_COUNT]: this._count,\n [ATTR_TBD_LOAF_LONGEST_DURATION]: Math.round(this._longestDuration),\n [ATTR_TBD_LOAF_LONGEST_DURATION_EXCLUDING_FIRST]: Math.round(\n this._longestDurationExcludingFirst,\n ),\n };\n\n try {\n this.logger.emit({\n eventName: LOAF_EVENT_NAME,\n severityNumber: SeverityNumber.INFO,\n attributes: attrs,\n });\n } catch (e) {\n this._diag.error('error emitting loaf report', e);\n }\n\n try {\n if (this._scriptSummaries.size > 0) {\n const scripts = [...this._scriptSummaries]\n .sort((a, b) => b[1].totalDuration - a[1].totalDuration)\n .slice(0, MAX_SCRIPT_ENTRIES)\n .map(([url, script]) => [\n url,\n {\n total_duration: Math.round(script.totalDuration),\n style_and_layout_duration: Math.round(\n script.styleAndLayoutDuration,\n ),\n count: script.count,\n },\n ]);\n\n this.logger.emit({\n eventName: LOAF_SCRIPTS_EVENT_NAME,\n severityNumber: SeverityNumber.INFO,\n body: JSON.stringify(Object.fromEntries(scripts)),\n attributes: {\n [KEY_EMB_TYPE]: EMB_TYPES.LoafScripts,\n },\n });\n }\n } catch (e) {\n this._diag.error('error emitting loaf script summary', e);\n }\n\n this._resetAccumulators();\n }\n\n private _resetAccumulators(): void {\n this._totalDuration = 0;\n this._workDuration = 0;\n this._styleLayoutDuration = 0;\n this._count = 0;\n this._longestDuration = 0;\n this._longestDurationExcludingFirst = 0;\n this._totalBlockingDuration = 0;\n this._scriptSummaries = new Map();\n }\n}\n"],"mappings":"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"}