{"id":13586891,"url":"https://github.com/piotrmurach/tty-logger","last_synced_at":"2025-06-12T13:09:32.785Z","repository":{"id":48871322,"uuid":"195463496","full_name":"piotrmurach/tty-logger","owner":"piotrmurach","description":"A readable, structured and beautiful logging for the terminal","archived":false,"fork":false,"pushed_at":"2024-04-14T21:12:53.000Z","size":282,"stargazers_count":293,"open_issues_count":2,"forks_count":13,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-03T01:15:36.626Z","etag":null,"topics":["logger","logging","ruby","rubygem","terminal"],"latest_commit_sha":null,"homepage":"https://ttytoolkit.org","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piotrmurach.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"piotrmurach"}},"created_at":"2019-07-05T20:23:06.000Z","updated_at":"2024-06-18T16:44:17.916Z","dependencies_parsed_at":"2024-04-11T23:40:26.650Z","dependency_job_id":"aec73ecd-8c34-467f-b642-feb76d3d5845","html_url":"https://github.com/piotrmurach/tty-logger","commit_stats":{"total_commits":249,"total_committers":8,"mean_commits":31.125,"dds":0.03614457831325302,"last_synced_commit":"9f51d8280854f4c976ae3d20c4303d33bd43fad1"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/piotrmurach/tty-logger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrmurach%2Ftty-logger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrmurach%2Ftty-logger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrmurach%2Ftty-logger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrmurach%2Ftty-logger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piotrmurach","download_url":"https://codeload.github.com/piotrmurach/tty-logger/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrmurach%2Ftty-logger/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259470950,"owners_count":22862999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["logger","logging","ruby","rubygem","terminal"],"created_at":"2024-08-01T15:05:53.181Z","updated_at":"2025-06-12T13:09:32.739Z","avatar_url":"https://github.com/piotrmurach.png","language":"Ruby","funding_links":["https://github.com/sponsors/piotrmurach"],"categories":["Ruby"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://ttytoolkit.org\" target=\"_blank\"\u003e\u003cimg width=\"130\" src=\"https://github.com/piotrmurach/tty/raw/master/images/tty.png\" alt=\"tty logo\" /\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n# TTY::Logger\n\n[![Gem Version](https://badge.fury.io/rb/tty-logger.svg)][gem]\n[![Actions CI](https://github.com/piotrmurach/tty-logger/actions/workflows/ci.yml/badge.svg)][gh_actions_ci]\n[![Build status](https://ci.appveyor.com/api/projects/status/vtrkdk0naknnxoog?svg=true)][appveyor]\n[![Code Climate](https://codeclimate.com/github/piotrmurach/tty-logger/badges/gpa.svg)][codeclimate]\n[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-logger/badge.svg)][coverage]\n\n[gem]: https://badge.fury.io/rb/tty-logger\n[gh_actions_ci]: https://github.com/piotrmurach/tty-logger/actions/workflows/ci.yml\n[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-logger\n[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-logger\n[coverage]: https://coveralls.io/github/piotrmurach/tty-logger\n\n\u003e A readable, structured and beautiful logging for the terminal\n\n**TTY::Logger** provides independent logging component for [TTY toolkit](https://github.com/piotrmurach/tty).\n\n![](assets/tty-logger-levels.png)\n\n## Features\n\n* Intuitive console output for an increased readability\n* Ability to stream data to any IO object\n* Supports structured data logging\n* Filters sensitive data\n* Allows to define custom log types\n* Formats and truncates messages to avoid clogging logging output\n* Customizable styling of labels and symbols for console output\n* Includes metadata information: time, location, scope\n* Handles multiple logging outputs\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem \"tty-logger\"\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install tty-logger\n\n\n## Contents\n\n* [1. Usage](#1-usage)\n* [2. Synopsis](#2-synopsis)\n  * [2.1 Logging](#21-logging)\n    * [2.1.1 Exceptions](#211-exceptions)\n    * [2.1.2 Types](#212-types)\n  * [2.2 Levels](#22-levels)\n    * [2.2.1 Scoped Level](#22-scoped-level)\n  * [2.3 Structured Data](#23-structured-data)\n  * [2.4 Configuration](#24-configuration)\n    * [2.4.1 Metadata](#241-metadata)\n    * [2.4.2 Filters](#242-filters)\n  * [2.5 Cloning](#25-cloning)\n  * [2.6 Handlers](#26-handlers)\n    * [2.6.1 Console Handler](#261-console-handler)\n    * [2.6.2 Stream Handler](#262-stream-handler)\n    * [2.6.3 Custom Handler](#263-custom-handler)\n    * [2.6.4 Multiple Handlers](#264-multiple-handlers)\n  * [2.7 Formatters](#27-formatters)\n  * [2.8 Output streams](#28-output-streams)\n* [3. Community Extensions](#3-community-extensions)\n  * [3.1 Sentry Handler](#31-sentry-handler)\n\n## 1. Usage\n\nCreate logger:\n\n```ruby\nlogger = TTY::Logger.new\n```\n\nAnd log information using any of the logger [built-in types](#212-types):\n\n```ruby\nlogger.info \"Deployed successfully\"\nlogger.info \"Deployed\", \"successfully\"\nlogger.info { \"Dynamically generated info\" }\n```\n\nInclude structured data:\n\n```ruby\nlogger.success \"Deployed successfully\", app: \"myapp\", env: \"prod\"\n# =\u003e\n# ✔ success Deployed successfully     app=myapp env=prod\n```\n\nAdd [metadata](#241-metadata) information:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.metadata = [:date, :time]\nend\nlogger.info \"Deployed successfully\", app: \"myapp\", env: \"prod\"\n# =\u003e\n# [2019-07-17] [23:21:55.287] › ℹ info    Info about the deploy     app=myapp env=prod\n```\n\nOr change structured data [formatting](#27-formatters) display to `JSON`:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.formatter = :json\nend\nlogger.info \"Deployed successfully\"\n# =\u003e\n# [2019-07-17] [23:21:55.287] › ℹ info    Info about the deploy     {\"app\":\"myapp\",\"env\":\"prod\"}\n```\n\n## 2. Synopsis\n\n## 2.1 Logging\n\nThere are many logger types to choose from:\n\n* `debug` - logs message at `:debug` level\n* `info` - logs message at `:info` level\n* `success` - logs message at `:info` level\n* `wait` - logs message at `:info` level\n* `warn` - logs message at `:warn` level\n* `error` - logs message at `:error` level\n* `fatal` - logs message at `:fatal` level\n\nTo log a message, simply choose one of the above types and pass in the actual message. For example, to log successfully deployment at info level do:\n\n```ruby\nlogger.success \"Deployed successfully\"\n# =\u003e\n# ✔ success Deployed successfully\n```\n\nOr pass in multiple messages:\n\n```ruby\nlogger.success \"Deployed\", \"successfully\"\n# =\u003e\n# ✔ success Deployed successfully\n```\n\nYou can delay message evaluation by passing it inside a block:\n\n```ruby\nlogger.success { \"Dynamically generated info\" }\n# =\u003e\n# ✔ success Dynamically generated info\n```\n\nSimilar to regular logging, you cal split your message into chunks inside a block:\n\n```ruby\nlogger.success { [\"Dynamically\", \"generated\", \"info\"] }\n# =\u003e\n# ✔ success Dynamically generated info\n```\n\nThe above comes handy when paired with [structured data](#23-structured-data).\n\n#### 2.1.1 Exceptions\n\nYou can also report on exceptions.\n\nFor example, let's say you caught an exception about incorrect data format and use `fatal` level to log it:\n\n```ruby\nbegin\n  raise ArgumentError, \"Wrong data\"\nrescue =\u003e ex\n  logger.fatal(\"Error:\", ex)\nend\n```\n\nThis will result in a message followed by a full backtrace:\n\n```ruby\n# =\u003e\n# ! fatal   Error: Wrong data\n#    tty-logger/spec/unit/exception_spec.rb:12:in `block (2 levels) in \u003ctop (required)\u003e'\n#    rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `instance_exec'\n#    rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'\n```\n\n#### 2.1.2 Types\n\nYou can define custom log types via the `types` configuration option:\n\nFor example, if you want to add `thanks` and `done` log types, you need to provide their names along with logging levels. You can further customise the `:console` output with your desired styling:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.types = {\n    thanks: {level: :info},\n    done: {level: :info}\n  }\n  config.handlers = [\n    [:console, {\n      styles: {\n        thanks: {\n          symbol: \"❤️ \",\n          label: \"thanks\",\n          color: :magenta,\n          levelpad: 0\n        },\n        done: {\n          symbol: \"!!\",\n          label: \"done\",\n          color: :green,\n          levelpad: 2\n        }\n      }\n    }]\n  ]\nend\n```\n\nOnce defined, you can call new log types:\n\n```ruby\nlogger.thanks(\"Great work!\")\nlogger.done(\"Work done!\")\n# =\u003e\n# ❤️  thanks Great work!\n# !! done   Work done!\n```\n\n![](assets/tty-logger-custom-log-types.png)\n\n### 2.2 Levels\n\nThe supported levels, ordered by precedence, are:\n\n* `:debug` - for debug-related messages\n* `:info` - for information of any kind\n* `:warn` - for warnings\n* `:error` - for errors\n* `:fatal` - for fatal conditions\n\nSo the order is: `:debug` \u003c `:info` \u003c `:warn` \u003c `:error` \u003c `:fatal`\n\nFor example, `:info` takes precedence over `:debug`. If your log level is set to `:info`, `:info`, `:warn`, `:error` and `:fatal` will be printed to the console. If your log level is set to `:warn`, only `:warn`, `:error` and `:fatal` will be printed.\n\nYou can set level using the `level` configuration option. The value can be a symbol, a string or level constant. For example, `:info`, `INFO` or `TTY::Logger::INFO_LEVEL` will qualify as valid level value.\n\n```ruby\nTTY::Logger.new do |config|\n  config.level = :info # or \"INFO\" or TTY::Logger::INFO_LEVEL\nend\n```\n\nOr you can specific level for each log events handler.\n\nFor example, to log messages above `:info` level to a stream and only `:error` level events to the console do:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.handlers = [\n    [:console, level: :error],\n    [:stream, level: :info]\n  ]\nend\n```\n\nYou can also change the [output streams](#28-output-streams) for each handler.\n\n#### 2.2.1 Scoped Level\n\nYou can temporarily change level, raise it or lower it by using the `log_at` call. By default messages are logged at `:info` level, but you can change this for the duration of a block:\n\n```ruby\nlogger = TTY::Logger.new\n\nlogger.info(\"not logged\")\n\nlogger.log_at :debug do\n  logger.debug(\"logged\")\nend\n# =\u003e\n# • debug   logged\n```\n\nOr elevate a level to an error with a constant `ERROR_LEVEL`:\n\n```ruby\nlogger.log_at TTY::Logger::ERROR_LEVEL do\n  logger.debug(\"not logged\")\n  logger.error(\"logged\")\nend\n# =\u003e\n# ⨯ error   logged\n```\n\n### 2.3 Structured data\n\nTo add global data available for all logger calls:\n\n```ruby\nlogger = TTY::Logger.new(fields: {app: \"myapp\", env: \"prod\"})\n\nlogger.info(\"Deploying...\")\n# =\u003e\n# ℹ info    Deploying...              app=myapp env=prod\n```\n\nTo only add data for a single log event:\n\n```ruby\nlogger = TTY::Logger.new\nlogger.wait \"Ready to deploy\", app: \"myapp\", env: \"prod\"\n# =\u003e\n# … waiting Ready to deploy           app=myapp env=prod\n```\n\nYou can delay data evaluation until it's evaluated by passing it inside a block:\n\n```ruby\nlogger.wait { [\"Ready to deploy\", {app: \"myapp\", env: \"prod\"}] }\n# =\u003e\n# … waiting Ready to deploy           app=myapp env=prod\n```\n\n### 2.4 Configuration\n\nAll the configuration options can be changed globally via `configure` or per logger instance.\n\n* `:filters` - the storage of placeholders to filter sensitive data out from the logs. Defaults to `{}`.\n* `:formatter` - the formatter used to display structured data. Defaults to `:text`. See [Formatters](#27-formatters) for more details.\n* `:handlers` - the handlers used to log messages. Defaults to `[:console]`. See [Handlers](#26-handlers) for more details.\n* `:level` - the logging level. Any message logged below this level will be simply ignored. Each handler may have it's own default level. Defaults to `:info`\n* `:max_bytes` - the maximum message size to be logged in bytes. Defaults to `8192` bytes. The truncated message will have `...` at the end.\n* `:max_depth` - the maximum depth for nested structured data. Defaults to `3`.\n* `:metadata` - the meta info to display before the message, can be `:pid`, `:date`, `:time` or `:file`. Defaults to empty array `[]`, no metadata. Setting this to `:all` will print all the metadata.\n* `:types` - the new custom log types. Defaults to `{}`.\n* `:date_format` - uses `strftime` format to display dates. Defaults to `\"%F\"`.\n* `:time_format` - uses `strftime` format to display times. Defaults to `\"%T.%3N\"`.\n\nFor example, to configure `:max_bytes`, `:level` and `:metadata` for all logger instances do:\n\n```ruby\nTTY::Logger.configure do |config|\n  config.max_bytes = 2**10\n  config.level = :error\n  config.metadata = [:time, :date]\nend\n```\n\nOr if you wish to setup configuration per logger instance use block:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.max_bytes = 2**20\n  config.metadata = [:all]\nend\n```\n\nYou can also change the logger's configuration at runtime:\n\n```ruby\nlogger.configure do |config|\n  config.level = :debug\nend\n```\n\n### 2.4.1 Metadata\n\nThe `:metdata` configuration option can include the following symbols:\n\n* `:pid` - the log event process identifier\n* `:date` - the log event date\n* `:time` - the log event time\n* `:file` - the file with a line number the log event is triggered from\n\n### 2.4.2 Filters\n\nYou can filter sensitive data out of log output with `filters` configuration option. The `filters` can be further configured to remove info from log message with `message` or structured data with `data`. Both methods, as a value accept a list of sensitive items to search for.\n\nIf you want to filter sensitive information from log messages use `message`:\n\n```ruby\nlogger = TTY::Logger.new(output: output) do |config|\n  config.filters.message = %w[secret password]\nend\n```\n\nWhich by default will replace each matching string with `[FILTERED]` placeholder:\n\n```ruby\nlogger.info(\"Super secret info with password\")\n# =\u003e\n# ℹ info    Super [FILTERED] info with [FILTERED]\n```\n\nYou can also replace each data item with a custom placeholder. To do so use a `:mask` keyword with a replacement placeholder.\n\nFor example, to replace \"secret\" content with placeholder `\"\u003cSECRET\u003e\"` do:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.filters.message = %w[secret]\n  config.filters.mask = \"\u003cSECRET\u003e\"\nend\n```\n\nWhen logged, it will produce:\n\n```ruby\nlogger.info(\"Super secret info\")\n# =\u003e\n# ℹ info    Super \u003cSECRET\u003e info\n```\n\nTo filter out sensitive information out of structured data use `data` method. By default any value matching a parameter name will be filtered regardless of the level of nesting. If you wish to filter only a specific deeply nested key use a dot notation like `params.card.password` to only filter `{params: {card: {password: \"Secret123\"}}}`.\n\nFor example to filter out a `:password` from data do:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.filters.data = %i[password]\nend\n```\n\nThis will filter out any key matching password:\n\n```ruby\nlogger.info(\"Secret info\", password: \"Secret123\", email: \"\")\n# =\u003e\n# ℹ info    Secret info     password=\"[FILTERED]\" email=\"secret@example.com\"\n```\n\nBut also any nested data item:\n\n```ruby\nlogger.info(\"Secret info\", params: {password: \"Secret123\", email: \"\"})\n# =\u003e\n# ℹ info    Secret info     params={password=\"[FILTERED]\" email=\"secret@example.com\"}\n```\n\nYou're not limited to using only direct string comparison. You can also match based on regular expressions. For example, to match keys starting with `ba` we can add a following filter:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.filters.data = [/ba/]\nend\n```\n\nThen appropriate values will be masked:\n\n```ruby\nlogger.info(\"Filtering data\", {\"foo\" =\u003e {\"bar\" =\u003e \"val\", \"baz\" =\u003e \"val\"}})\n# =\u003e\n# ℹ info    Filtering data            foo={bar=\"[FILTERED]\" baz=\"[FILTERED]\"}\n```\n\nYou can mix and match. To filter keys based on pattern inside a deeply nested hash use dot notation with regular expression. For example, to find keys for the `:foo` parent key that starts with `:b` character, we could do:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.filters.data = [/^foo\\.b/]\nend\n```\n\nThen only keys under the `:foo` key will be filtered:\n\n```ruby\nlogger.info(\"Filtering data\", {\"foo\" =\u003e {\"bar\" =\u003e \"val\"}, \"baz\" =\u003e {\"bar\" =\u003e val\"}})\n# =\u003e\n# ℹ info    Filtering data            foo={bar=\"[FILTERED]\"} baz={bar=val}\n```\n\n### 2.5 Cloning\n\nYou can create a copy of a logger with the current configuration using the `copy` method.\n\nFor example, given the following logger with `:app` and `:env` data:\n\n```ruby\nlogger = TTY::Logger.new(fields: {app: \"parent\", env: \"prod\"})\n```\n\nWe can create a copy with a custom configuration that changes filtered message content and `:app` data:\n\n```ruby\nchild_logger = logger.copy(app: \"child\") do |config|\n  config.filters = [\"logging\"]\nend\n```\n\n```ruby\nlogger.info(\"Parent logging\")\nchild_logger.warn(\"Child logging\")\n# =\u003e\n# ℹ info    Parent logging            app=parent env=prod\n# ⚠ warning Child [FILTERED]          app=child env=prod\n```\n\n### 2.6 Handlers\n\n`TTY::Logger` supports many ways to handle log messages.\n\nThe available handlers by default are:\n\n* `:console` - log messages to the console, enabled by default\n* `:null` - discards any log messages\n* `:stream` - log messages to an `IO` stream, a file, a socket or a console.\n\nYou can also implement your own [custom handler](#263-custom-handler).\n\nThe handlers can be configured via global or instance configuration with `handlers`. The handler can be a name or a class name:\n\n```ruby\nTTY::Logger.new do |config|\n  config.handlers = [:console]\nend\n```\n\nOr using class name:\n\n```ruby\nTTY::Logger.new do |config|\n  config.handlers = [TTY::Logger::Handlers::Console]\nend\n```\n\nHandlers can also be added/removed dynamically through `add_handler` or `remove_handler`.\n\n```ruby\nlogger = TTY::Logger.new\nlogger.add_handler(:console)\nlogger.remove_handler(:console)\n```\n\n#### 2.6.1 Console Handler\n\nThe console handler prints log messages to the console. It supports the following options:\n\n* `:styles` - a hash of styling options.\n* `:formatter` - the formatter for log messages. Defaults to `:text`.\n* `:output` - the device to log error messages to. Defaults to `$stderr`.\n* `:message_format` - uses `sprintf` format to display messages. Defaults to `\"%-25s\"`.\n* `:enable_color` - when `true` forces colored output, when `false` disables colored output.\n                    Defaults to `nil` which performs automatic terminal color support detection.\n\nThe supported options in the `:styles` are:\n\n* `:label` - the name for the log message.\n* `:symbol` - the graphics to display before the log message label.\n* `:color` - the color for the log message.\n* `:levelpad` - the extra amount of padding used to display log label.\n\nSee the [TTY::Logger::Handlers::Console](https://github.com/piotrmurach/tty-logger/blob/master/lib/tty/logger/handlers/console.rb) for full list of styles.\n\nConsole handler has many default styles such as `success` and `error`:\n\n```ruby\nlogger = TTY::Logger.new\nlogger.success(\"Default success\")\nlogger.error(\"Default error\")\n# =\u003e\n# ✔ success Default success\n# ⨯ error   Default error\n```\n\nYou can change the default styling with a tuple of handler name and options hash.\n\nIn our example, we want to change the styling of `success` and `error`:\n\n```ruby\nnew_styles = {\n  styles: {\n    success: {\n      symbol: \"+\",\n      label: \"Ohh yes\"\n    },\n    error: {\n      symbol: \"!\",\n      label: \"Dooh\",\n      levelpad: 3 # the amount of extra padding to align level names in a column\n    }\n  }\n}\n```\n\nAnd then use the `new_styles` when providing `handlers` configuration:\n\n```ruby\nstyled_logger = TTY::Logger.new do |config|\n  config.handlers = [[:console, new_styles]]\nend\n\nstyled_logger.success(\"Custom success\")\nstyled_logger.error(\"Custom error\")\n# =\u003e\n# + Ohh yes Custom success\n# ! Dooh    Custom error\n```\n\nTo increase message padding to a percentage of terminal width (depends on [tty-screen](https://github.com/piotrmurach/tty-screen/)):\n\n```ruby\nTTY::Logger.new do |config|\n  padding = (TTY::Screen.columns * 0.4).to_i\n  config.handlers = [[:console, { message_format: \"%-#{padding}s\" }]]\nend\n```\n\n#### 2.6.2 Stream handler\n\nTo send log event data outside of console to another service or `IO` stream, you can use `:stream` handler.\n\n```ruby\nlogger = TTY::Logger.new(output: output) do |config|\n  config.handlers = [:stream]\n  config.metadata = [:all]\nend\n```\n\nBy default, the output will be a plain text streamed to console. The text contains key and value pairs of all the metadata and the message of the log event.\n\n```ruby\nlogger.info(\"Info about the deploy\", app: \"myapp\", env: \"prod\")\n# =\u003e\n# pid=18315 date=\"2019-07-21\" time=\"15:42:12.463\" path=\"examples/stream.rb:17:in`\u003cmain\u003e`\"\n# level=info message=\"Info about the deploy\" app=myapp env=prod\n```\n\nYou can change stream formatter for ease of working with external services such as `Logstash`. For example, to use `:stream` handler with `:json` format do:\n\n```ruby\nlogger = TTY::Logger.new(output: output) do |config|\n  config.handlers = [[:stream, formatter: :json]]\n  config.metadata = [:all]\nend\n```\n\nThis will output JSON formatted text streamed to console.\n\n```ruby\nlogger.info(\"Info about the deploy\", app: \"myapp\", env: \"prod\")\n# =\u003e\n# {\"pid\":18513,\"date\":\"2019-07-21\",\"time\":\"15:54:09.924\",\"path\":\"examples/stream.rb:17:in`\u003cmain\u003e`\",\n# \"level\":\"info\",\"message\":\"Info about the deploy\",\"app\":\"myapp\",\"env\":\"prod\"}\n```\n\n#### 2.6.3 Custom Handler\n\nYou can create your own log event handler if the default ones don't match your needs.\n\nThe design of your handler should include two calls:\n\n* `initialize` - where all dependencies get injected\n* `call` - where the log event is handled\n\nWe start with the implementation of the `initialize` method. This method by default is injected with `:config` key that includes all global configuration options. The `:output` key for displaying log message in the console and `:formatter`.\n\nIn our case we also add custom `:label`:\n\n```ruby\nclass MyHandler\n  def initialize(output: nil, config: nil, formatter: nil, label: nil)\n    @label = label\n    @output = output\n  end\nend\n```\n\nNext is the `call` method that accepts the log `event`.\n\nThe `event` has the following attributes:\n\n* `message` - the array of message parts to be printed\n* `fields` - the structured data supplied with the event\n* `metadata` - the additional info about the event. See [metadata](#241-metadata) section for details.\n\nWe add implementation of `call`:\n\n```ruby\nclass MyHandler\n  def initialize(output: nil, config: nil, label: nil)\n    @label = label\n    @output = output\n  end\n\n  def call(event)\n    @output.puts \"(#{@label}) #{event.message.join}\"\n  end\nend\n```\n\nOnce you have your custom handler, you need to register it with the logger. You can do so using the `handlers` configuration option:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.handlers = [[MyHandler, label: \"myhandler\"]]\nend\n```\n\nOr add your handler dynamically after logger initialization:\n\n```ruby\nlogger = TTY::Logger.new\nlogger.add_handler [MyHandler, label: \"myhandler\"]\n```\n\n#### 2.6.4 Multiple Handlers\n\nYou can define as many handlers as you need. For example, you may log messages both to console and stream:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.handlers = [:console, :stream]\nend\n```\n\nEach handler can have its own configuration. For example, you can register `:console` handler to log messages above error level and `:stream` that logs any message with info or higher level:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.handlers = [\n    [:console, level: :error],\n    [:stream, level: :info]\n  ]\nend\n```\n\n### 2.7 Formatters\n\nThe available formatters are:\n\n* `:json`\n* `:text`\n\nYou can configure format for all the handlers:\n\n```ruby\nTTY::Logger.new do |config|\n  config.formatter = :json\nend\n```\n\nOr specify a different formatter for each handler. For example, let's say you want to log to console twice, once with default formatter and once with `:json` formatter:\n\n```ruby\nTTY::Logger.new do |config|\n  config.handlers = [:console, [:console, formatter: :json]]\nend\n```\n\n### 2.8 Output Streams\n\nBy default all log events are output to `stderr`. You can change this using configuration `output` option. Any `IO`-like stream such as file, socket or console can be used. For example, to log all messages to a file do:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.output = File.open(\"errors.log\", \"a\")\nend\n```\n\nYou can also specify multiple streams that all log messages will be sent to:\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.output = [$stderr, File.open(\"errors.log\", \"a\")]\nend\n```\n\nConversely, you can specify different output for each of the handlers used. For example, you can output all messages above info level to a file with a stream handler and only show error messages in the console with a nicely formatted output.\n\n```ruby\nlogger = TTY::Logger.new do |config|\n  config.handlers = [\n    [:console, output: $stderr, level: :error],\n    [:stream, output: File.open(\"errors.log\", \"a\"), level: :info)]\n  ]\nend\n```\n\n## 3. Community Extensions\n\n### 3.1 Sentry Handler\n\n[tty-logger-raven](https://github.com/ianks/tty-logger-raven) provides an extension for Sentry.io.\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-logger. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/piotrmurach/tty-logger/blob/master/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the TTY::Logger project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/tty-logger/blob/master/CODE_OF_CONDUCT.md).\n\n## Copyright\n\nCopyright (c) 2019 Piotr Murach. See LICENSE for further details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotrmurach%2Ftty-logger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiotrmurach%2Ftty-logger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotrmurach%2Ftty-logger/lists"}