logs: graceful watch exit and Cloud Logging API quota compliance
- Dominant language
- TypeScript
- Stars
- 5.8k
- Forks
- 510
- Avg merge
- 5h 27m
- Merged PRs (30d)
- 1
Description
## Expected Behavior
- `clasp logs --watch` (`tail-logs`) exits gracefully on `SIGINT`/`SIGTERM` by clearing active timers and resolving the polling promise.
- Transient API fetch errors during log polling are caught and logged to stderr without uncaught promise rejections crashing the process.
- Cloud Logging requests attribute quota to the configured GCP project via `x-goog-user-project: ` rather than the global shared OAuth client (`1072944905499`).
- Log polling rate and pagination in `Logs.getLogEntries` stay within Google Cloud Logging API quota (60 read requests/minute).
## Actual Behavior
- `clasp logs --watch` does not clean up polling interval timers on termination signals, preventing clean process exit.
- Unhandled API errors during async log polling can bypass standard error logging or break execution.
- Requests without `x-goog-user-project` attribute quota to the global shared OAuth client project (`1072944905499`), causing global quota collision.
- Default pagination in `fetchWithPages` combined with polling interval causes requests to exceed Google Cloud Logging API read quota limit (60 req/min), triggering `429 RESOURCE_EXHAUSTED: Quota exceeded for quota metric Read requests`.
The following is a snippet of the console output on exit.
```
$ clasp logs --watch
...
Error: Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute' of service 'logging.googleapis.com' for consumer 'project_number:1072944905499'.
at Gaxios._request (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/gaxios/build/cjs/src/gaxios.js:155:23)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async UserRefreshClient.requestAsync (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/google-auth-library/build/src/auth/oauth2client.js:463:20)
at async createAPIRequestAsync (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/googleapis-common/build/src/apirequest.js:308:25)
at async file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/core/logs.js:51:29
at async fetchWithPages (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/core/utils.js:90:22)
at async file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:32:67
at async withSpinner (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/utils.js:93:16)
at async fetchAndPrintLogs (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:32:25)
at async Timeout._onTimeout (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:63:13)
Error: Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute' of service 'logging.googleapis.com' for consumer 'project_number:1072944905499'.
at Gaxios._request (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/gaxios/build/cjs/src/gaxios.js:155:23)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async UserRefreshClient.requestAsync (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/google-auth-library/build/src/auth/oauth2client.js:463:20)
at async createAPIRequestAsync (/home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/node_modules/googleapis-common/build/src/apirequest.js:308:25)
at async file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/core/logs.js:51:29
at async fetchWithPages (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/core/utils.js:90:22)
at async file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:32:67
at async withSpinner (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/utils.js:93:16)
at async fetchAndPrintLogs (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:32:25)
at async Timeout._onTimeout (file:///home/lucasrangit/.nvm/versions/node/v24.14.0/lib/node_modules/@google/clasp/build/src/commands/tail-logs.js:63:13)
```
The following is an example of the quota exceeded console message that shows that quota from the shared GCP project https://console.cloud.google.com/home/dashboard?project=1072944905499 is being used not the configured `.clasp.json` project ID:
```
Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute' of service 'logging.googleapis.com' for consumer 'project_number:1072944905499'.
Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute' of service 'logging.googleapis.com' for consumer 'project_number:1072944905499'.
```
## Steps to Reproduce the Problem
1. Run `clasp logs --watch` on a project linked to Google Cloud Platform.
1. Send `SIGINT` (`Ctrl+C`) -> process does not clean up active polling timer before exit.
1. Run `clasp logs --watch` continuously on an active project -> Cloud Logging API throws 429 quota exhaustion.
## Specifications
- Node version (`node -v`): v20.x / v22.x
- Version (`clasp -v`): 3.4.1
- OS (Mac/Linux/Windows): Linux / macOS / Windows
## Proposed Fixes
1. https://github.com/lucasrangit/clasp/pull/1
1. https://github.com/lucasrangit/clasp/pull/2
Contributor guide
Research direction
Start with the polling entry points shown in commands/tail-logs.js, core/logs.js, and core/utils.js, tracing timer cleanup, error handling, pagination, and request headers. Run clasp logs --watch and reproduce SIGINT plus the 429 response; done means graceful termination, logged transient errors, project-attributed requests, and polling within the documented quota.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- google-cloud, typescript
- Domain
- api, cli, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100