google/cloud-logging
Idiomatic PHP client for Google Cloud Logging (Stackdriver). Write, store, search, and analyze logs from Google Cloud and AWS. Supports REST and gRPC (including streaming). Install via Composer and authenticate with Google Cloud credentials.
Installation:
composer require google/cloud-logging
Ensure your project uses PHP 8.0+ (tested up to 8.4).
Authentication:
Set up credentials via environment variables or a service account key file. Follow the Authentication Guide.
Example (using GOOGLE_APPLICATION_CREDENTIALS):
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account.json"
First Log Entry:
Use the Logger class to write logs with severity levels:
use Google\Cloud\Logging\V2\Logger;
use Google\Cloud\Logging\V2\LogEntry;
use Google\Cloud\Logging\V2\LogSeverity;
$logger = new Logger(['projectId' => 'your-project-id']);
$logEntry = (new LogEntry())
->setTextPayload('Application started')
->setSeverity(LogSeverity::INFO);
$logger->write($logEntry);
First Query:
Fetch logs using the EntriesClient:
use Google\Cloud\Logging\V2\EntriesClient;
use Google\Cloud\Logging\V2\ListLogEntriesRequest;
$entriesClient = new EntriesClient(['projectId' => 'your-project-id']);
$request = (new ListLogEntriesRequest())
->setResourceNames(['projects/your-project-id'])
->setFilter('severity=ERROR');
$iterator = $entriesClient->listLogEntries($request);
foreach ($iterator as $logEntry) {
echo $logEntry->getTextPayload() . PHP_EOL;
}
Integrate with existing Monolog setups using a custom handler:
use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;
use Google\Cloud\Logging\V2\Logger as CloudLogger;
use Google\Cloud\Logging\V2\LogEntry;
use Google\Cloud\Logging\V2\LogSeverity;
class CloudLoggingHandler extends AbstractProcessingHandler {
private $cloudLogger;
public function __construct(string $projectId) {
$this->cloudLogger = new CloudLogger(['projectId' => $projectId]);
parent::__construct(Monolog\Logger::DEBUG);
}
protected function write(array $record): void {
$logEntry = (new LogEntry())
->setTextPayload($record['formatted'])
->setSeverity($this->mapSeverity($record['level']))
->setResource((new \Google\Cloud\Logging\V2\LogResource())
->setType('global')
->setLabels(['service' => 'your-service-name']));
$this->cloudLogger->write($logEntry);
}
private function mapSeverity(int $level): LogSeverity {
return match ($level) {
Monolog\Logger::DEBUG => LogSeverity::DEBUG,
Monolog\Logger::INFO => LogSeverity::INFO,
Monolog\Logger::NOTICE => LogSeverity::NOTICE,
Monolog\Logger::WARNING => LogSeverity::WARNING,
Monolog\Logger::ERROR => LogSeverity::ERROR,
Monolog\Logger::CRITICAL => LogSeverity::CRITICAL,
Monolog\Logger::ALERT => LogSeverity::EMERGENCY,
default => LogSeverity::DEBUG,
};
}
}
// Usage:
$monolog = new Logger('name');
$monolog->pushHandler(new CloudLoggingHandler('your-project-id'));
$monolog->info('This is a test log');
Use writeAll() to batch log entries and reduce API calls:
$logger = new Logger(['projectId' => 'your-project-id']);
$entries = [];
// Simulate batching (e.g., from a queue or bulk operation)
for ($i = 0; $i < 100; $i++) {
$entries[] = (new LogEntry())
->setTextPayload("Log entry $i")
->setSeverity(LogSeverity::INFO);
}
$logger->writeAll($entries);
Fetch logs with filters and pagination:
$entriesClient = new EntriesClient(['projectId' => 'your-project-id']);
$request = (new ListLogEntriesRequest())
->setResourceNames(['projects/your-project-id/logs/my-log'])
->setFilter('severity=ERROR AND timestamp>="2023-01-01T00:00:00Z"')
->setPageSize(100)
->setPageToken($nextPageToken); // For pagination
$iterator = $entriesClient->listLogEntries($request);
foreach ($iterator as $logEntry) {
echo $logEntry->getTextPayload() . PHP_EOL;
}
Automatically include Cloud Run metadata (e.g., revision, container ID):
$logger = new Logger([
'projectId' => 'your-project-id',
'loggerName' => 'cloud-run-logs',
]);
$logEntry = (new LogEntry())
->setTextPayload('Request processed')
->setSeverity(LogSeverity::INFO)
->setResource((new \Google\Cloud\Logging\V2\LogResource())
->setType('cloud_run_revision')
->setLabels([
'revision_name' => 'your-revision-id',
'service_name' => 'your-service-name',
]));
$logger->write($logEntry);
Use Cloud Logging’s built-in export to BigQuery (configured via GCP Console) and query results directly:
use Google\Cloud\BigQuery\BigQueryClient;
$bigQuery = new BigQueryClient(['projectId' => 'your-project-id']);
$query = '
SELECT
timestamp,
severity,
textPayload
FROM `your-project-id._Default.CloudLogging_Logs`
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
';
$results = $bigQuery->query($query);
foreach ($results as $row) {
echo $row['textPayload'] . PHP_EOL;
}
Service Provider Setup:
Register the logging client in AppServiceProvider:
use Illuminate\Support\ServiceProvider;
use Google\Cloud\Logging\V2\Logger;
class LoggingServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('google.cloud.logging', function () {
return new Logger([
'projectId' => config('services.google.cloud.project_id'),
'loggerName' => config('services.google.cloud.logger_name', 'laravel-app'),
]);
});
}
}
Logging Middleware: Capture HTTP requests/responses:
use Closure;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class LoggingMiddleware {
public function handle(Request $request, Closure $next): Response {
$logger = app('google.cloud.logging');
$startTime = microtime(true);
$response = $next($request);
$duration = microtime(true) - $startTime;
$logEntry = (new \Google\Cloud\Logging\V2\LogEntry())
->setTextPayload(sprintf(
'HTTP %s %s in %.2fms',
$request->method(),
$request->path(),
$duration * 1000
))
->setSeverity(\Google\Cloud\Logging\V2\LogSeverity::INFO)
->setResource((new \Google\Cloud\Logging\V2\LogResource())
->setType('http_request')
->setLabels([
'method' => $request->method(),
'path' => $request->path(),
'status' => $response->getStatusCode(),
]));
$logger->write($logEntry);
return $response;
}
}
Exception Logging: Override Laravel’s exception handler:
How can I help you explore Laravel packages today?