cuprite icon indicating copy to clipboard operation
cuprite copied to clipboard

Feature request: Be able to see just console.log/console.error etc without all debug output

Open henrik opened this issue 4 years ago • 8 comments

As discussed here: https://github.com/machinio/cuprite/issues/110#issuecomment-584557319

henrik avatar Feb 11 '20 10:02 henrik

Indeed I just noticed this as I tried cuprite (coming from selenium + chrome headless). I would really like the ability to display (or get as string) the console output of the browser. Is there a way to get it using some method in an after(:each) maybe? I tried the logger option but it is slightly too verbose ^^.

Little suggestion: maybe when passing a ruby Logger object here you could send your debug with the "debug" level and the browser messages with their respective level so the user can then chose to set the logger level to "info" for example to not get those?

Otherwise a way to get them from a method would be perfect, as we could also filter them, mute them when we want, etc.. (like page.driver.browser.manage.logs.get("browser") from selenium-webdriver + chrome)

jarthod avatar Feb 19 '20 22:02 jarthod

I think we need to split them, that would solve all the issues. If I remember correct we pass IO like STDOUT not Ruby logger, maybe it's time to revisit this part, I borrowed it from Poltergeist.

route avatar Feb 20 '20 09:02 route

Hi, is there a workaround for this under than using grep to exclude debug lines? Thanks!

vitobotta avatar Jan 02 '21 17:01 vitobotta

Hi, is there a workaround for this under than using grep to exclude debug lines? Thanks!

You can define a custom logger (which still needs to omit the debug log lines, but is a different approach to grepping stdout as outlined here).

There's an example at https://github.com/rubycdp/ferrum/issues/55#issuecomment-595225879, I used this approach as a starting point. Happy to share more details about what I've done if that'd be helpful.

nfm avatar Jan 02 '21 22:01 nfm

Hi @nfm , yeah that's what I have been doing with grep. Not sure of how to use the custom logger though. Can you help or should I ask in that thread? Thanks! :)

vitobotta avatar Jan 03 '21 08:01 vitobotta

Happy to share my WIP. I expect you'll want to modify this a bit (we're trialing migrating from Selenium and I want to keep things backwards compatible-ish but haven't quite nailed that down yet):

# Create your own logger class
class FerrumLogger
  attr_reader :logs

  def initialize
    @logs = []
  end

  # Filter out the noise - I believe Runtime.exceptionThrown and Log.entryAdded are the interesting log methods but there might be others you need
  def puts(log_str)
    _log_symbol, _log_time, log_body_str = log_str.strip.split(' ', 3)
    log_body = JSON.parse(log_body_str)
    if %w[Runtime.exceptionThrown Log.entryAdded].include?(log_body['method'])
      selenium_compatible_log_message = "#{log_body["params"]["entry"]["url"]} - #{log_body["params"]["entry"]["text"]}"
      @logs << { message: selenium_compatible_log_message, level: log_body["params"]["entry"]["level"] }
    end
  end

  def truncate
    @logs = []
  end
end

# Here's how I'm setting up the cuprite driver with custom logger, you might have a different approach though
Capybara.register_driver(:cuprite) do |app|
  Capybara::Cuprite::Driver.new(
    app,
    **{
      logger: FerrumLogger.new,
      # bunch of other options here that aren't relevant to custom logger
    }
  )
end

# And then reading the logs from whatever context you're interested in them (eg. `after(:each)`)
errors = page.driver.browser.logger.logs
...

nfm avatar Jan 03 '21 10:01 nfm

Hi @nfm , thanks a lot! I made a couple of changes since I prefer to print the relevant log entries as they happen, plus I added Runtime.consoleAPICalled since that's what seems to be used when I use console.log from my code for debugging.

class FerrumLogger
  def puts(log_str)
    _log_symbol, _log_time, log_body_str = log_str.strip.split(' ', 3)
    
    return if log_body_str.nil?
    
    log_body = JSON.parse(log_body_str)

    case log_body['method']
    when "Runtime.consoleAPICalled"
      log_body["params"]["args"].each do |arg|
        Kernel.puts arg["value"]
      end
    when "Runtime.exceptionThrown", "Log.entryAdded"
      Kernel.puts "#{log_body["params"]["entry"]["url"]} - #{log_body["params"]["entry"]["text"]}"
    end
  end
end

Thanks again!

vitobotta avatar Jan 03 '21 12:01 vitobotta

An update version to log also object, not just strings. Also removed log of Runtime.exceptionThrown since that's already caught by js_errors: true.

class FerrumLogger
  def puts(log_str)
    _log_symbol, _log_time, log_body_str = log_str.strip.split(' ', 3)

    return if log_body_str.nil?

    log_body = JSON.parse(log_body_str)

    case log_body['method']
    when 'Runtime.consoleAPICalled'
      log_body['params']['args'].each do |arg|
        case arg['type']
        when 'string'
          Kernel.puts arg['value']
        when 'object'
          Kernel.puts arg['preview']['properties'].map { |x| [x["name"], x["value"]] }.to_h
        end

      end

    when 'Runtime.exceptionThrown'
      # noop, this is already logged because we have "js_errors: true" in cuprite.

    when 'Log.entryAdded'
      Kernel.puts "#{log_body['params']['entry']['url']} - #{log_body['params']['entry']['text']}"
    end
  end
end

rogercampos avatar Mar 17 '21 14:03 rogercampos