{"id":41443928,"url":"https://github.com/psykhi/uno","last_synced_at":"2026-01-23T15:00:01.059Z","repository":{"id":49776033,"uuid":"517927509","full_name":"psykhi/uno","owner":"psykhi","description":"Like uniq, but for logs.","archived":false,"fork":false,"pushed_at":"2022-07-30T13:43:48.000Z","size":17,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-06-19T18:12:27.817Z","etag":null,"topics":["command-line","go","golang","logging","logs","uniqueness"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psykhi.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}},"created_at":"2022-07-26T05:37:42.000Z","updated_at":"2023-07-24T02:53:09.000Z","dependencies_parsed_at":"2022-08-27T00:21:23.004Z","dependency_job_id":null,"html_url":"https://github.com/psykhi/uno","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/psykhi/uno","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psykhi%2Funo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psykhi%2Funo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psykhi%2Funo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psykhi%2Funo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psykhi","download_url":"https://codeload.github.com/psykhi/uno/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psykhi%2Funo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28694460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T14:15:13.573Z","status":"ssl_error","status_checked_at":"2026-01-23T14:09:05.534Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["command-line","go","golang","logging","logs","uniqueness"],"created_at":"2026-01-23T14:59:59.685Z","updated_at":"2026-01-23T15:00:01.045Z","avatar_url":"https://github.com/psykhi.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Like `uniq`, but for logs.\n\n`uno` is very useful when one wants to quickly identify the unique or new log statements in large log files. Unlike `uniq`, `uno` uses fuzzy matching\nto determine if two lines are similar or not.\nWhile it is certainly possible to write some custom awk/uniq/grep commands to do that on a specific log file,\n`uno` does that _well enough_ on pretty much any log file.\n\n_Uno was originally written while working at Unomaly, see this [blog post](https://unomaly.com/blog/its-in-the-anomalies/) for some context!_\n\n# Install\n\n```\ngo install github.com/psykhi/uno@latest\n```\n\nOr download from the [releases page](https://github.com/psykhi/uno/releases).\n\n# Example\n\nTake the following large `sshd` log file\n\n```\nDec 10 11:03:00 LabSZ sshd[25417]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\nDec 10 11:03:02 LabSZ sshd[25417]: Failed password for root from 183.62.140.253 port 45648 ssh2\nDec 10 11:03:02 LabSZ sshd[25417]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 11:03:02 LabSZ sshd[25419]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\nDec 10 11:03:05 LabSZ sshd[25419]: Failed password for root from 183.62.140.253 port 46059 ssh2\nDec 10 11:03:05 LabSZ sshd[25419]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 11:03:05 LabSZ sshd[25422]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\n...\nDec 10 11:03:17 LabSZ sshd[25430]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 11:03:17 LabSZ sshd[25432]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\nDec 10 11:03:19 LabSZ sshd[25432]: Failed password for root from 183.62.140.253 port 48708 ssh2\nDec 10 11:03:19 LabSZ sshd[25432]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 11:03:19 LabSZ sshd[25434]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\nDec 10 11:03:21 LabSZ sshd[25434]: Failed password for root from 183.62.140.253 port 49161 ssh2\nDec 10 11:03:21 LabSZ sshd[25434]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 09:18:33 LabSZ sshd[24641]: reverse mapping checking getaddrinfo for customer-187-141-143-180-sta.uninet-ide.com.mx [187.141.143.180] failed - POSSIBLE BREAK-IN ATTEMPT!\n...\nDec 10 11:04:27 LabSZ sshd[25516]: Failed password for root from 183.62.140.253 port 33233 ssh2\nDec 10 11:04:27 LabSZ sshd[25516]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 11:04:27 LabSZ sshd[25513]: Failed password for invalid user admin from 103.99.0.122 port 50289 ssh2\n```\n\nNow if we apply `uno` to it\n```\n~ uno test_file \nDec 10 11:03:00 LabSZ sshd[25417]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=183.62.140.253  user=root\nDec 10 11:03:02 LabSZ sshd[25417]: Failed password for root from 183.62.140.253 port 45648 ssh2\nDec 10 11:03:02 LabSZ sshd[25417]: Received disconnect from 183.62.140.253: 11: Bye Bye [preauth]\nDec 10 09:18:33 LabSZ sshd[24641]: reverse mapping checking getaddrinfo for customer-187-141-143-180-sta.uninet-ide.com.mx [187.141.143.180] failed - POSSIBLE BREAK-IN ATTEMPT!\nDec 10 11:04:27 LabSZ sshd[25513]: Failed password for invalid user admin from 103.99.0.122 port 50289 ssh2\n\n```\n\nWe now have a summary of all the logs that have happened, potentially highlighting \"unknown unknowns\". In this case,\n`uno` highlights the `POSSIBLE BREAK-IN ATTEMPT!` which happened once in the file, surrounded by millions of common statements.\n\n\n# Options\n\nTo see all options, use`uno -h`\n\n### -d\n\nThe distance option `-d` can be used to specify how different a new line must be from the others we've seen to be deemed\nnew/unique. It can take a value between `0` and `1`. The default is `0.2` (20% difference)\n\n### -all\n\nTo see all input lines and highlight the new ones in red, use `-all`\n\n```bash\ncat my_log_file.txt | uno -all\nuno -all my_log_file.txt\n```\n\n### -p\n\nOutput log patterns (numbers are replaced by `*`)\n\n```bash\ncat my_log_file.txt | uno -p\nuno -all my_log_file.txt\n\nJun * *:*:* combo ftpd[*]: connection from * (*-*-*-*.bflony.adelphia.net) at Fri Jun * *:*:* * \nJun * *:*:* combo cups: cupsd shutdown succeeded\nJul  * *:*:* combo gpm[*]: *** info [mice.c(*)]: \nJul  * *:*:* combo gpm[*]: imps2: Auto-detected intellimouse PS/*\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsykhi%2Funo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsykhi%2Funo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsykhi%2Funo/lists"}