{"id":20315240,"url":"https://github.com/sysread/app-jsonlogutils","last_synced_at":"2026-05-13T02:11:55.454Z","repository":{"id":56831607,"uuid":"147403900","full_name":"sysread/App-JsonLogUtils","owner":"sysread","description":"Command line utilities for dealing with JSON-formatted log files","archived":false,"fork":false,"pushed_at":"2018-09-15T09:13:39.000Z","size":71,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-24T05:58:44.219Z","etag":null,"topics":["cat","cli","column","command-line","command-line-tool","grep","json","log","perl","tail"],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sysread.png","metadata":{"files":{"readme":"README.pod","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-04T19:40:29.000Z","updated_at":"2023-02-13T19:12:52.000Z","dependencies_parsed_at":"2022-08-28T20:10:37.512Z","dependency_job_id":null,"html_url":"https://github.com/sysread/App-JsonLogUtils","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FApp-JsonLogUtils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FApp-JsonLogUtils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FApp-JsonLogUtils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysread%2FApp-JsonLogUtils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sysread","download_url":"https://codeload.github.com/sysread/App-JsonLogUtils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241818874,"owners_count":20025210,"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":["cat","cli","column","command-line","command-line-tool","grep","json","log","perl","tail"],"created_at":"2024-11-14T18:18:25.739Z","updated_at":"2026-05-13T02:11:55.422Z","avatar_url":"https://github.com/sysread.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"=pod\n\n=encoding UTF-8\n\n=head1 NAME\n\nApp::JsonLogUtils - Command line utilities for dealing with JSON-formatted log files\n\n=head1 VERSION\n\nversion 0.03\n\n=head1 SYNOPSIS\n\n  # From the command line\n  tail -f /path/to/log/file.log \\\n    | jgrep -m message=\"some pattern\" \\\n    | jcut -f \"timestamp priority message\" \\\n    | cols -c \"timestamp priority message\" -s '|' \\\n    | column -t -s '|'\n\n\n  # From code\n  use App::JsonLogUtils qw(tail json_log);\n\n  my $log = json_log tail '/path/to/file.log';\n\n  while (my $entry = \u003c$log\u003e) {\n    my ($json, $line) = @$entry;\n    ...\n  }\n\n\n  # Grepping JSON logs\n  use App::JsonLogUtils qw(lines json_log);\n  use Iterator::Simple qw(igrep imap);\n\n  my $entries = igrep{ $_-\u003e{foo} =~ /bar/ } # filter objects\n                imap{ $_-\u003e[0] }             # select the object\n                json_log                    # parse\n                lines '/path/to/file.log';  # read\n\n=head1 DESCRIPTION\n\nWriting logs in JSON, one object per line, makes them very easily machine\nreadable. Wonderful. Unfortunately, it also makes it unfuriating to deal with\nthem using the standard unix command line tools. This package provides a few\ntools to salve the burn.\n\n=head1 COMMAND LINE TOOLS\n\n=head2 L\u003cjgrep\u003e\n\nGreps patterns in individual object fields.\n\n=head2 L\u003cjcut\u003e\n\nFilter the fields included in objects.\n\n=head2 L\u003cjcols\u003e\n\nDisplay fields in a format suitable for C\u003ccolumn\u003e.\n\n=head2 L\u003cjshell\u003e\n\nAn interactive shell for monitoring JSON log files.\n\n=head1 EXPORTABLE ROUTINES\n\nIf desired, the iterators used to implement the tools above are optionally\nexported by the main module.\n\n=head1 lines\n\nAccepts a file path or opened file handle and returns an iterator which yields\nthe chomped lines from the file.\n\n  my $log = lines '/path/to/file.log';\n\n  while (my $line = \u003c$log\u003e) {\n    ...\n  }\n\n=head1 tail\n\nAccepts a file path or opened file handle and returns an iterator while yields\nchomped lines from the file as they are appended, starting from the end of the\nfile. Lines already written to the file when this routine is first called are\nignored (that is, there is no equivalent to C\u003ctail -c 10\u003e at this time).\n\n  my $log = tail '/path/to/file.log';\n\n  while (my $line = \u003c$log\u003e) { # sleeps until lines appended to file\n    ...\n  }\n\n=head1 json_log\n\nAccepts a file iterator (see L\u003c/tail\u003e and L\u003c/lines\u003e) and returns an iterator\nyielding an array ref holding two items, a hash ref of the parsed JSON log\nentry, and the original log entry string. Empty lines are skipped with a\nwarning. JSON decoding errors are ignored with a warning.\n\n  my $lines = json_log tail '/path/to/file.log';\n\n  while (my $entry = \u003c$lines\u003e) {\n    my ($object, $line) = @_;\n    ...\n  }\n\n=head2 json_cols\n\nAccepts a list of fields (as a space-separared string or array ref of strings),\na string separator, and an iterator over JSON object strings, and returns a new\niterator. The returned iterator will first yield a string of column names\njoined by the separator string. Subsequent calls will iterate over the JSON\nobject strings, return the value of each of the selected fields joined by the\nseparator string.\n\n  # File $input\n  {\"a\": 1, \"b\": 2, \"c\": 3}\n  {\"a\": 4, \"b\": 5, \"c\": 6}\n  {\"a\": 7, \"b\": 8, \"c\": 9}\n\n  # Select columns a and c, separated by a pipe\n  my $cols = json_cols \"a c\", \"|\" , lines $input;\n\n  # ...yields the following strings:\n  \"a|c\"\n  \"1|3\"\n  \"4|6\"\n  \"7|9\"\n\n=head2 json_cut\n\nAccepts a space-separated string or array ref of C\u003c$fields\u003e, boolean\nC\u003c$inverse\u003e, and an iterator of JSON log lines. Returns an iterator yielding\nobjects containing only the fields selected in C\u003c$fields\u003e. If C\u003c$inverse\u003e is\ntrue, instead yields objects containing only the fields I\u003cnot\u003e contained in\nC\u003c$fields\u003e.\n\nGive the same input as the L\u003cprevious example|/json_cols\u003e:\n\n  my $cut = json_cut \"a c\", 0, lines $input;\n\n  # ...yields the following hash refs:\n  {a =\u003e 1, c =\u003e 3}\n  {a =\u003e 4, c =\u003e 6}\n  {a =\u003e 7, c =\u003e 9}\n\n  # Inverted\n  my $cut = json_cut \"a c\", 1, lines $input;\n\n  # ...yields:\n  {b =\u003e 2}\n  {b =\u003e 5}\n  {b =\u003e 8}\n\n=head2 json_grep\n\nAccepts a hash ref where keys are field names and values are arrays of\nregular expressions, a boolean C\u003c$inverse\u003e, and an iterator of JSON object\nstrings. Returns an iterator yielding array refs of the parsed JSON object\nhash and the original string (just like L\u003c/json_log\u003e). Only those entries\nfor which all fields' patterns match are returned. If C\u003c$inverse\u003e is set,\nthe logic is negated and only those entries for which all patterns test\nfalse are returned.\n\n  # File $input\n  {\"foo\": \"bar\"}\n  {\"foo\": \"baz\"}\n  {\"foo\": \"bat\"}\n  {\"foo\": \"BAR\"}\n\n  # Code\n  my $entries = json_grep { foo =\u003e [qw/bar/i, qr/baz/] }, 0, lines $input;\n\n  # ...yields the following:\n  [ {foo =\u003e \"bar\"}, '{\"foo\": \"bar\"}' ]\n  [ {foo =\u003e \"baz\"}, '{\"foo\": \"baz\"}' ]\n  [ {foo =\u003e \"BAR\"}, '{\"foo\": \"BAR\"}' ]\n\n=head1 FUTURE PLANS\n\nNone, but will happily consider requests and patches.\n\n=head1 AUTHOR\n\nJeff Ober \u003csysread@fastmail.fm\u003e\n\n=head1 COPYRIGHT AND LICENSE\n\nThis software is copyright (c) 2018 by Jeff Ober.\n\nThis is free software; you can redistribute it and/or modify it under\nthe same terms as the Perl 5 programming language system itself.\n\n=cut\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysread%2Fapp-jsonlogutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsysread%2Fapp-jsonlogutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysread%2Fapp-jsonlogutils/lists"}