Google Cloud Synthetic Monitoring Tutorial

Romin Irani
Google Cloud - Community
8 min readJul 21, 2023

--

This tutorial covers step by step instructions on how you can get started with Google Cloud Synthetic Monitoring, that has just been released in PREVIEW.

What is Synthetic Monitoring?

As the documentation states and allow me to break it down:

  1. Test the availability, consistency, and performance of your services, applications, web pages, and APIs.
  2. It works by periodically issue simulated requests and then records whether those requests were successful, and they record additional data about the request such as the latency.
  3. You can be notified when a test fails by creating an alerting policy to monitor the test results.

That sounds pretty straightforward and a useful feature but you might ask if that is not what Uptime checks in Cloud Monitoring are all about? At a high level, these look similar and hence you will find both public/private Uptime checks documentation together under Synthetic Monitoring.

Uptime Checks allow you to hit one or more public/private resources like Cloud Run services, App Engine, GKE, Compute engine instances and you can do a few validations like HTTP Response Codes, check for a particular data pattern in the response, etc. What you would ideally like is the power and flexibility of Test Frameworks that you can use to write these tests and perform complex request/response validation, check for some business scenarios and more. In simple terms, you get to use the best in breed Javascript Test frameworks that are out there (you can opt not to use frameworks too) and the ability to create complex test cases.

I almost think of this as a tool that you as a QA Developer have to run on Google Cloud and run your test cases.

What do I need to know / which tools to use?

Synthetic Monitoring support is built on multiple Google Cloud services/features that you might be already familiar with. This is what is needed:

  • You need to write your test cases in supported JavaScript Test Frameworks (Mocha) or with no framework too. As the documentation states “Synthetic monitors supports development of tests without relying on a specific framework and tests that use the Mocha framework”
  • These Google Cloud Functions are 2nd generation Cloud Functions powered by Cloud Run.
  • There are no Triggers that you need to set for the Cloud Function. These Cloud Functions are invoked by the Synthetic Monitoring service behind the scenes.
  • You can configure the Synthetic Monitor Test to be created at a regular interval (every 1 min, 5 mins, 10 mins, etc) and the managed service will run it for you, execute all your test cases inside of the Cloud Function code, capture the results and additional metadata like latency and record that.
  • You can optionally configure an Alert to be sent to one or more of the Notification Channels that you configure. The Alert Policy, Notification Channels are all from Google Cloud Monitoring, so nothing new there.

Allright enough of a high level overview. All we need to do is have a Service that we can write our Test Cases against and configure the Synthetic Monitor to do the rest of the magic. Let’s go.

Sample code for this article is available at the following repository:

Sample Inventory API

To test out Synthetic Monitoring, we need something to test against. While we could have used some existing API endpoints and validated the results, its nice to see it all integrated within Google Cloud itself.

So the first thing that I am going to do is deploy a Sample Inventory API to my favourite service, Cloud Run.

The repository has a Python Flask API that I am going to Cloud Run. You can follow the instructions in the README, where it gives you the choice to use either VS Code with Cloud Code extension or if you prefer, directly via a gcloud command.

To keep things simple, just go to the python-flask-api folder and execute the following gcloud command to deploy the service to Google Cloud Run:

gcloud run deploy --source .

This will ask you multiple questions. Go ahead with them and within a couple of minutes, you should have the Inventory API deployed in Googele Cloud Run and you have a URL via which you can access the same. The Service URL will be of the format:

https://<SERVICE_NAME>.xxxxx.a.run.app

Let us refer to the above url as SERVICE_URL for the rest of the article.

Test out the Inventory API

Before we start writing the Tests and deploying the Synthetic Monitors, lets understand the basic API.

The Inventory API has 3 methods and it has pre-populated data of 3 Inventory Items (I-1, I-2 and I-3) along with their associated on-hand quantity. We can try out:

  • SERVICE_URL/inventory : This will give a list of all inventory items.
    [ { “I-1”: 10, “I-2”: 20, “I-3”: 30 }]
  • SERVICE_URL/inventory/I-1: This will give a specific Inventory record with its quantity.
    { “productid”: “I-1”, “qty”: 10}
  • SERVICE_URL/inventory/I-100: Since this record is not present, it is an incorrect product id and hence the qty returned is -1.
    { “productid”: I-200, “qty”: -1}

Write Synthetic Monitors

Its time now to write the Synthetic Monitors. All the code is available in the synthetic-tests folder in the Github project. I would also suggest to refer to the official documentation on writing these monitors.

The folder has 3 files:

  • package.json
  • index.js
  • mocha_tests.spec.js

The above files are because I plan to use the Mocha JavaScript Test framework but you can opt to not use it too. I use Mocha along with Chai, which is a BDD/TDD assertion library.

