> ## Documentation Index
> Fetch the complete documentation index at: https://docs.westyx.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP SDK - Custom Logging

> PSR-3 LoggerInterface integration, log levels emitted by the SDK, Monolog, Symfony, and Laravel examples.

The PHP SDK uses the [PSR-3 LoggerInterface](https://www.php-fig.org/psr/psr-3/) standard. Pass any PSR-3 compatible logger to `NexusConfig::$logger`. When `$logger` is `null` (the default), all SDK log output is suppressed.

## Configuration

```php theme={null}
use WestyxNexus\NexusClient;
use WestyxNexus\NexusConfig;

$client = NexusClient::create(new NexusConfig(
    baseUrl: $_ENV['NEXUS_URL'],
    apiKey:  $_ENV['NEXUS_API_KEY'],
    logger:  $myPsr3Logger,
));
```

## What the SDK logs

| Level   | Message examples                                                     | When emitted                                       |
| ------- | -------------------------------------------------------------------- | -------------------------------------------------- |
| `debug` | `Sync OK. configs=12 secrets=4 flags=7 key_type=sk`                  | After every successful sync                        |
| `debug` | `Sync 304 Not Modified - cache retained.`                            | When the server returns 304                        |
| `debug` | `SSE connected.`                                                     | When `connectStream` establishes a connection      |
| `debug` | `SSE event received: resync`                                         | On each SSE event                                  |
| `info`  | `Client ready. key_type=sk ttl=60s`                                  | After `NexusClient::create` returns                |
| `info`  | `WIF token exchange successful. provider=kubernetes expires_in=3600` | After a successful WIF token exchange              |
| `info`  | `SSE reconnecting (attempt 2, backoff 2s).`                          | On each reconnect attempt inside `connectStream`   |
| `error` | `Background sync failed: Connection refused`                         | When a TTL-triggered background sync fails         |
| `error` | `SSE transport error (attempt 1/3): Connection reset by peer`        | On each SSE transport error inside `connectStream` |
| `error` | `SSE max errors reached - falling back to TTL polling.`              | When `$maxErrors` consecutive SSE errors occur     |

The SDK **never logs the raw API key**. Key references in log messages use the type only (e.g. `key_type=sk`).

## Monolog example

[Monolog](https://github.com/Seldaek/monolog) is the most common PSR-3 implementation in PHP:

```php theme={null}
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use WestyxNexus\NexusClient;
use WestyxNexus\NexusConfig;

$logger = new Logger('nexus');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG));

$client = NexusClient::create(new NexusConfig(
    baseUrl: $_ENV['NEXUS_URL'],
    apiKey:  $_ENV['NEXUS_API_KEY'],
    logger:  $logger,
));
```

To route SDK logs to a dedicated channel:

```php theme={null}
$logger = new Logger('nexus');
$logger->pushHandler(new StreamHandler('/var/log/nexus-sdk.log', Logger::INFO));
```

## Symfony Dependency Injection

In a Symfony application, inject the `LoggerInterface` via DI:

```yaml theme={null}
# config/services.yaml
services:
    WestyxNexus\NexusClient:
        factory: ['WestyxNexus\NexusClient', 'create']
        arguments:
            - '@App\Config\NexusConfigFactory'
            - null
        calls: []

    App\Config\NexusConfigFactory:
        arguments:
            $logger: '@monolog.logger.nexus'
```

Or in a factory service:

```php theme={null}
// src/Config/NexusClientFactory.php

namespace App\Config;

use Psr\Log\LoggerInterface;
use WestyxNexus\NexusClient;
use WestyxNexus\NexusConfig;

final class NexusClientFactory
{
    public function __construct(private readonly LoggerInterface $logger) {}

    public function create(): NexusClient
    {
        return NexusClient::create(new NexusConfig(
            baseUrl: $_ENV['NEXUS_URL'],
            apiKey:  $_ENV['NEXUS_API_KEY'],
            logger:  $this->logger,
        ));
    }
}
```

## Laravel

In Laravel, pass a channel-specific logger using `Log::channel`:

```php theme={null}
// app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\Log;
use WestyxNexus\NexusClient;
use WestyxNexus\NexusConfig;

$this->app->singleton(NexusClient::class, function () {
    return NexusClient::create(new NexusConfig(
        baseUrl: config('services.nexus.url'),
        apiKey:  config('services.nexus.key'),
        logger:  Log::channel('nexus'),
    ));
});
```

Add a `nexus` channel to `config/logging.php`:

```php theme={null}
'nexus' => [
    'driver' => 'single',
    'path'   => storage_path('logs/nexus.log'),
    'level'  => env('NEXUS_LOG_LEVEL', 'info'),
],
```

## Silencing SDK logs

If you want the SDK to produce no output at all, pass a `NullLogger`:

```php theme={null}
use Psr\Log\NullLogger;

$client = NexusClient::create(new NexusConfig(
    baseUrl: $_ENV['NEXUS_URL'],
    apiKey:  $_ENV['NEXUS_API_KEY'],
    logger:  new NullLogger(),
));
```

`NullLogger` is part of `psr/log` which Guzzle already requires transitively, so no additional dependency is needed.

Alternatively, leave `$logger` as `null` (the default) - the SDK omits all logging in that case.
