Как я могу получить читабельные ошибки браузера / страницы из-за кукольника? - PullRequest
1 голос
/ 09 июля 2019

Я использую «Кукольник» для рендеринга некоторых страниц в формате PDF. Я хотел бы знать, есть ли какие-либо проблемы с отображением страницы во время выполнения в браузере, поэтому я настроил некоторые обработчики событий:

_page.Error += (sender, args) =>
{
    _logger.LogCritical(args.Error);
};

_page.PageError += (sender, args) =>
{
    _logger.LogError(args.Message);
};

_page.Console += (sender, args) =>
{
    switch (args.Message.Type)
    {
        case ConsoleType.Error:
            _logger.LogError(args.Message.Text);
            break;
        case ConsoleType.Warning:
            _logger.LogWarning(args.Message.Text);
            break;
        default:
            _logger.LogInformation(args.Message.Text);
            break;
    }
};

Когда я получаю сообщение об ошибке на странице, args.Message.Text, кажется, просто содержит "ERROR JSHandle@error". Это не очень полезно.

Я проверил нормальное console.log на странице, и это нормально регистрируется, похоже, проблема с ошибками.

Что мне нужно сделать, чтобы извлечь из этих ошибок что-то читаемое?

Обновление: я попытался получить доступ к args.Message.Args и использовать JsonValueAsync() в этих аргументах, но это, кажется, вызывает некоторую асинхронную странность, которая нарушает протокол devtools, потому что я начал получать ошибки тайм-аута, а затем ошибки, жалующиеся на повреждение веб-сокетов.

Похоже, это проблема самого кукловода: https://github.com/GoogleChrome/puppeteer/issues/3397

1 Ответ

1 голос
/ 10 июля 2019

Так что моя проблема возникла, потому что ошибки, по-видимому, не сериализуемы на земле javascript, поэтому нам нужно заставить браузер запустить функцию для извлечения сообщения и любых других деталей, которые нам нужны, из ошибки и ее возврата.

Это то, что работает для меня прямо сейчас:

_page.Console += async (sender, args) =>
{
    switch (args.Message.Type)
    {
        case ConsoleType.Error:
            try
            {
                var errorArgs = await Task.WhenAll(args.Message.Args.Select(arg => arg.ExecutionContext.EvaluateFunctionAsync("(arg) => arg instanceof Error ? arg.message : arg", arg)));
                _logger.LogError($"{args.Message.Text} args: [{string.Join<object>(", ", errorArgs)}]");
            }
            catch { }
            break;
        case ConsoleType.Warning:
            _logger.LogWarning(args.Message.Text);
            break;
        default:
            _logger.LogInformation(args.Message.Text);
            break;
    }
};

Я получил идею из комментария одного из авторов кукловодов здесь и портировал ее до уровня марионеток.

То, как это должно быть сделано в банкомате, выглядит так:

page.on('console', async msg => {
  // serialize my args the way I want
  const args = await Promise.all(msg.args.map(arg => arg.executionContext().evaluate(arg => {
    // I'm in a page context now. If my arg is an error - get me its message.
    if (arg instanceof Error)
      return arg.message;
    // return arg right away. since we use `executionContext.evaluate`, it'll return JSON value of
    // the argument if possible, or `undefined` if it fails to stringify it.
    return arg;
  }, arg)));
  console.log(...args);
});
...