google/cloud-logging
Idiomatic PHP client for Google Cloud Logging (formerly Stackdriver) to store, search, analyze, monitor, and alert on log data from Google Cloud and AWS. Install via Composer; supports REST and gRPC.
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?