Official PHP SDK for LogWard with advanced features: automatic batching, retry logic, circuit breaker, query API, live streaming, and middleware support.
- âś… Automatic batching with configurable size and interval
- âś… Retry logic with exponential backoff
- âś… Circuit breaker pattern for fault tolerance
- âś… Max buffer size with drop policy to prevent memory leaks
- âś… Query API for searching and filtering logs
- âś… Live tail with Server-Sent Events (SSE)
- âś… Trace ID context for distributed tracing
- âś… Global metadata added to all logs
- âś… Structured error serialization
- âś… Internal metrics (logs sent, errors, latency, etc.)
- âś… Laravel, Symfony & PSR-15 middleware for auto-logging HTTP requests
- âś… Full PHP 8.1+ support with strict types and enums
- PHP 8.1 or higher
- Composer
composer require logward/sdk-phpuse LogWard\SDK\LogWardClient;
use LogWard\SDK\Models\LogWardClientOptions;
$client = new LogWardClient(new LogWardClientOptions(
apiUrl: 'http://localhost:8080',
apiKey: 'lp_your_api_key_here',
));
// Send logs
$client->info('api-gateway', 'Server started', ['port' => 3000]);
$client->error('database', 'Connection failed', new PDOException('Timeout'));
// Graceful shutdown (auto-handled via register_shutdown_function)| Option | Type | Default | Description |
|---|---|---|---|
apiUrl |
string |
required | Base URL of your LogWard instance |
apiKey |
string |
required | Project API key (starts with lp_) |
batchSize |
int |
100 |
Number of logs to batch before sending |
flushInterval |
int |
5000 |
Interval in ms to auto-flush logs (not actively used, flush on shutdown) |
| Option | Type | Default | Description |
|---|---|---|---|
maxBufferSize |
int |
10000 |
Max logs in buffer (prevents memory leak) |
maxRetries |
int |
3 |
Max retry attempts on failure |
retryDelayMs |
int |
1000 |
Initial retry delay (exponential backoff) |
circuitBreakerThreshold |
int |
5 |
Failures before opening circuit |
circuitBreakerResetMs |
int |
30000 |
Time before retrying after circuit opens |
enableMetrics |
bool |
true |
Track internal metrics |
debug |
bool |
false |
Enable debug logging to error_log |
globalMetadata |
array |
[] |
Metadata added to all logs |
autoTraceId |
bool |
false |
Auto-generate trace IDs for logs |
$client = new LogWardClient(new LogWardClientOptions(
apiUrl: 'http://localhost:8080',
apiKey: 'lp_your_api_key_here',
// Batching
batchSize: 100,
flushInterval: 5000,
// Buffer management
maxBufferSize: 10000,
// Retry with exponential backoff (1s → 2s → 4s)
maxRetries: 3,
retryDelayMs: 1000,
// Circuit breaker
circuitBreakerThreshold: 5,
circuitBreakerResetMs: 30000,
// Metrics & debugging
enableMetrics: true,
debug: true,
// Global context
globalMetadata: [
'env' => getenv('APP_ENV'),
'version' => '1.0.0',
'hostname' => gethostname(),
],
// Auto trace IDs
autoTraceId: false,
));use LogWard\SDK\Enums\LogLevel;
$client->debug('service-name', 'Debug message');
$client->info('service-name', 'Info message', ['userId' => 123]);
$client->warn('service-name', 'Warning message');
$client->error('service-name', 'Error message', ['custom' => 'data']);
$client->critical('service-name', 'Critical message');The SDK automatically serializes Throwable objects:
try {
throw new RuntimeException('Database timeout');
} catch (Exception $e) {
// Automatically serializes error with stack trace
$client->error('database', 'Query failed', $e);
}Generated log metadata:
{
"error": {
"name": "RuntimeException",
"message": "Database timeout",
"stack": "...",
"file": "/path/to/file.php",
"line": 42
}
}Track requests across services with trace IDs.
$client->setTraceId('request-123');
$client->info('api', 'Request received');
$client->info('database', 'Querying users');
$client->info('api', 'Response sent');
$client->setTraceId(null); // Clear context$client->withTraceId('request-456', function() use ($client) {
$client->info('api', 'Processing in context');
$client->warn('cache', 'Cache miss');
});
// Trace ID automatically restored after closureuse Ramsey\Uuid\Uuid;
$client->withNewTraceId(function() use ($client) {
$client->info('worker', 'Background job started');
$client->info('worker', 'Job completed');
});Search and retrieve logs programmatically.
use LogWard\SDK\Models\QueryOptions;
use LogWard\SDK\Enums\LogLevel;
$result = $client->query(new QueryOptions(
service: 'api-gateway',
level: LogLevel::ERROR,
from: new DateTime('-24 hours'),
to: new DateTime(),
limit: 100,
offset: 0,
));
echo "Found {$result->total} logs\n";
foreach ($result->logs as $log) {
print_r($log);
}$result = $client->query(new QueryOptions(
q: 'timeout',
limit: 50,
));$logs = $client->getByTraceId('trace-123');
echo "Trace has " . count($logs) . " logs\n";use LogWard\SDK\Models\AggregatedStatsOptions;
$stats = $client->getAggregatedStats(new AggregatedStatsOptions(
from: new DateTime('-7 days'),
to: new DateTime(),
interval: '1h',
));
foreach ($stats->topServices as $service) {
echo "{$service['service']}: {$service['count']} logs\n";
}Stream logs in real-time using Server-Sent Events.
$client->stream(
onLog: function($log) {
echo "[{$log['time']}] {$log['level']}: {$log['message']}\n";
},
onError: function($error) {
echo "Stream error: {$error->getMessage()}\n";
},
filters: [
'service' => 'api-gateway',
'level' => 'error',
]
);
// Note: This blocks. Run in separate process for production.Track SDK performance and health.
$metrics = $client->getMetrics();
echo "Logs sent: {$metrics->logsSent}\n";
echo "Logs dropped: {$metrics->logsDropped}\n";
echo "Errors: {$metrics->errors}\n";
echo "Retries: {$metrics->retries}\n";
echo "Avg latency: {$metrics->avgLatencyMs}ms\n";
echo "Circuit breaker trips: {$metrics->circuitBreakerTrips}\n";
// Get circuit breaker state
echo $client->getCircuitBreakerState()->value; // CLOSED|OPEN|HALF_OPEN
// Reset metrics
$client->resetMetrics();Auto-log all HTTP requests and responses.
// app/Http/Kernel.php or bootstrap/app.php
use LogWard\SDK\Middleware\LaravelMiddleware;
$middleware->append(LaravelMiddleware::class);
// Service Provider
use LogWard\SDK\LogWardClient;
use LogWard\SDK\Models\LogWardClientOptions;
$this->app->singleton(LogWardClient::class, function() {
return new LogWardClient(new LogWardClientOptions(
apiUrl: env('LOGWARD_API_URL'),
apiKey: env('LOGWARD_API_KEY'),
));
});Logged automatically:
- Request:
POST /api/users - Response:
POST /api/users 201 (45ms) - Errors:
Request error: Internal Server Error
// config/services.yaml
services:
LogWard\SDK\Middleware\SymfonySubscriber:
arguments:
$client: '@LogWard\SDK\LogWardClient'
$serviceName: '%env(APP_NAME)%'
tags:
- { name: kernel.event_subscriber }Compatible with Slim, Mezzio, and other PSR-15 frameworks.
use LogWard\SDK\Middleware\Psr15Middleware;
$app->add(new Psr15Middleware(
client: $client,
serviceName: 'slim-api',
));See the examples/ directory for complete working examples:
- basic.php - Simple usage
- advanced.php - All advanced features
- laravel.php - Laravel integration
- symfony.php - Symfony integration
new LogWardClient(LogWardClientOptions $options)log(LogEntry $entry): voiddebug(string $service, string $message, array $metadata = []): voidinfo(string $service, string $message, array $metadata = []): voidwarn(string $service, string $message, array $metadata = []): voiderror(string $service, string $message, array|Throwable $metadataOrError = []): voidcritical(string $service, string $message, array|Throwable $metadataOrError = []): void
setTraceId(?string $traceId): voidgetTraceId(): ?stringwithTraceId(string $traceId, callable $fn): mixedwithNewTraceId(callable $fn): mixed
query(QueryOptions $options): LogsResponsegetByTraceId(string $traceId): arraygetAggregatedStats(AggregatedStatsOptions $options): AggregatedStatsResponse
stream(callable $onLog, ?callable $onError = null, array $filters = []): void
getMetrics(): ClientMetricsresetMetrics(): voidgetCircuitBreakerState(): CircuitState
flush(): voidclose(): void
Run the test suite:
# Install dependencies
composer install
# Run tests
composer test
# Run with coverage
composer test:coverage
# Run PHPStan
composer phpstan
# Code style check
composer csMIT
Contributions are welcome! Please open an issue or PR on GitHub.
- Documentation: https://logward.dev/docs
- Issues: GitHub Issues