influxdata/influxdb-client-php
Installation Add the package via Composer:
composer require influxdata/influxdb-client-php
Ensure your Laravel project has PHP 8.1+ (required by the package).
Basic Setup
Configure the client in config/services.php:
'influxdb' => [
'url' => env('INFLUXDB_URL', 'http://localhost:8086'),
'token' => env('INFLUXDB_TOKEN'),
'org' => env('INFLUXDB_ORG'),
'bucket' => env('INFLUXDB_BUCKET'),
],
Publish the config (if needed):
php artisan vendor:publish --provider="InfluxData\InfluxDBClient\InfluxDBClientServiceProvider"
First Write Operation Inject the client in a service or controller:
use InfluxData\InfluxDBClient\InfluxDBClient;
use InfluxData\InfluxDBClient\Domain\Write\Point;
public function __construct(private InfluxDBClient $client) {}
public function logMetric(string $measurement, array $tags, array $fields) {
$point = Point::measurement($measurement)
->tag($tags)
->floatField('value', $fields['value'])
->timestamp(time(), WritePrecision::S);
$this->client->getWriteApi()->writePoint($point);
}
First Query Use the query API to fetch data:
$queryApi = $this->client->getQueryApi();
$result = $queryApi->query('from(bucket:"my-bucket") |> range(start: -1h)');
foreach ($result as $row) {
// Process rows
}
Structured Logging Use a facade or service to abstract writes:
// app/Services/MetricsLogger.php
class MetricsLogger {
public function __construct(private InfluxDBClient $client) {}
public function log(string $measurement, array $data) {
$point = Point::measurement($measurement)
->addTags($data['tags'] ?? [])
->addFields($data['fields']);
$this->client->getWriteApi()->writePoint($point);
}
}
Call from anywhere:
$logger->log('api_requests', [
'tags' => ['endpoint' => '/users'],
'fields' => ['duration_ms' => 150, 'status' => 200],
]);
Batch Writes For high-throughput scenarios, use batch writes:
$writeApi = $this->client->getWriteApi();
$writeApi->writePoint($point1);
$writeApi->writePoint($point2);
$writeApi->flush(); // Force sync write
Query Caching Cache frequent queries (e.g., dashboards) in Laravel’s cache:
$cacheKey = 'influx_query_dashboard';
$result = Cache::remember($cacheKey, now()->addMinutes(5), function () {
return $this->client->getQueryApi()->query('from(bucket:"dashboard") |> ...');
});
Error Handling Wrap operations in try-catch:
try {
$this->client->getWriteApi()->writePoint($point);
} catch (InfluxDBException $e) {
Log::error("InfluxDB write failed: " . $e->getMessage());
// Retry or fallback logic
}
Async Processing Use queues for non-critical writes:
// Dispatch a job
LogMetricJob::dispatch($measurement, $tags, $fields);
// Job class
class LogMetricJob implements ShouldQueue {
public function handle() {
$this->client->getWriteApi()->writePoint($this->point);
}
}
Laravel Events
Hook into events (e.g., job.failed) to log metrics:
event(new JobFailed($job, $exception));
// In listener:
$logger->log('job_failures', ['job' => $job->name, 'exception' => $exception->getMessage()]);
Middleware Log request metrics in middleware:
public function handle($request, Closure $next) {
$start = microtime(true);
$response = $next($request);
$duration = (microtime(true) - $start) * 1000;
$logger->log('http_requests', [
'tags' => ['path' => $request->path()],
'fields' => ['duration_ms' => $duration, 'status' => $response->status()],
]);
return $response;
}
Artisan Commands Schedule data cleanup or maintenance:
class PruneOldData extends Command {
protected $signature = 'influx:prune';
public function handle() {
$this->client->getQueryApi()->query('delete from(bucket:"logs") where time < now() - 30d');
}
}
Token Permissions
try {
$this->client->getWriteApi()->writePoint($point);
} catch (InfluxDBException $e) {
if ($e->getStatusCode() === 403) {
Log::error("Permission denied. Check token/org/bucket.");
}
}
Connection Timeouts
$options = ['timeout' => 10.0];
$client = InfluxDBClientFactory::create($url, $token, $options);
Query Syntax
from(bucket: "...").time() without a range filter (returns no data).Point Overhead
$writeApi = $this->client->getWriteApi();
$writeApi->setBatchSize(1000); // Points per batch
$writeApi->setFlushInterval(5000); // ms
Thread Safety
Enable Logging Configure Monolog to log InfluxDB requests:
$client = InfluxDBClientFactory::create($url, $token, [
'logger' => new Monolog\Logger('influx', [new Monolog\Handler\StreamHandler(storage_path('logs/influx.log'))]),
]);
Check HTTP Status Codes
Catch InfluxDBException and log the status code:
catch (InfluxDBException $e) {
Log::error("InfluxDB Error: {$e->getStatusCode()} - {$e->getMessage()}");
}
Validate Points
Use Point::validate() to catch malformed data:
$point = Point::measurement('test')->floatField('value', 'invalid');
if (!$point->validate()) {
throw new \InvalidArgumentException("Invalid point: " . $point->getError());
}
Custom Writers
Extend WriteApi for domain-specific logic:
class CustomWriteApi extends WriteApi {
public function writeUserEvent(string $event, array $data) {
$point = Point::measurement('user_events')
->tag(['event' => $event])
->addFields($data);
$this->writePoint($point);
}
}
Query Builders Create a fluent query builder:
class InfluxQueryBuilder {
private $query = '';
public function fromBucket(string $bucket): self {
$this->query .= "from(bucket:\"{$bucket}\")";
return $this;
}
public function range(int $hours): self {
$this->query .= " |> range(start: -{$hours}h)";
return $this;
}
public function build(): string {
return $this->query;
}
}
Usage:
$query = (new InfluxQueryBuilder())
How can I help you explore Laravel packages today?