{"id":13621630,"url":"https://github.com/tkuchiki/alp","last_synced_at":"2025-10-24T18:42:25.832Z","repository":{"id":37431833,"uuid":"43059568","full_name":"tkuchiki/alp","owner":"tkuchiki","description":"Access Log Profiler","archived":false,"fork":false,"pushed_at":"2024-04-19T12:18:41.000Z","size":635,"stargazers_count":691,"open_issues_count":4,"forks_count":33,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-19T16:26:20.854Z","etag":null,"topics":["access-logs","golang","json","ltsv","profiler","regexp"],"latest_commit_sha":null,"homepage":null,"language":"Go","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/tkuchiki.png","metadata":{"files":{"readme":"README.ja.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","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},"funding":{"github":"tkuchiki"}},"created_at":"2015-09-24T10:10:02.000Z","updated_at":"2025-04-02T15:46:14.000Z","dependencies_parsed_at":"2023-09-24T17:36:44.859Z","dependency_job_id":"c9cb6a75-9d7f-4eb9-acf4-e812509d4e37","html_url":"https://github.com/tkuchiki/alp","commit_stats":{"total_commits":180,"total_committers":14,"mean_commits":"12.857142857142858","dds":"0.16666666666666663","last_synced_commit":"888c51d05cdb3f4efcd61db73060d5eeb85fe71d"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tkuchiki%2Falp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tkuchiki%2Falp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tkuchiki%2Falp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tkuchiki%2Falp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tkuchiki","download_url":"https://codeload.github.com/tkuchiki/alp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"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":["access-logs","golang","json","ltsv","profiler","regexp"],"created_at":"2024-08-01T21:01:08.839Z","updated_at":"2025-10-24T18:42:20.769Z","avatar_url":"https://github.com/tkuchiki.png","language":"Go","funding_links":["https://github.com/sponsors/tkuchiki"],"categories":["Go"],"sub_categories":[],"readme":"# alp\n\n![Test](https://github.com/tkuchiki/alp/workflows/Test/badge.svg?branch=master)\n\nalp はアクセスログ解析ツールです。\n読み方は、[éɪélpíː] または [ælp] です(作者は [éɪélpíː] 派)。\n\n# インストール\n\n### バイナリ配布\n\n[ここ](https://github.com/tkuchiki/alp/releases)から任意のOS向けのバイナリをダウンロードすることができ、次のようにしてインストールすることが可能です。\n\n```bash\nsudo install \u003cダウンロードしたファイル\u003e /usr/local/bin/alp\n```\n\n### ディストリビューションのパッケージシステムを使用\n\n#### macOS (Homebrew)\n\nHomebrewでalpをインストールします。\n\n- `brew install alp`\n\n### asdf\n\n[asdf](https://github.com/asdf-vm/asdf)と[asdf-alp](https://github.com/asdf-community/asdf-alp)でalpをインストールします。\n\n```bash\nasdf plugin-add alp https://github.com/asdf-community/asdf-alp.git\nasdf install alp \u003cバージョン\u003e\nasdf global alp \u003cバージョン\u003e\n```\n\n# v0.4.0 と v1.0.0 の違い\n\n[v0.4.0 と v1.0.0 の違い](./docs/the_difference_between_v0_4_0_and_v1_0_0.ja.md) を参照してください。\n\n# 使い方\n\n```console\n$ alp --help\nalp is the access log profiler for LTSV, JSON, Pcap, and others.\n\nUsage:\n  alp [flags]\n  alp [command]\n\nAvailable Commands:\n  completion  Generate the autocompletion script for the specified shell\n  count       Count by log entries\n  diff        Show the difference between the two profile results\n  help        Help about any command\n  json        Profile the logs for JSON\n  ltsv        Profile the logs for LTSV\n  pcap        Profile the HTTP requests for captured packets\n  regexp      Profile the logs that match a regular expression\n\nFlags:\n  -h, --help      help for alp\n  -v, --version   version for alp\n\nUse \"alp [command] --help\" for more information about a command.\n\n$ alp ltsv --help\nProfile the logs for LTSV\n\nUsage:\n  alp ltsv [flags]\n\nFlags:\n      --apptime-label string     Change the apptime label (default \"apptime\")\n      --config string            The configuration file\n      --decode-uri               Decode the URI\n      --dump string              Dump profiled data as YAML\n      --file string              The slowlog file\n  -f, --filters string           Only the logs are profiled that match the conditions\n      --format string            The output format (table, markdown, tsv, csv and html) (default \"table\")\n  -h, --help                     help for ltsv\n      --limit int                The maximum number of results to display (default 5000)\n      --load string              Load the profiled YAML data\n      --location string          Location name for the timezone (default \"Local\")\n  -m, --matching-groups string   Specifies Query matching groups separated by commas\n      --method-label string      Change the method label (default \"method\")\n      --noheaders                Output no header line at all (only --format=tsv, csv)\n      --nosave-pos               Do not save position file\n  -o, --output string            Specifies the results to display, separated by commas (default \"all\")\n      --page int                 Number of pages of pagination (default 100)\n      --percentiles string       Specifies the percentiles separated by commas\n      --pos string               The position file\n      --qs-ignore-values         Ignore the value of the query string. Replace all values with xxx (only use with -q)\n  -q, --query-string             Include the URI query string\n      --reqtime-label string     Change the reqtime label (default \"reqtime\")\n  -r, --reverse                  Sort results in reverse order\n      --show-footers             Output footer line at all (only --format=table, markdown)\n      --size-label string        Change the size label (default \"size\")\n      --sort string              Output the results in sorted order (default \"count\")\n      --status-label string      Change the status label (default \"status\")\n      --time-label string        Change the time label (default \"time\")\n      --uri-label string         Change the uri label (default \"uri\")\n      \n$ alp json --help\nProfile the logs for JSON\n\nUsage:\n  alp json [flags]\n\nFlags:\n      --body-bytes-key string    Change the body_bytes key (default \"body_bytes\")\n      --config string            The configuration file\n      --decode-uri               Decode the URI\n      --dump string              Dump profiled data as YAML\n      --file string              The slowlog file\n  -f, --filters string           Only the logs are profiled that match the conditions\n      --format string            The output format (table, markdown, tsv, csv and html) (default \"table\")\n  -h, --help                     help for json\n      --limit int                The maximum number of results to display (default 5000)\n      --load string              Load the profiled YAML data\n      --location string          Location name for the timezone (default \"Local\")\n  -m, --matching-groups string   Specifies Query matching groups separated by commas\n      --method-key string        Change the method key (default \"method\")\n      --noheaders                Output no header line at all (only --format=tsv, csv)\n      --nosave-pos               Do not save position file\n  -o, --output string            Specifies the results to display, separated by commas (default \"all\")\n      --page int                 Number of pages of pagination (default 100)\n      --percentiles string       Specifies the percentiles separated by commas\n      --pos string               The position file\n      --qs-ignore-values         Ignore the value of the query string. Replace all values with xxx (only use with -q)\n  -q, --query-string             Include the URI query string\n      --reqtime-key string       Change the request_time key (default \"request_time\")\n      --restime-key string       Change the response_time key (default \"response_time\")\n  -r, --reverse                  Sort results in reverse order\n      --show-footers             Output footer line at all (only --format=table, markdown)\n      --sort string              Output the results in sorted order (default \"count\")\n      --status-key string        Change the status key (default \"status\")\n      --time-key string          Change the time key (default \"time\")\n      --uri-key string           Change the uri key (default \"uri\")\n\n$ alp regexp --help\nProfile the logs that match a regular expression\n\nUsage:\n  alp regexp [flags]\n\nFlags:\n      --body-bytes-subexp string   Change the body_bytes sub expression (default \"body_bytes\")\n      --config string              The configuration file\n      --decode-uri                 Decode the URI\n      --dump string                Dump profiled data as YAML\n      --file string                The slowlog file\n  -f, --filters string             Only the logs are profiled that match the conditions\n      --format string              The output format (table, markdown, tsv, csv and html) (default \"table\")\n  -h, --help                       help for regexp\n      --limit int                  The maximum number of results to display (default 5000)\n      --load string                Load the profiled YAML data\n      --location string            Location name for the timezone (default \"Local\")\n  -m, --matching-groups string     Specifies Query matching groups separated by commas\n      --method-subexp string       Change the method sub expression (default \"method\")\n      --noheaders                  Output no header line at all (only --format=tsv, csv)\n      --nosave-pos                 Do not save position file\n  -o, --output string              Specifies the results to display, separated by commas (default \"all\")\n      --page int                   Number of pages of pagination (default 100)\n      --pattern string             Regular expressions pattern matching the log (default \"^(\\\\S+)\\\\s\\\\S+\\\\s+(\\\\S+\\\\s+)+\\\\[(?P\u003ctime\u003e[^]]+)\\\\]\\\\s\\\"(?P\u003cmethod\u003e\\\\S*)\\\\s?(?P\u003curi\u003e(?:[^\\\"]*(?:\\\\\\\\\\\")?)*)\\\\s([^\\\"]*)\\\"\\\\s(?P\u003cstatus\u003e\\\\S+)\\\\s(?P\u003cbody_bytes\u003e\\\\S+)\\\\s\\\"((?:[^\\\"]*(?:\\\\\\\\\\\")?)*)\\\"\\\\s\\\"(?:.+)\\\"\\\\s(?P\u003cresponse_time\u003e\\\\S+)(?:\\\\s(?P\u003crequest_time\u003e\\\\S+))?$\")\n      --percentiles string         Specifies the percentiles separated by commas\n      --pos string                 The position file\n      --qs-ignore-values           Ignore the value of the query string. Replace all values with xxx (only use with -q)\n  -q, --query-string               Include the URI query string\n      --reqtime-subexp string      Change the request_time sub expression (default \"request_time\")\n      --restime-subexp string      Change the response_time sub expression (default \"response_time\")\n  -r, --reverse                    Sort results in reverse order\n      --show-footers               Output footer line at all (only --format=table, markdown)\n      --sort string                Output the results in sorted order (default \"count\")\n      --status-subexp string       Change the status sub expression (default \"status\")\n      --time-subexp string         Change the time sub expression (default \"time\")\n      --uri-subexp string          Change the uri sub expression (default \"uri\")\n      \n$ alp pcap --help\nProfile the HTTP requests for captured packets\n\nUsage:\n  alp pcap [flags]\n\nFlags:\n      --config string             The configuration file\n      --decode-uri                Decode the URI\n      --dump string               Dump profiled data as YAML\n      --file string               The slowlog file\n  -f, --filters string            Only the logs are profiled that match the conditions\n      --format string             The output format (table, markdown, tsv, csv and html) (default \"table\")\n  -h, --help                      help for pcap\n      --limit int                 The maximum number of results to display (default 5000)\n      --load string               Load the profiled YAML data\n      --location string           Location name for the timezone (default \"Local\")\n  -m, --matching-groups string    Specifies Query matching groups separated by commas\n      --noheaders                 Output no header line at all (only --format=tsv, csv)\n      --nosave-pos                Do not save position file\n  -o, --output string             Specifies the results to display, separated by commas (default \"all\")\n      --page int                  Number of pages of pagination (default 100)\n      --pcap-server-ip strings    HTTP server IP address of the captured packets (default [127.0.0.1])\n      --pcap-server-port uint16   HTTP server TCP port of the captured packets (default 80)\n      --percentiles string        Specifies the percentiles separated by commas\n      --pos string                The position file\n      --qs-ignore-values          Ignore the value of the query string. Replace all values with xxx (only use with -q)\n  -q, --query-string              Include the URI query string\n  -r, --reverse                   Sort results in reverse order\n      --show-footers              Output footer line at all (only --format=table, markdown)\n      --sort string               Output the results in sorted order (default \"count\")\n\n$ alp diff --help\nShow the difference between the two profile results\n\nUsage:\n  alp diff \u003cfrom\u003e \u003cto\u003e [flags]\n\nFlags:\n      --from string   The comparison source file\n  -h, --help          help for diff\n      --to string     The comparison target file\n\n$ alp count --help\nCount by log entries\n\nUsage:\n  alp count [flags]\n\nFlags:\n      --file string      The access log file\n      --format string    Log format (json,ltsv,regexp) (default \"json\")\n  -h, --help             help for count\n      --keys string      Log key names (comma separated)\n      --pattern string   Regular expressions pattern matching the log. (only use with --format=regexp) (default \"^(\\\\S+)\\\\s\\\\S+\\\\s+(\\\\S+\\\\s+)+\\\\[(?P\u003ctime\u003e[^]]+)\\\\]\\\\s\\\"(?P\u003cmethod\u003e\\\\S*)\\\\s?(?P\u003curi\u003e(?:[^\\\"]*(?:\\\\\\\\\\\")?)*)\\\\s([^\\\"]*)\\\"\\\\s(?P\u003cstatus\u003e\\\\S+)\\\\s(?P\u003cbody_bytes\u003e\\\\S+)\\\\s\\\"((?:[^\\\"]*(?:\\\\\\\\\\\")?)*)\\\"\\\\s\\\"(?:.+)\\\"\\\\s(?P\u003cresponse_time\u003e\\\\S+)(?:\\\\s(?P\u003crequest_time\u003e\\\\S+))?$\")\n  -r, --reverse          Sort results in reverse order\n```\n\n- alp は ltsv, json, regexp, pcap, diff の5つのサブコマンドで構成されています\n- `cat /path/to/log | alp` のようにパイプでデータを送るか、後述する `-f, --file` オプションでファイルを指定して解析します\n\n## ltsv\n\n- [LTSV](http://ltsv.org/) 形式のログを解析します\n- デフォルトでは以下のラベルを抽出します\n    - `time`\n        - ログ時刻\n    - `method`\n        - HTTP Method\n    - `uri`\n        - URI\n    - `status`\n        - HTTP Status Code\n    - `apptime`\n        - Upstream server からのレスポンスタイム\n    - `reqtime`\n        - リクエスト処理時間(リクエストを受けてからレスポンスを返すまでの時間)\n- `--xxx-label` オプションで、任意のラベル名に変更することができます \n\n```console\n$ cat example/logs/ltsv_access.log\ntime:2015-09-06T05:58:05+09:00  method:POST     uri:/foo/bar?token=xxx\u0026uuid=1234        status:200      size:12 apptime:0.057\ntime:2015-09-06T05:58:41+09:00  method:POST     uri:/foo/bar?token=yyy  status:200      size:34 apptime:0.100\ntime:2015-09-06T06:00:42+09:00  method:GET      uri:/foo/bar?token=zzz  status:200      size:56 apptime:0.123\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/foo/bar    status:400      size:15 apptime:-\ntime:2015-09-06T05:58:44+09:00  method:POST     uri:/foo/bar?token=yyy  status:200      size:34 apptime:0.234\ntime:2015-09-06T05:58:44+09:00  method:POST     uri:/hoge/piyo?id=yyy   status:200      size:34 apptime:0.234\ntime:2015-09-06T05:58:05+09:00  method:POST     uri:/foo/bar?token=xxx\u0026uuid=1234        status:200      size:12 apptime:0.057\ntime:2015-09-06T05:58:41+09:00  method:POST     uri:/foo/bar?token=yyy  status:200      size:34 apptime:0.100\ntime:2015-09-06T06:00:42+09:00  method:GET      uri:/foo/bar?token=zzz  status:200      size:56 apptime:0.123\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/foo/bar    status:400      size:15 apptime:-\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/diary/entry/1234   status:200      size:15 apptime:0.135\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/diary/entry/5678   status:200      size:30 apptime:0.432\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/foo/bar/5xx        status:504      size:15 apptime:60.000\ntime:2015-09-06T06:00:43+09:00  method:GET      uri:/req        status:200      size:15 apptime:-       reqtime:0.321\n\n$ cat example/logs/ltsv_access.log | alp ltsv\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |        URI        |  MIN   |  MAX   |  SUM   |  AVG   |  P90   |  P95   |  P99   | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /req              |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | POST   | /hoge/piyo        |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.000 |    34.000 |    34.000 |    34.000 |    34.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/1234 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/5678 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.000 |    30.000 |    30.000 |    30.000 |    30.000 |\n|     1 |   0 |   0 |   0 |   0 |   1 | GET    | /foo/bar/5xx      | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     2 |   0 |   2 |   0 |   0 |   0 | GET    | /foo/bar          |  0.123 |  0.123 |  0.246 |  0.123 |  0.123 |  0.123 |  0.123 |  0.000 |    56.000 |    56.000 |   112.000 |    56.000 |\n|     5 |   0 |   5 |   0 |   0 |   0 | POST   | /foo/bar          |  0.057 |  0.234 |  0.548 |  0.110 |  0.234 |  0.234 |  0.234 |  0.065 |    12.000 |    34.000 |   126.000 |    25.200 |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n```\n\n### Log format \n\n#### Apache\n\n```\nLogFormat \"time:%t\\tforwardedfor:%{X-Forwarded-For}i\\thost:%h\\treq:%r\\tstatus:%\u003es\\tmethod:%m\\turi:%U%q\\tsize:%B\\treferer:%{Referer}i\\tua:%{User-Agent}i\\treqtime_microsec:%D\\tapptime:%D\\tcache:%{X-Cache}o\\truntime:%{X-Runtime}o\\tvhost:%{Host}i\" ltsv\n```\n\n#### Nginx\n\n```\nlog_format ltsv \"time:$time_local\"\n                \"\\thost:$remote_addr\"\n                \"\\tforwardedfor:$http_x_forwarded_for\"\n                \"\\treq:$request\"\n                \"\\tstatus:$status\"\n                \"\\tmethod:$request_method\"\n                \"\\turi:$request_uri\"\n                \"\\tsize:$body_bytes_sent\"\n                \"\\treferer:$http_referer\"\n                \"\\tua:$http_user_agent\"\n                \"\\treqtime:$request_time\"\n                \"\\tcache:$upstream_http_x_cache\"\n                \"\\truntime:$upstream_http_x_runtime\"\n                \"\\tapptime:$upstream_response_time\"\n                \"\\tvhost:$host\";\n```\n\n#### H2O\n\n```\naccess-log:\n  format: \"time:%t\\thost:%h\\tua:\\\"%{User-agent}i\\\"\\tstatus:%s\\treq:%r\\turi:%U\\tapptime:%{duration}x\\tsize:%b\\tmethod:%m\"\n```\n\n## json\n\n- 1 行に 1 つの JSON が書かれているログを解析します\n- デフォルトでは以下のキーを抽出します\n    - `time`\n        - ログ時刻\n    - `method`\n        - HTTP Method\n    - `uri`\n        - URI\n    - `status`\n        - HTTP Status Code\n    - `response_time`\n        - Upstream server からのレスポンスタイム\n    - `request_time`\n        - リクエスト処理時間(リクエストを受けてからレスポンスを返すまでの時間)\n- `--xxx-key` オプションで、任意のキー名に変更することができます\n\n```console\n$ cat example/logs/json_access.log\n{\"time\":\"2015-09-06T05:58:05+09:00\",\"method\":\"POST\",\"uri\":\"/foo/bar?token=xxx\u0026uuid=1234\",\"status\":200,\"body_bytes\":12,\"response_time\":0.057}\n{\"time\":\"2015-09-06T05:58:41+09:00\",\"method\":\"POST\",\"uri\":\"/foo/bar?token=yyy\",\"status\":200,\"body_bytes\":34,\"response_time\":0.100}\n{\"time\":\"2015-09-06T06:00:42+09:00\",\"method\":\"GET\",\"uri\":\"/foo/bar?token=zzz\",\"status\":200,\"body_bytes\":56,\"response_time\":0.123}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/foo/bar\",\"status\":400,\"body_bytes\":15,\"response_time\":\"-\"}\n{\"time\":\"2015-09-06T05:58:44+09:00\",\"method\":\"POST\",\"uri\":\"/foo/bar?token=yyy\",\"status\":200,\"body_bytes\":34,\"response_time\":0.234}\n{\"time\":\"2015-09-06T05:58:44+09:00\",\"method\":\"POST\",\"uri\":\"/hoge/piyo?id=yyy\",\"status\":200,\"body_bytes\":34,\"response_time\":0.234}\n{\"time\":\"2015-09-06T05:58:05+09:00\",\"method\":\"POST\",\"uri\":\"/foo/bar?token=xxx\u0026uuid=1234\",\"status\":200,\"body_bytes\":12,\"response_time\":0.057}\n{\"time\":\"2015-09-06T05:58:41+09:00\",\"method\":\"POST\",\"uri\":\"/foo/bar?token=yyy\",\"status\":200,\"body_bytes\":34,\"response_time\":0.100}\n{\"time\":\"2015-09-06T06:00:42+09:00\",\"method\":\"GET\",\"uri\":\"/foo/bar?token=zzz\",\"status\":200,\"body_bytes\":56,\"response_time\":0.123}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/foo/bar\",\"status\":400,\"body_bytes\":15,\"response_time\":\"-\"}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/diary/entry/1234\",\"status\":200,\"body_bytes\":15,\"response_time\":0.135}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/diary/entry/5678\",\"status\":200,\"body_bytes\":30,\"response_time\":0.432}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/foo/bar/5xx\",\"status\":504,\"body_bytes\":15,\"response_time\":60.000}\n{\"time\":\"2015-09-06T06:00:43+09:00\",\"method\":\"GET\",\"uri\":\"/req\",\"status\":200,\"body_bytes\":15,\"response_time\":\"-\", \"request_time\":0.321}\n\n$ cat example/logs/json_access.log | alp json\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |        URI        |  MIN   |  MAX   |  SUM   |  AVG   |  P90   |  P95   |  P99   | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /req              |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | POST   | /hoge/piyo        |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.000 |    34.000 |    34.000 |    34.000 |    34.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/1234 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/5678 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.000 |    30.000 |    30.000 |    30.000 |    30.000 |\n|     1 |   0 |   0 |   0 |   0 |   1 | GET    | /foo/bar/5xx      | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     2 |   0 |   2 |   0 |   0 |   0 | GET    | /foo/bar          |  0.123 |  0.123 |  0.246 |  0.123 |  0.123 |  0.123 |  0.123 |  0.000 |    56.000 |    56.000 |   112.000 |    56.000 |\n|     5 |   0 |   5 |   0 |   0 |   0 | POST   | /foo/bar          |  0.057 |  0.234 |  0.548 |  0.110 |  0.234 |  0.234 |  0.234 |  0.065 |    12.000 |    34.000 |   126.000 |    25.200 |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n```\n\n### Log format \n\n#### Apache\n\n```\nLogFormat \"{\\\"time\\\":\\\"%t\\\",\\\"forwardedfor\\\":\\\"%{X-Forwarded-For}i\\\",\\\"host\\\":\\\"%h\\\",\\\"req\\\":\\\"%r\\\",\\\"status\\\":%\u003es,\\\"method\\\":\\\"%m\\\",\\\"uri\\\":\\\"%U%q\\\",\\\"body_bytes\\\":%B,\\\"referer\\\":\\\"%{Referer}i\\\",\\\"ua\\\":\\\"%{User-Agent}i\\\",\\\"reqtime_microsec\\\":%D,\\\"response_time\\\":%D,\\\"cache\\\":\\\"%{X-Cache}o\\\",\\\"runtime\\\":\\\"%{X-Runtime}o\\\",\\\"vhost\\\":\\\"%{Host}i\\\"}\" json\n```\n\n#### Nginx\n\n```\n    log_format json escape=json '{\"time\":\"$time_local\",'\n                                '\"host\":\"$remote_addr\",'\n                                '\"forwardedfor\":\"$http_x_forwarded_for\",'\n                                '\"req\":\"$request\",'\n                                '\"status\":\"$status\",'\n                                '\"method\":\"$request_method\",'\n                                '\"uri\":\"$request_uri\",'\n                                '\"body_bytes\":$body_bytes_sent,'\n                                '\"referer\":\"$http_referer\",'\n                                '\"ua\":\"$http_user_agent\",'\n                                '\"request_time\":$request_time,'\n                                '\"cache\":\"$upstream_http_x_cache\",'\n                                '\"runtime\":\"$upstream_http_x_runtime\",'\n                                '\"response_time\":\"$upstream_response_time\",'\n                                '\"vhost\":\"$host\"}';\n```\n\n#### H2O\n\n```\naccess-log:\n  escape: json\n  format: '{\"time\":\"%t\",\"host\":\"%h\",\"ua\":\"%{User-agent}i\",\"status\":%s,\"req\":\"%r\",\"uri\":\"%U\",\"response_time\":%{duration}x,\"body_bytes\":%b,\"method\":\"%m\"}'\n```\n\n## regexp\n\n- 正規表現にマッチするログを解析します\n- デフォルトでは Apache combined log + ` \"response time\"` のログを、以下の名前付きキャプチャで抽出します\n    - `time`\n        - ログ時刻\n    - `method`\n        - HTTP Method\n    - `uri`\n        - URI\n    - `status`\n        - HTTP Status Code\n    - `response_time`\n        - Upstream server からのレスポンスタイム\n    - `request_time`\n        - リクエスト処理時間(リクエストを受けてからレスポンスを返すまでの時間)\n- 以下の正規表現\n    ```regexp\n    ^(\\S+)\\s\\S+\\s+(\\S+\\s+)+\\[(?P\u003ctime\u003e[^]]+)\\]\\s\"(?P\u003cmethod\u003e\\S*)\\s?(?P\u003curi\u003e(?:[^\"]*(?:\\\\\")?)*)\\s([^\"]*)\"\\s(?P\u003cstatus\u003e\\S+)\\s(?P\u003cbody_bytes\u003e\\S+)\\s\"((?:[^\"]*(?:\\\\\")?)*)\"\\s\"(?:.+)\"\\s(?P\u003cresponse_time\u003e\\S+)(?:\\s(?P\u003crequest_time\u003e\\S+))?$\n    ```\n- `--xxx-subexp` オプションで、任意の名前付きキャプチャに変更することができます\n\n```console\n$ cat example/logs/combined_access.log\n127.0.0.1 - - [06/Sep/2015:05:58:05 +0900] \"POST /foo/bar?token=xxx\u0026uuid=1234 HTTP/1.1\" 200 12 \"-\" \"curl/7.54.0\" \"-\" 0.057\n127.0.0.1 - - [06/Sep/2015:05:58:41 +0900] \"POST /foo/bar?token=yyy HTTP/1.1\" 200 34 \"-\" \"curl/7.54.0\" \"-\" 0.100\n127.0.0.1 - - [06/Sep/2015:06:00:42 +0900] \"GET /foo/bar?token=zzz HTTP/1.1\" 200 56 \"-\" \"curl/7.54.0\" \"-\" 0.123\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /foo/bar HTTP/1.1\" 400 15 \"-\" \"curl/7.54.0\" \"-\" -\n127.0.0.1 - - [06/Sep/2015:05:58:44 +0900] \"POST /foo/bar?token=yyy HTTP/1.1\" 200 34 \"-\" \"curl/7.54.0\" \"-\" 0.234\n127.0.0.1 - - [06/Sep/2015:05:58:44 +0900] \"POST /hoge/piyo?id=yyy HTTP/1.1\" 200 34 \"-\" \"curl/7.54.0\" \"-\" 0.234\n127.0.0.1 - - [06/Sep/2015:05:58:05 +0900] \"POST /foo/bar?token=xxx\u0026uuid=1234 HTTP/1.1\" 200 12 \"-\" \"curl/7.54.0\" \"-\" 0.057\n127.0.0.1 - - [06/Sep/2015:05:58:41 +0900] \"POST /foo/bar?token=yyy HTTP/1.1\" 200 34 \"-\" \"curl/7.54.0\" \"-\" 0.100\n127.0.0.1 - - [06/Sep/2015:06:00:42 +0900] \"GET /foo/bar?token=zzz HTTP/1.1\" 200 56 \"-\" \"curl/7.54.0\" \"-\" 0.123\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /foo/bar HTTP/1.1\" 400 15 \"-\" \"curl/7.54.0\" \"-\" -\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /diary/entry/1234 HTTP/1.1\" 200 15 \"-\" \"curl/7.54.0\" \"-\" 0.135\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /diary/entry/5678 HTTP/1.1\" 200 30 \"-\" \"curl/7.54.0\" \"-\" 0.432\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /foo/bar/5xx HTTP/1.1\" 504 15 \"-\" \"curl/7.54.0\" \"-\" 60.000\n127.0.0.1 - - [06/Sep/2015:06:00:43 +0900] \"GET /req HTTP/1.1\" 200 15 \"-\" \"curl/7.54.0\" \"-\" - 0.321\n\n$ cat example/logs/combined_access.log | alp regexp\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |        URI        |  MIN   |  MAX   |  SUM   |  AVG   |  P90   |  P95   |  P99   | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /req              |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | POST   | /hoge/piyo        |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.000 |    34.000 |    34.000 |    34.000 |    34.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/1234 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/5678 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.000 |    30.000 |    30.000 |    30.000 |    30.000 |\n|     1 |   0 |   0 |   0 |   0 |   1 | GET    | /foo/bar/5xx      | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     2 |   0 |   2 |   0 |   0 |   0 | GET    | /foo/bar          |  0.123 |  0.123 |  0.246 |  0.123 |  0.123 |  0.123 |  0.123 |  0.000 |    56.000 |    56.000 |   112.000 |    56.000 |\n|     5 |   0 |   5 |   0 |   0 |   0 | POST   | /foo/bar          |  0.057 |  0.234 |  0.548 |  0.110 |  0.234 |  0.234 |  0.234 |  0.065 |    12.000 |    34.000 |   126.000 |    25.200 |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n```\n\n### Log format\n\n#### Apache\n\n```\nLogFormat \"%h %l %u %t \\\"%r\\\" %\u003es %b \\\"%{Referer}i\\\" \\\"%{User-agent}i\\\" %D\" combined_plus\n```\n\n#### Nginx\n\n```\n    log_format combined_plus '$remote_addr - $remote_user [$time_local] '\n                             '\"$request\" $status $body_bytes_sent '\n                             '\"$http_referer\" \"$http_user_agent\" $upstream_response_time $request_time';\n```\n\n#### H2O\n\n```\naccess-log:\n  format: \"%h %l %u %t \\\"%r\\\" %s %b \\\"%{Referer}i\\\" \\\"%{User-agent}i\\\" %{duration}x\"\n```\n\n## pcap\n\n- pcap形式のファイルから生のHTTPのプロトコルとそのパケットのタイムスタンプをもとにその統計を分析します\n  - パケットのタイムスタンプの差をレスポンスタイムを見なすために、実態と誤差が出る場合がある点に注意してください\n  - サーバーへのリクエスト/レスポンスを区別するためにサーバーのIPアドレスとTCPポート番号が必要です\n- `--pcap-server-ip` オプションでサーバーのIPアドレスを指定できます\n  - このオプションは複数個指定することができます\n  - デフォルトではローカルのネットワークインターフェースから自動で抽出します\n  - ただし、ネットワークインターフェース情報の取得権限が制限されている環境下では `127.0.0.1` と `::1` がデフォルトになります\n- `--pcap-server-port` オプションでサーバーのTCPポート番号を指定できます\n  - デフォルトでは80になっています\n- `--pos` オプションとの併用はできません\n\n```console\n$ sudo tcpdump -i lo port 5000 -s0 -w http.cap -Z $USER\ntcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes\n10000 packets captured\n20000 packets received by filter\n0 packets dropped by kernel\n\n$ alp pcap --file=http.cap --pcap-server-port=5000\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |        URI        |  MIN   |  MAX   |  SUM   |  AVG   |  P90   |  P95   |  P99   | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /req              |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.321 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | POST   | /hoge/piyo        |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.234 |  0.000 |    34.000 |    34.000 |    34.000 |    34.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/1234 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.135 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/5678 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.432 |  0.000 |    30.000 |    30.000 |    30.000 |    30.000 |\n|     1 |   0 |   0 |   0 |   0 |   1 | GET    | /foo/bar/5xx      | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 | 60.000 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     2 |   0 |   2 |   0 |   0 |   0 | GET    | /foo/bar          |  0.123 |  0.123 |  0.246 |  0.123 |  0.123 |  0.123 |  0.123 |  0.000 |    56.000 |    56.000 |   112.000 |    56.000 |\n|     5 |   0 |   5 |   0 |   0 |   0 | POST   | /foo/bar          |  0.057 |  0.234 |  0.548 |  0.110 |  0.234 |  0.234 |  0.234 |  0.065 |    12.000 |    34.000 |   126.000 |    25.200 |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+--------+--------+--------+--------+--------+--------+--------+--------+-----------+-----------+-----------+-----------+\n```\n\n## diff\n\n- 2つの解析結果のダンプファイルを比較します\n- `+` はリクエスト数とボディサイズの増加、レスポンスタイムが遅くなったことを意味します\n- `-` はリクエスト数とボディサイズの減少、レスポンスタイムが速くなったことを意味します\n\n```console\n$ cat /path/to/access.log | alp json --dump dumpfile1.yaml\n\n$ cat /path/to/access.log | alp json --dump dumpfile2.yaml\n\n$ alp diff dumpfile1.yaml dumpfile2.yaml -o count,2xx,method,uri,min,max,sum,avg,p90 --show-footers\n+---------+---------+--------+-------------------+-----------------+-----------------+-----------------+-----------------+-----------------+\n|  COUNT  |   2XX   | METHOD |        URI        |       MIN       |       MAX       |       SUM       |       AVG       |       P90       |\n+---------+---------+--------+-------------------+-----------------+-----------------+-----------------+-----------------+-----------------+\n| 1       | 1       | GET    | /req              | 0.221 (-0.100)  | 0.221 (-0.100)  | 0.221 (-0.100)  | 0.221 (-0.100)  | 0.221 (-0.100)  |\n| 1       | 1       | GET    | /new              | 0.221           | 0.221           | 0.221           | 0.221           | 0.221           |\n| 1       | 1       | POST   | /hoge/piyo        | 0.134 (-0.100)  | 0.134 (-0.100)  | 0.134 (-0.100)  | 0.134 (-0.100)  | 0.134 (-0.100)  |\n| 1       | 1       | GET    | /diary/entry/1234 | 0.035 (-0.100)  | 0.035 (-0.100)  | 0.035 (-0.100)  | 0.035 (-0.100)  | 0.035 (-0.100)  |\n| 1       | 0       | GET    | /foo/bar/5xx      | 59.000 (-1.000) | 59.000 (-1.000) | 59.000 (-1.000) | 59.000 (-1.000) | 59.000 (-1.000) |\n| 2 (+1)  | 2 (+1)  | GET    | /diary/entry/5678 | 0.332 (-0.100)  | 2.332 (+1.900)  | 2.664 (+2.232)  | 1.332 (+0.900)  | 2.332 (+1.900)  |\n| 2       | 2       | GET    | /foo/bar          | 0.023 (-0.100)  | 0.023 (-0.100)  | 0.046 (-0.200)  | 0.023 (-0.100)  | 0.023 (-0.100)  |\n| 5       | 5       | POST   | /foo/bar          | 0.047 (-0.010)  | 0.134 (-0.100)  | 0.378 (-0.170)  | 0.076 (-0.034)  | 0.134 (-0.100)  |\n+---------+---------+--------+-------------------+-----------------+-----------------+-----------------+-----------------+-----------------+\n| 14 (+2) | 13 (+2) |\n+---------+---------+--------+-------------------+-----------------+-----------------+-----------------+-----------------+-----------------+\n```\n\n## グローバルオプション\n\nsample は [Usage samples](./docs/usage_samples.ja.md) を参照してください。\n\n- `-c, --config`\n    - 各種オプションの設定ファイル\n    - YAML\n- `--file=FILE` \n    - 解析するファイルのパス\n- `-d, --dump=DUMP`\n    - 解析結果をファイルに書き出す際のファイルパス\n- `-l, --load=LOAD`\n    - `-d, --dump` オプションで書き出した解析結果を読み込む際のファイルパス\n    - 同じ解析結果に対して、`--sort` や `--reverse` のオプションを変更したい場合に高速に動作することが期待できます\n- `--sort=count`\n    - 解析結果を表示する際にソートする条件\n    - 昇順でソートする \n    - `max`, `min`, `sum`, `avg`\n    - `max-body`, `min-body`, `sum-body`, `avg-body`  \n    - `p90`, `p95`, `p99`, `stddev`\n    - `uri`\n    - `method`\n    - `count`\n    - デフォルトは `count`\n    - `p90`, `p95`, `p99` は `--percentiles` で指定したパーセンタイル値によって変更されます\n- `-r, --reverse`\n    - `--sort` オプションのソート結果を降順にします\n- `-q, --query-string`\n    - Query String までを含めた URI を集計対象にする\n- `--qs-ignore-values`\n    - Query String の値を無視して集計します\n    - `-q, --query-string` を指定しないと有効になりません\n- `--decode-uri`\n    - 解析結果の URI をデコードして表示します\n- `--format=table`\n    - 解析結果を テーブル、Markdown, TSV, CSV, HTML 形式で出力する\n    - デフォルトはテーブル形式\n- `--noheaders`\n    - 解析結果を TSV, CSV で出力する際、header を表示しない\n- `--show-footers`\n    - 解析結果を テーブル, Markdown で出力する際、footer として 1xx ~ 5xx の合計数を表示する\n- `--limit=5000`\n    - 解析結果の表示上限数\n    - 解析結果の表示数が想定より多かった場合でも、リソースを使いすぎないための設定です\n    - デフォルトは 5000 行\n- `--location=\"Local\"`\n    - フィルタ条件で指定する時刻の timezone\n    - デフォルトは localhost に設定されている timezone\n- `-o, --output=\"all\"`\n    - 出力する解析結果をカンマ区切りで指定する\n    - `count`,`1xx`, `2xx`, `3xx`, `4xx`, `5xx`, `method`, `uri`, `min`, `max`, `sum`, `avg`, `p90`, `p95`, `p99`, `stddev`, `min_body`, `max_body`, `sum_body`, `avg_body`\n        - `p90`, `p95`, `p99` は `--percentiles` で指定したパーセンタイル値によって変更されます\n    - デフォルトはすべて出力(`all`)\n- `-m, --matching-groups=PATTERN,...`\n    - 正規表現にマッチした URI を同じ集計対象として扱います\n    - 指定した順序で正規表現を評価します。マッチした場合、それ以降の正規表現を評価しません。\n    - 後述の [URI matching groups](#uri-matching-groups) 参照\n- `-f, --filters=FILTERS`\n    - 集計対象をフィルタします\n    - 後述の[フィルタ](#フィルタ)参照\n- `--pos=POSITION_FILE`\n    - ファイルをどこまで読み込んだかバイト数を記録します\n    - POSITION_FILE にバイト数が書かれていた場合、そのバイト数以降のデータが解析対象になります\n    - ファイルを truncate することなく前回解析後からの増分だけを解析することができます\n        - また、ファイルを Seek して読み飛ばすので、高速に動作することが見込めます\n- `--nosave-pos`\n    - `--pos` で指定したバイト数以降のデータを解析対象としますが、読み込んだバイト数の記録はしないようにします\n- `--percentiles`\n    - 出力するパーセンタイル値をカンマ区切りで指定します\n    - デフォルトは `90,95,99`\n    \n## URI matching groups\n\n以下の `/diary/entry/1234` や `/diary/entry/5678` のように、同一のルーティングでパラメータが異なる URI を単純に集計すると、パラメータごとに集計されますが、ルーティングごとに集計したい場合もあるでしょう。\n\n```console\n$ cat example/logs/ltsv_access.log | alp ltsv --filters \"Uri matches '^/diary/entry'\"\n+-------+-----+-----+-----+-----+-----+--------+-------------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |        URI        |  MIN  |  MAX  |  SUM  |  AVG  |  P90  |  P95  |  P99  | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/1234 | 0.135 | 0.135 | 0.135 | 0.135 | 0.135 | 0.135 | 0.135 |  0.000 |    15.000 |    15.000 |    15.000 |    15.000 |\n|     1 |   0 |   1 |   0 |   0 |   0 | GET    | /diary/entry/5678 | 0.432 | 0.432 | 0.432 | 0.432 | 0.432 | 0.432 | 0.432 |  0.000 |    30.000 |    30.000 |    30.000 |    30.000 |\n+-------+-----+-----+-----+-----+-----+--------+-------------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n```\n\nそのようなケースで、正規表現にマッチした URI を同じ集計対象とするオプションが `-m, --matching-groups=PATTERN,...` です。\nカンマ区切りで複数指定することもできます。\n\n```console\n$ cat example/logs/ltsv_access.log | alp ltsv --filters \"Uri matches '^/diary/entry'\" -m \"/diary/entry/.+\"\n+-------+-----+-----+-----+-----+-----+--------+-----------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD |       URI       |  MIN  |  MAX  |  SUM  |  AVG  |  P90  |  P95  |  P99  | STDDEV | MIN(BODY) | MAX(BODY) | SUM(BODY) | AVG(BODY) |\n+-------+-----+-----+-----+-----+-----+--------+-----------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n|     2 |   0 |   2 |   0 |   0 |   0 | GET    | /diary/entry/.+ | 0.135 | 0.432 | 0.567 | 0.283 | 0.432 | 0.432 | 0.432 |  0.148 |    15.000 |    30.000 |    45.000 |    22.500 |\n+-------+-----+-----+-----+-----+-----+--------+-----------------+-------+-------+-------+-------+-------+-------+-------+--------+-----------+-----------+-----------+-----------+\n```\n\n## フィルタ\n\n集計対象を条件に応じて包含、除外する機能です。\n\n### 変数\n\n以下の変数に対してフィルタをかけることができます。\n\n- `Uri`\n    - URI\n- `Method`\n    - HTTP メソッド\n- `Time`\n    - 時刻文字列\n    - https://github.com/tkuchiki/parsetime でパースできる時刻文字列に対応しています\n- `ResponseTime`\n    - レスポンスタイム\n- `BodyBytes`\n    - HTTP Body のバイト数\n- `Status`\n    - HTTP Status Code\n\n### 演算子\n\n以下の演算子を使用できます。\n\n- `+`, `-`, `*`, `/`, `%`, `**(べき乗)` \n- `==`, `!=`, `\u003c`, `\u003e`, `\u003c=`, `\u003e=`\n- `not`, `!`\n- `and`, `\u0026\u0026`\n- `or`, `||`\n- `matches`\n    - 正規表現(`PATTERN`)にマッチするか否か\n    - e.g.\n       - `Uri matches \"PATTERN\"`\n       - `not(Uri matches \"PATTERN\")`\n- `contains`\n    - 文字列(`STRING`)を含むか否か\n    - e.g.\n        - `Uri contains \"STRING\"`\n        - `not(Uri contains \"STRING\")`\n- `startsWith`\n    - 文字列に前方一致するか否か\n    - e.g.\n        - `Uri startsWith \"PREFIX\"`\n        - `not(Uri startsWith \"PREFIX\")`\n- `endsWith`\n    - 文字列に後方一致するか否か\n    - e.g.\n        - `Uri endsWith \"SUFFIX\"`\n        - `not(Uri endsWith \"SUFFIX\")`\n- `in`\n    - 配列の値を含むか否か\n    - e.g.\n        - `Method in [\"GET\", \"POST\"]`\n        - `Method not in [\"GET\", \"POST\"]`\n\n詳細は https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md を参照してください。  \n\n### 関数\n\n- `TimeAgo(duration)`\n    - 現在時刻 - `duration` した時刻を返します\n    - Go の time.Duration で使用できる時刻の単位を指定できます\n    - `ns`, `us or µs`, `ms`, `s`, `m`, `h`\n    - e.g.\n        - `Time \u003e= TimeAgo(\"5m\")`\n        - `Time` が現在時刻 -5分以上のログを集計対象とする\n- `BetweenTime(val, start, end)`\n    - SQL の `BETWEEN` のように、`start \u003c= val \u0026\u0026 val \u003c= end` の結果を返す   \n    - e.g.\n        - `BetweenTime(Time, \"2019-08-06T00:00:00\", \"2019-08-06T00:05:00\")`\n        \n## 利用例\n\n[Usage samples](./docs/usage_samples.ja.md) を参照してください。\n\n## 寄付\n\n寄付はいつでも歓迎します！    \n[:heart: Sponsor](https://github.com/sponsors/tkuchiki)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftkuchiki%2Falp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftkuchiki%2Falp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftkuchiki%2Falp/lists"}