Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cloud Error Reporting Laravel Package

google/cloud-error-reporting

Idiomatic PHP client for Google Cloud Error Reporting (Stackdriver), which counts, analyzes, and aggregates crashes across your cloud services. Install via Composer; supports REST and gRPC. Beta component from Google Cloud PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and pick a transport

composer require google/cloud-error-reporting
# optional, only if you want gRPC instead of REST over HTTP/1.1
pecl install grpc

The package ships generated GAPIC clients for the V1beta1 API: ErrorGroupServiceClient, ErrorStatsServiceClient, and ReportErrorsServiceClient, all under Google\Cloud\ErrorReporting\V1beta1\Client\. Use those \Client\ classes — the older non-Client classes were deprecated in v0.22 and removed in v0.26.

2. Authenticate before writing any code

Follow the standard Google Cloud PHP auth chain, not a bespoke one:

  • Local dev: gcloud auth application-default login (ADC picks it up automatically).
  • CI / non-GCP hosts: GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json.
  • Cloud Run / GCE / GKE: metadata server, nothing to configure.

The old credentials client option is deprecated (v0.24); stick with ADC or a credentials fetcher/callback rather than passing raw arrays around.

3. Understand the two things this package does — and which one you actually need

  • Writing errors: ReportErrorsServiceClient::reportErrorEvent() sends a ReportedErrorEvent (message + stack trace + ServiceContext) directly to Error Reporting. You almost never want this in a normal Laravel app.
  • Reading errors: ErrorGroupServiceClient::getGroup() / updateGroup(), and ErrorStatsServiceClient::listGroupStats() / listEvents(). This is the 90% day-to-day use case — building an "errors" panel, a nightly digest command, or an ops dashboard.

Most Laravel apps should report errors by writing structured logs to Cloud Logging (severity ERROR, plus serviceContext and a stack_trace) and let Error Reporting ingest them, then use this package only to query. That avoids a second network call in the request path and gives you the Cloud Console experience for free.

4. First working call — list top error groups for the last hour

use Google\Cloud\ErrorReporting\V1beta1\Client\ErrorStatsServiceClient;
use Google\Cloud\ErrorReporting\V1beta1\ListGroupStatsRequest;
use Google\Cloud\ErrorReporting\V1beta1\QueryTimeRange;
use Google\Cloud\ErrorReporting\V1beta1\QueryTimeRange\Period;

$client = new ErrorStatsServiceClient(); // ['transport' => 'rest'] if no grpc ext

$request = (new ListGroupStatsRequest())
    ->setProjectName(ErrorStatsServiceClient::projectName('my-gcp-project'))
    ->setTimeRange((new QueryTimeRange())->setPeriod(Period::PERIOD_1_HOUR));

foreach ($client->listGroupStats($request)->iterateAllElements() as $stat) {
    printf("%s (%d)\n", $stat->getGroup()->getGroupId(), $stat->getCount());
}

5. First real use case to build: an artisan command (php artisan errors:digest) that pulls listGroupStats for your service for the last 24h and posts new groups to Slack. It is read-only, safe, cheap, and immediately proves the integration.

Implementation Patterns

Route reporting through the exception handler, not controllers

Bind a small ErrorReporter interface in a service provider and call it from bootstrap/app.php / App\Exceptions\Handler::report():

public function register(): void
{
    $this->app->singleton(ErrorReporter::class, fn ($app) => new CloudErrorReporter(
        projectId: config('services.gcp.project'),
        service:   config('app.name'),
        version:   config('app.version', 'dev'),
    ));
}

Report in report(), not render() — render() runs for handled/4xx exceptions you usually don't want counted, and you'd double-report.

Prefer the log-based path and keep the SDK for queries

If you already use google/cloud-logging with Monolog, emit an entry shaped like the Error Reporting log format:

{
  "severity": "ERROR",
  "message": "Unhandled exception: …",
  "serviceContext": { "service": "my-app", "version": "1.4.2" },
  "@type": "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent",
  "stack_trace": "…",
  "context": { "httpRequest": { "method": "POST", "url": "/orders", "userAgent": "…" } }
}

context.httpRequest is generated/supported by this library (v0.21+). Then use ErrorStatsServiceClient only for stats. Pick one path per environment; running both produces duplicate groups and skewed counts.

Sample and buffer — never block the request on a Google API

  • Sample: report 100% of 5xx, ~5–10% of everything else via random_int() or a config-driven rate.
  • Buffer: push report payloads into a queue job, or use dispatchAfterResponse(), or the Laravel terminate() middleware so the client call happens after the response is flushed.
  • For a monolith, an in-memory buffer flushed in a terminating callback reduces round trips dramatically.

