{"id":16643400,"url":"https://github.com/sonots/rack-ltsv_logger","last_synced_at":"2025-03-16T22:31:33.540Z","repository":{"id":56890164,"uuid":"21420367","full_name":"sonots/rack-ltsv_logger","owner":"sonots","description":"A rack middleware to output access log in ltsv format","archived":false,"fork":false,"pushed_at":"2019-02-08T05:38:28.000Z","size":124,"stargazers_count":25,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-14T23:14:24.629Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/sonots.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":"2014-07-02T10:30:33.000Z","updated_at":"2020-06-20T12:01:55.000Z","dependencies_parsed_at":"2022-08-21T00:50:33.519Z","dependency_job_id":null,"html_url":"https://github.com/sonots/rack-ltsv_logger","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonots%2Frack-ltsv_logger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonots%2Frack-ltsv_logger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonots%2Frack-ltsv_logger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonots%2Frack-ltsv_logger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sonots","download_url":"https://codeload.github.com/sonots/rack-ltsv_logger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243830952,"owners_count":20354854,"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-10-12T08:08:23.753Z","updated_at":"2025-03-16T22:31:33.223Z","avatar_url":"https://github.com/sonots.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rack::LtsvLogger\n\nA rack middleware to output access log in ltsv format, like [rack/commonlogger](https://github.com/rack/rack/blob/master/lib/rack/commonlogger.rb) (which output access log in apache common format).\n\n## Why Rack Middleware\n\ncf. https://speakerdeck.com/mirakui/high-performance-rails-long-edition\n\n\u003cimg src=\"doc/x_runtime.png\" alt=\"x_runtime\" width=\"50%\" height=\"50%\"/\u003e\n\nThe Completed Time, which the default logger of rails shows,\ndoes not include the routing time, and the elapsed time on rack middleware layers.\nTo measure the processing time accurately,\nit is necessary to insert a rack middleware at the head of rack middleware stacks.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'rack-ltsv_logger'\n\nAnd then execute:\n\n    $ bundle\n\n## How to Use\n\nInsert Rack::LtsvLogger on the head of rack middlewares. \n\n### Rails\n\n```ruby\n# config/application.rb\nclass Application \u003c Rails::Application\n  config.middleware.insert_after(0, Rack::LtsvLogger, $stdout)\nend\n```\n\nMiddleware check.\n\n```\nbundle exec rake middleware\n```\n\n### Sinatra\n\n```ruby\n# config.ru\nrequire 'rack/ltsv_logger'\n\nuse Rack::LtsvLogger, $stdout\nrun App\n```\n\n## Format\n\nSample (line feeded, but actually tab seperated):\n\n```\ntime:2014-07-02T21:52:31+09:00\npid:15189\nhost:127.0.0.1\nforwardedfor:127.0.0.2\nuser:user\nmethod:GET\nuri:/get\nquery:?foo\nprotocol:HTTP/1.1\nstatus:200\nsize:-\nreqtime:0.000000\n```\n\n### Default Fields\n\n| key          | value                                                                          |\n|--------------|--------------------------------------------------------------------------------|\n| time         | The datetime in ISO-8601 format                                                |\n| pid          | Procedd ID                                                                     |\n| host         | ENV['REMOTE_ADDR']                                                             |\n| forwardedfor | ENV['X_FORWARDED_FOR']                                                         |\n| user         | ENV['REMOTE_USER']                                                             |\n| method       | ENV['REQUEST_METHOD']                                                          |\n| uri          | ENV['PATH_INFO']                                                               |\n| query        | ENV['QUERY_STRING']                                                            |\n| protocol     | ENV['HTTP_VERSION']                                                            |\n| status       | Response Status Code                                                           |\n| size         | Response Content-Length                                                        |\n| reqtime      | The request time in secods. milli seconds are written after the decimal point. |\n\n\n## Arguments\n\nArguments:\n\n* io\n  * An IO object, or something which has `#write` method\n* ~~appends (deprecated)~~\n  * ~~A Hash object to append custom fields. See [#custom-fields](#custom-fields)~~\n\nKeyword Arguments:\n\n* params\\_proc\n  * A Proc object to generate fields. See [#custom-fields](#custom-fields)\n\n### Log Rotation\n\nIf you utilize log rotation functionality of Ruby's standard logger, you may write as\n\n```ruby\nclass MyLogger \u003c ::Logger\n  def write(msg)\n    @logdev.write msg\n  end\nend\n\nlogger = MyLogger.new('/path/to/access.log', 3, 1048576)\nconfig.middleware.insert_after(0, Rack::LtsvLogger, logger)\n```\n\n### Custom Fields\n\nPass a proc object to customize fields as:\n\n```ruby\nparams_proc = Proc.new do |env, status, headers, body, began_at|\n  params = Rack::LtsvLogger::DEFAULT_PARAMS_PROC.call(env, status, headers, body, began_at)\n  params.delete(:protocol)\n  params.merge!(\n    vhost: env['HTTP_HOST'] || \"-\",\n    ua: env['HTTP_USER_AGENT'] || \"-\",\n    referer: env['HTTP_REFERER'] || \"-\",\n  )\nend\nconfig.middleware.insert_after(0, Rack::LtsvLogger, $stdout, params_proc: params_proc)\n```\n\nor\n\n```ruby\nparams_proc = Proc.new do |env, status, headers, body, began_at|\n  now = Time.now\n  reqtime = now.instance_eval { to_i + (usec/1000000.0) } - began_at\n  {\n    time: now.iso8601,\n    pid: Process.pid,\n    host: env[\"REMOTE_ADDR\"] || \"-\",\n    forwardedfor: env['HTTP_X_FORWARDED_FOR'] || \"-\",\n    user: env[\"REMOTE_USER\"] || \"-\",\n    method: env[\"REQUEST_METHOD\"],\n    uri: env[\"PATH_INFO\"],\n    query: env[\"QUERY_STRING\"].empty? ? \"\" : \"?\"+env[\"QUERY_STRING\"],\n    status: ::Rack::LtsvLogger.extract_status(status),\n    size: ::Rack::LtsvLogger.extract_content_length(headers),\n    reqtime: \"%0.6f\" % reqtime,\n    vhost: env['HTTP_HOST'] || \"-\",\n    ua: env['HTTP_USER_AGENT'] || \"-\",\n    referer: env['HTTP_REFERER'] || \"-\",\n  }\nend\nconfig.middleware.insert_after(0, Rack::LtsvLogger, $stdout, params_proc: params_proc)\n```\n\nI recommend to follow http://ltsv.org/ to add new key names.\n\n**Deprecated**\n\n```ruby\nappends = {\n  vhost: Proc.new {|env| env['HTTP_HOST'] || \"-\" },\n  ua: Proc.new {|env| env['HTTP_USER_AGENT'] || \"-\" },\n  referer: Proc.new {|env| env['HTTP_REFERER'] || \"-\" },\n}\nconfig.middleware.insert_after(0, Rack::LtsvLogger, $stdout, appends)\n```\n\n## ChangeLog\n\nSee [CHANGELOG.md](CHANGELOG.md) for details.\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new [Pull Request](../../pull/new/master)\n\n## Copyright\n\nSee [LICENSE.txt](LICENSE.txt) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonots%2Frack-ltsv_logger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsonots%2Frack-ltsv_logger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonots%2Frack-ltsv_logger/lists"}