‘Can I get that in writing?’ Email logs from Cloud Run jobs and other services

Taneli Leppä
4 min readNov 24, 2023

--

The problem

While we all wish we had time to keep an eye on dashboards, nothing beats a well timed email to catch one’s attention. Not many services in Google Cloud have direct email integration and for that reason I originally built Pubsub2Inbox (and yes, it’s going to be another Pubsub2Inbox article).

This time I was looking for a job-agnostic way of getting logs from Cloud Run jobs (a very neat solution for recurrent automation tasks) to my email so I can keep up on what they are doing. If you haven’t tried Cloud Run jobs yet, they’re great — very flexible and no infrastructure required.

Cloud Run jobs log their output (ie. stdout and stderr) into Cloud Logging, but it’s not trivial to catch this output from different kinds of containers. Also, I really didn’t want each script to have an email solution of its own.

The solution

Architecture of the solution.

Pubsub2Inbox already has an email output. It can send email via:

But it doesn’t have to be email only! You could also send the logs via Slack or Google Chat (and we can even send SMS!).

I also wanted to get some information from the Cloud Run job execution and the actual logs from Cloud Logging (so talking to run.googleapis.com and logging.googleapis.com), so I wrote two new processors: cloudrun and logging .

Finally we need a way to trigger Pub/Sub. While it’s trivial to do with gcloud pubsub topics publish , I wanted a more lightweight and easy way as all we need to do is push a simple message to a Pub/Sub queue. This is done just with a few curl commands:

# Grab a token from the metadata endpoint
TOKEN=$(curl -sH "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" | jq -r ".access_token")
# Encode the task information in JSON and wrap it in base64
MESSAGE=$(echo -n "{\"job\":\"${CLOUD_RUN_JOB}\",\"execution\":\"${CLOUD_RUN_EXECUTION}\",\"index\":${CLOUD_RUN_TASK_INDEX},\"attempt\":${CLOUD_RUN_TASK_ATTEMPT}}" )
MESSAGE_B64=$(echo $MESSAGE | base64 | tr -d \\n)
# Post a message to the public topic
curl -sH "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-X POST \
-d "{'messages':[{'data':'${MESSAGE_B64}'}]}" \
"https://pubsub.googleapis.com/v1/${PUBSUB_TOPIC}:publish"

So that’s pretty easy. For the demo, we’ll be just using a simple container based on Google’s base images where we add the good old Unix fortune command, a tool that’s two years older than me.

For the Pubsub2Inbox configuration, we fetch the job details with cloudrun processor to get information such as when the job was completed and then fetch the logs using an entries.list request to Cloud Logging with the appropriate filter. Finally, we put the log entries in the email and send it either via SendGrid or a custom SMTP server (the demo can use smtp-relay.gmail.com but setting it up is cumbersome and requires “Less Secure Apps” support which is deprecated and will be removed by the end of 2024).

As always, full Terraform code is provided. Just clone the repository from https://github.com/GoogleCloudPlatform/pubsub2inbox/tree/main and navigate to examples/cloud-run-jobs .

You’ll need to build the container. I suggest setting up an Artifact Registry in the project and pushing it there:

docker build \
-t europe-west4-docker.pkg.dev/your-project-id/your-repository/cloud-run-example:latest \
.
docker push \
europe-west4-docker.pkg.dev/your-project-id/your-repository/cloud-run-example:latest

There you should create a terraform.tfvars file with content similar to:

project_id         = "your-project-id-here"
region = "europe-west4"
job_container = "europe-west4-docker.pkg.dev/your-project-id/your-repository/cloud-run-example:latest"
sender = "the-sender@example.com"
recipient = "your-email@example.com"
sendgrid_api_token = "SG....."

You can now run terraform init and then terraform apply . The example will create a Pub/Sub topic, a sample Cloud Run job and deploy Pubsub2Inbox as a Cloud Function v2 (I’ve always been partial to V2s).

After everything has been created, you can go into Cloud Console and click execute on the sample job that was created:

The Cloud Run job.

If you check the Cloud Function, you should see that it’s executing and sending the email:

Pubsub2Inbox processing.

Finally, check your mailbox and receive your fortune:

The email from Pubsub2Inbox containing the Cloud Run job output.

You could extend this in multiple ways:

  • Pass Cloud Storage links in the Pub/Sub messages and add them as attachments
  • Pass recipient information from the job as well

Did you find this useful? Reach out to me through the usual channels — like my T̶w̶i̶t̶t̶e̶r̶ X account: https://twitter.com/rosmo

PS. Some of the fortunes can be quite dark, so tread carefully.

--

--