{"id":13395038,"url":"https://github.com/roidrage/lograge","last_synced_at":"2025-05-12T05:20:00.762Z","repository":{"id":2685273,"uuid":"3677872","full_name":"roidrage/lograge","owner":"roidrage","description":"An attempt to tame Rails' default policy to log everything.","archived":false,"fork":false,"pushed_at":"2024-11-10T20:02:22.000Z","size":378,"stargazers_count":3501,"open_issues_count":69,"forks_count":300,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-04-30T20:53:23.416Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://www.paperplanes.de/2012/3/14/on-notifications-logsubscribers-and-bringing-sanity-to-rails-logging.html","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"liuguangqiang/shuba","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/roidrage.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"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":["iloveitaly"]}},"created_at":"2012-03-10T06:24:57.000Z","updated_at":"2025-04-28T15:09:51.000Z","dependencies_parsed_at":"2023-07-06T16:32:08.671Z","dependency_job_id":"574776a3-bdbb-41f8-9469-fef4a51d5221","html_url":"https://github.com/roidrage/lograge","commit_stats":{"total_commits":363,"total_committers":89,"mean_commits":4.078651685393258,"dds":0.7603305785123967,"last_synced_commit":"27066cd75d449cb91ed79b18c4271d62a76c9839"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roidrage%2Flograge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roidrage%2Flograge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roidrage%2Flograge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roidrage%2Flograge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roidrage","download_url":"https://codeload.github.com/roidrage/lograge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251840276,"owners_count":21652312,"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-07-30T17:01:40.022Z","updated_at":"2025-05-09T00:36:20.944Z","avatar_url":"https://github.com/roidrage.png","language":"Ruby","readme":"[![CI](https://github.com/roidrage/lograge/actions/workflows/ci.yml/badge.svg)](https://github.com/roidrage/lograge/actions/workflows/ci.yml)\n[![Gem Version](https://badge.fury.io/rb/lograge.svg)](http://badge.fury.io/rb/lograge)\n\n# Lograge - Taming Rails' Default Request Logging #\n\nLograge is an attempt to bring sanity to Rails' noisy and unusable, unparsable\nand, in the context of running multiple processes and servers, unreadable\ndefault logging output. Rails' default approach to log everything is great\nduring development, it's terrible when running it in production. It pretty much\nrenders Rails logs useless to me.\n\nLograge is a work in progress. I appreciate constructive feedback and criticism.\nMy main goal is to improve Rails' logging and to show people that they don't\nneed to stick with its defaults anymore if they don't want to.\n\nInstead of trying solving the problem of having multiple lines per request by\nswitching Rails' logger for something that outputs syslog lines or adds a\nrequest token, Lograge replaces Rails' request logging entirely, reducing the\noutput per request to a single line with all the important information, removing\nall that clutter Rails likes to include and that gets mingled up so nicely when\nmultiple processes dump their output into a single file.\n\nInstead of having an unparsable amount of logging output like this:\n\n```\nStarted GET \"/\" for 127.0.0.1 at 2012-03-10 14:28:14 +0100\nProcessing by HomeController#index as HTML\n  Rendered text template within layouts/application (0.0ms)\n  Rendered layouts/_assets.html.erb (2.0ms)\n  Rendered layouts/_top.html.erb (2.6ms)\n  Rendered layouts/_about.html.erb (0.3ms)\n  Rendered layouts/_google_analytics.html.erb (0.4ms)\nCompleted 200 OK in 79ms (Views: 78.8ms | ActiveRecord: 0.0ms)\n```\n\nyou get a single line with all the important information, like this:\n\n```\nmethod=GET path=/ format=json controller=HomeController action=index status=200 duration=79.0 view=78.8 db=0.0\n```\n\nThe second line is easy to grasp with a single glance and still includes all the\nrelevant information as simple key-value pairs. The syntax is heavily inspired\nby the log output of the Heroku router. It doesn't include any timestamp by\ndefault, instead it assumes you use a proper log formatter instead.\n\n## Supported Ruby and Rails Releases ##\n\nLograge is actively tested against current and officially supported Ruby and\nRails releases. That said, Lograge _should_ work with older releases.\n\n- [Rails](https://endoflife.date/rails): Edge, 7.1, 7.0, 6.1, 6.0, 5.2\n- Rubies:\n  - [MRI](https://endoflife.date/ruby): HEAD, 3.3, 3.2 3.1, 3.0, 2.7, 2.6\n  - JRuby: HEAD, 9.2, 9.1\n  - TruffleRuby: HEAD, 21.3\n\n## Installation ##\n\nIn your Gemfile\n\n```ruby\ngem \"lograge\"\n```\n\nEnable it in an initializer or the relevant environment config:\n\n```ruby\n# config/initializers/lograge.rb\n# OR\n# config/environments/production.rb\nRails.application.configure do\n  config.lograge.enabled = true\nend\n```\n\nIf you're using Rails 5's API-only mode and inherit from\n`ActionController::API`, you must define it as the controller base class which\nlograge will patch:\n\n```ruby\n# config/initializers/lograge.rb\nRails.application.configure do\n  config.lograge.base_controller_class = 'ActionController::API'\nend\n```\n\nIf you use multiple base controller classes in your application, specify an array:\n\n```ruby\n# config/initializers/lograge.rb\nRails.application.configure do\n  config.lograge.base_controller_class = ['ActionController::API', 'ActionController::Base']\nend\n```\n\nYou can also add a hook for own custom data\n\n```ruby\n# config/environments/staging.rb\nRails.application.configure do\n  config.lograge.enabled = true\n\n  # custom_options can be a lambda or hash\n  # if it's a lambda then it must return a hash\n  config.lograge.custom_options = lambda do |event|\n    # capture some specific timing values you are interested in\n    {:name =\u003e \"value\", :timing =\u003e some_float.round(2), :host =\u003e event.payload[:host]}\n  end\nend\n```\n\nOr you can add a timestamp:\n\n```ruby\nRails.application.configure do\n  config.lograge.enabled = true\n\n  # add time to lograge\n  config.lograge.custom_options = lambda do |event|\n    { time: Time.now }\n  end\nend\n```\n\nYou can also keep the original (and verbose) Rails logger by following this configuration:\n\n```ruby\nRails.application.configure do\n  config.lograge.keep_original_rails_log = true\n\n  config.lograge.logger = ActiveSupport::Logger.new \"#{Rails.root}/log/lograge_#{Rails.env}.log\"\nend\n```\n\nYou can then add custom variables to the event to be used in `custom_options` (available via the `event.payload` hash, which has to be processed in `custom_options` method to be included in log output, see above):\n\n```ruby\n# app/controllers/application_controller.rb\nclass ApplicationController \u003c ActionController::Base\n  def append_info_to_payload(payload)\n    super\n    payload[:host] = request.host\n  end\nend\n```\n\nAlternatively, you can add a hook for accessing controller methods directly (e.g. `request` and `current_user`).\nThis hash is merged into the log data automatically.\n\n```ruby\nRails.application.configure do\n  config.lograge.enabled = true\n\n  config.lograge.custom_payload do |controller|\n    {\n      host: controller.request.host,\n      user_id: controller.current_user.try(:id)\n    }\n  end\nend\n```\n\nTo further clean up your logging, you can also tell Lograge to skip log messages\nmeeting given criteria.  You can skip log messages generated from certain controller\nactions, or you can write a custom handler to skip messages based on data in the log event:\n\n```ruby\n# config/environments/production.rb\nRails.application.configure do\n  config.lograge.enabled = true\n\n  config.lograge.ignore_actions = ['HomeController#index', 'AController#an_action']\n  config.lograge.ignore_custom = lambda do |event|\n    # return true here if you want to ignore based on the event\n  end\nend\n```\n\nLograge supports multiple output formats. The most common is the default\nlograge key-value format described above. Alternatively, you can also generate\nJSON logs in the json_event format used by [Logstash](http://logstash.net/).\n\n```ruby\n# config/environments/production.rb\nRails.application.configure do\n  config.lograge.formatter = Lograge::Formatters::Logstash.new\nend\n```\n\n*Note:* When using the logstash output, you need to add the additional gem\n`logstash-event`. You can simply add it to your Gemfile like this\n\n```ruby\ngem \"logstash-event\"\n```\n\nDone.\n\nThe available formatters are:\n\n```ruby\n  Lograge::Formatters::Lines.new\n  Lograge::Formatters::Cee.new\n  Lograge::Formatters::Graylog2.new\n  Lograge::Formatters::KeyValue.new  # default lograge format\n  Lograge::Formatters::KeyValueDeep.new\n  Lograge::Formatters::Json.new\n  Lograge::Formatters::Logstash.new\n  Lograge::Formatters::LTSV.new\n  Lograge::Formatters::Raw.new       # Returns a ruby hash object\n```\n\nIn addition to the formatters, you can manipulate the data yourself by passing\nan object which responds to #call:\n\n```ruby\n# config/environments/production.rb\nRails.application.configure do\n  config.lograge.formatter = -\u003e(data) { \"Called #{data[:controller]}\" } # data is a ruby hash\nend\n```\n\n## Internals ##\n\nThanks to the notification system that was introduced in Rails 3, replacing the\nlogging is easy. Lograge unhooks all subscriptions from\n`ActionController::LogSubscriber` and `ActionView::LogSubscriber`, and hooks in\nits own log subscription, but only listening for two events: `process_action`\nand `redirect_to` (in case of standard controller logs).\nIt makes sure that only subscriptions from those two classes\nare removed. If you happened to hook in your own, they'll be safe.\n\nUnfortunately, when a redirect is triggered by your application's code,\nActionController fires two events. One for the redirect itself, and another one\nwhen the request is finished. Unfortunately, the final event doesn't include the\nredirect, so Lograge stores the redirect URL as a thread-local attribute and\nrefers to it in `process_action`.\n\nThe event itself contains most of the relevant information to build up the log\nline, including view processing and database access times.\n\nWhile the LogSubscribers encapsulate most logging pretty nicely, there are still\ntwo lines that show up no matter what. The first line that's output for every\nRails request, you know, this one:\n\n```\nStarted GET \"/\" for 127.0.0.1 at 2012-03-12 17:10:10 +0100\n```\n\nAnd the verbose output coming from rack-cache:\n\n```\ncache: [GET /] miss\n```\n\nBoth are independent of the LogSubscribers, and both need to be shut up using\ndifferent means.\n\nFor the first one, the starting line of every Rails request log, Lograge\nreplaces code in `Rails::Rack::Logger` to remove that particular log line. It's\nnot great, but it's just another unnecessary output and would still clutter the\nlog files. Maybe a future version of Rails will make this log line an event as\nwell.\n\nTo remove rack-cache's output (which is only enabled if caching in Rails is\nenabled), Lograge disables verbosity for rack-cache, which is unfortunately\nenabled by default.\n\nThere, a single line per request. Beautiful.\n\n## Action Cable ##\n\nStarting with version 0.11.0, Lograge introduced support for Action Cable logs.\nThis proved to be a particular challenge since the framework code is littered\nwith multiple (and seemingly random) logger calls in a number of internal classes.\nIn order to deal with it, the default Action Cable logger was silenced.\nAs a consequence, calling logger e.g. in user-defined `Connection` or `Channel`\nclasses has no effect - `Rails.logger` (or any other logger instance)\nhas to be used instead.\n\nAdditionally, while standard controller logs rely on `process_action` and `redirect_to`\ninstrumentations only, Action Cable messages are generated from multiple events:\n`perform_action`, `subscribe`, `unsubscribe`, `connect`, and `disconnect`.\n`perform_action` is the only one included in the actual Action Cable code and\nothers have been added by monkey patching [`ActionCable::Channel::Base`](https://github.com/roidrage/lograge/blob/master/lib/lograge/rails_ext/action_cable/channel/base.rb) and\n[`ActionCable::Connection::Base`](https://github.com/roidrage/lograge/blob/master/lib/lograge/rails_ext/action_cable/connection/base.rb) classes.\n\n## What it doesn't do ##\n\nLograge is opinionated, very opinionated. If the stuff below doesn't suit your\nneeds, it may not be for you.\n\nLograge removes ActionView logging, which also includes rendering times for\npartials. If you're into those, Lograge is probably not for you. In my honest\nopinion, those rendering times don't belong in the log file, they should be\ncollected in a system like New Relic, Librato Metrics or some other metrics\nservice that allows graphing rendering percentiles. I assume this for everything\nthat represents a moving target. That kind of data is better off being\nvisualized in graphs than dumped (and ignored) in a log file.\n\nLograge doesn't yet log the request parameters. This is something I'm actively\ncontemplating, mainly because I want to find a good way to include them, a way\nthat fits in with the general spirit of the log output generated by Lograge.\nIf you decide to include them be sure that sensitive data like passwords\nand credit cards are not stored via [filtered_parameters](https://api.rubyonrails.org/classes/ActionDispatch/Http/FilterParameters.html)\nor another means. The payload does already contain the params hash, so you can easily add\nit in manually using `custom_options`:\n\n```ruby\n# production.rb\nYourApp::Application.configure do\n  config.lograge.enabled = true\n  config.lograge.custom_options = lambda do |event|\n    exceptions = %w(controller action format id)\n    {\n      params: event.payload[:params].except(*exceptions)\n    }\n  end\nend\n```\n\n## FAQ ##\n\n### Logging errors / exceptions ###\n\nOur first recommendation is that you use exception tracking services built for\npurpose ;)\n\nIf you absolutely *must* log exceptions in the single-line format, you can\ndo something similar to this example:\n\n```ruby\n# config/environments/production.rb\n\nYourApp::Application.configure do\n  config.lograge.enabled = true\n  config.lograge.custom_options = lambda do |event|\n    {\n      exception: event.payload[:exception], # [\"ExceptionClass\", \"the message\"]\n      exception_object: event.payload[:exception_object] # the exception instance\n    }\n  end\nend\n```\n\nThe `:exception` is just the basic class and message whereas the\n`:exception_object` is the actual exception instance. You can use both /\neither. Be mindful when including this, you will probably want to cherry-pick\nparticular attributes and almost definitely want to `join` the `backtrace` into\nsomething without newline characters.\n\n### Handle ActionController::RoutingError ###\n\nAdd a ` get '*unmatched_route', to: 'application#route_not_found'` rule to the end of your `routes.rb`\nThen add a new controller action in your `application_controller.rb`.\n\n```ruby\ndef route_not_found\n  render 'error_pages/404', status: :not_found\nend\n```\n\n[#146](https://github.com/roidrage/lograge/issues/146)\n\n## Alternative \u0026 Related Projects\n\n* [`rails_semantic_logger` is a similar project with different functionality](https://logger.rocketjob.io/rails).\n* [`simple_structured_logger`](https://github.com/iloveitaly/simple_structured_logger) adds structured logging to the rest of your application\n\n## Contributing ##\n\nSee the CONTRIBUTING.md file for further information.\n\n## License ##\n\nMIT. Code extracted from [Travis CI](http://travis-ci.org).\n\n(c) Mathias Meyer\n\nSee `LICENSE.txt` for details.\n","funding_links":["https://github.com/sponsors/iloveitaly"],"categories":["Logging","Maintenance \u0026 Monitoring","Ruby","日志","Gems"],"sub_categories":["Omniauth","Logging","Articles"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froidrage%2Flograge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froidrage%2Flograge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froidrage%2Flograge/lists"}