{"id":31157429,"url":"https://github.com/ferderer/guard4j","last_synced_at":"2026-05-03T11:37:00.445Z","repository":{"id":313511702,"uuid":"1051671465","full_name":"ferderer/guard4j","owner":"ferderer","description":"Production-grade error handling and observability for Java. Framework-agnostic core with Spring Boot, Quarkus, and Micronaut integrations. Type-safe error codes, structured responses, automatic metrics and logging.","archived":false,"fork":false,"pushed_at":"2025-09-10T20:53:42.000Z","size":104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-18T22:47:41.544Z","etag":null,"topics":["enterprise","error-handling","framework-agnostic","java","micrometer","micronaut","observability","quarkus","slf4j","spring-boot"],"latest_commit_sha":null,"homepage":"https://guard4j.ferderer.de/","language":"Java","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/ferderer.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,"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":"2025-09-06T13:40:41.000Z","updated_at":"2025-09-10T20:43:43.000Z","dependencies_parsed_at":"2025-09-06T16:07:40.769Z","dependency_job_id":"6bd941f4-5929-474f-ac27-dd0bfcd2e935","html_url":"https://github.com/ferderer/guard4j","commit_stats":null,"previous_names":["ferderer/guard4j"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ferderer/guard4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferderer%2Fguard4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferderer%2Fguard4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferderer%2Fguard4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferderer%2Fguard4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ferderer","download_url":"https://codeload.github.com/ferderer/guard4j/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferderer%2Fguard4j/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32567753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: 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":["enterprise","error-handling","framework-agnostic","java","micrometer","micronaut","observability","quarkus","slf4j","spring-boot"],"created_at":"2025-09-18T22:03:47.229Z","updated_at":"2026-05-03T11:37:00.440Z","avatar_url":"https://github.com/ferderer.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Guard4j\n*– Guard4j events describe what happens in your domain, not how you measure it.*\n\nProduction-grade error handling and observability for Java applications. Framework-agnostic core with seamless Spring Boot, Quarkus, and Micronaut integration.\n\n## The Problem\n\nEnterprise Java applications typically suffer from inconsistent error handling that breaks down in production:\n\n- Generic `Map\u003cString, Object\u003e` error responses that clients can't reliably parse\n- Framework-specific error handling that doesn't work when you switch frameworks\n- No built-in observability - errors disappear into logs without metrics or alerting\n- Testing nightmares where MockMvc tests pass but production servlet errors fail\n\n## The Solution\n\nGuard4j provides type-safe error handling with automatic observability that works identically across all major Java frameworks:\n\n```java\n// Clean, fluent error creation with business context\nthrow new AppException(ErrorCodes.BUSINESS_RULE_VIOLATION)\n    .withData(\"rule\", \"DAILY_TRANSFER_LIMIT\")\n    .withData(\"limit\", 10000)\n    .withData(\"attempted\", 15000);\n```\n\n**Emitter Factory Pattern**\n```java\npublic class PaymentService {\n    private static final Emitter events = Guard4j.getEmitter(PaymentService.class);\n\n    public void processPayment(Payment payment) {\n        // Single event call generates both metrics and structured logs\n        events.info(new PaymentProcessedEvent(payment.getId(), payment.getAmount()));\n    }\n}\n```\n\n```json\n{\n  \"timestamp\": \"2024-01-15T10:30:00Z\",\n  \"status\": 422,\n  \"error\": \"Unprocessable Entity\",\n  \"code\": \"BUSINESS_RULE_VIOLATION\",\n  \"data\": {\n    \"userId\": \"user123\",\n    \"rule\": \"DAILY_TRANSFER_LIMIT\",\n    \"limit\": 10000,\n    \"attempted\": 15000,\n    \"retryable\": false,\n    \"severity\": \"medium\"\n  }\n}\n```\n\n## Key Features\n\n- **Type-safe error responses** - No more `Map\u003cString, Object\u003e` - structured, predictable JSON\n- **Framework-agnostic** - Same error handling code works in Spring Boot, Quarkus, and Micronaut\n- **Automatic observability** - Built-in metrics, structured logging, and alerting integration\n- **Production-ready** - Configurable alert levels, retry logic, and environment-specific behavior\n- **Zero-config setup** - Add dependency, start throwing better exceptions\n\n## Quick Start (Spring Boot)\n\n### 1. Add Dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ede.ferderer.guard4j\u003c/groupId\u003e\n    \u003cartifactId\u003eguard4j-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### 2. Use in Your Code\n\n```java\n@RestController\npublic class TransferController {\n    private static final Emitter events = Guard4j.getEmitter(TransferController.class);\n\n    @PostMapping(\"/transfers\")\n    public TransferResult transfer(@RequestBody TransferRequest request) {\n        // Business rule validation with context\n        if (account.getBalance() \u003c request.getAmount()) {\n            // Exception handling\n            throw new AppException(ErrorCodes.BUSINESS_RULE_VIOLATION)\n                .withData(\"rule\", \"INSUFFICIENT_FUNDS\")\n                .withData(\"balance\", account.getBalance())\n                .withData(\"requested\", request.getAmount());\n        }\n\n        // Business event observability - generates both metrics and logs\n        events.info(new TransferInitiatedEvent(request.getUserId(), request.getAmount()));\n\n        TransferResult result = transferService.execute(request);\n\n        events.info(new TransferCompletedEvent(result.getTransferId(), result.getStatus()));\n        return result;\n    }\n}\n\n// Simple event definition\npublic record TransferInitiatedEvent(String userId, BigDecimal amount) implements ObservableEvent {}\npublic record TransferCompletedEvent(String transferId, String status) implements ObservableEvent {}\n```\n\n### 3. Get Structured Errors + Automatic Observability\n\nGuard4j automatically provides:\n- **Structured error responses** that clients can reliably parse\n- **Micrometer metrics** for error rates, categories, and business impact\n- **Structured logging** with correlation IDs and business context\n- **Framework exception mapping** - Spring validation errors become consistent ErrorResponse objects\n\n## Framework Support\n\n| Framework | Status | Artifact |\n|-----------|--------|----------|\n| Spring Boot 3.x | ✅ Production Ready | `guard4j-spring-boot-starter` |\n| Quarkus 3.x | 🛠️ **In Active Development** | `guard4j-quarkus` |\n| Micronaut 4.x | 🚧 Coming Soon | `guard4j-micronaut` |\n\n\n## Custom Error Codes\n\nCreate domain-specific error codes for your business logic:\n\n```java\npublic enum PaymentErrorCodes implements ErrorCode {\n    PAYMENT_GATEWAY_UNAVAILABLE(\n        HttpStatus.SERVICE_UNAVAILABLE,\n        Message.of(\"payment.gateway.unavailable\", \"Payment gateway temporarily unavailable\"),\n        Severity.CRITICAL,\n        Category.EXTERNAL\n    ),\n    DAILY_LIMIT_EXCEEDED(\n        HttpStatus.UNPROCESSABLE_ENTITY,\n        Message.of(\"payment.daily_limit\", \"Daily payment limit exceeded\"),\n        Severity.WARN,\n        Category.BUSINESS\n    );\n\n    // Standard ErrorCode implementation...\n}\n\n// Usage with business events\npublic class PaymentService {\n    private static final Emitter events = Guard4j.getEmitter(PaymentService.class);\n\n    public void processPayment(Payment payment) {\n        if (exceedsDailyLimit(payment)) {\n            events.warn(new PaymentLimitExceededEvent(payment.getUserId(), payment.getAmount()));\n            throw new AppException(PaymentErrorCodes.DAILY_LIMIT_EXCEEDED)\n                .withUserId(payment.getUserId())\n                .withData(\"amount\", payment.getAmount())\n                .withData(\"dailyLimit\", getDailyLimit(payment.getUserId()));\n        }\n\n        events.info(new PaymentProcessedEvent(payment.getId(), payment.getAmount()));\n    }\n}\n```\n\n## Business Event Observability\n\nGuard4j's **Emitter Factory pattern** provides unified observability for business events:\n\n```java\npublic class LoanProcessorService {\n    private static final Emitter events = Guard4j.getEmitter(LoanProcessorService.class);\n\n    public void processLoan(LoanApplication loan) {\n        // Replace verbose MeterRegistry + Logger calls with single event\n        events.info(new LoanProcessingStartedEvent(loan.getId(), loan.getType()));\n\n        try {\n            LoanDecision decision = evaluateRules(loan);\n\n            // Business event generates automatic metrics + structured logs\n            events.info(new LoanProcessedEvent(loan, decision));\n        } catch (Exception ex) {\n            events.error(new LoanProcessingFailedEvent(loan, ex));\n            throw ex;\n        }\n    }\n}\n\n// Simple event definitions\npublic record LoanProcessingStartedEvent(String loanId, String loanType) implements ObservableEvent {}\n\npublic record LoanProcessedEvent(String loanId, BigDecimal amount, String decision, long processingTimeMs)\n    implements ObservableEvent {\n\n    @Override\n    public int metric() {\n        return \"APPROVED\".equals(decision) ? 1 : 0; // Success rate tracking\n    }\n}\n```\n\n**Automatic Output:**\n- **Metrics**: `guard4j_loan_processed_total{decision=\"approved\", loan_type=\"mortgage\"}`\n- **Logs**: `{\"level\":\"INFO\",\"logger\":\"com.company.LoanProcessorService\",\"event_type\":\"loan-processed\",\"loan_id\":\"12345\",...}`\n\n## Architecture\n\nGuard4j follows the **Emitter Factory Pattern** for clean, type-safe observability:\n\n```java\n// Get emitter for your class (cached, thread-safe)\nprivate static final Emitter events = Guard4j.getEmitter(MyService.class);\n\n// Emit events with appropriate log levels\nevents.info(new BusinessEvent(...));    // Business metrics + INFO logs\nevents.warn(new WarningEvent(...));     // Alert metrics + WARN logs\nevents.error(new ErrorEvent(...));      // Error metrics + ERROR logs\n```\n\n**Key Benefits:**\n- **Single Event Definition**: One record generates both metrics and structured logs\n- **Type Safety**: Compile-time validation of event structure\n- **Logger Correlation**: Events use your class logger name for perfect correlation\n- **Framework Agnostic**: Same API works across Spring Boot, Quarkus, Micronaut\n\n## Requirements\n\n- **Java 17+**\n- **Spring Boot 3.0+** / **Quarkus 3.0+** / **Micronaut 4.0+**\n\n## Documentation\n\n- [Getting Started Guide](https://guard4j.dev/docs/getting-started)\n- [Framework-Specific Setup](https://guard4j.dev/docs/frameworks)\n- [Custom Error Codes](https://guard4j.dev/docs/guides/custom-error-codes)\n- [Production Configuration](https://guard4j.dev/docs/guides/production)\n- [API Reference](https://guard4j.dev/docs/api)\n\n## Examples\n\nComplete working examples for all supported frameworks:\n\n- [FinStream Trading API - Spring Boot](examples/finstream-spring-boot/) 🛠️ **In Active Development**\n- [FinStream Trading API - Quarkus](examples/finstream-quarkus/) 🚧 **Coming Soon**\n- [FinStream Trading API - Micronaut](examples/finstream-micronaut/) 🚧 **Coming Soon**\n\n## Roadmap\n\n### Current Focus (September 2025)\n- **Quarkus Extension** development for ReTrust production deployment\n\n### Next Steps\n- Finalize Quarkus extension with native compilation support\n- Community feedback and improvements\n\n## License\n\nApache License 2.0 - see [LICENSE](LICENSE) for details.\n\n## Contributing\n\nContributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n---\n\n**Why Guard4j?** As an independent consultant since 2001 (Java/Spring since 2009), I've seen the same error handling mistakes in enterprise projects across many companies. Guard4j provides the production-grade error handling and observability that Java applications actually need.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferderer%2Fguard4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fferderer%2Fguard4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferderer%2Fguard4j/lists"}