{"id":16111118,"url":"https://github.com/mjpitz/go-gracefully","last_synced_at":"2025-03-18T09:31:01.648Z","repository":{"id":57531730,"uuid":"277309472","full_name":"mjpitz/go-gracefully","owner":"mjpitz","description":"A simple, efficient, and easy to use Golang library for implementing application health checks. Features first-class support for stream-based checks.","archived":false,"fork":false,"pushed_at":"2023-07-05T21:02:17.000Z","size":154,"stargazers_count":11,"open_issues_count":8,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-28T08:33:55.116Z","etag":null,"topics":["go","golang","health-check","healthcheck","status","statuspage"],"latest_commit_sha":null,"homepage":"","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/mjpitz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-05T13:39:35.000Z","updated_at":"2025-02-17T09:41:08.000Z","dependencies_parsed_at":"2024-06-19T22:50:26.474Z","dependency_job_id":"68cf980d-cb99-4bc6-ba3a-e979e779347a","html_url":"https://github.com/mjpitz/go-gracefully","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjpitz%2Fgo-gracefully","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjpitz%2Fgo-gracefully/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjpitz%2Fgo-gracefully/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjpitz%2Fgo-gracefully/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mjpitz","download_url":"https://codeload.github.com/mjpitz/go-gracefully/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243911171,"owners_count":20367640,"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":["go","golang","health-check","healthcheck","status","statuspage"],"created_at":"2024-10-09T19:40:24.966Z","updated_at":"2025-03-18T09:31:01.368Z","avatar_url":"https://github.com/mjpitz.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"![GitHub](https://img.shields.io/github/license/mjpitz/go-gracefully.svg)\n![branch](https://github.com/mjpitz/go-gracefully/workflows/branch/badge.svg?branch=main)\n![Codecov branch](https://img.shields.io/codecov/c/github/mjpitz/go-gracefully/main)\n![Google Analytics](https://www.google-analytics.com/collect?v=1\u0026tid=UA-172921913-1\u0026cid=555\u0026t=pageview\u0026ec=repo\u0026ea=open\u0026dp=go-gracefully\u0026dt=go-gracefully)\n\n# go-gracefully\n\n`go-gracefully` is a library for monitoring and reporting on an applications' health.\nUnlike many solutions out there, `go-gracefully` uses an asynchronous, stream based check scheme.\nThis enables real-time checks as well as push based changes.\n\n**Status:**\n\nThis library is currently available as a _preview_.\nI started development to support my existing work on [deps.cloud](http://github.com/depscloud).\n\nMost health check libraries you find are pull based.\nIn this model, you define your check as a function that's called on some set interval.\nWhile this is a great start to a solution, more advance techniques need to be able to push.\n\nThe flow of information in the system is as follows:\n\n[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggTFJcbiAgQVtQZXJpb2RpY0NoZWNrXSAtLT58UmVwb3J0fCBDaChDaGFubmVsKVxuICBCW1N0cmVhbUNoZWNrXSAtLT58UmVwb3J0fCBDaFxuICBDW1N0cmVhbUNoZWNrXSAtLT58UmVwb3J0fCBDaFxuXHRDaCAtLT4gTVtNb25pdG9yXVxuICBNIC0tPnxSZXBvcnR8IFNbU3Vic2NyaWJlcnNdXG4gIE0gLS0tfG1haW50YWluc3wgc3VtbWFyeSIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcbiAgQVtQZXJpb2RpY0NoZWNrXSAtLT58UmVwb3J0fCBDaChDaGFubmVsKVxuICBCW1N0cmVhbUNoZWNrXSAtLT58UmVwb3J0fCBDaFxuICBDW1N0cmVhbUNoZWNrXSAtLT58UmVwb3J0fCBDaFxuXHRDaCAtLT4gTVtNb25pdG9yXVxuICBNIC0tPnxSZXBvcnR8IFNbU3Vic2NyaWJlcnNdXG4gIE0gLS0tfG1haW50YWluc3wgc3VtbWFyeSIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9)\n\n1. Each `Check` produces a `Report`\n2. `Reports` are collected through the use of a channel by the `Monitor`.\n3. The monitor updates its `summary` of the system.\n4. When either a check, or the system state changes, a `Report` is published to subscribers.\n\nA snapshot of the full report can be obtained from the `Monitor`.\n\n## How does it work?\n\nAll checks in `go-gracefully` have a common block of metadata.\n\n* `Name` is a required descriptor of the check.\n  * Avoid whitespace where possible. Preferred character set: `[a-zA-Z0-9-_.]`\n* An optional `Runbook` can be provided to aid in the resolution of issues.\n  * When provided, this should be a valid URL.\n* Finally, a `Weight` is used to determine relative importance of check to the overall system.\n  * A check with `Weight: 100` has a greater impact on the system health than one with `Weight: 10`. \n\n```go\n    // ...\n    Metadata: check.Metadata{\n        Name: \"periodic-check\",\n        Runbook: \"http://path/to/runbook.md\",\n        Weight: 10,\n    },\n    // ...\n```\n\nWhen check's evaluated, it can return one of four possible states.\n\n* `OK` - The check is operating as expected.\n* `Minor` - The check is failing and will require attention soon.\n* `Major` - The check is failing and requires attention soon.\n* `Outage` - The check is failing and requires attention.\n\nOn its own, `state` represents a fractional value of health (i.e. `[0-1]`).\nTogether, the `state` and the `weight` are used to approximate an applications' health.  \n\n## Inspirations\n\nThere are a lot of prior work out there.\nIt's hard to list them all.\nThe list below was is just a few I drew inspiration from. \n\n* http://github.com/indeedeng/status\n* https://github.com/InVisionApp/go-health\n* https://godoc.org/github.com/heptiolabs/healthcheck\n* https://github.com/AppsFlyer/go-sundheit\n\n## Installation\n\n```bash\ngo get -u github.com/mjpitz/go-gracefully\n```\n\n## Usage\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"http\"\n    \"log\"\n    \"time\"\n\n    \"github.com/mjpitz/go-gracefully/check\"\n    \"github.com/mjpitz/go-gracefully/health\"\n    \"github.com/mjpitz/go-gracefully/state\"\n)\n\nfunc main() {\n    monitor := health.NewMonitor([]check.Check{\n        \u0026check.Periodic{\n            Metadata: check.Metadata{\n                Name: \"periodic-check\",\n                Runbook: \"http://path/to/runbook.md\",\n                Weight: 10,\n            },\n            Interval: time.Second * 5,\n            Timeout: time.Second,\n            RunFunc: func(ctx context.Context) (state.State, error) {\n                // make API call, check system health\n                return state.OK, nil\n            },\n        },\n        \u0026check.Stream{\n            Metadata: check.Metadata{\n                Name: \"stream-check\",\n                Runbook: \"http://path/to/runbook.md\",\n                Weight: 10,\n            },\n            WatchFunc: func(ctx context.Context, channel chan check.Result) {\n                stopCh := ctx.Done()\n\n                var upstreamCh chan interface{}\n                // make call that fills chan\n\n                for {\n                    select {\n                        case \u003c-stopCh:\n                            return\n                        case _ = \u003c-upstreamCh:\n                            channel \u003c- check.Result{\n                                State: state.OK,\n                                Error: nil,\n                            }\n                    }\n                }\n            },\n        },\n    }...)\n\n    reports, unsubscribe := monitor.Subscribe()\n    defer unsubscribe()\n\n    ctx := context.Background()\n    if err := monitor.Start(ctx); err != nil {\n        log.Fatal(err.Error())\n    }\n\n    // subscribe to changes in health\n    for report := range reports {\n        // access check information if present\n        // - Check will not be present for changes in overall system health\n        _ = report.Check\n\n        // access check evaluation result data\n        // - Result will be present for all reports\n        _ = report.Result\n    }\n    \n    // or add an HTTP endpoint to view the results of it\n    http.HandleFunc(\"/healthz\", health.HandlerFunc(monitor))\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjpitz%2Fgo-gracefully","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmjpitz%2Fgo-gracefully","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjpitz%2Fgo-gracefully/lists"}