{"id":35672409,"url":"https://github.com/bborbe/service","last_synced_at":"2026-01-05T19:04:17.451Z","repository":{"id":233431683,"uuid":"787033936","full_name":"bborbe/service","owner":"bborbe","description":null,"archived":false,"fork":false,"pushed_at":"2025-12-05T22:41:39.000Z","size":5751,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-09T12:37:57.982Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bborbe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-15T19:05:14.000Z","updated_at":"2025-12-05T22:41:43.000Z","dependencies_parsed_at":"2024-04-29T19:41:43.025Z","dependency_job_id":"8fde81e8-c7c5-4379-834b-e08cedc75c85","html_url":"https://github.com/bborbe/service","commit_stats":null,"previous_names":["bborbe/service"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/bborbe/service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bborbe%2Fservice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bborbe%2Fservice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bborbe%2Fservice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bborbe%2Fservice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bborbe","download_url":"https://codeload.github.com/bborbe/service/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bborbe%2Fservice/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28218054,"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":"2026-01-05T02:00:06.358Z","response_time":57,"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":[],"created_at":"2026-01-05T19:02:24.702Z","updated_at":"2026-01-05T19:04:17.440Z","avatar_url":"https://github.com/bborbe.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Service\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/bborbe/service.svg)](https://pkg.go.dev/github.com/bborbe/service)\n[![CI](https://github.com/bborbe/service/actions/workflows/ci.yml/badge.svg)](https://github.com/bborbe/service/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/bborbe/service)](https://goreportcard.com/report/github.com/bborbe/service)\n\nA Go service framework library that provides a standardized way to build HTTP services with Sentry integration, structured logging, and graceful shutdown capabilities.\n\n## Features\n\n- **Standardized Service Architecture**: Interface → Constructor → Struct → Method pattern\n- **Sentry Integration**: Built-in error reporting and exception handling\n- **Graceful Shutdown**: Context-aware service lifecycle management\n- **HTTP Server Utilities**: Health checks, metrics, and routing with Gorilla Mux\n- **Concurrent Execution**: Run multiple service components with proper error handling\n- **Automatic Error Handling**: Panic recovery, error logging, and Sentry reporting\n- **Argument Parsing**: Type-safe CLI argument parsing with struct tags\n- **Testing Support**: Counterfeiter mock generation and Ginkgo/Gomega test framework\n\n## Installation\n\n```bash\ngo get github.com/bborbe/service\n```\n\n## Quick Start\n\nHere's a minimal example to get started:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"os\"\n\n    libsentry \"github.com/bborbe/sentry\"\n    \"github.com/bborbe/service\"\n)\n\ntype application struct {\n    SentryDSN   string `required:\"true\" arg:\"sentry-dsn\" env:\"SENTRY_DSN\"`\n    SentryProxy string `arg:\"sentry-proxy\" env:\"SENTRY_PROXY\"`\n}\n\nfunc (a *application) Run(ctx context.Context, sentryClient libsentry.Client) error {\n    // Your application logic here\n    \u003c-ctx.Done()\n    return ctx.Err()\n}\n\nfunc main() {\n    app := \u0026application{}\n    os.Exit(service.Main(context.Background(), app, \u0026app.SentryDSN, \u0026app.SentryProxy))\n}\n```\n\nRun with:\n```bash\n./myservice --sentry-dsn=\"https://key@sentry.io/project\"\n```\n\n## Core Concepts\n\n### Application Interface\n\nYour application must implement the `Application` interface:\n\n```go\ntype Application interface {\n    Run(ctx context.Context, sentryClient libsentry.Client) error\n}\n```\n\nThe framework handles:\n- **Argument Parsing**: Automatically parses CLI arguments and environment variables from struct tags\n- **Sentry Setup**: Configures error reporting with the provided DSN\n- **Global Settings**: Sets timezone to UTC, configures logging, and GOMAXPROCS\n- **Graceful Shutdown**: Manages context cancellation and signal handling\n- **Exit Codes**: Returns appropriate exit codes (0=success, 1=runtime error, 2=Sentry failure, 3=missing DSN, 4=argument error)\n\n### Running Multiple Components\n\nUse `service.Run()` to execute multiple concurrent functions with automatic error handling:\n\n```go\nfunc (a *application) Run(ctx context.Context, sentryClient libsentry.Client) error {\n    return service.Run(\n        ctx,\n        a.createHTTPServer(),\n        a.createBackgroundWorker(),\n    )\n}\n```\n\nEach function automatically receives:\n- **Panic Recovery**: Automatic panic catching and error conversion\n- **Error Logging**: Structured logging with glog\n- **Error Filtering**: Excludes expected errors (like `context.Canceled`) from Sentry\n- **Context Cancellation**: Stops all functions when any one finishes or fails\n\n### Argument Parsing\n\nUse struct tags to define CLI arguments and environment variables:\n\n```go\ntype application struct {\n    SentryDSN string `required:\"true\" arg:\"sentry-dsn\" env:\"SENTRY_DSN\" usage:\"Sentry DSN for error reporting\"`\n    Listen    string `required:\"true\" arg:\"listen\" env:\"LISTEN\" usage:\"Address to listen on\"`\n}\n```\n\nSupported tags:\n- `required`: Whether the argument is mandatory\n- `arg`: CLI flag name (e.g., `--listen`)\n- `env`: Environment variable name\n- `usage`: Help text description\n- `display`: How to display value in logs (`\"length\"` masks sensitive data)\n\n## Full Example\n\nComplete HTTP service with health checks and metrics:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"os\"\n\n    libhttp \"github.com/bborbe/http\"\n    \"github.com/bborbe/run\"\n    libsentry \"github.com/bborbe/sentry\"\n    \"github.com/bborbe/service\"\n    \"github.com/golang/glog\"\n    \"github.com/gorilla/mux\"\n    \"github.com/prometheus/client_golang/prometheus/promhttp\"\n)\n\nfunc main() {\n    app := \u0026application{}\n    os.Exit(service.Main(context.Background(), app, \u0026app.SentryDSN, \u0026app.SentryProxy))\n}\n\ntype application struct {\n    SentryDSN   string `required:\"true\"  arg:\"sentry-dsn\"   env:\"SENTRY_DSN\"   display:\"length\"`\n    SentryProxy string `required:\"false\" arg:\"sentry-proxy\" env:\"SENTRY_PROXY\"`\n    Listen      string `required:\"true\"  arg:\"listen\"       env:\"LISTEN\"       usage:\"address to listen to\"`\n}\n\nfunc (a *application) Run(ctx context.Context, sentryClient libsentry.Client) error {\n    return service.Run(\n        ctx,\n        a.createBackgroundWorker(),\n        a.createHTTPServer(),\n    )\n}\n\nfunc (a *application) createBackgroundWorker() run.Func {\n    return func(ctx context.Context) error {\n        // Background task logic\n        \u003c-ctx.Done()\n        return ctx.Err()\n    }\n}\n\nfunc (a *application) createHTTPServer() run.Func {\n    return func(ctx context.Context) error {\n        ctx, cancel := context.WithCancel(ctx)\n        defer cancel()\n\n        router := mux.NewRouter()\n        router.Path(\"/healthz\").Handler(libhttp.NewPrintHandler(\"OK\"))\n        router.Path(\"/readiness\").Handler(libhttp.NewPrintHandler(\"OK\"))\n        router.Path(\"/metrics\").Handler(promhttp.Handler())\n\n        glog.V(2).Infof(\"starting http server listen on %s\", a.Listen)\n        return libhttp.NewServer(a.Listen, router).Run(ctx)\n    }\n}\n```\n\nRun with:\n```bash\n./myservice --sentry-dsn=\"https://key@sentry.io/project\" --listen=\":8080\"\n```\n\nThe service provides:\n- Health check endpoint: `http://localhost:8080/healthz`\n- Readiness endpoint: `http://localhost:8080/readiness`\n- Prometheus metrics: `http://localhost:8080/metrics`\n\n## API Documentation\n\nFor complete API documentation, visit [pkg.go.dev/github.com/bborbe/service](https://pkg.go.dev/github.com/bborbe/service).\n\n## Development\n\n### Running Tests\n\n```bash\nmake test\n```\n\nTests run with race detection enabled and coverage reporting.\n\n### Code Generation\n\nGenerate mocks for testing:\n\n```bash\nmake generate\n```\n\nThis creates Counterfeiter mocks for all interfaces in the `mocks/` directory.\n\n### Full Development Workflow\n\nBefore committing changes:\n\n```bash\nmake precommit\n```\n\nThis runs:\n- Dependency verification\n- Code formatting (gofmt, goimports-reviser, golines)\n- Code generation (mocks)\n- Tests with race detection and coverage\n- Static analysis (vet, errcheck, lint)\n- Security scanning (gosec, trivy, osv-scanner, govulncheck)\n- License header verification\n\n## Testing Your Service\n\nExample test using Counterfeiter mocks:\n\n```go\npackage myapp_test\n\nimport (\n    \"context\"\n    \"testing\"\n\n    libsentry \"github.com/bborbe/sentry\"\n    \"github.com/bborbe/service\"\n    \"github.com/bborbe/service/mocks\"\n\n    . \"github.com/onsi/ginkgo/v2\"\n    . \"github.com/onsi/gomega\"\n)\n\nfunc TestService(t *testing.T) {\n    RegisterFailHandler(Fail)\n    RunSpecs(t, \"MyApp Suite\")\n}\n\nvar _ = Describe(\"Application\", func() {\n    var (\n        app          *application\n        sentryClient *mocks.SentryClient\n    )\n\n    BeforeEach(func() {\n        sentryClient = \u0026mocks.SentryClient{}\n        app = \u0026application{\n            Listen: \":8080\",\n        }\n    })\n\n    It(\"should run successfully\", func() {\n        ctx, cancel := context.WithCancel(context.Background())\n        defer cancel()\n\n        // Test your application logic\n        err := app.Run(ctx, sentryClient)\n        Expect(err).To(BeNil())\n    })\n})\n```\n\n## Exit Codes\n\nThe framework returns standard exit codes:\n\n- `0`: Success\n- `1`: Runtime error\n- `2`: Sentry setup failure\n- `3`: Missing Sentry DSN\n- `4`: Argument parsing failure\n\n## Dependencies\n\nKey runtime dependencies:\n\n- [github.com/bborbe/argument/v2](https://github.com/bborbe/argument) - Type-safe argument parsing\n- [github.com/bborbe/sentry](https://github.com/bborbe/sentry) - Sentry error reporting wrapper\n- [github.com/bborbe/run](https://github.com/bborbe/run) - Concurrent function execution\n- [github.com/bborbe/http](https://github.com/bborbe/http) - HTTP server utilities\n- [github.com/gorilla/mux](https://github.com/gorilla/mux) - HTTP routing\n- [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) - BDD testing framework\n- [github.com/onsi/gomega](https://github.com/onsi/gomega) - Matcher library\n\n## License\n\nCopyright (c) 2024-2025 Benjamin Borbe\n\nThis project is licensed under the BSD-2-Clause License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbborbe%2Fservice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbborbe%2Fservice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbborbe%2Fservice/lists"}