PHP code example of partner-api / logger

1. Go to this page and download the library: Download partner-api/logger library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

partner-api / logger example snippets


use PartnerApi\Logger\Laravel\Facades\PartnerLogger;

$apiKey = (string) $request->header('x-api-key'); // sent by the partner app

PartnerLogger::info($apiKey, 'Order created', ['orderId' => $order->id]);

use PartnerApi\Logger\Logger;

$logger = new Logger(tenantToken: getenv('PARTNER_API_TENANT_TOKEN'));

$logger->info($apiKey, 'Order created', ['orderId' => 42]);

$logger->info($apiKey, 'Something happened', ['key' => 'value']);
$logger->warn($apiKey, 'Watch out');
$logger->error($apiKey, 'Something broke', ['error' => 'Insufficient funds']);
$logger->debug($apiKey, 'Debug details');

$logger->setContext([
    'partnerId' => 'partner-123',
    'requestId' => 'req_abc123',
]);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use PartnerApi\Logger\Logger;

class ScopePartnerLogs
{
    public function __construct(private Logger $logger)
    {
    }

    public function handle(Request $request, Closure $next)
    {
        return $this->logger->runWithContext(
            ['requestId' => $request->header('x-request-id')],
            fn () => $next($request),
        );
    }
}

// Returns the correlation ID that pairs the request with its response.
$correlationId = $logger->logRequest($apiKey, [
    'method' => 'POST',
    'path' => '/api/v1/orders',
    'headers' => ['x-request-id' => 'req_abc123', 'authorization' => 'Bearer secret'],
    'body' => ['sku' => 'A-100', 'quantity' => 2],
]);

$logger->logResponse($apiKey, [
    'statusCode' => 201,
    'headers' => ['content-type' => 'application/json'],
    'body' => ['id' => 'ord_123', 'status' => 'created'],
    'duration' => 120, // milliseconds
    'correlationId' => $correlationId,
]);

// After verifying the signature and finding the partner that sent it:
$apiKey = $appKeys->forPartner($partnerId); // your own mapping
$correlationId = $logger->logRequest($apiKey, [
    'method' => $request->method(),
    'path' => $request->path(),
    'headers' => [
        'content-type' => $request->header('content-type'),
        'x-signature' => '[REDACTED]',
    ],
    'body' => $request->json()->all(),
]);

// One logger for deliveries. 'to' => 'partner' needs 'direction' => 'outbound'.
$deliveries = $logger->child(['direction' => 'outbound', 'to' => 'partner']);

$fields = [
    'event_type' => $event->type,          // 'booking.created'
    'delivery_id' => $event->deliveryId,   // the same on every retry
    'attempt' => $attempt,                 // 1 for the first try
    'method' => 'POST',
    'path' => parse_url($endpoint, PHP_URL_PATH),
];
$startedAt = microtime(true);
try {
    $response = $http->post($endpoint, ['json' => $event->payload, 'http_errors' => false]);
    $status = $response->getStatusCode();
    $fields += ['status_code' => $status, 'duration_ms' => (int) ((microtime(true) - $startedAt) * 1000)];
    $status < 400
        ? $deliveries->info($apiKey, 'Webhook delivery', $fields)
        : $deliveries->warn($apiKey, 'Webhook delivery', $fields);
} catch (\GuzzleHttp\Exception\TransferException $e) {
    // No response: no status_code.
    $deliveries->warn($apiKey, 'Webhook delivery failed', $fields + [
        'duration_ms' => (int) ((microtime(true) - $startedAt) * 1000),
        'error' => $e->getMessage(),
    ]);
}

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

// Once, where you build the client. Every request through it is recorded
// against the request that makes it.
$stack = HandlerStack::create();
$stack->push($logger->upstreamMiddleware('stripe'));
$stripe = new Client(['handler' => $stack]);

// In a handler:
$correlationId = $logger->logRequest($apiKey, ['method' => 'POST', 'path' => '/orders']);
$stripe->post('https://api.stripe.com/v1/charges', ['form_params' => ['amount' => 1000]]);