Use the static name formatters

Every new-surface client exposes helpers such as ErrorStatsServiceClient::projectName($project) and ErrorGroupServiceClient::groupName($project, $groupId). Do not hand-build projects/…/groups/… strings; group IDs are opaque and easy to mangle.

Query patterns for dashboards

  • QueryTimeRange with a Period enum (PERIOD_1_HOUR, PERIOD_1_DAY, PERIOD_1_WEEK, PERIOD_30_DAYS) is the cheap path. Use explicit startTime/endTime only when you need a custom window — anything older than 30 days is gone.
  • Filter with ServiceContextFilter (service, version) so multi-tenant apps don't blend services.
  • Use iterateAllElements() for full pagination, or ->getPage()->getPageElementCount() plus getNextPageToken() when you need explicit control.
  • For listEvents, cap pageSize and use TimedCountAlignment / setPageSize() deliberately — this is the most expensive call in the API.
  • Cache dashboard results for 60–300s in Redis; the underlying data doesn't change fast enough to justify per-request calls.

Build an ops/tooling layer, not a user-facing feature

The realistic Laravel wins are: an /admin/errors page, an artisan digest, an on-call Slack alert job, and a "recent regressions after deploy" widget keyed on version from serviceContext. These map cleanly onto listGroupStats + getGroup.

Test against a fake, not the API

$this->app->instance(ErrorReporter::class, new FakeErrorReporter());
$this->assertCount(1, $fake->reported());

For client-level tests, Mockery::mock(ErrorStatsServiceClient::class) works because the class is not final in the generated surface. Don't let CI touch real GCP.

Gotchas and Tips

This is a 0.x beta package. Pin ^0.27 and read the release notes before bumping. v0.26 removed the deprecated GAPIC classes — a silent breaking change if you copy an older tutorial. composer why google/cloud-error-reporting on every major Laravel/PHP upgrade.

Reporting to the API ≠ appearing in Cloud Logging. reportErrorEvent() writes to Error Reporting's own store; it does not create log entries. Conversely, Error Reporting's automatic ingestion (Cloud Run, GAE, GKE) reads logs. Mixing the two gives you two different error counts in two different consoles. Choose consciously and document it.

Missing serviceContext.service lands everything under "unknown". This is the single most common reason dashboards look empty. Set service + version explicitly on every report/log entry, and use the same values Cloud Run/GKE would infer.

Never let monitoring break the app. Wrap every client call in try { } catch (\Throwable $e) { Log::warning(...); }. A Google\ApiCore\ApiException on a network blip inside Handler::report() will turn a 500 into a fatal. Also guard against recursion: if the logger or queue that reports errors itself throws, you get a loop.

Error grouping is stack-trace based. Small refactors, varying closure line numbers, or interpolated values in the message fragment groups badly. Keep messages stable and strip absolute paths / temp paths from stack_trace before reporting.

Redact before you send. ReportedErrorEvent payloads routinely capture PDO DSNs, bearer tokens, and user emails from exception messages. Sanitize in one place (a Sanitizer class) rather than per call site.

getGroup() throws NOT_FOUND for groups that were auto-deleted or aged out. Treat 404 as a normal branch, not an error — check $ex->getStatus() / getDetails() for diagnostics.

Transport and latency. gRPC is faster but requires the extension and adds cold-start cost on serverless (Bref, Lambda, Cloud Run scale-to-zero). Default to ['transport' => 'rest'] there, and set an explicit ['timeoutMillis' => 500] or requestTimeout — the default timeouts are far longer than you want in a request lifecycle.

The client has its own logger. Pass ['logger' => $psrLogger] in the client options to see actual RPCs, retries, and auth resolution. This is the fastest way to diagnose "it works locally, not in prod" — you'll usually see Could not load the default credentials or a project-ID mismatch.

Retries/backoff are configured via RetrySettings in the client options. Defaults are sane; only override if you're batching large listEvents queries, and add jitter when running many workers.

Local development: set ERROR_REPORTING_ENABLED=false in .env and bind a no-op reporter. Otherwise every dev-time exception hits your production project (or fails auth and slows the request).

Project ID resolution falls back to the metadata server / GOOGLE_CLOUD_PROJECT. If you run outside GCP, pass it explicitly in client options; a wrong project silently reports into a project you don't own.

Extension point: keep ErrorReporter as an interface with Cloud, Log-only, Sentry, and Fake implementations. It's the only way to swap vendors without touching Handler, and it keeps the beta status of this package from becoming an architectural dependency.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings