@@ -108,41 +108,158 @@ class StripePaymentService
108108
109109### Controlled Execution Blocks
110110
111- ** What it does:** Monitors critical operations with automatic start/end logging, exception handling, DB transactions, circuit breakers, and failure callbacks.
111+ ** What it does:** Monitors critical operations with automatic start/end logging, exception-specific handling, DB transactions, circuit breakers, and true escalation for uncaught exceptions.
112+
113+ #### ** Factory & Execution**
112114
113115``` php
114116use Kirschbaum\Monitor\Facades\Monitor;
115117
118+ // Create and execute controlled block
119+ $result = Monitor::controlled('payment_processing')
120+ ->run(function() {
121+ return processPayment($data);
122+ });
123+ ```
124+
125+ #### ** Context Management**
126+
127+ ``` php
128+ /*
129+ * Adds additional context to the structured logger.
130+ */
131+ ->addContext([
132+ 'transaction_id' => 'txn_456',
133+ 'gateway' => 'stripe'
134+ ]);
135+
136+ /*
137+ * Will completely replace structured logger context.
138+ * ⚠️ Not recommended unless you have a good reason to do so.
139+ */
140+ ->overrideContext([
141+ 'user_id' => 123,
142+ 'operation' => 'payment',
143+ 'amount' => 99.99
144+ ]);
145+ ```
146+
147+ #### ** Exception Handling**
148+
149+ ** Exception-Specific Handlers (` catching ` ):**
150+ ``` php
151+ ->catching([
152+ DatabaseException::class => function($exception, $meta) {
153+ $cachedData = ExampleModel::getCachedData();
154+ return $cachedData; // Recovery value
155+ },
156+ NetworkException::class => function($exception, $meta) {
157+ $this->exampleRetryLater($meta);
158+ // No return = just handle, don't recover
159+ },
160+ PaymentException::class => function($exception, $meta) {
161+ $this->exampleNotifyFinanceTeam($exception, $meta);
162+ throw $exception; // Re-throw if needed
163+ },
164+ // Other exception types remain uncaught.
165+ ])
166+ ```
167+
168+ ** Uncaught Exception Handling (` onUncaughtException ` ):**
169+ ``` php
170+ ->onUncaughtException(function($exception, $meta) {
171+ // Example actions, the exception will remain uncaught
172+ $this->alertOpsTeam($exception, $meta);
173+ $this->sendToErrorTracking($exception);
174+ })
175+ ```
176+
177+ ** Key Behavior:**
178+ - Only specified exception types in ` catching() ` are handled
179+ - Handlers can return recovery values to prevent re-throwing
180+ - ` onUncaughtException() ` ** only** fires for exceptions not caught by ` catching() ` handlers
181+ - True separation between expected (caught) and unexpected (uncaught) failures
182+
183+ #### ** Circuit Breaker & Database Protection**
184+
185+ ``` php
186+ ->withCircuitBreaker('payment_gateway', 3, 60) // 3 failures, 60s timeout
187+ ->withDatabaseTransaction(2, [DeadlockException::class], [ValidationException::class])
188+ ```
189+
190+ #### ** Tracing & Logging**
191+
192+ ``` php
193+ ->overrideTraceId('custom-trace-12345')
194+ ->from('PaymentService') // Custom logger origin
195+ ```
196+
197+ #### ** Complete Example**
198+
199+ ``` php
116200class PaymentService
117201{
118202 public function processPayment($amount, $userId)
119203 {
120- return Monitor::controlled('payment_processing')
121- ->with(['amount' => $amount, 'user_id' => $userId]) // Additional log context
122- ->transactioned(3)
123- ->escalated(fn (ControlledFailureMeta $meta) => Slack::notify($meta->toArray()))
124- ->run(function () use ($amount) {
204+ return Monitor::controlled('payment_processing', $this)
205+ ->addContext([
206+ 'user_id' => $userId,
207+ 'amount' => $amount,
208+ 'currency' => 'USD'
209+ ])
210+ ->withCircuitBreaker('payment_gateway', 3, 120)
211+ ->withDatabaseTransaction(1, [DeadlockException::class])
212+ ->catching([
213+ PaymentDeclinedException::class => function($e, $meta) {
214+ return ['status' => 'declined', 'reason' => $e->getMessage()];
215+ },
216+ InsufficientFundsException::class => function($e, $meta) {
217+ return ['status' => 'insufficient_funds'];
218+ }
219+ ])
220+ ->onUncaughtException(fn($e, $meta) => Monitor::escalate($e, $meta))
221+ ->run(function() use ($amount) {
125222 return $this->chargeCard($amount);
126223 });
127224 }
128225}
129226```
130227
131- ** What it logs:**
228+ #### ** 📊 What it logs:**
229+
230+ ** Success:**
132231``` json
133- // Success
134- {"message" : " [PaymentService] STARTED " , "controlled_block " : " payment_processing " , "block_id " : " 01HK... " }
135- { "message" : " [PaymentService] ENDED " , "status" : " ok " , "duration_ms" : 1250 }
232+ { "message" : " [PaymentProcessor] STARTED " , "controlled_block" : " payment_processing " , "controlled_block_id" : " 01HK... " }
233+ {"message" : " [PaymentProcessor] ENDED " , "status " : " ok " , "duration_ms " : 1250 }
234+ ```
136235
137- // Failure
138- {"message" : " [PaymentService] STARTED" , "controlled_block" : " payment_processing" }
139- {"message" : " [PaymentService] FAILED" , "exception" : " RuntimeException" , "trace" : [... ]}
236+ ** Caught Exception (Recovery):**
237+ ``` json
238+ {"message" : " [PaymentProcessor] STARTED" , "controlled_block" : " payment_processing" }
239+ {"message" : " [PaymentProcessor] CAUGHT" , "exception" : " PaymentDeclinedException" , "duration_ms" : 500 }
240+ {"message" : " [PaymentProcessor] RECOVERED" , "recovery_value" : " array" }
241+ ```
242+
243+ ** Uncaught Exception (Escalation):**
244+ ``` json
245+ {"message" : " [PaymentProcessor] STARTED" , "controlled_block" : " payment_processing" }
246+ {"message" : " [PaymentProcessor] UNCAUGHT" , "exception" : " RuntimeException" , "uncaught" : true , "duration_ms" : 300 }
140247```
141248
142- ** Advanced Features:**
143- - ** Circuit Breakers:** ` ->breaker('service_name', threshold, decaySeconds) ` - Automatically opens/closes breaker based on failures
144- - ** Database Transactions:** ` ->transactioned(retries, onlyExceptions, excludeExceptions) ` . This allows to only retry transaction on specific exceptions, or otherwise ignore specific exception.
145- - ** Failure Escalation Path:** ` ->escalated($callback) ` for critical business processes
249+ #### ** 🎯 API Reference**
250+
251+ | Method | Purpose | Returns |
252+ | --------| ---------| ---------|
253+ | ` Controlled::for(string $name) ` | Create controlled block | ` self ` |
254+ | ` ->overrideContext(array $context) ` | Replace entire context | ` self ` |
255+ | ` ->addContext(array $context) ` | Merge additional context | ` self ` |
256+ | ` ->catching(array $handlers) ` | Define exception-specific handlers | ` self ` |
257+ | ` ->onUncaughtException(Closure $callback) ` | Handle uncaught exceptions only | ` self ` |
258+ | ` ->withCircuitBreaker(string $name, int $threshold, int $decay) ` | Configure circuit breaker | ` self ` |
259+ | ` ->withDatabaseTransaction(int $retries, array $only, array $exclude) ` | Wrap in DB transaction with retry | ` self ` |
260+ | ` ->overrideTraceId(string $traceId) ` | Set custom trace ID | ` self ` |
261+ | ` ->from(string\|object $origin) ` | Set logger origin | ` self ` |
262+ | ` ->run(Closure $callback) ` | Execute the controlled block | ` mixed ` |
146263
147264### Distributed Tracing
148265
0 commit comments