[pipeline] Make logging more structured
--- Add types for logged events, including a `CompileSuccess` event which can help us record successfully compiled Forget functions and their compilation details (e.g. # memoSlots used).
Mofei Zhang committed
Sep 14, 2023 at 19:40 UTC
b2230f62a38350f19cf02b4ee4b7f42e43610b9a
3 files changed
+56
-8
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Options.ts
+21
-1
@@ -5,6 +5,8 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
+import * as t from "@babel/types";
9
+import { CompilerErrorDetailOptions } from "../CompilerError";
10
import { EnvironmentConfig } from "../HIR/Environment";
11
12
export type ExternalFunction = {
@@ -113,8 +115,26 @@ export type CompilationMode =
115
// Compile all top-level functions
116
| "all";
117
118
+export type LoggerEvent =
119
+ | {
120
+ kind: "CompileError";
121
+ fnLoc: t.SourceLocation | null;
122
+ detail: CompilerErrorDetailOptions;
123
+ }
124
+ | {
125
+ kind: "CompileSuccess";
126
+ fnLoc: t.SourceLocation | null;
127
+ fnName: string | null;
128
+ memoSlots: number;
129
+ }
130
+ | {
131
+ kind: "PipelineError";
132
+ fnLoc: t.SourceLocation | null;
133
+ data: any;
134
+ };
135
+
136
export type Logger = {
117
- logEvent(name: string, data: any): void;
137
+ logEvent: (filename: string | null, event: LoggerEvent) => void;
138
};
139
140
export const defaultOptions: PluginOptions = {
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts
+31
-7
@@ -50,9 +50,27 @@ function hasAnyUseNoForgetDirectives(directives: t.Directive[]): boolean {
50
}
51
return false;
52
}
53
-function handleError(pass: CompilerPass, err: unknown): void {
54
- if (pass.opts.logger && err) {
55
- pass.opts.logger.logEvent("err", err);
53
+function handleError(
54
+ pass: CompilerPass,
55
+ fnLoc: t.SourceLocation | null,
56
+ err: unknown
57
+): void {
58
+ if (pass.opts.logger) {
59
+ if (err instanceof CompilerError) {
60
+ for (const detail of err.details) {
61
+ pass.opts.logger.logEvent(pass.filename, {
62
+ kind: "CompileError",
63
+ fnLoc,
64
+ detail: detail.options,
65
+ });
66
+ }
67
+ } else {
68
+ pass.opts.logger.logEvent(pass.filename, {
69
+ kind: "PipelineError",
70
+ fnLoc,
71
+ data: err,
72
+ });
73
+ }
74
}
75
/** Always throw if the flag is enabled, otherwise we only throw if the error is critical
76
* (eg an invariant is broken, meaning the compiler may be buggy). See
@@ -88,8 +106,14 @@ function compileAndInsertNewFunctionDeclaration(
106
let compiledFn: CodegenFunction;
107
try {
108
compiledFn = compileFn(fnPath, pass.opts.environment);
109
+ pass.opts.logger?.logEvent(pass.filename, {
110
+ kind: "CompileSuccess",
111
+ fnLoc: fnPath.node.loc ?? null,
112
+ fnName: compiledFn.id?.name ?? null,
113
+ memoSlots: compiledFn.memoSlotsUsed,
114
+ });
115
} catch (err) {
92
- handleError(pass, err);
116
+ handleError(pass, fnPath.node.loc ?? null, err);
117
return false;
118
}
119
@@ -266,7 +290,7 @@ export function compileProgram(
290
if (!shouldVisitNode(fn, pass)) {
291
return;
292
} else if (lintError != null) {
269
- handleError(pass, lintError);
293
+ handleError(pass, fn.node.loc ?? null, lintError);
294
} else {
295
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
296
hasForgetMutatedOriginalSource ||= hasMutated;
@@ -280,7 +304,7 @@ export function compileProgram(
304
if (!shouldVisitNode(fn, pass)) {
305
return;
306
} else if (lintError != null) {
283
- handleError(pass, lintError);
307
+ handleError(pass, fn.node.loc ?? null, lintError);
308
} else {
309
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
310
hasForgetMutatedOriginalSource ||= hasMutated;
@@ -294,7 +318,7 @@ export function compileProgram(
318
if (!shouldVisitNode(fn, pass)) {
319
return;
320
} else if (lintError != null) {
297
- handleError(pass, lintError);
321
+ handleError(pass, fn.node.loc ?? null, lintError);
322
} else {
323
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
324
hasForgetMutatedOriginalSource ||= hasMutated;
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+4
@@ -43,6 +43,9 @@ export type CodegenFunction = {
43
generator: boolean;
44
async: boolean;
45
loc: SourceLocation;
46
+
47
+ // Compiler info for logging and heuristics
48
+ memoSlotsUsed: number;
49
};
50
51
export function codegenReactiveFunction(
@@ -89,6 +92,7 @@ export function codegenReactiveFunction(
92
body,
93
generator: fn.generator,
94
async: fn.async,
95
+ memoSlotsUsed: cacheCount,
96
});
97
}
98