{"id":13879461,"url":"https://github.com/emartech/ezlog","last_synced_at":"2025-07-16T15:32:23.591Z","repository":{"id":34876118,"uuid":"184727527","full_name":"emartech/ezlog","owner":"emartech","description":"A zero-configuration structured logging solution for projects using Rails, Sidekiq, Sequel, etc.","archived":true,"fork":false,"pushed_at":"2022-12-06T14:59:49.000Z","size":176,"stargazers_count":9,"open_issues_count":0,"forks_count":5,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-11-16T12:35:44.207Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/emartech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-03T09:07:59.000Z","updated_at":"2022-12-06T15:06:29.000Z","dependencies_parsed_at":"2023-01-15T09:49:01.670Z","dependency_job_id":null,"html_url":"https://github.com/emartech/ezlog","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emartech%2Fezlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emartech%2Fezlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emartech%2Fezlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emartech%2Fezlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emartech","download_url":"https://codeload.github.com/emartech/ezlog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226143895,"owners_count":17580245,"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":[],"created_at":"2024-08-06T08:02:21.810Z","updated_at":"2024-11-24T08:31:21.944Z","avatar_url":"https://github.com/emartech.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Ezlog\n\n## ⚠️ This repository is no longer actively maintained. \n#### ⚠️ For Rails 7 support please check: [Logcraft](https://github.com/zormandi/logcraft)\n\n[![Gem Version](https://badge.fury.io/rb/ezlog.svg)](https://badge.fury.io/rb/ezlog)\n[![Build Status](https://travis-ci.com/emartech/ezlog.svg?branch=master)](https://travis-ci.com/emartech/ezlog)\n\nEzlog is intended to be a zero-configuration structured logging setup for pure Ruby or [Ruby on Rails](https://rubyonrails.org/) \nprojects using any (or all) of the following libraries or frameworks:\n\n* [Ruby on Rails](https://rubyonrails.org/) (5.x and 6.x supported)\n* [Sidekiq](https://github.com/mperham/sidekiq)\n* [Sequel](https://sequel.jeremyevans.net/) \n* [Rack::Timeout](https://github.com/heroku/rack-timeout)\n\nIt uses Tim Pease's wonderful [Logging](https://github.com/TwP/logging) gem under the hood for an all-purpose structured logging solution.\n\nEzlog's purpose is threefold:\n1. Make sure that our applications are logging in a concise and sensible manner; emitting no unnecessary \"noise\" but \n   containing all relevant and necessary information (like timing).\n2. Make sure that all log messages are written to STDOUT in a machine-processable format (JSON) across all of our projects.\n3. Achieving the above goals should require no configuration in the projects where the library is used.\n\n## Installation\n\n### Rails\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'ezlog'\n```\n\nAlthough Ezlog sets up sensible defaults for all logging configuration settings, it leaves you the option to override these\nsettings manually in the way you're used to; via [Rails](https://rubyonrails.org/)'s configuration mechanism. Unfortunately\nthe [Rails](https://rubyonrails.org/) new project generator automatically generates code for the production environment\nconfiguration that overrides these settings.\n\nFor Ezlog to work properly, you also need to delete the logging configuration options in the \n`config/environments/production.rb` generated file.\n\n### Non-Rails applications\n\nAt the moment Ezlog only support [Rails](https://rubyonrails.org/) apps. Non-Rails support is planned.\n\n## What it does\n\n* Initializes the [Logging](https://github.com/TwP/logging) library\n* Configures [Rails](https://rubyonrails.org/)'s logging\n* Configures [Sidekiq](https://github.com/mperham/sidekiq) logging\n* Configures [Sequel](https://sequel.jeremyevans.net/) logging\n* Configures [Rack::Timeout](https://github.com/heroku/rack-timeout) logging\n* Provides support for adding context information to log messages\n* Provides testing support for [RSpec](https://rspec.info/)\n\n### Initializes the Logging library\n\nEzlog sets up [Logging](https://github.com/TwP/logging)'s root logger to have an appender that writes to STDOUT.\nAny loggers created by the application will inherit this appender and will thus write their logs to STDOUT.\nEzlog also comes with its own log layout, which it uses to output messages sent to the STDOUT appender. This layout\ndoes several very useful things to make our lives easier:\n\n* It can handle log messages in several formats:\n  * String (obviously)\n  * Hash\n  * Exception\n  * any object that can be coerced into a String\n* It automatically adds basic information to all log messages, such as:\n  * name of the logger\n  * timestamp\n  * log level (as string)\n  * hostname\n  * PID\n\nExamples:\n```ruby\nlogger.info 'Log message'\n#=\u003e {\"logger\":\"App\",\"timestamp\":\"2019-05-11T16:08:38+02:00\",\"level\":\"INFO\",\"hostname\":\"MacbookPro.local\",\"pid\":71674,\"message\":\"Log message\"}\n\nlogger.info message: 'Job finished', duration: 2\n#=\u003e {\"logger\":\"App\",\"timestamp\":\"2019-05-11T16:08:38+02:00\",\"level\":\"INFO\",\"hostname\":\"MacbookPro.local\",\"pid\":71674,\"message\":\"Job finished\",\"duration\":2}\n\nlogger.error ex\n#=\u003e {\"logger\":\"App\",\"timestamp\":\"2019-05-11T16:08:38+02:00\",\"level\":\"ERROR\",\"hostname\":\"MacbookPro.local\",\"pid\":71674,\"message\":\"Error message\",\"error\":{\"class\":\"StandardError\",\"message\":\"Error message\",\"backtrace\":[...]}}\n```\n\n### Configures Rails logging\n\nEzlog configures the `Rails.logger` to be an instance of a [Logging](https://github.com/TwP/logging) logger by the name \nof `Application`, behaving as described above. \n\nIn addition to this, Ezlog also does the following:\n* It adds the environment (`Rails.env`) to the logger's initial context, so it will automatically be appended to all log messages \n  emitted by the application.\n* It disables Rails's default logging of uncaught errors and injects its own error logger into the application, which\n  * logs 1 line per error, including the error's name and context (stack trace, etc.),\n  * logs every error at ERROR level instead of the default FATAL.\n  * does not log exceptions which are handled by Rails (`ActionDispatch::ExceptionWrapper.rescue_responses`)\n* It disables Rails's default request logging, which logs several lines per event during the processing of an action,\n  and replaces the default Rack access log with its own access log middleware. The end result is an access log that\n  * contains all relevant information (request ID, method, path, params, client IP, duration and response status code), and\n  * has 1 log line per request, logged at the end of the request.\n\nThanks to Mathias Meyer for writing [Lograge](https://github.com/roidrage/lograge), which inspired the solution. \nIf Ezlog's not your cup of tea but you're looking for a way to tame Rails's logging then be sure to check out\n[Lograge](https://github.com/roidrage/lograge). \n\n```\nGET /welcome?subsession_id=34ea8596f9764f475f81158667bc2654\n\nWith default Rails logging:\n\nStarted GET \"/welcome?subsession_id=34ea8596f9764f475f81158667bc2654\" for 127.0.0.1 at 2019-06-08 08:49:31 +0200\nProcessing by PagesController#welcome as HTML\n  Parameters: {\"subsession_id\"=\u003e\"34ea8596f9764f475f81158667bc2654\"}\n  Rendering pages/welcome.html.haml within layouts/application\n  Rendered pages/welcome.html.haml within layouts/application (5.5ms)\nCompleted 200 OK in 31ms (Views: 27.3ms | ActiveRecord: 0.0ms)\n\nWith Ezlog:\n\n{\"logger\":\"AccessLog\",\"timestamp\":\"2019-06-08T08:49:31+02:00\",\"level\":\"INFO\",\"hostname\":\"MacbookPro.local\",\"pid\":75463,\"environment\":\"development\",\"request_id\":\"9a43631b-284c-4677-9d08-9c1cc5c7d3a7\",\"duration_sec\":0.031,\"message\":\"GET /welcome?subsession_id=34ea8596f9764f475f81158667bc2654 - 200 (OK)\",\"remote_ip\":\"127.0.0.1\",\"method\":\"GET\",\"path\":\"/welcome?subsession_id=34ea8596f9764f475f81158667bc2654\",\"params\":{\"subsession_id\":\"34ea8596f9764f475f81158667bc2654\",\"controller\":\"pages\",\"action\":\"welcome\"},\"response_status_code\":200}\n```\n\nBy default, Ezlog logs all request parameters as a hash (JSON object) under the `params` key. This is very convenient\nin a structured logging system and makes it easy to search for specific request parameter values e.g. in ElasticSearch\n(should you happen to store your logs there). Unfortunately, in some cases - such as when handling large forms - this\ncan create quite a bit of noise and impact the searchability of your logs negatively. For this reason, you have the\noption to restrict which parameters get logged by adding something like the following to your application's configuration:\n\n```ruby\nconfig.ezlog.log_only_whitelisted_params = true  # default is false\nconfig.ezlog.whitelisted_params = [:action]      # default is [:controller, :action]\n```\n\nUsing this configuration, Ezlog will only log the `action` parameter under the `params` key, but will still log\nall parameters serialized into a single string under the key `params_serialized`. You won't lose any information,\nbut you can make sure that only the relevant parameters of your requests are searchable (and thus protect your logs).\n\nShould you want to exclude certain paths (e.g. a healthcheck URL) from your access logs, you can use the following option:\n\n```ruby\nconfig.ezlog.exclude_paths = ['/healthcheck', %r(/monitoring/.*)]  # default is empty so everything gets logged\n```\n\n#### The log level\n\nThe logger's log level is determined as follows (in order of precedence):\n* the log level set in the application's configuration,\n* the LOG_LEVEL environment variable, or\n* `INFO` as the default log level if none of the above are set.\n\nThe following log levels are available: `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`.\n\n### Configures Sidekiq logging\n\nEzlog configures the `Sidekiq.logger` to be an instance of a [Logging](https://github.com/TwP/logging) logger by the name\nof `Sidekiq`, behaving as described above. The logger uses the same log level as the [Rails](https://rubyonrails.org/) \nlogger (see above). Ezlog also comes with its own job logger for [Sidekiq](https://github.com/mperham/sidekiq) \nwhich does several things that come in very handy when working with background jobs.\n \n* It emits two log messages per job run; one when the job is started and another one when the job is finished (successfully or unsuccessfuly).\n* It measures the time it took to execute the job and appends the benchmark information to the final log message.\n* It adds all basic information about the job (worker, queue, JID, created_at, enqueued_at, run_count) to the log context so\nall log messages emitted during the execution of the job will contain this information.\n* It also adds all of the job's parameters (by name) to the log context, which means that all log messages emitted \nduring the execution of the job will contain this information as well.\n\n```ruby\nclass TestWorker\n  include Sidekiq::Worker\n\n  def perform(customer_id)\n    logger.warn 'Customer not found'\n  end\nend\n\nTestWorker.perform_async 42\n\n#=\u003e {\"logger\":\"Sidekiq\",\"timestamp\":\"2019-05-12T10:38:10+02:00\",\"level\":\"INFO\",\"hostname\":\"MacbookPro.local\",\"pid\":75538,\"jid\":\"abcdef1234567890\",\"queue\":\"default\",\"worker\":\"TestWorker\",\"created_at\":\"2019-05-12 10:38:10 +0200\",\"enqueued_at\":\"2019-05-12 10:38:10 +0200\",\"run_count\":1,\"customer_id\":42,\"message\":\"TestWorker started\"}\n#=\u003e {\"logger\":\"Sidekiq\",\"timestamp\":\"2019-05-12T10:38:10+02:00\",\"level\":\"WARN\",\"hostname\":\"MacbookPro.local\",\"pid\":75538,\"jid\":\"abcdef1234567890\",\"queue\":\"default\",\"worker\":\"TestWorker\",\"created_at\":\"2019-05-12 10:38:10 +0200\",\"enqueued_at\":\"2019-05-12 10:38:10 +0200\",\"run_count\":1,\"customer_id\":42,\"message\":\"Customer not found\"}\n#=\u003e {\"logger\":\"Sidekiq\",\"timestamp\":\"2019-05-12T10:38:12+02:00\",\"level\":\"INFO\",\"hostname\":\"MacbookPro.local\",\"pid\":75538,\"jid\":\"abcdef1234567890\",\"queue\":\"default\",\"worker\":\"TestWorker\",\"created_at\":\"2019-05-12 10:38:10 +0200\",\"enqueued_at\":\"2019-05-12 10:38:10 +0200\",\"run_count\":1,\"customer_id\":42,\"duration_sec\":2.667,\"message\":\"TestWorker finished\"}\n```\n\n### Configures Sequel logging\n\nEzlog adds a logging extension to [Sequel](https://sequel.jeremyevans.net/) that appends a logger to any newly opened\ndatabase connection. This logger is an instance of a [Logging](https://github.com/TwP/logging) logger by the name of\n`Sequel`, behaving as described above. It also sets [Sequel](https://sequel.jeremyevans.net/)'s `sql_log_level` to `debug`. \n\nThis extension isn't enabled by default, because [Sequel](https://sequel.jeremyevans.net/) logging isn't necessarily\nneeded in every project. You can enable it by adding the following line to your application's configuration:\n```\nconfig.ezlog.enable_sequel_logging = true\n```\n\n### Configures Rack::Timeout logging\n\n[Rack::Timeout](https://github.com/heroku/rack-timeout) is a very useful tool for people running services on Heroku\nbut it is way too verbose by default and all of its important messages (i.e. Timeout errors) are logged by the application\nas well. For this reason, Ezlog turns off [Rack::Timeout](https://github.com/heroku/rack-timeout) logging completely. \n\n### Provides support for adding context information to log messages\n\nEzlog provides two helper methods which can be used to add context information to log messages:\n\n* `within_log_context(context)`: Starts a new log context initialized with `context` and executes the provided block \n  within that context. Once execution is finished, the log context is cleaned up and the previous context (if any) is\n  reinstated. In practice, this means that every time we log something (within the block), the log message will include\n  the information that's in the current context. This can be useful for storing request-specific information \n  (request ID, user ID, ...) in the log context early on (for example in a middleware) and not have to worry about \n  including it every time we want to log a message.\n  \n  Example:\n  \n  ```ruby\n  within_log_context customer_id: 1234 do\n    Rails.logger.info 'test 1'\n  end\n  Rails.logger.info 'test 2'\n  \n  #=\u003e {...,\"level\":\"INFO\",\"customer_id\":1234,\"message\":\"test 1\"}\n  #=\u003e {...,\"level\":\"INFO\",\"message\":\"test 2\"}\n  ```\n  \n* `add_to_log_context(context)`: Adds the provided `context` to the current log context but provides no mechanism for\n  removing it later. Only use this method if you are sure that you're working within a specific log context and that it\n  will be cleaned up later (e.g. by only using this method in a block passed to the previously explained \n  `within_log_context` method).\n\nYou can access these methods either in the global scope by calling them via `Ezlog.within_log_context` and \n`Ezlog.add_to_log_context` or locally by including the `Ezlog::LogContextHelper` module into your class/module.\n\n### Provides testing support for RSpec\n\nEzlog comes with built-in support for testing your logging activity using [RSpec](https://rspec.info/).\nTo enable spec support for Ezlog, put this line in your `spec_helper.rb` or `rails_helper.rb`:\n\n```ruby\nrequire \"ezlog/rspec\"\n```\n\nWhat you get:\n* Helpers\n  * `log_output` provides access to the complete log output in your specs\n  * `log_output_is_expected` shorthand for writing expectations for the log output\n* Matchers\n  * `include_log_message` matcher for expecting a certain message in the log output\n  * `log` matcher for expecting an operation to log a certain message\n\n```ruby\n# Check that the log contains a certain message\nexpect(log_output).to include_log_message message: 'Test message'\nlog_output_is_expected.to include_log_message message: 'Test message'\n\n# Check that the message is not present in the logs before the operation but is present after it \nexpect { operation }.to log message: 'Test message', \n                            user_id: 123456 \n\n# Expect a certain log level\nlog_output_is_expected.to include_log_message(message: 'Test message').at_level(:info)\nexpect { operation }.to log(message: 'Test message').at_level(:info)\n```\n\n## Disclaimer\n\nEzlog is highly opinionated software and does in no way aim or claim to be useful for everyone. Use at your own discretion.\n\n## License\n\nThe gem is available as open source under the terms of the MIT License - see the [LICENSE](/LICENSE.txt) file for the full text.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femartech%2Fezlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femartech%2Fezlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femartech%2Fezlog/lists"}