[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).
This commit is contained in:
Mofei Zhang
2023-09-14 19:40:39 +01:00
parent 869466bb0b
commit b2230f62a3
3 changed files with 56 additions and 8 deletions
@@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
import * as t from "@babel/types";
import { CompilerErrorDetailOptions } from "../CompilerError";
import { EnvironmentConfig } from "../HIR/Environment";
export type ExternalFunction = {
@@ -113,8 +115,26 @@ export type CompilationMode =
// Compile all top-level functions
| "all";
export type LoggerEvent =
| {
kind: "CompileError";
fnLoc: t.SourceLocation | null;
detail: CompilerErrorDetailOptions;
}
| {
kind: "CompileSuccess";
fnLoc: t.SourceLocation | null;
fnName: string | null;
memoSlots: number;
}
| {
kind: "PipelineError";
fnLoc: t.SourceLocation | null;
data: any;
};
export type Logger = {
logEvent(name: string, data: any): void;
logEvent: (filename: string | null, event: LoggerEvent) => void;
};
export const defaultOptions: PluginOptions = {
@@ -50,9 +50,27 @@ function hasAnyUseNoForgetDirectives(directives: t.Directive[]): boolean {
}
return false;
}
function handleError(pass: CompilerPass, err: unknown): void {
if (pass.opts.logger && err) {
pass.opts.logger.logEvent("err", err);
function handleError(
pass: CompilerPass,
fnLoc: t.SourceLocation | null,
err: unknown
): void {
if (pass.opts.logger) {
if (err instanceof CompilerError) {
for (const detail of err.details) {
pass.opts.logger.logEvent(pass.filename, {
kind: "CompileError",
fnLoc,
detail: detail.options,
});
}
} else {
pass.opts.logger.logEvent(pass.filename, {
kind: "PipelineError",
fnLoc,
data: err,
});
}
}
/** Always throw if the flag is enabled, otherwise we only throw if the error is critical
* (eg an invariant is broken, meaning the compiler may be buggy). See
@@ -88,8 +106,14 @@ function compileAndInsertNewFunctionDeclaration(
let compiledFn: CodegenFunction;
try {
compiledFn = compileFn(fnPath, pass.opts.environment);
pass.opts.logger?.logEvent(pass.filename, {
kind: "CompileSuccess",
fnLoc: fnPath.node.loc ?? null,
fnName: compiledFn.id?.name ?? null,
memoSlots: compiledFn.memoSlotsUsed,
});
} catch (err) {
handleError(pass, err);
handleError(pass, fnPath.node.loc ?? null, err);
return false;
}
@@ -266,7 +290,7 @@ export function compileProgram(
if (!shouldVisitNode(fn, pass)) {
return;
} else if (lintError != null) {
handleError(pass, lintError);
handleError(pass, fn.node.loc ?? null, lintError);
} else {
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
hasForgetMutatedOriginalSource ||= hasMutated;
@@ -280,7 +304,7 @@ export function compileProgram(
if (!shouldVisitNode(fn, pass)) {
return;
} else if (lintError != null) {
handleError(pass, lintError);
handleError(pass, fn.node.loc ?? null, lintError);
} else {
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
hasForgetMutatedOriginalSource ||= hasMutated;
@@ -294,7 +318,7 @@ export function compileProgram(
if (!shouldVisitNode(fn, pass)) {
return;
} else if (lintError != null) {
handleError(pass, lintError);
handleError(pass, fn.node.loc ?? null, lintError);
} else {
const hasMutated = compileAndInsertNewFunctionDeclaration(fn, pass);
hasForgetMutatedOriginalSource ||= hasMutated;
@@ -43,6 +43,9 @@ export type CodegenFunction = {
generator: boolean;
async: boolean;
loc: SourceLocation;
// Compiler info for logging and heuristics
memoSlotsUsed: number;
};
export function codegenReactiveFunction(
@@ -89,6 +92,7 @@ export function codegenReactiveFunction(
body,
generator: fn.generator,
async: fn.async,
memoSlotsUsed: cacheCount,
});
}