Amazon CloudWatch Logs Insights Query Snippets as Code
Tags: aws, cloudwatch, cdk, serverless
Published: 2021-10-25 14:03:02

---
title: Amazon CloudWatch Logs Insights Query Snippets as Code
published: true
description: How to predefine Amazon CloudWatch Logs Insights queries in your architecture pipeline.
tags: aws, cloudwatch, cdk, serverless
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxjhwwv3d11uhgznbiaj.jpeg
---

[_Amazon CloudWatch_](https://aws.amazon.com/cloudwatch/) is a suite of observability-related products. From log filtering to alerting, the service can do it all!

In this blog post, I would like us to focus on a feature of the [_Amazon CloudWatch Logs Insights_](https://aws.amazon.com/blogs/aws/new-amazon-cloudwatch-logs-insights-fast-interactive-log-analytics/) that I feel is deeply underutilized - the **predefined queries**.

> This blog post assumes the reader is familiar with [_AWS CloudFormation_](https://aws.amazon.com/cloudformation/). The code presented is written using [_AWS CDK_](https://aws.amazon.com/cdk/). If you are not familiar with it, fear not! In the [example architecture GitHub repository](https://github.com/WojciechMatuszewski/cw-insights-prepopulated-queries), you can find the same architecture deployed using [_AWS SAM_](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html).

## Amazon CloudWatch Logs Insights refresher

Living under the _Amazon CloudWatch_ umbrella, the _Amazon CloudWatch Logs Insights_ allow you to query logs of your application using a [declarative query language](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html).

![Amazon CloudWatch Logs Insights console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37s2ji2vad9nyfzp3i4p.png)

If your understanding of the query language is deep enough, you will be able to create elaborate diagrams or even business metrics using this service.

The thing to remember here is that, **in my opinion**, the _AWS CloudWatch Logs Insights_ service is essential in the context of day-to-day development on AWS.

## The problem

Given my passion for everything AWS (and serverless), I find myself interacting with the _Amazon CloudWatch Logs Insights_ quite frequently.

During my time spent with the service, I discovered the "Queries" tab in the service console.

![Amazon CloudWatch Logs Insights "Queries" tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fec7jjtvev75e3z8xqnm.png)

The "Queries" tab contains various predefined queries one might use to filter through application logs. What I think some people do not realize is that **it is possible to save custom queries**.

Imagine being woken up in the middle of the night by [_PagerDuty_](https://www.pagerduty.com/). You login into the AWS console, search for _CloudWatch Logs Insights_, and, using the predefined query, dig into application logs within seconds. All of this without having to remember the query language.

Sounds fantastic, right? I think so as well. Sadly, this reality is often not possible because **in my experience, most people underutilize the "save query" feature**.

![Amazon CloudWatch Logs Insights predefined queries](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bbgjkjhuxebqunab98z.png)

Maybe it is a problem of adoption – perhaps teams are using different tools for searching their application logs. I'm not sure.

Suppose your team uses _Amazon CloudWatch Logs Insights_ for log filtering. In that case, I believe that having a predefined set of queries tailored to your application ready to go will make every developer's life easier.

Let us explore how one might **create predefined queries using (AWS CDK)**. This method works great if your infrastructure is defined using code already (if it is not the case, please consider doing so).

## Queries as Code

Since, to my best knowledge, there is no "predefined Amazon CloudWatch Logs Insights query" _AWS CloudFormation_ resource available, we have to turn our attention to either [_AWS CloudFormation custom resources_](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) or [_AWS CloudFormation modules_](https://aws.amazon.com/blogs/mt/introducing-aws-cloudformation-modules/).

> I'm going to use _AWS CloudFormation custom resources_ since they work well with _AWS CDK_.

The **first step** is to identify the API call responsible for creating, updating, and deleting the query. After a bit of googling, I was able to pinpoint the operations I need to get myself familiar with – [_PutQueryDefinition_](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutQueryDefinition.html) and the [_DeleteQueryDefinition_](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteQueryDefinition.html).

The **second step** is to create a _custom AWS CloudFormation resource_ that uses those APIs. Luckily for us _AWS CDK_ exposes great abstractions that will help us greatly in this department – enter the [_custom-resource_ package](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html).

The following is a modified excerpt from the code found in the [example architecture GitHub repository](https://github.com/WojciechMatuszewski/cw-insights-prepopulated-queries).

```ts
import * as cdk from "@aws-cdk/core";
import * as customResources from "@aws-cdk/custom-resources";
import * as iam from "@aws-cdk/aws-iam";

export class YourStackName extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // This is the name that will be visible in the AWS CloudWatch Logs Insights "Queries" tab.
    const queryName = "EXAMPLE_QUERY_NAME";
    // Remember to format the query for readability purposes!
    const byAPIGWRequestIdQuery = `fields @timestamp, @logStream, @message
    | sort @timestamp desc
    | filter @requestId = "PASTE_REQUEST_ID_HERE"`;

    new customResources.AwsCustomResource(this, "insightsQuery", {
      policy: customResources.AwsCustomResourcePolicy.fromStatements([
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["logs:PutQueryDefinition", "logs:DeleteQueryDefinition"],
          resources: [`arn:aws:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:*`]
        })
      ]),
      onCreate: {
        action: "putQueryDefinition",
        service: "CloudWatchLogs",
        parameters: {
          name: queryName,
          queryString: byAPIGWRequestIdQuery
        },
        physicalResourceId:
          customResources.PhysicalResourceId.fromResponse("queryDefinitionId")
      },
      onUpdate: {
        action: "putQueryDefinition",
        service: "CloudWatchLogs",
        parameters: {
          name: queryName,
          queryString: byAPIGWRequestIdQuery,
          queryDefinitionId: new customResources.PhysicalResourceIdReference()
        },
        physicalResourceId:
          customResources.PhysicalResourceId.fromResponse("queryDefinitionId")
      },
      onDelete: {
        action: "deleteQueryDefinition",
        service: "CloudWatchLogs",
        parameters: {
          queryDefinitionId: new customResources.PhysicalResourceIdReference()
        }
      }
    });
  }
}
```

That might seem like a lot of code, but in reality, we repeat many things in-between the `onCreate`, `onUpdate`, and `onDelete` calls.

After deployment, open the _AWS CloudWatch Logs Insights_ console and navigate to the "Queries" tab. The newly defined query will be visible there.

![Example predefined CloudWatch Logs Insights Query](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo30hq43nnn9atayec21.png)

Looking at the code, I think the **most crucial part is the [_IAM_](https://aws.amazon.com/iam/) policy definition**. Please **remember to always scope _IAM_ policies down as much as possible**. If you find more granular [_resources ARN_](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html), I could use here, please let me know!

As for the `customResource` class itself, please consult the [_custom-resource module documentation_](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html) – it is excellent!

## Closing words

There you have it – how to create _AWS CloudWatch Logs Insights_ queries and incorporate that flow into your [_IaC_](https://en.wikipedia.org/wiki/Infrastructure_as_code) pipeline.

I would argue that the effort required to create those queries is relatively low, but the potential gains from having them available are relatively high. I hope that you or your team find some value in this blog post.

Thank you for your time.

---

- Source code that this blog post was based on can be found [here](https://github.com/WojciechMatuszewski/cw-insights-prepopulated-queries).

- You can find me on Twitter [@wm_matuszewski](https://twitter.com/wm_matuszewski) – DMs are open!