Compatibility
Log collection works with:- The
pubsub-to-chronosphereDataflow Flex Template, version1.0.1. - Pub/Sub subscriptions whose messages are JSON objects. Cloud Logging
LogEntrymessages get built-in normalization. Other JSON objects pass through as received. The template adds_ingest_source,project_id, andsubscription_idto every log, replacing any fields with the same names. When the template can look up the subscription’s topic, it addstopicin the same way. - One or more subscriptions for each job. A subscription can attach to a topic in another Google Cloud project.
How logs are labeled
Every log gets two labels:xcor.integration.name: alwaysgcp, the integration’s catalog ID.xcor_integration: the Google Cloud service that wrote the log, such asgcp_gke,gcp_cloud_run,gcp_cloud_sql, orgcp_compute_engine. Cortex XCOR derives this label from the log’s monitored resource type and log name. Audit logs that aren’t associated with a single service getgcp_audit_logs. Logs that Cortex XCOR can’t attribute getgcp_otherand are stored like any other log.
- Service: The
servicefield is thexcor_integrationvalue withoutgcp_, such asgke,cloud_run, orcloud_sql. Logs labeledgcp_otherget their monitored resource type, such asglobal. Workload names, such as a container or Cloud Run service name, stay in theresource.labelsfields. - Severity: Cloud Logging severities map to
DEBUG,INFO(INFOandNOTICE),WARN,ERROR, andFATAL(CRITICAL,ALERT, andEMERGENCY).DEFAULTmeans the log has no severity. An audit log without a severity getsERRORwhenprotoPayload.status.codeis non-zero, andINFOotherwise. Other logs without a severity get your organization’s default.
Prerequisites
Log collection requires:- A Cortex XCOR tenant with logging enabled. Contact Cortex XCOR Support if you’re unsure whether logging is enabled.
- A Google Cloud project to run the job in, where you can enable APIs and create the resources in the setup steps.
- The
gcloudcommand-line tool, authenticated against that project. - A project Owner to grant roles to the job’s service account, or the other identities that Create the worker service account lists. The Editor role can’t grant roles. If the deploying identity isn’t an Editor, only the Owner can let it launch jobs as that service account.
Required permissions
The identity that deploys the job can be a person or an automation account. It needs either theroles/editor role on the project plus the following two roles, or the full list of roles after
them. The Editor role can’t create log sinks or change a topic’s Identity and Access Management
(IAM) policy.
If the deploying identity isn’t an Editor, it needs the following roles instead:
The worker service account, created during setup, needs the roles listed in
Create the worker service account. No step requires
organization-level roles.
Configure the integration
The Integrations Hub has no configuration form for logs. You deploy the job in Google Cloud, and it sends logs to your tenant. The setup creates the following pipeline in your project: Complete the following steps in order. Skip any step whose resource already exists. To create the same resources with Terraform instead, see Set up with Terraform.Set up the project
Set these shell variables, which the later commands use:Store an API token in Secret Manager
- In Cortex XCOR, create a restricted service account with Write-only access and no label restrictions. The write-only restriction covers logs ingest too, though the option’s description in Cortex XCOR mentions only metric data. For the procedure, see Create a restricted service account.
- Copy the account’s token, which Cortex XCOR shows only once.
-
Store the token in Secret Manager, replacing
<TOKEN>:If your organization policy rejects automatic replication, use--replication-policy=user-managed --locations=$REGIONinstead.
Create the worker service account
The job’s virtual machines run as a dedicated service account. Create it:roles/resourcemanager.projectIamAdmin) can run the loop instead, but not the secret binding,
which needs the Owner or an identity with roles/secretmanager.admin:
<DEPLOYER> with the identity, such as user:alice@example.com:
The
--condition=None flag keeps the commands non-interactive in projects that have
conditional IAM bindings. If you created the service account moments earlier, the first binding
can fail with service account does not exist for up to a minute while IAM propagates the
account. Run the command again.
Export logs to Pub/Sub
Create a topic, a log sink that routes Cloud Logging logs to it, and a subscription for the job:--log-filter:
- The filter keeps logs with no severity, which Cloud Logging stores as
DEFAULTandseverity>=INFOalone would drop. - It leaves out the job’s own worker logs, which would otherwise flow back into the job’s input
and be ingested. The
job_namein the filter must match the name you launch the job with. - Because it keeps
DEFAULT, the filter also exports the Kubernetes API audit logs (k8s.io) from Google Kubernetes Engine (GKE) clusters, which carry no severity. These are Admin Activity audit logs, and lease updates can make up most of their volume. To leave out the lease updates, addAND NOT protoPayload.methodName="io.k8s.coordination.v1.leases.update"to the filter. To leave out all of them, addAND NOT protoPayload.serviceName="k8s.io", which also drops the record of changes such as creates, deletes, and permission changes. - If you enable Data Access audit logs for Pub/Sub, update the sink filter to exclude audit logs for the export topic.
AND NOT (resource.type="dataflow_step" AND resource.labels.job_name="<OTHER_JOB>").
A new sink can take a few minutes to start exporting. Logs written before then aren’t exported.
Keep subscription retention under 24 hours. Cortex XCOR discards logs with timestamps more than
24 hours in the past, so an older backlog can’t be delivered.
To ship other JSON messages, such as app events published directly to Pub/Sub, point the job at
a subscription on that topic instead.
If a source topic lives in a different project, create the subscription in the job’s project
and reference the topic as projects/<TOPIC_PROJECT>/topics/<TOPIC>. The identity that creates
the subscription needs roles/pubsub.subscriber on the source topic. The worker service
account needs no grants in the source project.
Create the staging bucket and dead-letter topic
Launch the job
The template spec for version1.0.1 is
gs://chronosphere-release/dataflow-templates/pubsub-to-chronosphere/1.0.1/spec.json. Its
container image is us-docker.pkg.dev/chronosphereio/release/pubsub-to-chronosphere:1.0.1.
Running within
a few minutes. If it shows Failed, open the job’s logs on the Dataflow Jobs page. A message
such as Failed to start the launcher VM followed by Operation denied by org policy means an
organization policy blocked the virtual machine. Add the settings in
Locked-down environments and launch again.
To choose --max-workers, see Sizing. For the other template parameters, see
Parameters reference.
To read several subscriptions with one job, separate them with commas. Because the comma
collides with the gcloud parameter syntax, use the alternate-delimiter form and quote the
whole flag:
Set up with Terraform
Terraform can create everything after the API token. Complete Set up the project and Store an API token in Secret Manager first, so the token stays in Secret Manager and out of Terraform state. The configuration creates its own log sink, so first read the one-sink-per-project guidance in Export logs to Pub/Sub. It also grants the worker service account its roles, so apply it as a project Owner, or as an identity that holdsroles/resourcemanager.projectIamAdmin and roles/secretmanager.admin along with the roles in
Required permissions.
An identity that has neither the Owner nor the Editor role also needs
roles/iam.serviceAccountUser on the worker service account before Terraform creates the job.
The account doesn’t exist until Terraform creates it, and only the Owner can grant that role on
it, so apply in two passes. Run terraform apply -target=google_service_account.worker to create
only the account. Have the Owner run the roles/iam.serviceAccountUser command in
Create the worker service account, with SA set to the
account’s email, cortex-xcor-dataflow@<PROJECT_ID>.iam.gserviceaccount.com for the default
name. Then run terraform apply again. Alternatively, the Owner can grant
roles/iam.serviceAccountUser on the project before the apply, which lets the identity act as
every service account in the project.
-
The configuration needs the
googleandgoogle-betaproviders because the Dataflow flex template job resource is available only ingoogle-beta. The configuration was tested with version 8 of both providers. Set the project and region on each: -
Set values for these variables, and apply the configuration. In a project that blocks
external IP addresses, also set
subnetworkandprivate_ips, as in Locked-down environments.Terraform example
name updates both. Destroying the configuration
drains the job before deleting it.
Locked-down environments
Common organization policies need these additional launch settings:-
No external IP addresses, enforced by
constraints/compute.vmExternalIpAccessorconstraints/compute.managed.vmExternalIpAccess: Add--disable-public-ipsand run on a subnet with Private Google Access enabled. The subnet also needs the following:- If your Virtual Private Cloud (VPC) network uses custom private DNS zones for Google APIs,
such as
private.googleapis.comorrestricted.googleapis.comsetups, the zones must coverpkg.devfor the template image andgcr.iofor a logging agent that the Dataflow launcher pulls. For the options, see Private Google Access domain options. Older setups that predate Artifact Registry often covergcr.iobut misspkg.dev. - The job sends data to
<TENANT>.chronosphere.ioon port 443. Private Google Access doesn’t cover this external traffic. Provide Cloud Network Address Translation (Cloud NAT) or equivalent egress to that host. The job runs continuously, so the egress path must stay up.
- If your Virtual Private Cloud (VPC) network uses custom private DNS zones for Google APIs,
such as
-
No default VPC network: Add
--network,--subnetwork, or both. For Shared VPC, use the full subnetwork URL,https://www.googleapis.com/compute/v1/projects/<HOST_PROJECT>/regions/<REGION>/subnetworks/<SUBNET>, and grant the deploying identityroles/compute.networkUseron the subnet. -
Firewall rules keyed on network tags: Dataflow virtual machines carry only the default
dataflownetwork tag. Add tags at launch with--additional-experiments=use_network_tags=<TAG1>;<TAG2>for worker virtual machines and--additional-experiments=use_network_tags_for_flex_templates=<TAG>for the launcher virtual machine. You can’t add tags after the job starts. -
Mandatory virtual machine labels: Add
--additional-user-labels=<KEY1>=<VALUE1>,<KEY2>=<VALUE2>. - VPC Service Controls: Confirm that the perimeter’s egress policy allows the job to reach the ingest endpoint, and that cross-project subscriptions stay inside the perimeter.
Validate log ingestion
- Allow several minutes for Dataflow to start the job’s virtual machines. After the job is running, a message usually reaches Cortex XCOR within seconds of arriving in Pub/Sub. The job sends a partial batch after the batch timeout, 5 seconds by default.
-
In the Google Cloud console, open the job on the Dataflow Jobs page and review the
custom counters for its steps. The
valid_messages,batches_sent, andevents_sentcounters should increase, andinvalid_messagesandbatches_failedshould stay at 0. Theevents_sentcounter includes logs that Cortex XCOR accepted and then discarded, so confirm arrival in the next step. -
In the navigation menu, select
Explorers > Logs Explorer, and run this query:
Each Google Cloud service sending logs appears as a row. Each log also carries
project_idandsubscription_idfields that identify the subscription it came through, and atopicfield when the job could look up the subscription’s topic.project_idis the subscription’s project, not the project that wrote the log. For more about queries, see Search and filter log data.
LogEntry-shaped message to the
input topic:
message set to the textPayload value.
Sizing
With Streaming Engine enabled, as in the launch command, horizontal autoscaling is on by default, and you can change the minimum and maximum workers with an in-flight update. Always set--max-workers, because it caps the job’s cost. To estimate it:
- Average events per second = logs per day ÷ 86,400.
- Peak events per second ≈ 2 × average. Adjust for your burst profile.
- Virtual CPUs needed = peak events per second ÷ 2,000, rounded up. The estimate is conservative for logs of about 1 KB.
--max-workers= virtual CPUs needed ÷ 4, rounded up, for the defaultn1-standard-4workers.
n1-standard-4 worker sustained about 150 million logs per day at under
half its CPU.
The job batches by event count, not size. A batch holds up to batchSize events, with a default
of 500. A Cloud Logging entry can be up to 256 KiB, so a batch of large entries can pass the
16 MiB limit on one ingest request. The job then splits the batch in half and retries, so nothing
is lost. Each oversized batch costs extra requests. If your entries are large, lower batchSize,
for example to 100.
Monitoring
You run the job, so you own detecting its failures. If you collect Google Cloud metrics too, add thepubsub.googleapis.com/subscription and dataflow.googleapis.com/job metric type
prefixes so Cortex XCOR ingests pipeline health metrics into the same tenant as the logs. Alert
on these conditions:
- The subscription’s
oldest_unacked_message_ageapproaches the retention window. Messages older than the retention window are lost. - The subscription’s
num_undelivered_messagesgrows steadily. - The Dataflow job’s
system_lagrises, or the job leaves the running state. - The dead-letter subscription holds any messages.
valid_messages, invalid_messages, empty_messages, batches_sent, batches_failed,
batches_bisected, events_sent, events_dead_lettered, retries_performed,
udf_transformed, udf_filtered, udf_errors, and udf_invalid_output. It also reports the
batch_size and request_duration_ms distributions.
Parameters reference
The following table lists the template parameters:Normalization
Normalization applies only to messages that contain atextPayload, jsonPayload, or
protoPayload field. It only adds fields and never overwrites them:
message: Set fromtextPayload, from themessage,msg, orlogfield ofjsonPayload, or from theprotoPayloadmethod name and resource name for audit logs. When none of those fields exist, the payload itself becomes the message as a JSON string.severity: Set toDEFAULTwhen missing.timestamp: Set fromreceiveTimestampwhen missing.kubernetes: Fork8s_containerresources, set to an object with thecluster_name,namespace_name, andpod_nameresource labels.
_ingest_source, project_id,
subscription_id, and, when the job could look it up, topic. The job sets these fields after
defaultLabels, so a default label with one of these keys has no effect, except topic when
the lookup failed.
User-defined functions
A JavaScript user-defined function runs after normalization. It receives each log as a JSON string and returns either a string containing a JSON object ornull to drop the log. Write it
in ES5 syntax. The job loads the file at worker startup, so update the file and then update or
relaunch the job to apply changes.
Don’t use a user-defined function to redact data. If the function throws an error, the job
sends the original log unchanged. Output that isn’t a JSON object goes to the dead-letter
topic.
Delivery semantics and the dead-letter topic
Delivery is at least once. After an outage or a restart, Pub/Sub can redeliver some messages that were already sent. The job handles each response from the logs ingest API as follows:200: Delivered.429, any5xxstatus, or a network error: The job retries with exponential backoff up tomaxRetriestimes and honors aRetry-Afterheader whose value is specified in seconds. When retries run out, Dataflow retries the work while Pub/Sub holds the backlog, so an endpoint outage doesn’t lose data or fill the dead-letter topic.401or403: The job stops delivering and Dataflow retries the work, so an authentication problem stalls the pipeline instead of dead-lettering all traffic.- Any other status, such as
400or413: The API rejects a request as a whole, so the job splits the batch in half and sends each half again until it isolates the rejected events. Only those events go to the dead-letter topic.
empty_messages and dropped.
Cortex XCOR can accept a request with a 200 status and still discard individual
logs in it. It discards logs with timestamps more than 24 hours in the past or future, logs
larger than 1 MB, and logs over your tenant’s ingest limits. The job counts these logs in
events_sent, and they never reach the dead-letter topic.
To replay dead-lettered events after you fix the cause, pull them from the monitor subscription
and publish them to the input topic within 24 hours of their original timestamps. Older logs are
discarded.
Upgrading
A running job doesn’t update itself. To move to a new template version, rungcloud dataflow flex-template run with the --update flag and the new spec. This updates the
streaming job in place when the versions are compatible. Otherwise, drain the old job and launch
a new one. If the new job has a different name, change the job_name in the sink’s filter to
match. Otherwise, the new job’s worker logs are ingested. Each request carries a
User-Agent: pubsub-to-chronosphere/<VERSION> header that identifies the deployed version.
To upgrade a running job, run your original launch command again with --update, SPEC set to
the new version, and every parameter and option you launched with. If the new version runs a
later Beam SDK than your job, also pass
--additional-pipeline-options=updateCompatibilityVersion=<current_job_beam_version>, using the
Beam SDK version from the following table for the template version your job runs. With Terraform,
set additional_pipeline_options = ["updateCompatibilityVersion=<current_job_beam_version>"]
on the google_dataflow_flex_template_job resource, not in parameters. Keep the same job name.
Dataflow checks compatibility before it replaces the job. If the check fails, the running job
keeps running, and you can drain it and launch the new version.
Troubleshooting
The following table lists common problems and how to resolve them:Limitations
- This page covers logs only. For metrics, see Google Cloud metrics.
- You deploy, run, scale, and upgrade the job in your own Google Cloud project, and Google Cloud bills you for it.
- Cortex XCOR discards logs with timestamps more than 24 hours in the past or future, and logs larger than 1 MB, without returning an error. A backlog older than 24 hours can’t be delivered.
- Delivery is at least once, so some logs can arrive twice after an outage or restart.
- A user-defined function that throws an error passes the original log through, so it can’t enforce redaction.