UNPKG

next

Version:

The React Framework

197 lines (196 loc) • 6.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { Span: null, SpanStatus: null, clearTraceEvents: null, exportTraceState: null, flushAllTraces: null, getTraceEvents: null, initializeTraceState: null, recordTraceEvents: null, trace: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { Span: function() { return Span; }, SpanStatus: function() { return SpanStatus; }, clearTraceEvents: function() { return clearTraceEvents; }, exportTraceState: function() { return exportTraceState; }, flushAllTraces: function() { return flushAllTraces; }, getTraceEvents: function() { return getTraceEvents; }, initializeTraceState: function() { return initializeTraceState; }, recordTraceEvents: function() { return recordTraceEvents; }, trace: function() { return trace; } }); const _report = require("./report"); const NUM_OF_MICROSEC_IN_NANOSEC = BigInt('1000'); const NUM_OF_MILLISEC_IN_NANOSEC = BigInt('1000000'); let count = 0; const getId = ()=>{ count++; return count; }; let defaultParentSpanId; let shouldSaveTraceEvents; let savedTraceEvents = []; const RECORD_SPAN_THRESHOLD_MS = parseInt(process.env.NEXT_TRACE_SPAN_THRESHOLD_MS ?? '-1'); var SpanStatus = /*#__PURE__*/ function(SpanStatus) { SpanStatus["Started"] = "started"; SpanStatus["Stopped"] = "stopped"; return SpanStatus; }({}); class Span { constructor({ name, parentId, attrs, startTime }){ this.name = name; this.parentId = parentId ?? defaultParentSpanId; this.attrs = attrs ? { ...attrs } : {}; this.status = "started"; this.id = getId(); this._start = startTime || process.hrtime.bigint(); // hrtime cannot be used to reconstruct tracing span's actual start time // since it does not have relation to clock time: // `These times are relative to an arbitrary time in the past, and not related to the time of day and therefore not subject to clock drift` // https://nodejs.org/api/process.html#processhrtimetime // Capturing current datetime as additional metadata for external reconstruction. this.now = Date.now(); } // Durations are reported as microseconds. This gives 1000x the precision // of something like Date.now(), which reports in milliseconds. // Additionally, ~285 years can be safely represented as microseconds as // a float64 in both JSON and JavaScript. stop(stopTime) { if (this.status === "stopped") { // Don't report the same span twice. // TODO: In the future this should throw as `.stop()` shouldn't be called multiple times. return; } const end = stopTime || process.hrtime.bigint(); const duration = (end - this._start) / NUM_OF_MICROSEC_IN_NANOSEC; this.status = "stopped"; if (duration > Number.MAX_SAFE_INTEGER) { throw Object.defineProperty(new Error(`Duration is too long to express as float64: ${duration}`), "__NEXT_ERROR_CODE", { value: "E513", enumerable: false, configurable: true }); } const timestamp = this._start / NUM_OF_MICROSEC_IN_NANOSEC; const traceEvent = { name: this.name, duration: Number(duration), timestamp: Number(timestamp), id: this.id, parentId: this.parentId, tags: this.attrs, startTime: this.now }; if (duration > RECORD_SPAN_THRESHOLD_MS * 1000) { _report.reporter.report(traceEvent); if (shouldSaveTraceEvents) { savedTraceEvents.push(traceEvent); } } } traceChild(name, attrs) { return new Span({ name, parentId: this.id, attrs }); } manualTraceChild(name, // Start time in nanoseconds since epoch. startTime, // Stop time in nanoseconds since epoch. stopTime, attrs) { // We need to convert the time info to the same base as hrtime since that is used usually. const correction = process.hrtime.bigint() - BigInt(Date.now()) * NUM_OF_MILLISEC_IN_NANOSEC; const span = new Span({ name, parentId: this.id, attrs, startTime: startTime ? startTime + correction : process.hrtime.bigint() }); span.stop(stopTime ? stopTime + correction : process.hrtime.bigint()); } getId() { return this.id; } setAttribute(key, value) { this.attrs[key] = value; } traceFn(fn) { try { return fn(this); } finally{ this.stop(); } } async traceAsyncFn(fn) { try { return await fn(this); } finally{ this.stop(); } } } const trace = (name, parentId, attrs)=>{ return new Span({ name, parentId, attrs }); }; const flushAllTraces = (opts)=>_report.reporter.flushAll(opts); const exportTraceState = ()=>({ defaultParentSpanId, lastId: count, shouldSaveTraceEvents }); const initializeTraceState = (state)=>{ count = state.lastId; defaultParentSpanId = state.defaultParentSpanId; shouldSaveTraceEvents = state.shouldSaveTraceEvents; }; function getTraceEvents() { return savedTraceEvents; } function recordTraceEvents(events) { for (const traceEvent of events){ _report.reporter.report(traceEvent); if (traceEvent.id > count) { count = traceEvent.id + 1; } } if (shouldSaveTraceEvents) { savedTraceEvents.push(...events); } } const clearTraceEvents = ()=>savedTraceEvents = []; //# sourceMappingURL=trace.js.map