// Anything that is not Guzzle: record it yourself.
$logger->upstream([
    'name' => 'pricing',
    'method' => 'GET',
    'url' => 'https://pricing.internal/quote',
    'status' => 200,
    'durationMs' => 41,
]);

$logger->logResponse($apiKey, ['statusCode' => 201, 'duration' => 250, 'correlationId' => $correlationId]);

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;

$stack = HandlerStack::create();
$stack->push(Middleware::retry(fn (int $retries, $request, $response = null) => $retries < 2 && $response?->getStatusCode() >= 500));
$stack->push($logger->upstreamMiddleware('stripe'));

use PartnerApi\Logger\RedactPii;
use function PartnerApi\Logger\redactPII;

redactPII('contact [email protected]');
// → 'contact [EMAIL_REDACTED]'

redactPII('call me on +44 20 7946 0000 today');
// → 'call me on [PHONE_REDACTED] today'

redactPII('GET https://api.example.com/v1/orders?token=abc 200');
// → 'GET https://api.example.com/v1/orders?[QUERY_REDACTED] 200'

redactPII([
    'Authorization' => 'Bearer secret',
    'X-Api-Key' => 'abc123',
    'user' => ['email' => '[email protected]', 'password' => 'hunter2'],
]);
// → ['Authorization' => 'Bearer [TOKEN_REDACTED]', 'X-Api-Key' => '[KEY_REDACTED]', 'user' => ['email' => '[EMAIL_REDACTED]', 'password' => '[PASSWORD_REDACTED]']]

redactPII(['+44 20 7946 0000' => 'sent', '+44 20 7946 0001' => 'failed']);
// → ['[PHONE_REDACTED]' => 'sent', '[PHONE_REDACTED]#2' => 'failed']

RedactPii::redact('task_123e4567-e89b-12d3-a456-426614174000', ['redactUuids' => true]);
// → 'task_[ID]'

// One data point
$logger->metric($apiKey, [
    'slug' => 'revenue',
    'timestamp' => '2024-06-01T00:00:00Z',
    'value' => 54000,
    'period' => 'Jun 01',
    'metadata' => ['currency' => 'EUR'], // optional
]);

// Several points for one metric
$logger->metrics($apiKey, 'revenue', [
    ['timestamp' => '2024-06-01T00:00:00Z', 'value' => 54000, 'period' => 'Jun 01'],
    ['timestamp' => '2024-06-08T00:00:00Z', 'value' => 55200, 'period' => 'Jun 08'],
]);

use PartnerApi\Logger\Logger;
use PartnerApi\Logger\LoggerErrorEvent;

$logger = new Logger(
    tenantToken: getenv('PARTNER_API_TENANT_TOKEN'),
    options: [
        'onError' => function (LoggerErrorEvent $event): void {
            error_log("[partner-logger] {$event->reason}: {$event->message}");
        },
    ],
);

$logger->stats();
// ['buffered' => 0, 'delivered' => 480, 'dropped' => 0, 'upstreamDropped' => 0]

$logger = new Logger(
    tenantToken: getenv('PARTNER_API_TENANT_TOKEN'),
    options: ['mode' => Logger::MODE_STDOUT],
);
$logger->info($apiKey, 'Order created', ['orderId' => 42]);

use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
use PartnerApi\Logger\Logger;

$sent = [];
$stack = HandlerStack::create(new MockHandler([new Response(200)]));
$stack->push(Middleware::history($sent));

$logger = new Logger(
    tenantToken: 'test-token',
    httpClient: new Client(['handler' => $stack]),
    timestampProvider: fn () => 1700000000000,
    options: ['flushOnShutdown' => false, 'batchSize' => 0],
);

$logger->info('app-key', 'Order created');
$logger->flush();

$body = json_decode((string) $sent[0]['request']->getBody(), true);
// $body['entries'][0]['timestamp'] === '1700000000000000000'
bash
php artisan vendor:publish --tag=partner-logger-config