This commit is contained in:
Kismet Hasanaj
2026-05-02 20:07:02 +02:00
parent ce8672e283
commit 34dc9aec52
9428 changed files with 1733330 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
import type { TraceEvent } from '../types';
import type { Reporter } from './types';
declare class MultiReporter implements Reporter {
private reporters;
constructor(reporters: Reporter[]);
flushAll(opts?: {
end: boolean;
}): Promise<void>;
report(event: TraceEvent): void;
}
export declare const reporter: MultiReporter;
export {};
+37
View File
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "reporter", {
enumerable: true,
get: function() {
return reporter;
}
});
const _totelemetry = /*#__PURE__*/ _interop_require_default(require("./to-telemetry"));
const _tojson = /*#__PURE__*/ _interop_require_default(require("./to-json"));
const _tojsonbuild = /*#__PURE__*/ _interop_require_default(require("./to-json-build"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class MultiReporter {
constructor(reporters){
this.reporters = [];
this.reporters = reporters;
}
async flushAll(opts) {
await Promise.all(this.reporters.map((reporter)=>reporter.flushAll(opts)));
}
report(event) {
this.reporters.forEach((reporter)=>reporter.report(event));
}
}
const reporter = new MultiReporter([
_tojson.default,
_tojsonbuild.default,
_totelemetry.default
]);
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/trace/report/index.ts"],"sourcesContent":["import type { TraceEvent } from '../types'\nimport reportToTelemetry from './to-telemetry'\nimport reportToJson from './to-json'\nimport reportToJsonBuild from './to-json-build'\nimport type { Reporter } from './types'\n\nclass MultiReporter implements Reporter {\n private reporters: Reporter[] = []\n\n constructor(reporters: Reporter[]) {\n this.reporters = reporters\n }\n\n async flushAll(opts?: { end: boolean }) {\n await Promise.all(this.reporters.map((reporter) => reporter.flushAll(opts)))\n }\n\n report(event: TraceEvent) {\n this.reporters.forEach((reporter) => reporter.report(event))\n }\n}\n\n// JSON is always reported to allow for diagnostics\nexport const reporter = new MultiReporter([\n reportToJson,\n reportToJsonBuild,\n reportToTelemetry,\n])\n"],"names":["reporter","MultiReporter","constructor","reporters","flushAll","opts","Promise","all","map","report","event","forEach","reportToJson","reportToJsonBuild","reportToTelemetry"],"mappings":";;;;+BAuBaA;;;eAAAA;;;oEAtBiB;+DACL;oEACK;;;;;;AAG9B,MAAMC;IAGJC,YAAYC,SAAqB,CAAE;aAF3BA,YAAwB,EAAE;QAGhC,IAAI,CAACA,SAAS,GAAGA;IACnB;IAEA,MAAMC,SAASC,IAAuB,EAAE;QACtC,MAAMC,QAAQC,GAAG,CAAC,IAAI,CAACJ,SAAS,CAACK,GAAG,CAAC,CAACR,WAAaA,SAASI,QAAQ,CAACC;IACvE;IAEAI,OAAOC,KAAiB,EAAE;QACxB,IAAI,CAACP,SAAS,CAACQ,OAAO,CAAC,CAACX,WAAaA,SAASS,MAAM,CAACC;IACvD;AACF;AAGO,MAAMV,WAAW,IAAIC,cAAc;IACxCW,eAAY;IACZC,oBAAiB;IACjBC,oBAAiB;CAClB","ignoreList":[0]}
+63
View File
@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _promises = require("fs/promises");
const _ = require(".");
const _shared = require("../shared");
const _path = require("path");
const _os = require("os");
const TRACE_EVENT = {
name: 'test-span',
duration: 321,
timestamp: Date.now(),
id: 127,
startTime: Date.now()
};
const WEBPACK_INVALIDATED_EVENT = {
name: 'webpack-invalidated',
duration: 100,
timestamp: Date.now(),
id: 112,
startTime: Date.now()
};
describe('Trace Reporter', ()=>{
describe('JSON reporter', ()=>{
it('should write the trace events to JSON file', async ()=>{
const tmpDir = await (0, _promises.mkdtemp)((0, _path.join)((0, _os.tmpdir)(), 'json-reporter'));
(0, _shared.setGlobal)('distDir', tmpDir);
(0, _shared.setGlobal)('phase', 'anything');
_.reporter.report(TRACE_EVENT);
await _.reporter.flushAll();
const traceFilename = (0, _path.join)(tmpDir, 'trace');
const traces = JSON.parse(await (0, _promises.readFile)(traceFilename, 'utf-8'));
expect(traces.length).toEqual(1);
expect(traces[0].name).toEqual('test-span');
expect(traces[0].id).toEqual(127);
expect(traces[0].duration).toEqual(321);
expect(traces[0].traceId).toBeDefined();
});
});
describe('Telemetry reporter', ()=>{
it('should record telemetry event', async ()=>{
const recordMock = jest.fn();
const telemetryMock = {
record: recordMock
};
(0, _shared.setGlobal)('telemetry', telemetryMock);
// This should be ignored.
_.reporter.report(TRACE_EVENT);
expect(recordMock).toHaveBeenCalledTimes(0);
_.reporter.report(WEBPACK_INVALIDATED_EVENT);
expect(recordMock).toHaveBeenCalledTimes(1);
expect(recordMock).toHaveBeenCalledWith({
eventName: 'WEBPACK_INVALIDATED',
payload: {
durationInMicroseconds: 100
}
});
});
});
});
//# sourceMappingURL=index.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/trace/report/index.test.ts"],"sourcesContent":["import { mkdtemp, readFile } from 'fs/promises'\nimport { reporter } from '.'\nimport { setGlobal } from '../shared'\nimport { join } from 'path'\nimport { tmpdir } from 'os'\n\nconst TRACE_EVENT = {\n name: 'test-span',\n duration: 321,\n timestamp: Date.now(),\n id: 127,\n startTime: Date.now(),\n}\nconst WEBPACK_INVALIDATED_EVENT = {\n name: 'webpack-invalidated',\n duration: 100,\n timestamp: Date.now(),\n id: 112,\n startTime: Date.now(),\n}\n\ndescribe('Trace Reporter', () => {\n describe('JSON reporter', () => {\n it('should write the trace events to JSON file', async () => {\n const tmpDir = await mkdtemp(join(tmpdir(), 'json-reporter'))\n setGlobal('distDir', tmpDir)\n setGlobal('phase', 'anything')\n reporter.report(TRACE_EVENT)\n await reporter.flushAll()\n const traceFilename = join(tmpDir, 'trace')\n const traces = JSON.parse(await readFile(traceFilename, 'utf-8'))\n expect(traces.length).toEqual(1)\n expect(traces[0].name).toEqual('test-span')\n expect(traces[0].id).toEqual(127)\n expect(traces[0].duration).toEqual(321)\n expect(traces[0].traceId).toBeDefined()\n })\n })\n\n describe('Telemetry reporter', () => {\n it('should record telemetry event', async () => {\n const recordMock = jest.fn()\n const telemetryMock = {\n record: recordMock,\n }\n setGlobal('telemetry', telemetryMock)\n // This should be ignored.\n reporter.report(TRACE_EVENT)\n expect(recordMock).toHaveBeenCalledTimes(0)\n reporter.report(WEBPACK_INVALIDATED_EVENT)\n expect(recordMock).toHaveBeenCalledTimes(1)\n expect(recordMock).toHaveBeenCalledWith({\n eventName: 'WEBPACK_INVALIDATED',\n payload: {\n durationInMicroseconds: 100,\n },\n })\n })\n })\n})\n"],"names":["TRACE_EVENT","name","duration","timestamp","Date","now","id","startTime","WEBPACK_INVALIDATED_EVENT","describe","it","tmpDir","mkdtemp","join","tmpdir","setGlobal","reporter","report","flushAll","traceFilename","traces","JSON","parse","readFile","expect","length","toEqual","traceId","toBeDefined","recordMock","jest","fn","telemetryMock","record","toHaveBeenCalledTimes","toHaveBeenCalledWith","eventName","payload","durationInMicroseconds"],"mappings":";;;;0BAAkC;kBACT;wBACC;sBACL;oBACE;AAEvB,MAAMA,cAAc;IAClBC,MAAM;IACNC,UAAU;IACVC,WAAWC,KAAKC,GAAG;IACnBC,IAAI;IACJC,WAAWH,KAAKC,GAAG;AACrB;AACA,MAAMG,4BAA4B;IAChCP,MAAM;IACNC,UAAU;IACVC,WAAWC,KAAKC,GAAG;IACnBC,IAAI;IACJC,WAAWH,KAAKC,GAAG;AACrB;AAEAI,SAAS,kBAAkB;IACzBA,SAAS,iBAAiB;QACxBC,GAAG,8CAA8C;YAC/C,MAAMC,SAAS,MAAMC,IAAAA,iBAAO,EAACC,IAAAA,UAAI,EAACC,IAAAA,UAAM,KAAI;YAC5CC,IAAAA,iBAAS,EAAC,WAAWJ;YACrBI,IAAAA,iBAAS,EAAC,SAAS;YACnBC,UAAQ,CAACC,MAAM,CAACjB;YAChB,MAAMgB,UAAQ,CAACE,QAAQ;YACvB,MAAMC,gBAAgBN,IAAAA,UAAI,EAACF,QAAQ;YACnC,MAAMS,SAASC,KAAKC,KAAK,CAAC,MAAMC,IAAAA,kBAAQ,EAACJ,eAAe;YACxDK,OAAOJ,OAAOK,MAAM,EAAEC,OAAO,CAAC;YAC9BF,OAAOJ,MAAM,CAAC,EAAE,CAACnB,IAAI,EAAEyB,OAAO,CAAC;YAC/BF,OAAOJ,MAAM,CAAC,EAAE,CAACd,EAAE,EAAEoB,OAAO,CAAC;YAC7BF,OAAOJ,MAAM,CAAC,EAAE,CAAClB,QAAQ,EAAEwB,OAAO,CAAC;YACnCF,OAAOJ,MAAM,CAAC,EAAE,CAACO,OAAO,EAAEC,WAAW;QACvC;IACF;IAEAnB,SAAS,sBAAsB;QAC7BC,GAAG,iCAAiC;YAClC,MAAMmB,aAAaC,KAAKC,EAAE;YAC1B,MAAMC,gBAAgB;gBACpBC,QAAQJ;YACV;YACAd,IAAAA,iBAAS,EAAC,aAAaiB;YACvB,0BAA0B;YAC1BhB,UAAQ,CAACC,MAAM,CAACjB;YAChBwB,OAAOK,YAAYK,qBAAqB,CAAC;YACzClB,UAAQ,CAACC,MAAM,CAACT;YAChBgB,OAAOK,YAAYK,qBAAqB,CAAC;YACzCV,OAAOK,YAAYM,oBAAoB,CAAC;gBACtCC,WAAW;gBACXC,SAAS;oBACPC,wBAAwB;gBAC1B;YACF;QACF;IACF;AACF","ignoreList":[0]}
+2
View File
@@ -0,0 +1,2 @@
declare const _default: import("./types").Reporter;
export default _default;
+40
View File
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _shared = require("../shared");
const _constants = require("../../shared/lib/constants");
const _tojson = require("./to-json");
const allowlistedEvents = new Set([
'next-build',
'run-turbopack',
'run-webpack',
'run-typescript',
'run-eslint',
'static-check',
'collect-build-traces',
'static-generation',
'output-export-full-static-export',
'adapter-handle-build-complete',
'output-standalone',
'telemetry-flush',
'turbopack-build-events',
'turbopack-persistence',
'turbopack-compaction'
]);
const _default = (0, _tojson.createJsonReporter)({
filename: 'trace-build',
sizeLimit: Infinity,
filter: (event)=>{
const phase = _shared.traceGlobals.get('phase');
return phase === _constants.PHASE_PRODUCTION_BUILD && allowlistedEvents.has(event.name);
}
});
//# sourceMappingURL=to-json-build.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/trace/report/to-json-build.ts"],"sourcesContent":["import { traceGlobals } from '../shared'\nimport { PHASE_PRODUCTION_BUILD } from '../../shared/lib/constants'\nimport { createJsonReporter } from './to-json'\n\nconst allowlistedEvents = new Set([\n 'next-build',\n 'run-turbopack',\n 'run-webpack',\n 'run-typescript',\n 'run-eslint',\n 'static-check',\n 'collect-build-traces',\n 'static-generation',\n 'output-export-full-static-export',\n 'adapter-handle-build-complete',\n 'output-standalone',\n 'telemetry-flush',\n 'turbopack-build-events',\n 'turbopack-persistence',\n 'turbopack-compaction',\n])\n\nexport default createJsonReporter({\n filename: 'trace-build',\n sizeLimit: Infinity,\n filter: (event) => {\n const phase = traceGlobals.get('phase')\n return phase === PHASE_PRODUCTION_BUILD && allowlistedEvents.has(event.name)\n },\n})\n"],"names":["allowlistedEvents","Set","createJsonReporter","filename","sizeLimit","Infinity","filter","event","phase","traceGlobals","get","PHASE_PRODUCTION_BUILD","has","name"],"mappings":";;;;+BAsBA;;;eAAA;;;wBAtB6B;2BACU;wBACJ;AAEnC,MAAMA,oBAAoB,IAAIC,IAAI;IAChC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;MAED,WAAeC,IAAAA,0BAAkB,EAAC;IAChCC,UAAU;IACVC,WAAWC;IACXC,QAAQ,CAACC;QACP,MAAMC,QAAQC,oBAAY,CAACC,GAAG,CAAC;QAC/B,OAAOF,UAAUG,iCAAsB,IAAIX,kBAAkBY,GAAG,CAACL,MAAMM,IAAI;IAC7E;AACF","ignoreList":[0]}
+13
View File
@@ -0,0 +1,13 @@
import type { TraceEvent } from '../types';
import type { Reporter } from './types';
export declare function batcher(reportEvents: (evts: TraceEvent[]) => Promise<void>): {
flushAll: () => Promise<void>;
report: (event: TraceEvent) => void;
};
export declare function createJsonReporter(options: {
filename: string;
sizeLimit: number | ((phase: string) => number);
filter?: (event: TraceEvent) => boolean;
}): Reporter;
declare const _default: Reporter;
export default _default;
+165
View File
@@ -0,0 +1,165 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
batcher: null,
createJsonReporter: null,
default: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
batcher: function() {
return batcher;
},
createJsonReporter: function() {
return createJsonReporter;
},
default: function() {
return _default;
}
});
const _shared = require("../shared");
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _constants = require("../../shared/lib/constants");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function batcher(reportEvents) {
const events = [];
// Promise queue to ensure events are always sent on flushAll
const queue = new Set();
return {
flushAll: async ()=>{
await Promise.all(queue);
if (events.length > 0) {
await reportEvents(events);
events.length = 0;
}
},
report: (event)=>{
events.push(event);
if (events.length > 100) {
const evts = events.slice();
events.length = 0;
const report = reportEvents(evts);
queue.add(report);
report.then(()=>queue.delete(report));
}
}
};
}
const writeStreamOptions = {
flags: 'a',
encoding: 'utf8'
};
class RotatingWriteStream {
constructor(file, sizeLimit){
this.file = file;
this.size = 0;
this.sizeLimit = sizeLimit;
this.createWriteStream();
}
createWriteStream() {
this.writeStream = _fs.default.createWriteStream(this.file, writeStreamOptions);
}
// Recreate the file
async rotate() {
await this.end();
try {
_fs.default.unlinkSync(this.file);
} catch (err) {
// It's fine if the file does not exist yet
if (err.code !== 'ENOENT') {
throw err;
}
}
this.size = 0;
this.createWriteStream();
this.rotatePromise = undefined;
}
async write(data) {
if (this.rotatePromise) await this.rotatePromise;
this.size += data.length;
if (this.size > this.sizeLimit) {
await (this.rotatePromise = this.rotate());
}
if (!this.writeStream.write(data, 'utf8')) {
if (this.drainPromise === undefined) {
this.drainPromise = new Promise((resolve, _reject)=>{
this.writeStream.once('drain', ()=>{
this.drainPromise = undefined;
resolve();
});
});
}
await this.drainPromise;
}
}
end() {
return new Promise((resolve)=>{
this.writeStream.end(resolve);
});
}
}
function createJsonReporter(options) {
let writeStream;
let batch;
function report(event) {
if (options.filter && !options.filter(event)) {
return;
}
const distDir = _shared.traceGlobals.get('distDir');
const phase = _shared.traceGlobals.get('phase');
if (!distDir || !phase) {
return;
}
if (!batch) {
batch = batcher(async (events)=>{
if (!writeStream) {
await _fs.default.promises.mkdir(distDir, {
recursive: true
});
const file = _path.default.join(distDir, options.filename);
const limit = typeof options.sizeLimit === 'function' ? options.sizeLimit(phase) : options.sizeLimit;
writeStream = new RotatingWriteStream(file, limit);
}
const eventsJson = JSON.stringify(events);
try {
await writeStream.write(eventsJson + '\n');
} catch (err) {
console.log(err);
}
});
}
batch.report({
...event,
traceId: _shared.traceId
});
}
return {
flushAll: (opts)=>batch ? batch.flushAll().then(()=>{
const phase = _shared.traceGlobals.get('phase');
// Only end writeStream when manually flushing in production
if ((opts == null ? void 0 : opts.end) || phase !== _constants.PHASE_DEVELOPMENT_SERVER) {
return writeStream.end();
}
}) : undefined,
report
};
}
const _default = createJsonReporter({
filename: 'trace',
sizeLimit: (phase)=>// Development is limited to 50MB, production is unlimited
phase === _constants.PHASE_DEVELOPMENT_SERVER ? 52428800 : Infinity
});
//# sourceMappingURL=to-json.js.map
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
import type { TraceEvent } from '../types';
declare const _default: {
flushAll: () => void;
report: ({ name, duration }: TraceEvent) => void;
};
export default _default;
+36
View File
@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _shared = require("../shared");
const TRACE_EVENT_ACCESSLIST = new Map(Object.entries({
'webpack-invalidated': 'WEBPACK_INVALIDATED'
}));
const reportToTelemetry = ({ name, duration })=>{
const eventName = TRACE_EVENT_ACCESSLIST.get(name);
if (!eventName) {
return;
}
const telemetry = _shared.traceGlobals.get('telemetry');
if (!telemetry) {
return;
}
telemetry.record({
eventName,
payload: {
durationInMicroseconds: duration
}
});
};
const _default = {
flushAll: ()=>{},
report: reportToTelemetry
};
//# sourceMappingURL=to-telemetry.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/trace/report/to-telemetry.ts"],"sourcesContent":["import type { Telemetry } from '../../telemetry/storage'\nimport { traceGlobals } from '../shared'\nimport type { TraceEvent } from '../types'\n\nconst TRACE_EVENT_ACCESSLIST = new Map(\n Object.entries({\n 'webpack-invalidated': 'WEBPACK_INVALIDATED',\n })\n)\n\nconst reportToTelemetry = ({ name, duration }: TraceEvent) => {\n const eventName = TRACE_EVENT_ACCESSLIST.get(name)\n if (!eventName) {\n return\n }\n const telemetry: Telemetry | undefined = traceGlobals.get('telemetry')\n if (!telemetry) {\n return\n }\n\n telemetry.record({\n eventName,\n payload: {\n durationInMicroseconds: duration,\n },\n })\n}\n\nexport default {\n flushAll: () => {},\n report: reportToTelemetry,\n}\n"],"names":["TRACE_EVENT_ACCESSLIST","Map","Object","entries","reportToTelemetry","name","duration","eventName","get","telemetry","traceGlobals","record","payload","durationInMicroseconds","flushAll","report"],"mappings":";;;;+BA4BA;;;eAAA;;;wBA3B6B;AAG7B,MAAMA,yBAAyB,IAAIC,IACjCC,OAAOC,OAAO,CAAC;IACb,uBAAuB;AACzB;AAGF,MAAMC,oBAAoB,CAAC,EAAEC,IAAI,EAAEC,QAAQ,EAAc;IACvD,MAAMC,YAAYP,uBAAuBQ,GAAG,CAACH;IAC7C,IAAI,CAACE,WAAW;QACd;IACF;IACA,MAAME,YAAmCC,oBAAY,CAACF,GAAG,CAAC;IAC1D,IAAI,CAACC,WAAW;QACd;IACF;IAEAA,UAAUE,MAAM,CAAC;QACfJ;QACAK,SAAS;YACPC,wBAAwBP;QAC1B;IACF;AACF;MAEA,WAAe;IACbQ,UAAU,KAAO;IACjBC,QAAQX;AACV","ignoreList":[0]}
+7
View File
@@ -0,0 +1,7 @@
import type { TraceEvent } from '../types';
export type Reporter = {
flushAll: (opts?: {
end: boolean;
}) => Promise<void> | void;
report: (event: TraceEvent) => void;
};
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","ignoreList":[]}