{"id":18151294,"url":"https://github.com/msantos/slv","last_synced_at":"2025-08-30T02:03:58.497Z","repository":{"id":136621513,"uuid":"142687320","full_name":"msantos/slv","owner":"msantos","description":"slv: simple log viewer","archived":false,"fork":false,"pushed_at":"2023-12-01T12:06:34.000Z","size":50,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-07T01:45:50.125Z","etag":null,"topics":["logging"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/msantos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-07-28T15:15:59.000Z","updated_at":"2024-08-22T22:11:11.000Z","dependencies_parsed_at":"2023-12-01T13:55:16.303Z","dependency_job_id":"37103614-1a52-44e6-a5bc-b06d3624c100","html_url":"https://github.com/msantos/slv","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/msantos/slv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Fslv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Fslv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Fslv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Fslv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/msantos","download_url":"https://codeload.github.com/msantos/slv/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msantos%2Fslv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272793017,"owners_count":24993830,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["logging"],"created_at":"2024-11-02T01:07:16.426Z","updated_at":"2025-08-30T02:03:57.596Z","avatar_url":"https://github.com/msantos.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# slv\n\nElasticsearch, ugh, Kibana, meh ... all you wanted to do was look at a\nfew log files, maybe see what happened in the last hour or grep through\nfor something that happened a few days ago.\n\nShouldn't be hard, but what do you have to show except gigabytes of\nsquandered memory, terabytes of disk wasted, processes stuck in the\nrun queue and an ongoing maintenance burden?\n\n`slv` is a stupidly simple viewer for actual log files on disk. How\nthe log files get there and how they are rotated is up to you.\n\n`slv` is a SPA that streams log files over a websocket. `slv` uses\ntouch gestures on mobile and uses vi style keyboard shortcuts everywhere\nelse. There is also a command line interface.\n\n## Screenshot\n\n~~~\n2019-03-29T21:55:16.000Z host1 stderr/service java.io.IOException: Connection reset by peer\n2019-03-29T21:55:16.000Z host1 stderr/service     at sun.nio.ch.FileDispatcherImpl.read0(Native Method)\n2019-03-29T21:55:16.000Z host1 stderr/service     at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)\n2019-03-29T21:55:16.000Z host1 stderr/service     at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)\n2019-03-29T21:55:16.000Z host1 stderr/service     at sun.nio.ch.IOUtil.read(IOUtil.java:192)\n2019-03-29T21:55:16.000Z host1 stderr/service     at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)\n~~~\n\n## Installation\n\n### Requirements\n\n* [websocketd](http://websocketd.com/)\n\n* slvgrep: basic cli client\n    * [wsta](https://github.com/esphen/wsta)\n    * jq\n\n### Configuration\n\n~~~ shell\ngit clone https://github.com/msantos/slv\ncd slv\n~~~\n\n~~~ shell\n#!/bin/sh\n\nBASEDIR=\"${BASEDIR-.}\"\n\nexport PATH=$PATH:$BASEDIR/bin\n\nexec websocketd \\\n    --loglevel=\"${SLV_LOGLEVEL-debug}\" \\\n    --passenv=SLV_LOGDIR \\\n    --passenv=SLV_FILE \\\n    --passenv=SLV_SERVICE \\\n    --passenv=SLV_DIR \\\n    --passenv=SLV_CONTEXT \\\n    --reverselookup=false \\\n    --address=127.0.0.1 \\\n    --port=8080 \\\n    --staticdir=$BASEDIR/html \\\n    slv\n~~~\n\n### Environment Variables\n\n* `SLV_LOGDIR`: path to log directory (default: log)\n\n  This directory contains one or more service directories holding\n  logfiles.\n\n* `SLV_SERVICE`: the default service directory (default: system)\n\n* `SLV_FILE`: name of the log file (default: stderr.log)\n\n  The default log rotation date format is: `.YYYY-MM-DD`\n\n* `SLV_DIR`: default direction for paging through file\n\n      * tail: newest data first\n      * head: oldest data first\n\n  (default: tail)\n\n### Directory Layout\n\n~~~\n$SLV_LOGDIR -+-$SLV_SERVICE-+-stderr.log\n             |              |-stderr.log-2018-08-08\n             |              |-stderr.log-2018-08-07\n             |              |-stderr.log-2018-08-06\n             |              |-stderr.log-2018-08-05\n             |\n             |-other_service\n             |-another_service\n~~~\n\n### nginx\n\nDon't expose `slv` directly to the internet!\n\nWell, unless you want to make your log files public. Otherwise, set it\nup behind something like nginx as follows:\n\n* Generate a uuid:\n\n    # example only, don't use this uuid\n    $ uuidgen\n    e84656e6-7972-4223-b593-ac24c1320663\n\n* Configure nginx (assuming you're using let's encrypt):\n\n~~~\nserver {\n    listen              443 ssl;\n    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;\n    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;\n\n    location = /e84656e6-7972-4223-b593-ac24c1320663/slv {\n        return 302 /e84656e6-7972-4223-b593-ac24c1320663/slv/;\n    }\n    location  /e84656e6-7972-4223-b593-ac24c1320663/slv/ {\n        rewrite /e84656e6-7972-4223-b593-ac24c1320663/slv/(.*) /$1  break;\n\n        proxy_pass http://127.0.0.1:8080/;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_read_timeout 86400s;\n        proxy_redirect off;\n    }\n}\n~~~\n\n## Features\n\n## (Mis)Features\n\n* Highly configurable!\n\n  Translation: you might have to change the source code to make it work!\n\n* Just like reading logs in a terminal!\n\n  Translation: it's ugly!\n\n* Mobile friendly!\n\n  Translation: the touch interface sort of works!\n\n* Actively maintained!\n\n  Translation: it's buggy!\n\n* Highly secure!\n\n  Translation: probably not! It's a shell script! I ran shellcheck!\n\n* Educational!\n\n  Translation: feel free to read the javascript, shake your head and\n  silently judge me! Then send a patch!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsantos%2Fslv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmsantos%2Fslv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsantos%2Fslv/lists"}