Google Cloud Operations¶
Google Cloud Operations (formerly Stackdriver) covers both Cloud Logging and Cloud Monitoring. A single SerOps integration serves both — one service-account key, one config record, both capabilities.
| Type | Logs + Metrics |
| Auth | Service-account JSON key |
| Log Query Language | Cloud Logging filter syntax |
| Metric Query Language | Cloud Monitoring filter |
| SDK | google-cloud-logging + google-cloud-monitoring |
Prerequisites¶
- A GCP project where your workloads write logs and expose metrics
- A service account with these IAM roles on the target project:
roles/logging.viewerfor Cloud Logging read accessroles/monitoring.viewerfor Cloud Monitoring read access- The service-account JSON key (Console → IAM → Service Accounts → Keys → Add Key → JSON)
- Network egress from the SerOps backend to
logging.googleapis.com+monitoring.googleapis.com
Store the key file carefully
The service-account JSON is a full credential — anyone with a copy can read logs and metrics until you rotate the key. Never paste it into a screenshot or a public issue. SerOps encrypts it at rest with Fernet the moment you save the integration.
Configuration¶
{
"provider": "gcp",
"display_name": "GCP · production project",
"capabilities": ["logs", "metrics"],
"password": "{\"type\":\"service_account\",\"project_id\":\"prod-42\",...}",
"extra_config": {
"project_id": "prod-42"
}
}
Notes:
passwordmust contain the entire JSON key file contents (a single JSON string). SerOps parses + validates it on save; a malformed or non-service-account key fails fast rather than blowing up on the first search.extra_config.project_idis required and must match theproject_idinside the JSON key. Two separate fields because Cloud Logging + Cloud Monitoring endpoints take the project name in the request, not the credential.
Authentication¶
SerOps deliberately loads credentials only from the JSON key you paste, never from Application Default Credentials, GCE metadata service, or any host-level auth. This matters for multi-tenant deployments: without the explicit-credential rule, a SerOps process running on a GCE VM would silently pick up whatever service account the VM has attached — which almost certainly is not the customer's project.
To rotate the key:
- Create a new key in the GCP Console for the same service account
- Update the
passwordfield on the integration (SerOps re-encrypts) - Delete the old key in the GCP Console
What SerOps does with your query¶
Logs (GcpCloudLoggingProvider):
The canonical LogQuery translates via to_gcp_filter() into GCP filter syntax:
severity>=ERROR
AND labels.project_name="acme-checkout"
AND labels.environment="production"
AND (labels.service_name="backend-api" OR labels.service_name="payment-worker")
AND jsonPayload.message:"timeout"
AND timestamp>="2026-08-27T09:00:00Z"
AND timestamp<="2026-08-27T10:00:00Z"
- Severity is expressed as
>=THRESHOLDusing GCP's ordinal severity scale (DEBUG=100, INFO=200, NOTICE=300, WARNING=400, ERROR=500, CRITICAL=600, ALERT=700, EMERGENCY=800). Requesting["ERROR", "WARNING"]becomesseverity>=WARNING— captures everything at or above the lowest requested level. - Time range is embedded in the filter (unlike Splunk / CloudWatch which take it as a separate param) because Cloud Logging's
list_entriesAPI accepts only the filter as its selector. - Every user-supplied value goes through
_gcp_escape— backslash and double-quote are both escaped. Non-string inputs raiseTypeErrorat build time. - Barewords (severity thresholds, resource types) are validated against a strict
[A-Za-z0-9_]allowlist. Any character outside that set fails loudly rather than being silently rewritten.
Metrics (GcpCloudMonitoringProvider):
The canonical TimeSeries query uses a filter like:
Canonical Prometheus-style metric names (node_cpu_seconds_total, container_memory_usage_bytes) map to the corresponding GCP metric types via a small dictionary in the adapter. Unknown names pass through unchanged so you can query raw GCP types directly.
Health Check¶
Runs the cheapest authenticated call in each capability:
- Logs: single-entry
list_entriesiteration (forces the auth handshake to actually run) - Metrics: single
list_metric_descriptorsiteration
A 200 response with healthy: true proves both the credentials and that the service account has read access to the target project's log/metric data.
Async & Partial Results¶
Cloud Logging and Cloud Monitoring are both paged iterators. SerOps intentionally returns partial results if the iterator raises mid-stream (rate-limits, token refresh mid-stream, etc.) — partial context is more useful than an empty investigation.
Troubleshooting¶
| Issue | Solution |
|---|---|
| "not valid JSON" on save | The password field is not a well-formed JSON string. Paste the whole file contents including the outer { and } |
| "expected a service-account JSON key" | The JSON is well-formed but is not a service-account key (probably a user credential or expired API key) |
project_id missing / mismatch |
The integration record's extra_config.project_id differs from the project_id inside the JSON key. They must match |
| 401 / 403 during search | The service account lacks roles/logging.viewer or roles/monitoring.viewer on the project |
| Empty results with no error | The time-range window has no matching entries, or the log labels differ from SerOps's canonical schema (labels.project_name, labels.environment, labels.service_name). Enrich your log shipper to add those labels |
| Invalid GCP bareword error | A severity string contains characters outside [A-Za-z0-9_] — usually a bad config value |
| Health check passes but searches return nothing | The service account can list metadata but has no data-read grant on the specific log names / metric types |
Kubernetes (GKE) mode¶
Not yet validated on a live GKE cluster
This mode is implemented and unit-tested, but has not yet run against a live GKE cluster. See Tested environments.
For GKE clusters, set the integration's topology_mode to kubernetes.
SerOps will then:
- Route canonical
node_cpu_seconds_total/node_memory_*metric names to their GKE equivalents (kubernetes.io/container/cpu/core_usage_time,kubernetes.io/container/memory/used_bytes, …). - Filter by resource labels (
resource.labels.cluster_name,namespace_name,pod_name,container_name) instead ofmetric.labels.*. Canonical SerOps labels are aliased automatically:
| SerOps label | GKE resource label |
|---|---|
service_name / service / container |
container_name |
namespace |
namespace_name |
pod |
pod_name |
cluster |
cluster_name |
discover_hostsreturns pods (as workload identity) instead of Compute Engine instances.
Prerequisite: GKE Cloud Monitoring for GKE must be enabled on
the cluster (default for standard GKE; check for Autopilot). The
service account needs roles/monitoring.viewer.