TTY::Logger

repository·master·Indexed 43 days ago

https://github.com/piotrmurach/tty-logger

A component of the TTY toolkit providing readable, structured, and colorized logging for Ruby terminal applications. It supports multiple log levels (debug, info, success, wait, warn, error, fatal), structured data formatting in text or JSON, metadata inclusion, and sensitive data filtering. TTY::Logger allows for custom handlers, configurable output streams, and the ability to define custom log types.

Tokens
8.1K
Snippets
37
Records
39
Agent score
55%

What's inside TTY::Logger

  1. Implement a Custom Handler

    master

    To create a custom handler, implement a class with an initialize method (to receive dependencies like output, config, or formatter) and a call method that accepts an event object.

    The event object provides:

    • message: Array of message parts.
    • fields: Structured data hash.
    • metadata: Metadata hash (pid, date, time, file).
    class MyHandler
      def initialize(output: nil, config: nil, label: nil)
        @label = label
        @output = output
      end
    
      def call(event)
        @output.puts "(#{@label}) #{event.message.join}"
      end
    end
    
    # Registering the custom handler
    logger = TTY::Logger.new do |config|
      config.handlers = [[MyHandler, label: "myhandler"]]
    end
  2. Manage logging levels and precedence

    master

    Logging levels determine which messages are displayed. The supported levels, ordered by increasing precedence, are:

    :debug < :info < :warn < :error < :fatal

    If the logger level is set to :info, it will print :info, :warn, :error, and :fatal messages, but ignore :debug.

    Setting the level:

    • Globally/Instance: Use config.level = :symbol, "STRING", or TTY::Logger::LEVEL_CONSTANT.
    • Per Handler: You can specify a different level for each handler in the handlers array.
    # Set global level
    TTY::Logger.new do |config|
      config.level = :info
    end
    
    # Set per-handler levels
    logger = TTY::Logger.new do |config|
      config.handlers = [
        [:console, level: :error],
        [:stream, level: :info]
      ]
    end
  3. Filter sensitive data in logs

    master

    Use the filters configuration to mask sensitive information in both log messages and structured data.

    Filtering Messages: Use config.filters.message = ["string", /regex/] to replace matches in the message text with a placeholder (default is [FILTERED]). You can customize the placeholder using config.filters.mask = "<CUSTOM>".

    Filtering Structured Data: Use config.filters.data = ["key", /regex/] to mask values associated with specific keys. For deeply nested keys, use dot notation (e.g., params.card.password).

    # Filter message content
    logger = TTY::Logger.new do |config|
      config.filters.message = %w[secret password]
      config.filters.mask = "<SECRET>"
    end
    
    # Filter structured data keys
    logger = TTY::Logger.new do |config|
      config.filters.data = %i[password]
    end
    
    # Filter nested data using dot notation and regex
    logger = TTY::Logger.new do |config|
      config.filters.data = [/^foo\.b/]
    end
  4. Basic Usage of TTY::Logger

    master

    To use the logger, instantiate it with TTY::Logger.new. You can then log messages using built-in types like info, success, etc. The logger supports passing strings, multiple arguments, or blocks for dynamic content.

    logger = TTY::Logger.new
    
    logger.info "Deployed successfully"
    logger.info "Deployed", "successfully"
    logger.info { "Dynamically generated info" }
  5. Configure TTY::Logger options

    master

    Configuration can be applied globally via TTY::Logger.configure, per instance via a block in TTY::Logger.new, or at runtime via logger.configure.

    # Global configuration
    TTY::Logger.configure do |config|
      config.max_bytes = 2**10
      config.level = :error
      config.metadata = [:time, :date]
    end
    
    # Per-instance configuration
    logger = TTY::Logger.new do |config|
      config.max_bytes = 2**20
      config.metadata = [:all]
    end
    
    # Runtime configuration
    logger.configure do |config|
      config.level = :debug
    end
  6. Install and use TTY::Logger

    master

    To use the TTY::Logger library in your Ruby project, you must first require it. The library is typically loaded via require_relative "tty/logger" or require "tty-logger" depending on your project structure. Once required, you can instantiate a logger to provide formatted, colorized terminal output for various log levels (e.g., info, success, warn, error, fatal).

    require "tty-logger"
    
    # Example usage (based on library capabilities):
    logger = TTY::Logger.new
    logger.success("Deployed successfully")
  7. Log structured data

    master

    You can include structured data in your logs by passing a hash as an argument to the logging method. By default, this is rendered as key-value pairs in the console.

    logger.success "Deployed successfully", app: "myapp", env: "prod"
    # Output: ✔ success Deployed successfully     app=myapp env=prod
  8. Add structured data to logs

    master

    Structured data allows you to attach key-value pairs to log events for better context.

    • Global data: Pass a fields hash to TTY::Logger.new to make data available to every log call.
    • Single event data: Pass a hash as an argument to a logging method.
    • Delayed data: Pass a block that returns an array containing [message, data_hash] to delay evaluation.
    # Global fields
    logger = TTY::Logger.new(fields: {app: "myapp", env: "prod"})
    logger.info("Deploying...")
    
    # Single event fields
    logger.wait "Ready to deploy", app: "myapp", env: "prod"
    
    # Delayed evaluation
    logger.wait { ["Ready to deploy", {app: "myapp", env: "prod"}] }
  9. Temporarily change level with log_at

    master

    The log_at method allows you to temporarily change the logging level for the duration of a block. This is useful for forcing a specific level for certain operations.

    logger = TTY::Logger.new
    
    # Change level to :debug for this block
    logger.log_at :debug do
      logger.debug("logged")
    end
    
    # Elevate to a specific level using constants
    logger.log_at TTY::Logger::ERROR_LEVEL do
      logger.debug("not logged")
      logger.error("logged")
    end