{"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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"}