PHP
Send logs from PHP applications to Parseable
Send logs from PHP applications to Parseable using HTTP or logging libraries.
Overview
Integrate PHP with Parseable to:
- Application Logs - Send structured logs from PHP apps
- Laravel/Symfony - Works with popular frameworks
- Monolog Integration - Use with Monolog handler
- Structured Logging - JSON-formatted log entries
Prerequisites
- PHP 7.4+
- Parseable instance accessible
- cURL extension or Guzzle HTTP client
Basic HTTP Integration
Using cURL
<?php
class ParseableLogger
{
private string $url;
private string $dataset;
private string $auth;
public function __construct(string $url, string $dataset, string $username, string $password)
{
$this->url = rtrim($url, '/') . '/api/v1/ingest';
$this->dataset = $dataset;
$this->auth = base64_encode("$username:$password");
}
public function log(string $level, string $message, array $context = []): void
{
$entry = [
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
'level' => $level,
'message' => $message,
...$context
];
$this->send([$entry]);
}
public function info(string $message, array $context = []): void
{
$this->log('info', $message, $context);
}
public function error(string $message, array $context = []): void
{
$this->log('error', $message, $context);
}
public function warning(string $message, array $context = []): void
{
$this->log('warning', $message, $context);
}
private function send(array $entries): void
{
$ch = curl_init($this->url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($entries),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"Authorization: Basic {$this->auth}",
"X-P-Stream: {$this->dataset}"
],
CURLOPT_TIMEOUT => 5
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
error_log("Failed to send log to Parseable: HTTP $httpCode");
}
}
}
// Usage
$logger = new ParseableLogger(
'http://parseable:8000',
'php-app',
'admin',
'admin'
);
$logger->info('Application started', ['version' => '1.0.0']);
$logger->error('Database error', ['error' => 'Connection refused']);Using Guzzle
<?php
use GuzzleHttp\Client;
class ParseableLogger
{
private Client $client;
private string $dataset;
public function __construct(string $url, string $dataset, string $username, string $password)
{
$this->dataset = $dataset;
$this->client = new Client([
'base_uri' => $url,
'auth' => [$username, $password],
'timeout' => 5.0,
]);
}
public function log(string $level, string $message, array $context = []): void
{
$entry = [
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
'level' => $level,
'message' => $message,
...$context
];
try {
$this->client->post('/api/v1/ingest', [
'json' => [$entry],
'headers' => [
'X-P-Stream' => $this->dataset
]
]);
} catch (\Exception $e) {
error_log("Failed to send log: " . $e->getMessage());
}
}
}Monolog Handler
Create a custom Monolog handler:
<?php
namespace App\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\LogRecord;
class ParseableHandler extends AbstractProcessingHandler
{
private string $url;
private string $dataset;
private string $auth;
private array $buffer = [];
private int $batchSize;
public function __construct(
string $url,
string $dataset,
string $username,
string $password,
int $batchSize = 100,
$level = Logger::DEBUG,
bool $bubble = true
) {
parent::__construct($level, $bubble);
$this->url = rtrim($url, '/') . '/api/v1/ingest';
$this->dataset = $dataset;
$this->auth = base64_encode("$username:$password");
$this->batchSize = $batchSize;
}
protected function write(LogRecord $record): void
{
$this->buffer[] = [
'timestamp' => $record->datetime->format('Y-m-d\TH:i:s.v\Z'),
'level' => strtolower($record->level->name),
'message' => $record->message,
'channel' => $record->channel,
'context' => $record->context,
'extra' => $record->extra
];
if (count($this->buffer) >= $this->batchSize) {
$this->flush();
}
}
public function flush(): void
{
if (empty($this->buffer)) {
return;
}
$entries = $this->buffer;
$this->buffer = [];
$ch = curl_init($this->url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($entries),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"Authorization: Basic {$this->auth}",
"X-P-Stream: {$this->dataset}"
]
]);
curl_exec($ch);
curl_close($ch);
}
public function close(): void
{
$this->flush();
parent::close();
}
}Laravel Integration
Custom Log Channel
In config/logging.php:
'channels' => [
'parseable' => [
'driver' => 'custom',
'via' => App\Logging\CreateParseableLogger::class,
'url' => env('PARSEABLE_URL'),
'dataset' => env('PARSEABLE_STREAM', 'laravel-app'),
'username' => env('PARSEABLE_USERNAME'),
'password' => env('PARSEABLE_PASSWORD'),
],
],Create app/Logging/CreateParseableLogger.php:
<?php
namespace App\Logging;
use Monolog\Logger;
class CreateParseableLogger
{
public function __invoke(array $config): Logger
{
$logger = new Logger('parseable');
$logger->pushHandler(new ParseableHandler(
$config['url'],
$config['dataset'],
$config['username'],
$config['password']
));
return $logger;
}
}Usage
Log::channel('parseable')->info('User logged in', ['user_id' => 123]);Symfony Integration
Service Configuration
# config/services.yaml
services:
App\Logging\ParseableHandler:
arguments:
$url: '%env(PARSEABLE_URL)%'
$dataset: '%env(PARSEABLE_STREAM)%'
$username: '%env(PARSEABLE_USERNAME)%'
$password: '%env(PARSEABLE_PASSWORD)%'Monolog Configuration
# config/packages/monolog.yaml
monolog:
handlers:
parseable:
type: service
id: App\Logging\ParseableHandlerBest Practices
- Use Batching - Buffer logs and send in batches
- Async Sending - Use queues for non-blocking sends
- Handle Failures - Log locally on send failures
- Add Context - Include request ID, user ID
- Flush on Shutdown - Register shutdown handler
Troubleshooting
Connection Errors
- Verify cURL extension is installed
- Check Parseable URL is accessible
- Verify SSL certificates
Missing Logs
- Check buffer is being flushed
- Verify dataset name
- Check for cURL errors
Next Steps
- Configure alerts for error patterns
- Create dashboards for PHP metrics
- Explore OpenTelemetry for tracing
Was this page helpful?