case 4703 - report script console.error details in render errors
The page log showed console.error objects only as JSHandle@object and errors without their stack. Each ERROR line is still logged at once; object and Error arguments are then fetched from the page and added as detail lines (object JSON, error stack without Puppeteer frames and with file names only). A failing render waits up to 2 s for pending details. Page log appends are locked. Report designer manual (Script errors) and changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -898,6 +898,14 @@ What could be the issue here?
|
||||
}
|
||||
log.LogDebug($"Report browser launch arguments: '{string.Join(" ", lo.Args)}'");
|
||||
System.Text.StringBuilder PageLog = new System.Text.StringBuilder();
|
||||
//case 4703: console events and the API relay add to the page log from other threads
|
||||
void AppendPageLog(string line)
|
||||
{
|
||||
lock (PageLog)
|
||||
PageLog.AppendLine(line);
|
||||
}
|
||||
//case 4703: details of console.error arguments are fetched from the page after the error line is logged
|
||||
var PendingConsoleDetails = new List<Task>();
|
||||
|
||||
if (!ReportRenderManager.KeepGoing(job.GId))
|
||||
return;
|
||||
@@ -930,22 +938,21 @@ What could be the issue here?
|
||||
switch (args.Message.Type)
|
||||
{
|
||||
case ConsoleType.Error:
|
||||
try
|
||||
AppendPageLog($"ERROR: {args.Message.Text}");
|
||||
//case 4703: the message text shows an object only as JSHandle@object and an error without its stack, so
|
||||
//for each argument the page is asked for an error's stack or an object's JSON; added as detail lines
|
||||
if (args.Message.Args != null && args.Message.Args.Any())
|
||||
{
|
||||
//case 4586 todo force an error here and see what we can do with it old vs new behaviour test on current release same report with erorr triggered
|
||||
//ok, I tested it with an exception and it worked just find so shrug emoji
|
||||
PageLog.AppendLine($"ERROR: {args.Message.Text}");
|
||||
//case 4586 this no longer works due to no executioncontext in arg in teh block below
|
||||
// var errorArgs = await Task.WhenAll(args.Message.Args.Select(arg => arg.ExecutionContext.EvaluateFunctionAsync("(arg) => arg instanceof Error ? arg.message : arg", arg)));
|
||||
// PageLog.AppendLine($"ERROR: {args.Message.Text} args: [{string.Join<object>(", ", errorArgs)}]");
|
||||
var detailTask = AppendConsoleErrorDetailsAsync(args.Message.Text ?? string.Empty, args.Message.Args, AppendPageLog);
|
||||
lock (PendingConsoleDetails)
|
||||
PendingConsoleDetails.Add(detailTask);
|
||||
}
|
||||
catch { }
|
||||
break;
|
||||
case ConsoleType.Warning:
|
||||
PageLog.AppendLine($"WARNING: {args.Message.Text}");
|
||||
AppendPageLog($"WARNING: {args.Message.Text}");
|
||||
break;
|
||||
default:
|
||||
PageLog.AppendLine($"INFO: {args.Message.Text}");
|
||||
AppendPageLog($"INFO: {args.Message.Text}");
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -962,7 +969,7 @@ What could be the issue here?
|
||||
pageClientMeta["DownloadToken"] = ReportApiRelay.DOWNLOAD_KEY_PLACEHOLDER;
|
||||
//case 4632: inside IIS the page's API calls are also relayed by the server
|
||||
log.LogDebug($"Handling report API calls under {apiUrl}{(relayTarget == null ? "" : $", relayed to {relayTarget}")}");
|
||||
relayClient = await ReportApiRelay.AttachAsync(page, apiUrl, relayTarget, realAuthorization, realDownloadKey, TimeSpan.FromMinutes(ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT), s => PageLog.AppendLine(s), log);
|
||||
relayClient = await ReportApiRelay.AttachAsync(page, apiUrl, relayTarget, realAuthorization, realDownloadKey, TimeSpan.FromMinutes(ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT), AppendPageLog, log);
|
||||
|
||||
log.LogDebug($"Preparing page: adding base reporting scripts to page");
|
||||
if (!ReportRenderManager.KeepGoing(job.GId))
|
||||
@@ -1258,18 +1265,27 @@ What could be the issue here?
|
||||
//This is the error when a helper is used on the template but doesn't exist:
|
||||
//Evaluation failed: d
|
||||
//(it might also mean other things wrong with template)
|
||||
if (PageLog.Length > 0)
|
||||
//case 4703: let console.error details still being fetched reach the page log (at most 2 seconds)
|
||||
Task[] pendingDetails;
|
||||
lock (PendingConsoleDetails)
|
||||
pendingDetails = PendingConsoleDetails.ToArray();
|
||||
if (pendingDetails.Length > 0)
|
||||
await Task.WhenAny(Task.WhenAll(pendingDetails), Task.Delay(2000));
|
||||
string pageLogText;
|
||||
lock (PageLog)
|
||||
pageLogText = PageLog.ToString();
|
||||
if (pageLogText.Length > 0)
|
||||
{
|
||||
log.LogInformation(
|
||||
$"Exception caught while rendering report \"{report.Name}\", report Page console log:"
|
||||
);
|
||||
log.LogInformation(PageLog.ToString());
|
||||
log.LogInformation(pageLogText);
|
||||
var json = Newtonsoft.Json.JsonConvert.SerializeObject(
|
||||
new
|
||||
{
|
||||
rendererror = new
|
||||
{
|
||||
pagelog = PageLog.ToString(),
|
||||
pagelog = pageLogText,
|
||||
exception = ExceptionUtil.ExtractAllExceptionMessages(ex),
|
||||
},
|
||||
},
|
||||
@@ -1345,6 +1361,42 @@ What could be the issue here?
|
||||
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Failed);
|
||||
}
|
||||
|
||||
//case 4703: for each console.error argument that is an Error (its stack: message, file and line) or an object (its
|
||||
//JSON, cut at 1000 characters) adds an indented detail line to the page log, labelled with the start of the error's
|
||||
//message text as details arrive after the error lines; other values are already in the message text.
|
||||
//Stack lines from Puppeteer's own evaluation code are left out and file paths shortened to the file name
|
||||
static async Task AppendConsoleErrorDetailsAsync(string messageText, IEnumerable<IJSHandle> consoleArgs, Action<string> appendPageLog)
|
||||
{
|
||||
const string detailScript = @"(arg) => {
|
||||
if (arg instanceof Error) {
|
||||
const s = arg.stack || String(arg);
|
||||
return s.split('\n')
|
||||
.filter(l => !/__puppeteer_evaluation_script__|RAFPoller|createFunction/.test(l))
|
||||
.map(l => l.replace(/\((?:[^()]*[\\\/])?([^\\\/()]+:\d+:\d+)\)/, '($1)'))
|
||||
.join('\n');
|
||||
}
|
||||
if (arg !== null && typeof arg === 'object') {
|
||||
try { const s = JSON.stringify(arg); return s && s.length > 1000 ? s.substring(0, 1000) + '...' : s; }
|
||||
catch (e) { return String(arg); }
|
||||
}
|
||||
return null;
|
||||
}";
|
||||
var label = messageText.Length > 60 ? messageText.Substring(0, 60) + "..." : messageText;
|
||||
foreach (var arg in consoleArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detail = await arg.EvaluateFunctionAsync<string>(detailScript);
|
||||
if (!string.IsNullOrWhiteSpace(detail))
|
||||
appendPageLog($" detail for \"{label}\": " + detail.Replace("\n", "\n "));
|
||||
}
|
||||
catch
|
||||
{
|
||||
//the page may already be closed; the error line itself is logged regardless
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Report browser could not be downloaded or started: log it properly and give the client a specific error
|
||||
//instead of the generic job failure it got when this escaped to the job processor
|
||||
static async Task HandleBrowserFailure(OpsJob job, ILogger log, string what, Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user