The package.json contains the following:

{
"name": "inventory-api-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"request": "^2.88.2",
"@google-cloud/synthetics-sdk-mocha": "^0.1.1",
"chai": "^4.3.7",
"node-fetch": "^2.6.0",
"@google-cloud/functions-framework": "^3.1.2"
},
"author": "Romin Irani",
"license": "Apache-2.0"
}

Notice that I have borrowed this from the Mocha URL OK Test Case that Google Cloud has provided. I have added my specific modules in there i.e. request and chai.

The index.js is a standard template that invokes the mocha_tests.spec.js in which we are going to write our test cases.

I will just break down our Tests into individual snippets now:

First up is the fetch all inventory items shown below. This invokes the /inventory endpoint and then performs two tests:

  • returns status 200
  • inventory dictionary length should be 1
var expect  = require("chai").expect;
var request = require("request");

describe("My Inventory API", function() {

describe("Get Inventory List", function() {

var url = "SERVICE_URL/inventory";

it("returns status 200", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
expect(response.statusCode).to.equal(200);
done();
})
});

it("inventory dictionary length should be 1", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
const obj = JSON.parse(body)
expect(obj).to.be.an.instanceOf(Object);
const dictionary_length = Object.keys(obj).length;
expect(dictionary_length == 1);
done();
})
});
});

Next up is the test for an incorrect inventory item. In this case, we will use a product id that is not among the 3 product ids that we know exist i.e. I-1, I-2 and I-3.

Two tests are again performed here:

  • returns status 200
  • returns quantity as -1 (when product id is wrong)
  describe("Get Incorrect Inventory Item", function() {

var url = "SERVICE_URL/inventory/ABC";

it("returns status 200", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
expect(response.statusCode).to.equal(200);
done();
})
});

it("returns quantity as -1", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
const obj = JSON.parse(body)
expect(parseInt(obj["qty"])).to.equal(-1);
expect(obj["productid"]).to.equal("ABC");
done();
})
});

});

Finally, we test the Inventory API for a correct product item. Two tests are performed:

  • returns status 200
  • returns specific inventory item with productid as I-1
describe("Get Inventory Item", function() {

var url = "SERVICE_URL/inventory/I-1";

it("returns status 200", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
expect(response.statusCode).to.equal(200);
done();
})
});

it("returns specific inventory items with productid as I-1", function(done) {
request(url, function(error, response, body) {
if (error) {
throw error;
}
const obj = JSON.parse(body)
expect(obj["productid"]).to.equal("I-1");
done();
})
});
});

Deploying the Synthetic Monitor

Now that we have the code in place for our Synthetic Monitor, it is time to deploy it. I have followed the steps given below:

  1. Zip the folder containing all the above 3 files.
  2. Upload this ZIP file to a specific Google Cloud Storage Bucket. We will be deploying the Cloud Function from a ZIP file in Cloud Storage.
  3. Visit Google Cloud Console → Monitoring → Synthetic Monitoring as shown below:

This will lead you to the Synthetic Monitoring page, from where you can click on the following button to create one:

This will bring up a form as shown below:

Give it a name, select a frequency at which this Test will be run. This is important so that you can notified within a reasonable time and which does not end up creating issues for you vis-a-vis the SLO/SLA. You can opt to create an Alert Notification (this is recommended) so that you can get notified on the configured Notification channels.

The most important thing is the CREATE FUNCTION , which you need to click to configure the Cloud Function. If you are familiar with Cloud Functions, this screen will look familiar.

Ensure that you select the correct Entry point. In my case, I changed it to SyntheticMochaSuite , which is the entry point in the index.js file. The ZIP from Cloud Storage option is selected since I had uploaded all the source code for the Cloud Function as a ZIP file to Cloud Storage.

Once you apply and create the Synthetic Monitor, it will :

  1. Deploy the Cloud Function (2nd Generation)
  2. Create an Uptime Check Alerting Policy with the Notification Channels setup for the same.

Monitoring the Result

Once deployed, the Synthetic Monitors are run based on the frequency that you had selected. Here is a sample run from my machine:

When I click on inventory-check, it provides me detail on the execution(s):

Pricing

The Cloud Monitoring pricing summary page has details for Synthetic Monitoring pricing. The pricing is at $1.20/1,000 executions with a free tier of 100 executions per billing account per month. The pricing is expected to take effect from November 1, 2023.

Disable the Synthetic Monitor

One feature that I would like to see is to disable the Synthetic Monitor Tests while I am doing development/testing — so that I don’t end up hitting the number of invocations quota. Currently the only way seems to be to delete the Synthetic Monitor.

Conclusion

Hope this gives you a gentle introduction to Synthetic Monitoring in Google Cloud. Refer to the Documentation for more details.

--

--