google-cloud-logging
The google-cloud-logging plugin sends APISIX and API7 Gateway request and response logs to Google Cloud Logging in batches. It supports monitored-resource selection and customizable log formats.
Examples
The examples show how to send gateway logs to Google Cloud Logging with a service-account key and add fields with plugin metadata.
The plugin does not use Application Default Credentials. It requires either service-account key fields in auth_config or the path to a service-account key file in auth_file. Google recommends avoiding user-managed service-account keys when a more secure authentication method is available. If an organization policy prevents key creation, the plugin cannot authenticate with its current configuration interface.
To prepare a dedicated service account for these examples:
- In Google Cloud, select the project that will receive the logs.
- Go to IAM & Admin → Service Accounts and create or select a dedicated service account.
- Grant the service account the Logs Writer role (
roles/logging.logWriter). - On the service account's Keys tab, select Add key → Create new key, choose JSON, and select Create.
Google lets you download the key file only once. Store it in the organization's credential-management system, do not commit it to source control, and revoke it when it is no longer required.
Configure Credentials Inline
The auth_config field configures the service-account email, project ID, private key, and OAuth token endpoint directly on the plugin instance. Use this option only when the deployment's secret-delivery system can inject the values without committing the private key to a declarative file.
Create a route with the google-cloud-logging plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "google-cloud-logging-route",
"uri": "/anything",
"plugins": {
"google-cloud-logging": {
"auth_config": {
"client_email": "replace-with-service-account@your-project-id.iam.gserviceaccount.com",
"project_id": "your-project-id",
"private_key": "replace-with-private-key",
"token_uri": "https://oauth2.googleapis.com/token"
},
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'services:
- name: httpbin
labels:
docs-example: google-cloud-logging
routes:
- uris:
- /anything
name: google-cloud-logging-route
plugins:
google-cloud-logging:
auth_config:
client_email: "replace-with-service-account@your-project-id.iam.gserviceaccount.com"
project_id: "your-project-id"
private_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
token_uri: "https://oauth2.googleapis.com/token"
batch_max_size: 1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Preview changes to services with the example label:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=google-cloud-loggingSynchronize the reviewed changes:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=google-cloud-loggingapiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: google-cloud-logging-plugin-config
spec:
plugins:
- name: google-cloud-logging
config:
auth_config:
client_email: "replace-with-service-account@your-project-id.iam.gserviceaccount.com"
project_id: "your-project-id"
private_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
token_uri: "https://oauth2.googleapis.com/token"
batch_max_size: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: google-cloud-logging-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: google-cloud-logging-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: google-cloud-logging-route
spec:
ingressClassName: apisix
http:
- name: google-cloud-logging-route
match:
paths:
- /anything
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: google-cloud-logging
config:
auth_config:
client_email: "replace-with-service-account@your-project-id.iam.gserviceaccount.com"
project_id: "your-project-id"
private_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
token_uri: "https://oauth2.googleapis.com/token"
batch_max_size: 1Apply the configuration:
kubectl apply -f google-cloud-logging-ic.yamlThe example sends each log entry immediately for verification.
❶ Configure the dedicated service account email.
❷ Configure the Google Cloud project ID that receives the logs.
❸ Configure the private key exactly as it appears in the downloaded JSON file. Preserve the escaped newline characters in JSON payloads.
❹ Keep the Google OAuth token endpoint from the downloaded file. The shown value is the schema default.
Send a request to the route to generate a log entry:
curl -i "http://127.0.0.1:9080/anything"You should receive an HTTP/1.1 200 OK response.
In Google Cloud, open Logging → Logs Explorer and query log_id("apisix.apache.org/logs"). The result should contain fields similar to the following:
{
"httpRequest": {
"requestMethod": "GET",
"requestUrl": "http://127.0.0.1:9080/anything",
"status": 200
},
"resource": {
"type": "global"
},
"labels": {
"source": "apache-apisix-google-cloud-logging"
},
"logName": "projects/your-project-id/logs/apisix.apache.org%2Flogs"
}Load Credentials From a File
The auth_file field keeps the service-account key outside the gateway configuration and points the plugin to a JSON file at runtime. The plugin reads this file directly, requires entries_uri in the file, and uses the cloud-platform OAuth scope when scope is omitted.
Add the following top-level field to the downloaded JSON key:
{
"entries_uri": "https://logging.googleapis.com/v2/entries:write"
}Mount the resulting file into every gateway instance at /usr/local/apisix/conf/gcp-logging-auth.json. Restrict file access to the gateway process and use the deployment's secret-management mechanism instead of baking the key into an image.
Create a route with the google-cloud-logging plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "google-cloud-logging-route",
"uri": "/anything",
"plugins": {
"google-cloud-logging": {
"auth_file": "/usr/local/apisix/conf/gcp-logging-auth.json",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'services:
- name: httpbin
labels:
docs-example: google-cloud-logging
routes:
- uris:
- /anything
name: google-cloud-logging-route
plugins:
google-cloud-logging:
auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json"
batch_max_size: 1
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Preview changes to services with the example label:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=google-cloud-loggingSynchronize the reviewed changes:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=google-cloud-loggingapiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: google-cloud-logging-plugin-config
spec:
plugins:
- name: google-cloud-logging
config:
auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json"
batch_max_size: 1
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: google-cloud-logging-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: google-cloud-logging-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: google-cloud-logging-route
spec:
ingressClassName: apisix
http:
- name: google-cloud-logging-route
match:
paths:
- /anything
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: google-cloud-logging
config:
auth_file: "/usr/local/apisix/conf/gcp-logging-auth.json"
batch_max_size: 1Apply the configuration:
kubectl apply -f google-cloud-logging-ic.yaml❶ Configure the path to the mounted service-account JSON key. The same path must exist in every gateway instance.
Send a request to the route to generate a log entry:
curl -i "http://127.0.0.1:9080/anything"You should receive an HTTP/1.1 200 OK response.
In Google Cloud, open Logging → Logs Explorer and query log_id("apisix.apache.org/logs"). The result should contain fields similar to the following:
{
"httpRequest": {
"requestMethod": "GET",
"requestUrl": "http://127.0.0.1:9080/anything",
"status": 200
},
"resource": {
"type": "global"
},
"labels": {
"source": "apache-apisix-google-cloud-logging"
},
"logName": "projects/your-project-id/logs/apisix.apache.org%2Flogs"
}Add Fields With Plugin Metadata
The following example uses plugin metadata (opens in Apache APISIX docs) to add selected request and response fields to every google-cloud-logging instance. The metadata values reference built-in variables (opens in Apache APISIX docs), so one configuration applies across multiple routes and services.
Create a route using the mounted credential file from the previous example:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "google-cloud-logging-route",
"uri": "/anything",
"plugins": {
"google-cloud-logging": {
"auth_file": "/usr/local/apisix/conf/gcp-logging-auth.json",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'Next, configure the plugin metadata for google-cloud-logging:
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/google-cloud-logging" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"log_format_extra": {
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'Plugin metadata is a global collection and cannot be isolated with a label selector. Export the complete collection before changing this entry:
adc dump -o adc-metadata.yaml --with-id \
--include-resource-type plugin_metadataAdd or update the google-cloud-logging entry while preserving every other entry in adc-metadata.yaml:
plugin_metadata:
# Keep all other plugin metadata entries from the exported file.
google-cloud-logging:
log_format_extra:
env: "$http_env"
resp_content_type: "$sent_http_Content_Type"Preview the complete metadata change and confirm that it contains no unintended updates or deletions:
adc diff -f adc-metadata.yaml \
--include-resource-type plugin_metadataSynchronize the reviewed plugin metadata collection:
adc sync -f adc-metadata.yaml \
--include-resource-type plugin_metadataAdd the following entry under spec.pluginMetadata in the complete GatewayProxy manifest used by the deployment:
google-cloud-logging:
log_format_extra:
env: "$http_env"
resp_content_type: "$sent_http_Content_Type"Apply the updated complete manifest through the deployment's normal Kubernetes or GitOps workflow.
❶ Add the custom request header env to each default log entry.
❷ Add the upstream response header Content-Type to each default log entry.
Send a request with the env header:
curl -i "http://127.0.0.1:9080/anything" -H "env: dev"You should receive an HTTP/1.1 200 OK response.
In Google Cloud, open Logging → Logs Explorer and query log_id("apisix.apache.org/logs"). The result's jsonPayload should include fields similar to the following:
{
"env": "dev",
"resp_content_type": "application/json"
}