Skip to content

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

Closed

Description

@henrik

As discussed here: #110 (comment)

Activity

  1. jarthod commented on Feb 19, 2020

    @jarthod

    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)

  2. route commented on Feb 20, 2020

    @route
    Member

    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.

  3. vitobotta commented on Jan 2, 2021

    @vitobotta

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

  4. nfm commented on Jan 2, 2021

    @nfm

    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 rubycdp/ferrum#55 (comment), I used this approach as a starting point. Happy to share more details about what I've done if that'd be helpful.

  5. vitobotta commented on Jan 3, 2021

    @vitobotta

    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! :)

  6. nfm commented on Jan 3, 2021

    @nfm

    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
    ...
  7. vitobotta commented on Jan 3, 2021

    @vitobotta

    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!

  8. rogercampos commented on Mar 17, 2021

    @rogercampos

    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
  9. phikes commented on Aug 9, 2024

    @phikes
    Contributor

    Since the preview field used above is truncated and the CDP allows to experimentally get a deep serialized value I came up with this (I use a gem to draw a fancy box, but you get the idea).

    # spec/support/capybara.rb
    
    require "capybara/cuprite"
    
    class FerrumLogger
      attr_accessor :page
    
      COLORS = {
        "error" => :red,
        "warn" => :yellow
      }
    
      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)
    
        return unless log_body["method"] === "Runtime.consoleAPICalled"
    
        Thread.new do
          type = log_body.dig "params", "type"
          args = log_body.dig "params", "args"
    
          args.each do |arg|
            json = to_json(arg)
    
            Rails.logger.debug TTY::Box.frame((json.is_a?(Array) || json.is_a?(Hash)) ? JSON.pretty_generate(json) : json, padding: 1, title: {top_left: "console.#{type}"}, style: {border: {fg: COLORS[type]}}, width: TTY::Screen.width)
          end
        end
      end
    
      protected
    
      def to_json(remote_object)
        type, object_id, value = remote_object.values_at "type", "objectId", "value"
    
        if type === "object" && value
          value.reduce({}) do |object, (key, value)|
            object.merge(key => to_json(value))
          end
        elsif type === "array" && value
          value.map do |array_value|
            to_json(array_value)
          end
        elsif object_id
          page.command(
            "Runtime.callFunctionOn",
            functionDeclaration: "function test() { return this }",
            objectId: object_id,
            serializationOptions: {serialization: "deep"}
          ).dig("result", "deepSerializedValue", "value").reduce({}) do |object, (key, value)|
            object.merge(key => to_json(value))
          end
        else
          value
        end
      rescue Ferrum::NoExecutionContextError => e
        e.message
      end
    end
    
    Capybara.register_driver(:cuprite) do |app|
      Capybara::Cuprite::Driver.new(app, logger: FerrumLogger.new)
      end
    end
    
    RSpec.configure do |config|
      config.before(:each, type: :feature) do
        page.driver.browser.options.logger.page = page.driver.browser.page
      end
    end
  10. route commented on Oct 19, 2026

    @route
    Member

    going to be addressed by rubycdp/ferrum#658

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions