Usage¶
The Logger component provides a decorator for PSR-3 loggers with additional methods specifically designed for exception handling. This document covers the main usage patterns and features.
Exception logging¶
The primary feature of this component is the ability to log exceptions with a clean API. The component provides two methods for exception logging:
exception()- Logs the exception but does not throw it (unless in debug mode)throw()- Logs the exception and always throws it
exception() method¶
Use the exception() method when you want to log an exception and handle it
gracefully without re-throwing it:
1<?php
2
3declare(strict_types=1);
4
5namespace App\Service;
6
7use RunOpenCode\Component\Logger\Contract\LoggerInterface;
8
9final readonly class OrderService
10{
11 public function __construct(private LoggerInterface $logger)
12 {
13 // noop.
14 }
15
16 public function placeOrder(Order $order): OrderResult
17 {
18 try {
19 $this->validateOrder($order);
20 $this->processPayment($order);
21 $this->notifyCustomer($order);
22
23 return OrderResult::success($order);
24 } catch (\Throwable $exception) {
25 // Log the exception with context
26 $this->logger->exception(
27 $exception,
28 'Order placement failed',
29 [
30 'order_id' => $order->getId(),
31 'customer_id' => $order->getCustomerId(),
32 'total' => $order->getTotal(),
33 ]
34 );
35
36 return OrderResult::failure($exception->getMessage());
37 }
38 }
39}
In the example above, when an exception occurs, it is logged with additional context, but the method returns a failure result instead of crashing. This is useful for non-critical operations where you want to continue execution.
throw() method¶
Use the throw() method when you want to log an exception and then re-throw
it:
1<?php
2
3public function criticalDatabaseOperation(): void
4{
5 try {
6 $this->database->execute('CRITICAL_OPERATION');
7 } catch (\Exception $exception) {
8 // Log and re-throw
9 $this->logger->throw(
10 $exception,
11 'Critical database operation failed',
12 ['operation' => 'CRITICAL_OPERATION']
13 );
14 }
15}
This is useful when you need to log the exception with context but still want the exception to propagate up the call stack.
Custom messages¶
Both methods accept an optional custom message parameter. If provided, this message will be used for logging instead of the exception’s message:
1<?php
2
3try {
4 $this->externalApi->call();
5} catch (\Throwable $exception) {
6 // Use a custom message for logging
7 $this->logger->exception(
8 $exception,
9 'External API call failed - retrying later'
10 );
11}
If no custom message is provided, the exception’s message will be used.
Log levels¶
You can specify the log level for each exception:
1<?php
2
3use Psr\Log\LogLevel;
4
5try {
6 $this->cache->clear();
7} catch (\Throwable $exception) {
8 // Log at WARNING level instead of the default CRITICAL
9 $this->logger->exception(
10 $exception,
11 'Cache clear failed',
12 level: LogLevel::WARNING
13 );
14}
If no level is specified, the logger will use the default level configured
during initialization (which defaults to LogLevel::CRITICAL).
Context enrichment¶
The exception() and throw() methods automatically add the exception
object to the log context under the exception key:
1<?php
2
3$this->logger->exception(
4 $exception,
5 'Operation failed',
6 ['user_id' => 123]
7);
8
9// The actual context passed to the underlying PSR-3 logger will be:
10// [
11// 'user_id' => 123,
12// 'exception' => $exception - Automatically added
13// ]
This ensures that the exception object is always available in the log context for further processing by your logging infrastructure (e.g., Sentry, error tracking services, etc.).
Additionally, if you have configured context providers (see Context providers), they will automatically enrich the context with additional information.
PSR-3 compatibility¶
The Logger component fully implements PSR-3’s LoggerInterface, so you can
use all standard PSR-3 methods:
1<?php
2
3use Psr\Log\LogLevel;
4
5// Standard PSR-3 methods work as expected
6$logger->emergency('System is down');
7$logger->alert('Database connection lost');
8$logger->critical('Critical error occurred');
9$logger->error('An error occurred');
10$logger->warning('Warning: deprecated method used');
11$logger->notice('User logged in');
12$logger->info('Operation completed successfully');
13$logger->debug('Debug information');
14
15// Generic log method
16$logger->log(LogLevel::INFO, 'Custom log message', ['key' => 'value']);
All these methods are forwarded to the underlying PSR-3 logger that was passed to the Logger constructor. If context providers are configured, they will also enrich the context for these standard PSR-3 methods.
Debug mode behavior¶
The behavior of the exception() method changes based on the debug mode:
1<?php
2
3use RunOpenCode\Component\Logger\Logger;
4
5// Production mode (debug = false)
6$logger = new Logger($psrLogger, debug: false);
7
8try {
9 throw new \RuntimeException('Test exception');
10} catch (\Throwable $exception) {
11 // This will log the exception but NOT throw it
12 $logger->exception($exception);
13
14 // Execution continues here
15 echo "Exception was logged, continuing execution...";
16}
17
18// Development mode (debug = true)
19$logger = new Logger($psrLogger, debug: true);
20
21try {
22 throw new \RuntimeException('Test exception');
23} catch (\Throwable $exception) {
24 // This will log the exception AND throw it again
25 $logger->exception($exception);
26
27 // This line will NOT be reached
28 echo "This will never be printed";
29}
This allows you to use the same code in both environments, with different behavior based on the debug flag. In production, you can log exceptions and handle them gracefully, while in development, exceptions are still thrown so you can see stack traces and debug issues.
Note that the throw() method always re-throws the exception regardless of
the debug mode.
Working with context¶
You can pass any additional context data when logging exceptions:
1<?php
2
3try {
4 $this->api->updateUser($userId, $data);
5} catch (\Throwable $exception) {
6 $this->logger->exception(
7 $exception,
8 'User update failed',
9 [
10 'user_id' => $userId,
11 'request_data' => $data,
12 'timestamp' => time(),
13 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
14 ]
15 );
16}
The context array can contain any data that will help you debug the issue. This data is passed to the underlying PSR-3 logger and can be processed by your log handlers (e.g., written to files, sent to log aggregation services, etc.).
For automatically enriching context across all log calls, see Context providers.