

# Analyzing log data with CloudWatch Logs Insights
<a name="AnalyzingLogData"></a>

With CloudWatch Logs Insights, you can interactively search and analyze your log data in Amazon CloudWatch Logs. You can perform queries to help you more efficiently and effectively respond to operational issues. In addition to querying using log groups, you can query using facets, data source, and data type. If an issue occurs, you can use CloudWatch Logs Insights to identify potential causes and validate deployed fixes. You are limited to 100 concurrent CloudWatch Logs Insights QL per account, including queries added to dashboards. Additionally, you can run 15 concurrent queries for either OpenSearch Service PPL or OpenSearch Service SQL. 

CloudWatch Logs Insights supports three query languages that you can use for your queries:
+ A purpose-built **Logs Insights query language (Logs Insights QL)** with a few simple but powerful commands.
+ **OpenSearch Service Piped Processing Language (PPL)**. OpenSearch PPL enables you to analyze your logs using a set of commands delimited by pipes (\$1).

  With OpenSearch PPL you can retrieve, query, and analyze data by using commands that are piped together, making it easier to understand and compose complex queries. The syntax enables the chaining of commands to transform and process data. With PPL, you can filter and aggregate data, and use a rich set of math, string, date, conditional and other functions for analysis.
+ **OpenSearch Service Structured Query Language (SQL)**. With OpenSearch SQL queries, you can analyze your logs in a declarative manner. You can use commands such as SELECT, FROM, WHERE, GROUP BY, HAVING, and various other commands and functions available in SQL. You can execute JOINs across log groups, correlate data across logs using sub-queries, and use the rich set of JSON, Mathematical, String, Conditional and other SQL functions to perform powerful analysis on logs.

  When you use either SQL or PPL commands, make sure to enclose fields with special characters (non-alphabetic and non-numeric) in backticks to successfully query them. For example, enclose `@message`, `Operation.Export`, and `Test::Field` in backticks. You don't need to enclose fields with purely alphabetical names in backticks.

CloudWatch Logs Insights offers the following features that are available for use with any of the query languages.
+ Automatic [*discovery of log fields*](CWL_AnalyzeLogData-discoverable-fields.md) in logs from AWS services such as Amazon Route 53, AWS Lambda, AWS CloudTrail, and Amazon VPC, and any application or custom log that emits log events as JSON.
+ Creating [*field indexes*](CloudWatchLogs-Field-Indexing.md) to reduce costs and speed results, especially for queries of large number of log groups or log events. After creating field indexes of fields that are common in your log events, you can use them in a query. The query skips processing log events that are known to not include the indexed field, and processes less data.
**Note**  
The `filterIndex` command is available only in Logs Insights QL.
+ [*Detection and analysis of patterns*](CWL_AnalyzeLogData_Patterns.md) in your log events. A pattern is a shared text structure that recurs among your log fields. When you view the results of a query, you can choose the **Patterns** tab to see the patterns that CloudWatch Logs found based on a sample of your results.
+ [*Saving queries*](CWL_Insights-Saving-Queries.md), seeing your query history, re-running saved queries, and [using saved queries with parameters](CWL_Insights-Saving-Queries.md#CWL_Insights-Parameterized-Queries).
+ [*Adding queries to dashboards*](CWL_ExportQueryResults.md).
+ [*Encrypting query results with AWS Key Management Service*](CloudWatchLogs-Insights-Query-Encrypt.md).
+ [Query generation using natural language](CloudWatchLogs-Insights-Query-Assist.md) lets you use natural language to create CloudWatch Logs Insights queries. You can ask questions about or describe the data you're looking for, then the AI generates a query based on your prompt and provides a line-by-line explanation of how the query works.
+ [Use facets to group, filter, and interactively explore your logs](CloudWatchLogs-Facets.md).

The following CloudWatch Logs Insights features are supported only when you use Logs Insights QL.
+ [Comparison queries](CWL_AnalyzeLogData_Compare.md) that compare log events in a log group with log events from a previous time period.

**Important**  
CloudWatch Logs Insights can't access log events with timestamps that pre-date the creation time of the log group.

If you are signed in to an account set up as a monitoring account in CloudWatch cross-account observability, you can run CloudWatch Logs Insights queries on log groups in source accounts linked to this monitoring account. You can run a query that queries multiple log groups located in different accounts. For more information, see [CloudWatch cross-account observability](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html).

When you create queries using Logs Insights QL, you can also use natural language to create CloudWatch Logs Insights queries. To do so, ask questions about or describe the data you're looking for. This AI-assisted capability generates a query based on your prompt and provides a line-by-line explanation of how the query works. For more information, see [Use natural language to generate and update CloudWatch Logs Insights queries](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatchLogs-Insights-Query-Assist.html). 

Queries using any of the supported query languages time out after 60 minutes, if they have not completed. Query results are available for seven days.

CloudWatch Logs Insights queries incur charges based on the amount of data that is queried, regardless of query language. For more information, see [Amazon CloudWatch Pricing](https://aws.amazon.com/cloudwatch/pricing/).

You can use CloudWatch Logs Insights to search log data that was sent to CloudWatch Logs on November 5, 2018 or later.

**Important**  
If your network security team doesn't allow the use of web sockets, you can't currently access the CloudWatch Logs Insights portion of the CloudWatch console. You can use the CloudWatch Logs Insights query capabilities using APIs. For more information, see [StartQuery](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_StartQuery.html) in the *Amazon CloudWatch Logs API Reference*.

**Topics**
+ [

# Supported query languages
](CWL_AnalyzeLogData_Languages.md)
+ [

# Use natural language to generate and update CloudWatch Logs Insights queries
](CloudWatchLogs-Insights-Query-Assist.md)
+ [

# Supported logs and discovered fields
](CWL_AnalyzeLogData-discoverable-fields.md)
+ [

# Create field indexes to improve query performance and reduce scan volume
](CloudWatchLogs-Field-Indexing.md)
+ [

# Use facets to group and explore logs
](CloudWatchLogs-Facets.md)
+ [

# Pattern analysis
](CWL_AnalyzeLogData_Patterns.md)
+ [

# Save and re-run CloudWatch Logs Insights queries
](CWL_Insights-Saving-Queries.md)
+ [

# Add query to dashboard or export query results
](CWL_ExportQueryResults.md)
+ [

# View running queries or query history
](CloudWatchLogs-Insights-Query-History.md)
+ [

# Encrypt query results with AWS Key Management Service
](CloudWatchLogs-Insights-Query-Encrypt.md)
+ [

# Generate a natural language summary from CloudWatch Logs Insights query results
](CloudWatchLogs-Insights-Query-Results-Summary.md)

# Supported query languages
<a name="CWL_AnalyzeLogData_Languages"></a>

The following sections list the commands supported in each query language. They also describe the syntax format and provide sample queries.

**Topics**
+ [

# CloudWatch Logs Insights query language (Logs Insights QL)
](CWL_AnalyzeLogData_LogsInsights.md)
+ [

# OpenSearch Piped Processing Language (PPL)
](CWL_AnalyzeLogData_PPL.md)
+ [

# OpenSearch Structured Query Language (SQL)
](CWL_AnalyzeLogData_SQL.md)

# CloudWatch Logs Insights query language (Logs Insights QL)
<a name="CWL_AnalyzeLogData_LogsInsights"></a>

This section includes full documentation of Logs Insights QL commands and functions. It also includes sample queries for this language.

For information on other query languages you can use, see [OpenSearch Service PPL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_PPL.html), [OpenSearch Service SQL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_SQL.html), and [CloudWatch Metrics Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/query_with_cloudwatch-metrics-insights.html).

**Topics**
+ [

# CloudWatch Logs Insights language query syntax
](CWL_QuerySyntax.md)
+ [

# Get started with Logs Insights QL: Query tutorials
](CWL_AnalyzeLogData_Tutorials.md)
+ [

# Sample queries
](CWL_QuerySyntax-examples.md)
+ [

# Compare (diff) with previous time ranges
](CWL_AnalyzeLogData_Compare.md)
+ [

# Visualize log data in graphs
](CWL_Insights-Visualizing-Log-Data.md)

# CloudWatch Logs Insights language query syntax
<a name="CWL_QuerySyntax"></a>

 This section provides details about the Logs Insights QL. The query syntax supports different functions and operations that include but aren't limited to general functions, arithmetic and comparison operations, and regular expressions.

**Important**  
To avoid incurring excessive charges by running large queries, keep in mind the following best practices:  
Select only the necessary log groups for each query.
Always specify the narrowest possible time range for your queries.
When you use the console to run queries, cancel all your queries before you close the CloudWatch Logs Insights console page. Otherwise, queries continue to run until completion.
When you add a CloudWatch Logs Insights widget to a dashboard, ensure that the dashboard is not refreshing at a high frequency, because each refresh starts a new query.

To create queries that contain multiple commands, separate the commands with the pipe character (**\$1**).

To create queries that contain comments, set off the comments with the hash character (**\$1**). 

**Note**  
 CloudWatch Logs Insights automatically discovers fields for different log types and generates fields that start with the **@** character. For more information about these fields, see [ Supported logs and discovered fields](https://docs.aws.amazon.com/en_us/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData-discoverable-fields.html) in the *Amazon CloudWatch User Guide*. 

The following table briefly describes each command. Following this table is a more comprehensive description of each command, with examples.

**Note**  
All Logs Insights QL query commands are supported on log groups in the Standard log class. Log groups in the Infrequent Access log class support all Logs Insights QL query commands except `pattern`, `diff`, and `unmask`.


|  |  | 
| --- |--- |
| **` anomaly`**  | Identifies unusual patterns in your log data using machine learning.  | 
| **` display`**  |  Displays a specific field or fields in query results.  | 
| **` fields`**  |  Displays specific fields in query results and supports functions and operations you can use to modify field values and create new fields to use in your query.  | 
| **` filter`**  |  Filters the query to return only the log events that match one or more conditions.  | 
| **` filterIndex`**  |  Forces a query to attempt to scan only the log groups that are both indexed on the field mentioned in a field index and also contain a value for that field index. This reduces scanned volume by attempting to scan only log events from these log groups that contain the value specified in the query for this field index.  This command is not supported for log groups in the Infrequent Access log class. | 
| **` pattern`**  | Automatically clusters your log data into patterns. A pattern is shared text structure that recurs among your log fields. CloudWatch Logs Insights provides ways for you to analyze the patterns found in your log events. For more information, see [Pattern analysis](CWL_AnalyzeLogData_Patterns.md). | 
| **` diff`**  | Compares the log events found in your requested time period with the log events from a previous time period of equal length, so that you can look for trends and find out if certain log events are new.  | 
| **` parse`**  |  Extracts data from a log field to create an extracted field that you can process in your query. **`parse`** supports both glob mode using wildcards, and regular expressions.  | 
| **` sort`**  | Displays the returned log events in ascending (`asc`) or descending (`desc`) order.  | 
| **` SOURCE`**  | Including `SOURCE` in a query is a useful way to specify a large amount of log groups based on log group name prefix, account identifiers, and log group class to include in a query. This command is supported only when you create a query in the AWS CLI or programmatically, not in the CloudWatch console.  | 
| **` stats`**  |  Calculate aggregate statistics using values in the log fields.  | 
| **` limit`**  | Specifies a maximum number of log events that you want your query to return. Useful with **`sort`** to return "top 20" or "most recent 20" results.  | 
| **` dedup`**  |  Removes duplicate results based on specific values in fields that you specify. | 
| **` unmask`**  |  Displays all the content of a log event that has some content masked because of a data protection policy. For more information about data protection in log groups, see [Help protect sensitive log data with masking](mask-sensitive-log-data.md).  | 
|   **`[unnest](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Unnest.html)`**   |   Flattens a list taken as input to produce multiple records with a single record for each element in the list.   | 
| **` lookup`**  | Enriches log events with data from a lookup table by matching field values. Use lookup tables to add reference data such as user details, application names, or product information to your query results. | 
| ** [Other operations and functions](CWL_QuerySyntax-operations-functions.md)**  | CloudWatch Logs Insights also supports many comparison, arithmetic, datetime, numeric, string, IP address, and general functions and operations.  | 

The following sections provide more details about the CloudWatch Logs Insights query commands.

**Topics**
+ [

# Logs Insights QL commands supported in log classes
](CWL_AnalyzeLogData_Classes.md)
+ [

# anomaly
](CWL_QuerySyntax-Anomaly.md)
+ [

# **display**
](CWL_QuerySyntax-Display.md)
+ [

# fields
](CWL_QuerySyntax-Fields.md)
+ [

# filter
](CWL_QuerySyntax-Filter.md)
+ [

# filterIndex
](CWL_QuerySyntax-FilterIndex.md)
+ [

# SOURCE
](CWL_QuerySyntax-Source.md)
+ [

# pattern
](CWL_QuerySyntax-Pattern.md)
+ [

# diff
](CWL_QuerySyntax-Diff.md)
+ [

# parse
](CWL_QuerySyntax-Parse.md)
+ [

# sort
](CWL_QuerySyntax-Sort.md)
+ [

# stats
](CWL_QuerySyntax-Stats.md)
+ [

# limit
](CWL_QuerySyntax-Limit.md)
+ [

# dedup
](CWL_QuerySyntax-Dedup.md)
+ [

# unmask
](CWL_QuerySyntax-Unmask.md)
+ [

# unnest
](CWL_QuerySyntax-Unnest.md)
+ [

# lookup
](CWL_QuerySyntax-Lookup.md)
+ [

# Boolean, comparison, numeric, datetime, and other functions
](CWL_QuerySyntax-operations-functions.md)
+ [

# Fields that contain special characters
](CWL_QuerySyntax-Guidelines.md)
+ [

# Use aliases and comments in queries
](CWL_QuerySyntax-alias.md)

# Logs Insights QL commands supported in log classes
<a name="CWL_AnalyzeLogData_Classes"></a>

All Logs Insights QL query commands are supported on log groups in the Standard log class. Log groups in the Infrequent Access log class support all query commands except `pattern`, `diff`, `filterIndex`, and `unmask`.

# anomaly
<a name="CWL_QuerySyntax-Anomaly"></a>

 Use `anomaly` to automatically identify unusual patterns and potential issues within your log data using machine learning. 

The `anomaly` command extends the existing `pattern` functionality and leverages advanced analytics to help identify potential anomalies in log data. You can use `anomaly` to reduce the time it takes to identify and resolve operational issues by automatically surfacing unusual patterns or behaviors in your logs.

The `anomaly` command works with the ` pattern` command to first identify log patterns, then detect anomalies within those patterns. You can also combine `anomaly` with the ` filter` or ` sort` commands to focus anomaly detection on specific subsets of your data. 

**Anomaly Command Input**

 The `anomaly` command is typically used after the ` pattern` command to analyze the patterns identified in your log data. The command does not require additional parameters and analyzes the output from preceding commands in your query. 

**Types of Anomalies Identified**

 The `anomaly` command identifies five distinct types of anomalies:
+ *Pattern Frequency Anomalies*: Unusual frequencies of specific log patterns, such as when an application starts generating more error messages than usual.
+ *New Pattern Anomalies*: Previously unseen log patterns that may indicate new types of errors or messages appearing in your logs.
+ *Token Variation Anomalies*: Unexpected changes in log message contents that may indicate unusual variations in expected log formats.
+ *Numerical Token Anomalies*: Unusual changes in numerical values within logs that can help detect potential performance issues or unexpected metric variations.
+ *HTTP Error Code Anomalies*: Patterns related to HTTP error responses, particularly useful when monitoring web applications and APIs.

**Anomaly Command Output**

 The `anomaly` command preserves all fields from the input data and adds anomaly detection results to help identify unusual patterns in your log data.

**Examples**

The following command identifies patterns in your log data and then detects anomalies within those patterns:

```
fields @timestamp, @message
| pattern @message
| anomaly
```

The `anomaly` command can be used with filtering to focus on specific log types:

```
fields @timestamp, @message
| filter @type = "REPORT"
| pattern @message
| anomaly
```

The `anomaly` command can be combined with sorting to organize results:

```
fields @timestamp, @message
| filter @type = "ERROR"
| pattern @message
| anomaly
| sort @timestamp desc
```

# **display**
<a name="CWL_QuerySyntax-Display"></a>

 Use `display` to show a specific field or fields in query results. 

 The `display` command shows only the fields you specify. If your query contains multiple `display` commands, the query results show only the field or fields that you specified in the final `display` command.

 **Example: Display one field** 

 The code snippet shows an example of a query that uses the parse command to extract data from `@message` to create the extracted fields `loggingType` and `loggingMessage`. The query returns all log events where the values for `loggingType` are **ERROR**. `display` shows only the values for `loggingMessage` in the query results. 

```
fields @message
| parse @message "[*] *" as loggingType, loggingMessage
| filter loggingType = "ERROR"
| display loggingMessage
```

**Tip**  
 Use `display` only once in a query. If you use `display` more than once in a query, the query results show the field specified in the last occurrence of `display` command being used. 

# fields
<a name="CWL_QuerySyntax-Fields"></a>

 Use `fields` to show specific fields in query results. 

If your query contains multiple `fields` commands and doesn't include a `display` command, the results display all of the fields that are specified in the `fields` commands.

 ** Example: Display specific fields ** 

 The following example shows a query that returns 20 log events and displays them in descending order. The values for `@timestamp` and `@message` are shown in the query results. 

```
fields @timestamp, @message
| sort @timestamp desc
| limit 20
```

Use `fields` instead of `display` when you want to use the different functions and operations supported by `fields` for modifying field values and creating new fields that can be used in queries. 

You can use the `fields` command with the keyword *as* to create extracted fields that use fields and functions in your log events. For example, `fields ispresent as isRes` creates an extracted field named `isRes`, and the extracted field can be used in the rest of your query. 

# filter
<a name="CWL_QuerySyntax-Filter"></a>

 Use `filter` to get log events that match one or more conditions. 

 ** Example: Filter log events using one condition ** 

 The code snippet shows an example of a query that returns all log events where the value for `range` is greater than ***3000***. The query limits the results to 20 log events and sorts the logs events by `@timestamp` and in descending order. 

```
fields @timestamp, @message
| filter (range>3000)
| sort @timestamp desc
| limit 20
```

 ** Example: Filter log events using more than one condition ** 

 You can use the keywords `and` and `or` to combine more than one condition. 

 The code snippet shows an example of a query that returns log events where the value for `range` is greater than ***3000*** and value for `accountId` is equal to ***123456789012***. The query limits the results to 20 log events and sorts the logs events by `@timestamp` and in descending order. 

```
fields @timestamp, @message
| filter (range>3000 and accountId=123456789012)
| sort @timestamp desc
| limit 20
```

## Indexed fields and the filter command
<a name="CWL_QuerySyntax-index"></a>

If you have created field indexes for a log group, you can leverage those field indexes to make your `filter` queries more efficient and reduce scanned volume. For example, suppose you have created a field index for `requestId`. Then, any CloudWatch Logs Insights query on that log group that includes `filter requestId = value` or `filter requestId IN [value, value, ...]` will attempt to skip processing log events that are known not to include the indexed field. By attempting to scan only the log events that are known to contain that indexed field, scan volume can be reduced and the query is faster.

For more information about field indexes and how to create them, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md).

**Important**  
Only queries with `filter fieldName =...` and `filter fieldName IN...` will benefit from the field index improvements. Queries with `filter fieldName like` don't use indexes and always scan all log events in the selected log groups.

** Example: Find log events that are related to a certain request ID, using indexes ** 

 This example assumes that you have created a field index on `requestId`. For log groups that use this field index, the query will leverage field indexes to attempt to scan the least amount of log events to find events with `requestId` with a value of `123456` 

```
fields @timestamp, @message
| filter requestId = "1234656"
| limit 20
```

## Matches and regular expressions in the filter command
<a name="CWL_QuerySyntax-regex"></a>

The filter command supports the use of regular expressions. You can use the following comparison operators (`=`, `!=`, `<`, `<=`, `>`, `>=`) and Boolean operators (`and`, `or`, and `not`).

You can use the keyword `in` to test for set membership and check for elements in an array. To check for elements in an array, put the array after `in`. You can use the Boolean operator `not` with `in`. You can create queries that use `in` to return log events where fields are string matches. The fields must be complete strings. For example, the following code snippet shows a query that uses `in` to return log events where the field `logGroup` is the complete string `example_group`.

```
fields @timestamp, @message
| filter logGroup in ["example_group"]
```

You can use the keyword phrases `like` and `not like` to match substrings. You can use the regular expression operator `=~` to match substrings. To match a substring with `like` and `not like`, enclose the substring that you want to match in single or double quotation marks. You can use regular expression patterns with `like` and `not like`. To match a substring with the regular expression operator, enclose the substring that you want to match in forward slashes. The following examples contain code snippets that show how you can match substrings using the `filter` command.

**Examples: Match substrings**

 The following examples return log events where `f1` contains the word ***Exception***. All three examples are case sensitive. 

The first example matches a substring with `like`. 

```
fields f1, f2, f3 
| filter f1 like "Exception"
```

 The second example matches a substring with `like` and a regular expression pattern. 

```
fields f1, f2, f3 
| filter f1 like /Exception/
```

 The third example matches a substring with a regular expression. 

```
fields f1, f2, f3 
| filter f1 =~ /Exception/
```

**Example: Match substrings with wildcards**

 You can use the period symbol (`.`) as a wildcard in regular expressions to match substrings. In the following example, the query returns matches where the value for `f1` begins with the string `ServiceLog`. 

```
fields f1, f2, f3
| filter f1 like /ServiceLog./
```

 You can place the asterisk symbol after the period symbol (`.*`) to create a greedy quantifier that returns as many matches as possible. For example, the following query returns matches where the value for `f1` not only begins with the string `ServiceLog`, but also includes the string `ServiceLog`. 

```
fields f1, f2, f3
| filter f1 like /ServiceLog.*/
```

 Possible matches can be formatted like the following: 
+  `ServiceLogSampleApiLogGroup` 
+  `SampleApiLogGroupServiceLog` 

**Example: Exclude substrings from matches**

The following example shows a query that returns log events where `f1` doesn't contain the word ***Exception***. The example is case senstive.

```
fields f1, f2, f3 
| filter f1 not like "Exception"
```

**Example: Match substrings with case-insensitive patterns**

You can match substrings that are case insensitive with `like` and regular expressions. Place the following parameter (**?i**) before the substring you want to match. The following example shows a query that returns log events where `f1` contains the word ***Exception*** or ***exception***.

```
fields f1, f2, f3 
| filter f1 like /(?i)Exception/
```

# filterIndex
<a name="CWL_QuerySyntax-FilterIndex"></a>

 Use `filterIndex` to return indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query. For these log groups that are indexed on this field, it further optimizes the query by skipping the log groups that do not have any log events containing the field specified in the query for the indexed field. It further reduces scanned volume by attempting to scan only log events from these log groups that match the value specified in the query for this field index. For more information about field indexes and how to create them, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md).

Using `filterIndex` with indexed fields can help you query log groups that include petabytes of log data efficiently by limiting the actual search space to log groups and log events that have field indexes.

For example, suppose that you have created a field index for `IPaddress` in some of the log groups in your account. You can then create the following query and choose to query all log groups in the account to find log events that include the value `198.51.100.0` in the `IPaddress` field.

```
fields @timestamp, @message
| filterIndex IPaddress = "198.51.100.0"
| limit 20
```

The `filterIndex` command causes this query to attempt to skip all log groups that are not indexed for `IPaddress`. Additionally, within the log groups that are indexed, the query skips log events that have an `IPaddress` field but not observed `198.51.100.0` as the value for that field.

Use the `IN` operator to expand the results to any of multiple values for the indexed fields. The following example finds logs events that include either the value `198.51.100.0` or `198.51.100.1` in the `IPaddress` field. 

```
fields @timestamp, @message 
| filterIndex IPaddress in ["198.51.100.0", "198.51.100.1"]
| limit 20
```

CloudWatch Logs provides default field indexes for all log groups in the Standard log class. Default field indexes are automatically available for the following fields: 
+ `@logStream`
+ `@aws.region`
+ `@aws.account`
+ `@source.log`
+ `@data_source_name`
+ `@data_source_type`
+ `@data_format`
+ `traceId`
+ `severityText`
+ `attributes.session.id`

CloudWatch Logs provides default field indexes for certain data source name and type combinations as well. Default field indexes are automatically available for the following data source name and type combinations:


| Data Source Name and Type | Default Field Indexes | 
| --- | --- | 
|  `amazon_vpc.flow`  |  `action` `logStatus` `region` `flowDirection` `type`  | 
|  `amazon_route53.resolver_query`  |  `query_type` `transport` `rcode`  | 
|  `aws_waf.access`  |  `action` `httpRequest.country`  | 
|  `aws_cloudtrail.data` ` aws_cloudtrail.management`  |  `eventSource` `eventName` `awsRegion` `userAgent` `errorCode` `eventType` `managementEvent` `readOnly` `eventCategory` `requestId`  | 

Default field indexes are in addition to any custom field indexes you define within your policy. Default field indexes are not counted towards your [field index quota](CloudWatchLogs-Field-Indexing-Syntax.md). 

## filterIndex compared to filter
<a name="CWL_QuerySyntax-FilterIndex-Filter"></a>

To illustrate the difference between `filterIndex` and `filter`, consider the following example queries. Assume that you have created a field index for `IPaddress`, for four of your log groups, but not for a fifth log group. The following query using `filterIndex` will skip scanning the log group that doesn't have the field indexed. For each indexed log group, it attempts to scan only log events that have the indexed field, and it also returns only results from after the field index was created.

```
fields @timestamp, @message 
| filterIndex IPaddress = "198.51.100.0" 
| limit 20
```

In contrast, if you use `filter` instead of `filterIndex` for a query of the same five log groups, the query will attempt to scan not only the log events that contain the value in the indexed log groups, but will also scan the fifth log group that isn't indexed, and it will scan every log event in that fifth log group.

```
fields @timestamp, @message 
| filter IPaddress = "198.51.100.0" 
| limit 20
```

# SOURCE
<a name="CWL_QuerySyntax-Source"></a>

Including `SOURCE` in a query is a useful way to specify the log groups and/or data sources to include in a query when you are using the AWS CLI or API to create a query. The `SOURCE` command is supported only in the AWS CLI and API, not in the CloudWatch console. When you use the CloudWatch console to start a query, you use the console interface to specify the log groups. 

Query log groups

To use `SOURCE` to specify the log groups to query, you can use the following keywords:
+ `namePrefix` runs the query against log groups that have names that start with the string that you specify. If you omit this, all log groups are queried.

  You can include as many as five prefixes in the list.
+ `accountIdentifier` runs the query against log groups in the specified AWS account. This works only when you run the query in a monitoring account. If you omit this, the default is to query all linked source accounts and the current monitoring account. For more information about cross-account observability, see [CloudWatch cross-account observability](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html).

  You can include as many as 20 account identifiers in the list.
+ `logGroupClass` runs the query against log groups that are in the specified log class, either Standard or Infrequent Access. If you omit this, the default of Standard log class is used. For more information about log classes, see [Log classes](CloudWatch_Logs_Log_Classes.md).

Because you can specify large numbers of log groups to query this way, we recommend that you use `SOURCE` only in queries that leverage field indexes that you have created. For more information about indexing fields in log groups, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md)

The following example selects all log groups in the account. If this is a monitoring account then the log groups across monitoring and all the source accounts will be selected. If the total number of log groups exceed 10,000 then you will see an error prompting you to reduce the number of log groups by using a different log group selection method.

```
SOURCE logGroups()
```

The following example selects the log groups in the `111122223333` source account. If you start a query in a monitoring account in CloudWatch cross-account observability, log groups in all source accounts and in the monitoring account are selected by default.

```
SOURCE logGroups(accountIdentifiers:['111122223333'])
```

The next example selects log groups based on name prefixes.

```
SOURCE logGroups(namePrefix: ['namePrefix1', 'namePrefix2'])
```

The following example selects all log groups in the Infrequent Access log class. If you don't include the `class` identifier, the query applies only to log groups in the Standard log class, which is the default. 

```
SOURCE logGroups(class: ['INFREQUENT_ACCESS'])
```

The next example selects log groups in the 111122223333 account that start with specific name prefixes and are in the Standard log class. The class is not mentioned in the command because Standard is the default log class value. 

```
SOURCE logGroups(accountIdentifiers:['111122223333'], namePrefix: ['namePrefix1', 'namePrefix2']
```

The final example displays how to use the `SOURCE` command with the `start-query` AWS CLI command.

```
aws logs start-query 
--region us-east-1 
--start-time 1729728200 
--end-time 1729728215 
--query-string "SOURCE logGroups(namePrefix: ['Query']) | fields @message | limit 5"
```

Query data sources

To use `SOURCE` to specify the data sources to query, you can use the `dataSource` keyword. You can include as many as ten data sources in the list.

 The following example selects the `amazon_vpc.flow` data source. 

```
SOURCE dataSource(['amazon_vpc.flow'])
```

 The following example selects the `amazon_vpc.flow` data source and limits the log groups based on a log group name prefix. 

```
SOURCE dataSource(['amazon_vpc.flow']) logGroups(namePrefix: ['namePrefix1'])
```

# pattern
<a name="CWL_QuerySyntax-Pattern"></a>

 Use `pattern` to automatically cluster your log data into patterns. 

A pattern is a shared text structure that recurs among your log fields. You can use `pattern` to surface emerging trends, monitor known errors, and identify frequently occurring or high-cost log lines. CloudWatch Logs Insights also provides a console experience you can use to find and further analyze patterns in your log events. For more information, see [Pattern analysis](CWL_AnalyzeLogData_Patterns.md).

Because the `pattern` command automatically identifies common patterns, you can use it as a starting point to search and analyze yours logs. You can also combine `pattern` with the ` filter`, ` parse`, or ` sort` commands to identify patterns in more fine-tuned queries. 

**Pattern Command Input**

 The `pattern` command expects one of the following inputs: the `@message` field, an extracted field created using the ` parse` command, or a string manipulated using one or more [String functions](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-operations-functions.html#CWL_QuerySyntax-string-functions). 

If CloudWatch Logs can't infer the type of data that a dynamic token represents, displays it as <Token-*number*>, and *number* indicates where in the pattern this token appears, compared to the other dynamic tokens.

Common examples of dynamic tokens include error codes, IP addresses, timestamps, and request IDs.

**Pattern Command Output**

 The `pattern` command produces the following output:
+ `@pattern`: A shared text structure that recurs among your log event fields. Fields that vary within a pattern, such as a request ID or timestamp, are represented by *tokens*. If CloudWatch Logs can determine the type of data that a dynamic token represents, it displays the token as `<string-number>`. The *string* is a description of the type of data that the token represents. The *number* shows where in the pattern this token appears, compared to the other dynamic tokens.

  CloudWatch Logs assigns the string part of the name based on analyzing the content of the log events that contain it.

  If CloudWatch Logs can't infer the type of data that a dynamic token represents, displays it as <Token-*number*>, and *number* indicates where in the pattern this token appears, compared to the other dynamic tokens.

  For example, `[INFO] Request time: <Time-1> ms` is a potential output for the log message `[INFO] Request time: 327 ms`.
+ `@ratio`: The ratio of log events from a selected time period and specified log groups that match an identified pattern. For example, if half of the log events in the selected log groups and time period match the pattern, `@ratio` returns `0.50`
+ `@sampleCount`: A count of the number of log events from a selected time period and specified log groups that match an identified pattern.
+ `@severityLabel`: The log severity or level, which indicates the type of information contained in a log. For example, `Error`, `Warning`, `Info`, or `Debug`.

**Examples**

The following command identifies logs with similar structures in specified log group(s) over the selected time range, grouping them by pattern and count

```
pattern @message
```

The `pattern` command can be used in combination with the ` filter` command

```
filter @message like /ERROR/
| pattern @message
```

The `pattern` command can be use with the ` parse` and ` sort` commands

```
filter @message like /ERROR/
| parse @message 'Failed to do: *' as cause
| pattern cause
| sort @sampleCount asc
```

# diff
<a name="CWL_QuerySyntax-Diff"></a>

Compares the log events found in your requested time period with the log events from a previous time period of equal length. This way, you can look for trends and find whether specific log events are new.

Add a modifier to the `diff` command to specify the time period that you want to compare with:
+ `diff` compares the log events in the currently selected time range to the log events of the immediately preceding time range.
+ `diff previousDay` compares the log events in the currently selected time range to the log events from the same time the preceding day.
+ `diff previousWeek` compares the log events in the currently selected time range to the log events from the same time the preceding week.
+ `diff previousMonth` compares the log events in the currently selected time range to the log events from the same time the preceding month.

For more information, see [Compare (diff) with previous time ranges](CWL_AnalyzeLogData_Compare.md).

# parse
<a name="CWL_QuerySyntax-Parse"></a>

 Use `parse` to extract data from a log field and create an extracted field that you can process in your query. **`parse`** supports both glob mode using wildcards, and regular expressions. For information about regular expression syntax, see [Supported regular expressions (regex) syntax](FilterAndPatternSyntax.md#regex-expressions).

 You can parse nested JSON fields with a regular expression. 

**Example: Parsing a nested JSON field**

 The code snippet shows how to parse a JSON log event that's been flattened during ingestion. 

```
{'fieldsA': 'logs', 'fieldsB': [{'fA': 'a1'}, {'fA': 'a2'}]}
```

 The code snippet shows a query with a regular expression that extracts the values for `fieldsA` and `fieldsB` to create the extracted fields `fld` and `array`. 

```
parse @message "'fieldsA': '*', 'fieldsB': ['*']" as fld, array
```

**Named capturing groups**

When you use **`parse`** with a regular expression, you can use named capturing groups to capture a pattern into a field. The syntax is `parse @message (?<Name>pattern)`

The following example uses a capturing group on a VPC flow log to extract the ENI into a field named `NetworkInterface`.

```
parse @message /(?<NetworkInterface>eni-.*?) / | display NetworkInterface, @message
```

**Note**  
 JSON log events are flattened during ingestion. Currently, parsing nested JSON fields with a glob expression isn't supported. You can only parse JSON log events that include no more than 200 log event fields. When you parse nested JSON fields, you must format the regular expression in your query to match the format of your JSON log event. 

## Examples of the parse command
<a name="CWL_QuerySyntax-parse-examples"></a>

**Use a glob expression to extract the fields `@user`, `@method`, and `@latency` from the log field `@message` and return the average latency for each unique combination of `@method` and `@user`.** 

```
parse @message "user=*, method:*, latency := *" as @user,
    @method, @latency | stats avg(@latency) by @method,
    @user
```

**Use a regular expression to extract the fields `@user2`, `@method2`, and `@latency2` from the log field `@message` and return the average latency for each unique combination of `@method2` and `@user2`.**

```
parse @message /user=(?<user2>.*?), method:(?<method2>.*?),
    latency := (?<latency2>.*?)/ | stats avg(latency2) by @method2, 
    @user2
```

**Extracts the fields `loggingTime`, `loggingType` and `loggingMessage`, filters down to log events that contain `ERROR` or `INFO` strings, and then displays only the `loggingMessage` and `loggingType` fields for events that contain an `ERROR` string.**

```
FIELDS @message
    | PARSE @message "* [*] *" as loggingTime, loggingType, loggingMessage
    | FILTER loggingType IN ["ERROR", "INFO"]
    | DISPLAY loggingMessage, loggingType = "ERROR" as isError
```

# sort
<a name="CWL_QuerySyntax-Sort"></a>

 Use `sort` to display log events in ascending (`asc`) or descending (`desc`) order by a specified field. You can use this with the `limit` command to create "top N" or "bottom N" queries. 

The sorting algorithm is an updated version of natural sorting. If you sort in ascending order, the following logic is used.
+  All non-number values come before all number values. *Number values* are values that include only numbers, not a mix of numbers and other characters.
+ For non-number values, the algorithm groups consecutive numeric characters and consecutive alphabetic characters into separate chunks for comparison. It orders non-numeric portions by their Unicode values, and it orders numeric portions by their length first and then by their numerical value.

For more information about Unicode order, see [List of Unicode characters](https://en.wikipedia.org/wiki/List_of_Unicode_characters).

For example, the following is the result of a sort in ascending order.

```
!:	>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> sorted by unicode order
#
*%04
0#	>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Alphanumeric starting with numbers
5A
111A   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  Starts with more digits than 5A, so it sorted to be later than 5A
2345_
@	>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2345 is compared with @ in the unicode order, 
@_
A	>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Values starting with letters
A9876fghj
a12345hfh
0	>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Number values
01
1
2
3
```

If you sort in descending order, the sort results are the reverse.

For example, the following query for Amazon VPC flow logs finds the top 15 packet transfers across hosts.

```
stats sum(packets) as packetsTransferred by srcAddr, dstAddr
    | sort packetsTransferred  desc
    | limit 15
```

# stats
<a name="CWL_QuerySyntax-Stats"></a>

 Use `stats` to create visualizations of your log data such as bar charts, line charts, and stacked area charts. This helps you more efficiently identify patterns in your log data. CloudWatch Logs Insights generates visualizations for queries that use the `stats` function and one or more aggregation functions. 

For example, the following query in a Route 53 log group returns visualizations showing the distribution of Route 53 records per hour, by query type.

```
stats count(*) by queryType, bin(1h)
```

All such queries can produce bar charts. If your query uses the `bin()` function to group the data by one field over time, you can also see line charts and stacked area charts.

The following time units and abbreviations are supported with the `bin` function. For all units and abbreviations that include more than one character, adding s to pluralize is supported. So both `hr` and `hrs` work to specify hours.
+ `millisecond` `ms` `msec`
+ `second` `s` `sec`
+ `minute` `m` `min`
+ `hour` `h` `hr`
+ `day` `d` 
+ `week` `w` 
+ `month` `mo` `mon`
+ `quarter` `q` `qtr`
+ `year` `y` `yr`

**Topics**
+ [

## Visualize time series data
](#CWL_Insights-Visualizing-TimeSeries)
+ [

## Visualize log data grouped by fields
](#CWL_Insights-Visualizing-ByFields)
+ [

## Use multiple stats commands in a single query
](#CWL_QuerySyntax-stats-multi)
+ [

## Functions to use with stats
](#CWL_QuerySyntax-stats-functions)

## Visualize time series data
<a name="CWL_Insights-Visualizing-TimeSeries"></a>

Time series visualizations work for queries with the following characteristics:
+ The query contains one or more aggregation functions. For more information, see [Aggregation Functions in the Stats Command](#CWL_Insights_Aggregation_Functions).
+ The query uses the `bin()` function to group the data by one field. 

These queries can produce line charts, stacked area charts, bar charts, and pie charts. 

**Examples**

For a complete tutorial, see [Tutorial: Run a query that produces a time series visualization](CWL_AnalyzeLogData_VisualizationQuery.md). 

Here are more example queries that work for time series visualization.

The following query generates a visualization of the average values of the `myfield1` field, with a data point created every five minutes. Each data point is the aggregation of the averages of the `myfield1` values from the logs from the previous five minutes.

```
stats avg(myfield1) by bin(5m)
```

The following query generates a visualization of three values based on different fields, with a data point created every five minutes. The visualization is generated because the query contains aggregate functions and uses `bin()` as the grouping field.

```
stats avg(myfield1), min(myfield2), max(myfield3) by bin(5m)
```

**Line chart and stacked area chart restrictions**

Queries that aggregate log entry information but don't use the `bin()` function can generate bar charts. However, the queries cannot generate line charts or stacked area charts. For more information about these types of queries, see [Visualize log data grouped by fields](#CWL_Insights-Visualizing-ByFields).

## Visualize log data grouped by fields
<a name="CWL_Insights-Visualizing-ByFields"></a>

You can produce bar charts for queries that use the `stats` function and one or more aggregation functions. For more information, see [Aggregation Functions in the Stats Command](#CWL_Insights_Aggregation_Functions).

To see the visualization, run your query. Then choose the **Visualization** tab, select the arrow next to **Line**, and choose **Bar**. Visualizations are limited to up to 100 bars in the bar chart.

**Examples**

For a complete tutorial, see [Tutorial: Run a query that produces a visualization grouped by log fields](CWL_AnalyzeLogData_VisualizationFieldQuery.md). The following paragraphs include more example queries for visualization by fields.

The following VPC flow log query finds the average number of bytes transferred per session for each destination address.

```
stats avg(bytes) by dstAddr
```

You can also produce a chart that includes more than one bar for each resulting value. For example, the following VPC flow log query finds the average and maximum number of bytes transferred per session for each destination address.

```
stats avg(bytes), max(bytes) by dstAddr
```

The following query finds the number of Amazon Route 53 query logs for each query type.

```
stats count(*) by queryType
```

## Use multiple stats commands in a single query
<a name="CWL_QuerySyntax-stats-multi"></a>

You can use as many as two `stats` commands in a single query. This enables you to perform an additional aggregation on the output of the first aggregation.

**Example: Query with two `stats` commands**

For example, the following query first find the total traffic volume in 5-minute bins, then calculates the highest, lowest, and average traffic volume among those 5-minute bins.

```
FIELDS strlen(@message) AS message_length
| STATS sum(message_length)/1024/1024 as logs_mb BY bin(5m)
| STATS max(logs_mb) AS peak_ingest_mb, 
        min(logs_mb) AS min_ingest_mb, 
        avg(logs_mb) AS avg_ingest_mb
```

**Example: Combine multiple stats commands with other functions such as `filter`, `fields`, `bin`**

You can combine two `stats` commands with other commands such as `filter` and `fields` in a single query. For example, the following query finds the number of distinct IP addresses in sessions and finds the number of sessions by client platform, filters those IP addresses, and then finally finds the average of session requests per client platform.

```
STATS count_distinct(client_ip) AS session_ips, 
      count(*) AS requests BY session_id, client_platform
| FILTER session_ips > 1
| STATS count(*) AS multiple_ip_sessions, 
        sum(requests) / count(*) AS avg_session_requests BY client_platform
```

You can use `bin` and `dateceil` functions in queries with multiple `stats` commands. For example, the following query first combines messages into 5-minute blocks, then aggregates those 5-minute blocks into 10-minute blocks and calculates the highest, lowest, and average traffic volumes within each 10-minute block.

```
FIELDS strlen(@message) AS message_length
| STATS sum(message_length) / 1024 / 1024 AS logs_mb BY BIN(5m) as @t
| STATS max(logs_mb) AS peak_ingest_mb, 
        min(logs_mb) AS min_ingest_mb,
        avg(logs_mb) AS avg_ingest_mb BY dateceil(@t, 10m)
```

**Notes and limitations**

A query can have a maximum of two `stats` commands. This quota can't be changed. 

If you use a `sort` or `limit` command, it must appear after the second `stats` command. If it is before the second `stats` command, the query is not valid.

When a query has two `stats` commands, the partial results from the query do not begin displaying until the first `stats` aggregation is complete.

In the second `stats` command in a single query, you can refer only to fields that are defined in the first `stats` command. For example, the following query is not valid because the `@message` field won't be available after the first `stats` aggregation.

```
FIELDS @message
| STATS SUM(Fault) by Operation
# You can only reference `SUM(Fault)` or Operation at this point
| STATS MAX(strlen(@message)) AS MaxMessageSize # Invalid reference to @message
```

Any fields that you reference after the first `stats` command must be defined in that first `stats` command.

```
STATS sum(x) as sum_x by y, z
| STATS max(sum_x) as max_x by z
# You can only reference `max(sum_x)`, max_x or z at this point
```

**Important**  
The `bin` function always implicitly uses the `@timestamp` field. This means that you can't use `bin` in the second `stats` command without using the first `stats` command to propagate the `timestamp` field. For example, the following query is not valid.  

```
FIELDS strlen(@message) AS message_length
 | STATS sum(message_length) AS ingested_bytes BY @logStream
 | STATS avg(ingested_bytes) BY bin(5m) # Invalid reference to @timestamp field
```
Instead, define the `@timestamp` field in the first `stats` command, and then you can use it with `dateceil` in the second `stats` command as in the following example.  

```
FIELDS strlen(@message) AS message_length
 | STATS sum(message_length) AS ingested_bytes, max(@timestamp) as @t BY @logStream
 | STATS avg(ingested_bytes) BY dateceil(@t, 5m)
```

## Functions to use with stats
<a name="CWL_QuerySyntax-stats-functions"></a><a name="CWL_Insights_Aggregation_Functions"></a>

CloudWatch Logs Insights supports both stats aggregation functions and stats non-aggregation functions.

 Use statsaggregation functions in the `stats` command and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|  `avg(fieldName: NumericLogField)` |  number |  The average of the values in the specified field.  | 
|  `count()` `count(fieldName: LogField)` |  number |  Counts the log events. `count()` (or `count(*)`) counts all events returned by the query, while `count(fieldName)` counts all records that include the specified field name.  | 
|  `count_distinct(fieldName: LogField)` |  number |  Returns the number of unique values for the field. If the field has very high cardinality (contains many unique values), the value returned by `count_distinct` is just an approximation.  | 
|  `max(fieldName: LogField)` |  LogFieldValue |  The maximum of the values for this log field in the queried logs.  | 
|  `min(fieldName: LogField)` |  LogFieldValue |  The minimum of the values for this log field in the queried logs.  | 
|  `pct(fieldName: LogFieldValue, percent: number)` |  LogFieldValue |  A percentile indicates the relative standing of a value in a dataset. For example, `pct(@duration, 95)` returns the `@duration` value at which 95 percent of the values of `@duration` are lower than this value, and 5 percent are higher than this value.  | 
|  `stddev(fieldName: NumericLogField)` |  number |  The standard deviation of the values in the specified field.  | 
|  `sum(fieldName: NumericLogField)` |  number |  The sum of the values in the specified field.  | 

 **Stats non-aggregation functions** <a name="CWL_Insights_Non-Aggregation_Functions"></a>

 Use non-aggregation functions in the `stats` command and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|  `earliest(fieldName: LogField)` |  LogField |  Returns the value of `fieldName` from the log event that has the earliest timestamp in the queried logs.  | 
|  `latest(fieldName: LogField)` |  LogField |  Returns the value of `fieldName` from the log event that has the latest timestamp in the queried logs.  | 
|  `sortsFirst(fieldName: LogField)` |  LogField |  Returns the value of `fieldName` that sorts first in the queried logs.  | 
|  `sortsLast(fieldName: LogField)` |  LogField |  Returns the value of `fieldName` that sorts last in the queried logs.  | 

# limit
<a name="CWL_QuerySyntax-Limit"></a>

 Use `limit` to specify the number of log events that you want your query to return. If you omit `limit`, the query will return as many as 10,000 log events in the results. 

For example, the following example returns only the 25 most recent log events

```
fields @timestamp, @message | sort @timestamp desc | limit 25
```

# dedup
<a name="CWL_QuerySyntax-Dedup"></a>

 Use `dedup` to remove duplicate results based on specific values in fields that you specify. You can use `dedup` with one or more fields. If you specify one field with `dedup`, only one log event is returned for each unique value of that field. If you specify multiple fields, then one log event is returned for each unique combination of values for those fields.

Duplicates are discarded based on the sort order, with only the first result in the sort order being kept. We recommend that you sort your results before putting them through the `dedup` command. If the results are not sorted before being run through `dedup`, then the default descending sort order using `@timestamp` is used. 

Null values are not considered duplicates for evaluation. Log events with null values for any of the specified fields are retained. To eliminate fields with null values, use **`filter`** using the `isPresent(field)` function. 

The only query command that you can use in a query after the `dedup` command is `limit`.

When you use `dedup` in a query, the console displays a message such as **Showing X of Y records**, where X is the number of deduplicated results and Y is the total number of records matched before deduplication. This indicates that duplicate records were removed and does not mean that data is missing.

 **Example: See only the most recent log event for each unique value of the field named `server`** 

 The following example displays the `timestamp`, `server`, `severity`, and `message` fields for only the most recent event for each unique value of `server`. 

```
fields @timestamp, server, severity, message 
| sort @timestamp desc 
| dedup server
```

For more samples of CloudWatch Logs Insights queries, see [General queries](CWL_QuerySyntax-examples.md#CWL_QuerySyntax-examples-general). 

# unmask
<a name="CWL_QuerySyntax-Unmask"></a>

 Use `unmask` to display all the content of a log event that has some content masked because of a data protection policy. To use this command, you must have the `logs:Unmask` permission.

For more information about data protection in log groups, see [Help protect sensitive log data with masking](mask-sensitive-log-data.md). 

# unnest
<a name="CWL_QuerySyntax-Unnest"></a>

 Use `unnest` to flatten a list taken as input to produce multiple records with a single record for each element in the list. Based on the number of items a field contains, this command discards the current record and generates new records. Each record includes the `unnested_field`, which represents an item. All other fields come from the original record. 

 The input for `unnest` is `LIST`, which comes from the `jsonParse` function. For more information, see [Structure types](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-operations-functions.html#CWL_QuerySyntax-structure-types). Any other types, such as `MAP`, `String` and `numbers`, are treated as a list with one item in `unnest`. 

**Command structure**  
 The following example describes the format of this command. 

```
unnest field into unnested_field
```

**Example query**  
 The following example parses a JSON object string and expands a list of field events. 

```
fields jsonParse(@message) as json_message 
| unnest json_message.events into event
| display event.name
```

The log event for this example query could be a JSON string as follows:

```
{
   "events": [
        {
            "name": "exception"
        },
        {
            "name": "user action"
        }
   ]
}
```

In this case, the sample query produces two records in the query result, one with `event.name` as `exception` and another with `event.name` as **user action**

**Example query**  
 The following example flattens a list and then filters out items. 

```
fields jsonParse(@message) as js 
| unnest js.accounts into account 
| filter account.type = "internal"
```

**Example query**  
 The following example flattens a list for aggregation. 

```
fields jsonParse(trimmedData) as accounts 
| unnest accounts into account 
| stats sum(account.droppedSpans) as n by account.accountId 
| sort n desc 
| limit 10
```

# lookup
<a name="CWL_QuerySyntax-Lookup"></a>

Use `lookup` to enrich your query results with reference data from a lookup table. A lookup table contains CSV data that you upload to Amazon CloudWatch Logs. When a query runs, the `lookup` command matches a field in your log events against a field in the lookup table and appends the specified output fields to the results.

Use lookup tables for data enrichment scenarios such as mapping user IDs to user details, product codes to product information, or error codes to error descriptions.

## Creating and managing lookup tables
<a name="CWL_QuerySyntax-Lookup-tables"></a>

Before you can use the `lookup` command in a query, you must create a lookup table. You can create and manage lookup tables from the CloudWatch console or by using the Amazon CloudWatch Logs API.

**To create a lookup table (console)**  


1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Settings**, and then choose the **Logs** tab.

1. Scroll to **Lookup tables** and choose **Manage**.

1. Choose **Create lookup table**.

1. Enter a name for the lookup table. The name can contain only alphanumeric characters, hyphens, and underscores.

1. (Optional) Enter a description.

1. Upload a CSV file. The file must include a header row with column names, use UTF-8 encoding, and not exceed 10 MB.

1. (Optional) Specify a AWS KMS key to encrypt the table data.

1. Choose **Create**.

After you create a lookup table, you can view it in the CloudWatch Logs Insights query editor. Choose the **Lookup tables** tab to browse available tables and their fields.

To update a lookup table, select the table and choose **Actions**, **Update**. Upload a new CSV file to replace all existing content. To delete a lookup table, choose **Actions**, **Delete**.

**Note**  
You can create up to 100 lookup tables per account per AWS Region. CSV files can be up to 10 MB. You can also manage lookup tables by using the Amazon CloudWatch Logs API. For more information, see [CreateLookupTable](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLookupTable.html) in the *Amazon CloudWatch Logs API Reference*.

**Note**  
If the lookup table is encrypted with a KMS key, the caller must have the `kms:Decrypt` permission on the key (the KMS key used to encrypt the lookup table) to use the `StartQuery` API with a query that references that lookup table. For more information, see [Encrypt lookup tables in CloudWatch Logs using AWS Key Management Service](encrypt-lookup-tables-kms.md).

## Query syntax for lookup
<a name="CWL_QuerySyntax-Lookup-syntax"></a>

**Command structure**  
The following shows the format of this command.

```
lookup table lookup-field as log-field [,...] output-mode output-field[,...]
```

The command uses the following arguments:
+ `table` – The name of the lookup table to use.
+ `lookup-field` – The field in the lookup table to match against.
+ `log-field` – The field in your log events to match. The match is exact and case-sensitive.
+ `output-mode` – Specify `OUTPUT` to add the output fields to the results. If a field with the same name already exists in the log event, it is overwritten.
+ `output-field` – One or more fields from the lookup table to add to the results.

**Example: Enrich log events with user details**  
Suppose you have a log group with events that contain an `id` field, and a lookup table named `user_data` with columns `id`, `name`, `email`, and `department`. The following query enriches each log event with the user's name, email, and department from the lookup table.

```
fields action, status, name, email, department
| lookup user_data id OUTPUT name, email, department
```

**Example: Use lookup with aggregation**  
You can use lookup output fields with aggregation functions. The following query enriches log events with user details and then counts events grouped by email address.

```
fields user_id, action, username, email, department
| lookup user_data user_id OUTPUT username, email, department
| stats count(*) by email
```

**Example: Use lookup with filter**  
You can filter results based on fields returned by the lookup. The following query enriches log events and then filters to show only events from a specific department.

```
fields user_id, action
| lookup user_data user_id OUTPUT username, email, department
| filter department = "Engineering"
```

# Boolean, comparison, numeric, datetime, and other functions
<a name="CWL_QuerySyntax-operations-functions"></a>

 CloudWatch Logs Insights supports many other operations and functions in queries, as explained in the following sections. 

**Topics**
+ [

## Arithmetic operators
](#CWL_QuerySyntax-operations-arithmetic)
+ [

## Boolean operators
](#CWL_QuerySyntax-operations-Boolean)
+ [

## Comparison operators
](#CWL_QuerySyntax-operations-comparison)
+ [

## Numeric operators
](#CWL_QuerySyntax-operations-numeric)
+ [

## Structure types
](#CWL_QuerySyntax-structure-types)
+ [

## Datetime functions
](#CWL_QuerySyntax-datetime)
+ [

## General functions
](#CWL_QuerySyntax-general-functions)
+ [

## JSON functions
](#CWL_QuerySyntax-json-functions)
+ [

## IP address string functions
](#CWL_QuerySyntax-IPaddress-functions)
+ [

## String functions
](#CWL_QuerySyntax-string-functions)

## Arithmetic operators
<a name="CWL_QuerySyntax-operations-arithmetic"></a>

 Arithmetic operators accept numeric data types as arguments and return numeric results. Use arithmetic operators in the `filter` and `fields` commands and as arguments for other functions. 


| Operation | Description | 
| --- | --- | 
|  `a + b` |  Addition  | 
|  `a - b` |  Subtraction  | 
|  `a * b` |  Multiplication  | 
|  `a / b` |  Division  | 
|  `a ^ b` |   Exponentiation (`2 ^ 3` returns `8`)   | 
|  `a % b` |   Remainder or modulus (`10 % 3` returns `1`)   | 

## Boolean operators
<a name="CWL_QuerySyntax-operations-Boolean"></a>

 Use the Boolean operators `and`, `or`, and `not`. 

**Note**  
 Use Boolean operators only in functions that return a value of **TRUE** or **FALSE**. 

## Comparison operators
<a name="CWL_QuerySyntax-operations-comparison"></a>

 Comparison operators accept all data types as arguments and return a Boolean result. Use comparison operations in the `filter` command and as arguments for other functions. 


| Operator | Description | 
| --- | --- | 
|   `=`   |   Equal   | 
|   `!=`   |   Not equal   | 
|   `<`   |   Less than   | 
|  `>` |   Greater than   | 
|  `<=` |   Less than or equal to   | 
|   `>=`   |   Greater than or equal to   | 

## Numeric operators
<a name="CWL_QuerySyntax-operations-numeric"></a>

 Numeric operations accept numeric data types as arguments and return numeric results. Use numeric operations in the `filter` and `fields` commands and as arguments for other functions. 


| Operation | Result type | Description | 
| --- | --- | --- | 
|   `abs(a: number)`   |   number   |   Absolute value   | 
|   `ceil(a: number)`   |   number   |   Round to ceiling (the smallest integer that is greater than the value of `a`)   | 
|   `floor(a: number)`   |  number |   Round to floor (the largest integer that is smaller than the value of `a`)   | 
|   `greatest(a: number, ...numbers: number[])`   |   number   |   Returns the largest value   | 
|   `least(a: number, ...numbers: number[])`   |  number |   Returns the smallest value   | 
|   `log(a: number)`   |   number   |   Natural log   | 
|   `sqrt(a: number)`   |   number   |   Square root   | 

## Structure types
<a name="CWL_QuerySyntax-structure-types"></a>

 A map or list is a structure type in CloudWatch Logs Insights that allows you to access and use attributes for queries. 

**Example: To get a map or list**  
 Use `jsonParse` to parse a field that's a json string into a map or a list. 

```
fields jsonParse(@message) as json_message
```

**Example: To access attributes**  
 Use the dot access operator (map.attribute) to access items in a map.. If an attribute in a map contains special characters, use backticks to enclose the attribute name (map.attributes.`special.char`). 

```
fields jsonParse(@message) as json_message
| stats count() by json_message.status_code
```

 Use the bracket access operator (list[index]) to retrieve an item at a specific position within the list. 

```
fields jsonParse(@message) as json_message
| filter json_message.users[1].action = "PutData"
```

 Wrap special characters in backticks (``) when special characters are present in the key name. 

```
fields jsonParse(@message) as json_message
| filter json_message.`user.id` = "123"
```

**Example: empty results**  
 Maps and lists are treated as null for string, number, and datetime functions. 

```
fields jsonParse(@message) as json_message
| display toupper(json_message)
```

 Comparing map and list to any other fields result in `false`. 

**Note**  
 Using map and list in `dedup`,`pattern`, `sort`, and `stats` isn't supported. 

## Datetime functions
<a name="CWL_QuerySyntax-datetime"></a>

 **Datetime functions** 

 Use datetime functions in the `fields` and `filter`commands and as arguments for other functions. Use these functions to create time buckets for queries with aggregate functions. Use time periods that consist of a number and one of the following:
+ `ms` for milliseconds 
+ `s` for seconds 
+ `m` for minutes 
+ `h` for hours 

 For example, `10m` is 10 minutes, and `1h` is 1 hour. 

**Note**  
Use the most appropriate time unit for your datetime function. CloudWatch Logs caps your request according to the time unit that you choose. For example, it caps 60 as the maximum value for any request that uses `s`. So, if you specify `bin(300s)`, CloudWatch Logs actually implements this as 60 seconds, because 60 is the number of seconds in a minute so CloudWatch Logs won't use a number higher than 60 with `s`. To create a 5-minute bucket, use `bin(5m)` instead.  
The cap for `ms` is 1000, the caps for `s` and `m` are 60, and the cap for `h` is 24.

The following table contains a list of the different datetime functions that you can use in query commands. The table lists each function's result type and contains a description of each function. 

**Tip**  
 When you create a query command, you can use the time interval selector to select a time period that you want to query. For example, you can set a time period between 5 and 30-minute intervals; 1, 3, and 12-hour intervals; or a custom time frame. You also can set time periods between specific dates. 


| Function | Result type | Description | 
| --- | --- | --- | 
|  `bin(period: Period)` |  Timestamp |  Rounds the value of `@timestamp` to the given time period and then truncates. For example, `bin(5m)` rounds the value of `@timestamp` to the nearest 5 minutes. You can use this to group multiple log entries together in a query. The following example returns the count of exceptions per hour: <pre>filter @message like /Exception/ <br />    | stats count(*) as exceptionCount by bin(1h)<br />    | sort exceptionCount desc</pre> The following time units and abbreviations are supported with the `bin` function. For all units and abbreviations that include more than one character, adding s to pluralize is supported. So both `hr` and `hrs` work to specify hours. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-operations-functions.html)  | 
|  `datefloor(timestamp: Timestamp, period: Period)` |  Timestamp |  Truncates the timestamp to the given period. For example, `datefloor(@timestamp, 1h)` truncates all values of `@timestamp` to the bottom of the hour.  | 
|  `dateceil(timestamp: Timestamp, period: Period)` |  Timestamp |  Rounds up the timestamp to the given period and then truncates. For example, `dateceil(@timestamp, 1h)` truncates all values of `@timestamp` to the top of the hour.  | 
|  `fromMillis(fieldName: number)` |  Timestamp |  Interprets the input field as the number of milliseconds since the Unix epoch and converts it to a timestamp.  | 
|  `toMillis(fieldName: Timestamp)` |  number |  Converts the timestamp found in the named field into a number representing the milliseconds since the Unix epoch. For example, `toMillis(@timestamp)` converts the timestamp `2022-01-14T13:18:031.000-08:00` to `1642195111000`.  | 
|  `now()`  |  number  |  Returns the time that the query processing was started, in epoch seconds. This function takes no arguments. You can use this to filter your query results according to the current time. For example, the following query returns all 4xx errors from the past two hours: <pre>parse @message "Status Code: *;" as statusCode\n <br />| filter statusCode >= 400 and statusCode <= 499  \n <br />| filter toMillis(@timestamp) >= (now() * 1000 - 7200000)</pre> The following example returns all log entries from the past five hours that contain either the word `error` or `failure` <pre>fields @timestamp, @message <br />| filter @message like /(?i)(error|failure)/ <br />| filter toMillis(@timestamp) >= (now() * 1000 - 18000000)</pre>  | 

**Note**  
 Currently, CloudWatch Logs Insights doesn't support filtering logs with human readable timestamps. 

## General functions
<a name="CWL_QuerySyntax-general-functions"></a>

 **General functions** 

 Use general functions in the `fields` and `filter` commands and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|   `ispresent(fieldName: LogField)`   |   Boolean   |   Returns `true` if the field exists   | 
|   `coalesce(fieldName: LogField, ...fieldNames: LogField[])`   |   LogField   |   Returns the first non-null value from the list   | 

## JSON functions
<a name="CWL_QuerySyntax-json-functions"></a>

 **JSON functions** 

 Use JSON functions in the `fields` and `filter` commands and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|   `jsonParse(fieldName: string)`   |   Map \$1 List \$1 Empty   |   Returns a map or list when the input is a string representation of JSON object or a JSON array. Returns an empty value, if the input is not one of the representation.   | 
|   `jsonStringify(fieldName: Map \| List)`   |   String   |   Returns a JSON string from a map or list data.   | 

## IP address string functions
<a name="CWL_QuerySyntax-IPaddress-functions"></a>

 **IP address string functions** 

 Use IP address string functions in the `filter` and `fields` commands and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|  `isValidIp(fieldName: string)` |  boolean |  Returns `true` if the field is a valid IPv4 or IPv6 address.  | 
|  `isValidIpV4(fieldName: string)` |  boolean |  Returns `true` if the field is a valid IPv4 address.  | 
|  `isValidIpV6(fieldName: string)` |  boolean |  Returns `true` if the field is a valid IPv6 address.  | 
|  `isIpInSubnet(fieldName: string, subnet: string)` |  boolean |  Returns `true` if the field is a valid IPv4 or IPv6 address within the specified v4 or v6 subnet. When you specify the subnet, use CIDR notation such as `192.0.2.0/24` or `2001:db8::/32`, where `192.0.2.0` or `2001:db8::` is the start of the CIDR block.  | 
|  `isIpv4InSubnet(fieldName: string, subnet: string)` |  boolean |  Returns `true` if the field is a valid IPv4 address within the specified v4 subnet. When you specify the subnet, use CIDR notation such as `192.0.2.0/24` where `192.0.2.0` is the start of the CIDR block..  | 
|  `isIpv6InSubnet(fieldName: string, subnet: string)` |  boolean |  Returns `true` if the field is a valid IPv6 address within the specified v6 subnet. When you specify the subnet, use CIDR notation such as `2001:db8::/32` where `2001:db8::` is the start of the CIDR block.  | 

## String functions
<a name="CWL_QuerySyntax-string-functions"></a>

 **String functions** 

 Use string functions in the `fields` and `filter` commands and as arguments for other functions. 


| Function | Result type | Description | 
| --- | --- | --- | 
|  `isempty(fieldName: string)` |  Number |  Returns `1` if the field is missing or is an empty string.  | 
|  `isblank(fieldName: string)` |  Number |  Returns `1` if the field is missing, an empty string, or contains only white space.  | 
|  `concat(str: string, ...strings: string[])` |  string |  Concatenates the strings.  | 
|  `ltrim(str: string)` `ltrim(str: string, trimChars: string)` |  string |  If the function does not have a second argument, it removes white space from the left of the string. If the function has a second string argument, it does not remove white space. Instead, it removes the characters in `trimChars` from the left of `str`. For example, `ltrim("xyZxyfooxyZ","xyZ")` returns `"fooxyZ"`.  | 
|  `rtrim(str: string)` `rtrim(str: string, trimChars: string)` |  string |  If the function does not have a second argument, it removes white space from the right of the string. If the function has a second string argument, it does not remove white space. Instead, it removes the characters of `trimChars` from the right of `str`. For example, `rtrim("xyZfooxyxyZ","xyZ")` returns `"xyZfoo"`.  | 
|  `trim(str: string)` `trim(str: string, trimChars: string)` |  string |  If the function does not have a second argument, it removes white space from both ends of the string. If the function has a second string argument, it does not remove white space. Instead, it removes the characters of `trimChars` from both sides of `str`. For example, `trim("xyZxyfooxyxyZ","xyZ")` returns `"foo"`.  | 
|  `strlen(str: string)` |  number |  Returns the length of the string in Unicode code points.  | 
|  `toupper(str: string)` |  string |  Converts the string to uppercase.  | 
|  `tolower(str: string)` |  string |  Converts the string to lowercase.  | 
|  `substr(str: string, startIndex: number)` `substr(str: string, startIndex: number, length: number)` |  string |  Returns a substring from the index specified by the number argument to the end of the string. If the function has a second number argument, it contains the length of the substring to be retrieved. For example, `substr("xyZfooxyZ",3, 3)` returns `"foo"`.  | 
|  `replace(fieldName: string, searchValue: string, replaceValue: string)` |  string |  Replaces all instances of `searchValue` in `fieldName: string` with `replaceValue`. For example, the function `replace(logGroup,"smoke_test","Smoke")` searches for log events where the field `logGroup` contains the string value `smoke_test` and replaces the value with the string `Smoke`.  | 
|  `strcontains(str: string, searchValue: string)` |  number |  Returns 1 if `str` contains `searchValue` and 0 otherwise.  | 

# Fields that contain special characters
<a name="CWL_QuerySyntax-Guidelines"></a>

If a field contains non-alphanumeric characters other than the `@` symbol or the period (`.`), you must surround the field with backtick characters (```). For example, the log field `foo-bar` must be enclosed in backticks (``foo-bar``) because it contains a non-alphanumeric character, the hyphen (`-`).

# Use aliases and comments in queries
<a name="CWL_QuerySyntax-alias"></a>

 Create queries that contain aliases. Use aliases to rename log fields or when extracting values into fields. Use the keyword `as` to give a log field or result an alias. You can use more than one alias in a query. You can use aliases in the following commands: 
+  `fields` 
+  `parse` 
+  `sort` 
+  ` stats ` 

 The following examples show how to create queries that contain aliases. 

 **Example** 

 The query contains an alias in the `fields` command. 

```
fields @timestamp, @message, accountId as ID
| sort @timestamp desc
| limit 20
```

 The query returns the values for the fields `@timestamp`, `@message`, and `accountId`. The results are sorted in descending order and limited to 20. The values for `accountId` are listed under the alias `ID`. 

 **Example** 

 The query contains aliases in the `sort` and `stats` commands. 

```
stats count(*) by duration as time 
| sort time desc
```

 The query counts the number of times the field `duration` occurs in the log group and sorts the results in descending order. The values for `duration` are listed under the alias `time`. 

## Use comments
<a name="CWL_QuerySyntax-comments"></a>

 CloudWatch Logs Insights supports comments in queries. Use the hash character (**\$1**) to set off comments. You can use comments to ignore lines in queries or document queries. 

 **Example: Query** 

 When the following query is run, the second line is ignored. 

```
fields @timestamp, @message, accountId
# | filter accountId not like "7983124201998"
| sort @timestamp desc
| limit 20
```

# Get started with Logs Insights QL: Query tutorials
<a name="CWL_AnalyzeLogData_Tutorials"></a>

The following sections include sample query tutorials to help you get started with Logs Insights QL.

**Topics**
+ [

# Tutorial: Run and modify a sample query
](CWL_AnalyzeLogData_RunSampleQuery.md)
+ [

# Tutorial: Run a query with an aggregation function
](CWL_AnalyzeLogData_AggregationQuery.md)
+ [

# Tutorial: Run a query that produces a visualization grouped by log fields
](CWL_AnalyzeLogData_VisualizationFieldQuery.md)
+ [

# Tutorial: Run a query that produces a time series visualization
](CWL_AnalyzeLogData_VisualizationQuery.md)

# Tutorial: Run and modify a sample query
<a name="CWL_AnalyzeLogData_RunSampleQuery"></a>

The following tutorial helps you get started with CloudWatch Logs Insights. You run a sample query in Logs Insights QL, and then see how to modify and rerun it.

To run a query, you must already have logs stored in CloudWatch Logs. If you are already using CloudWatch Logs and have log groups and log streams set up, you are ready to start. You may also already have logs if you use services such as AWS CloudTrail, Amazon Route 53, or Amazon VPC and you have set up logs from those services to go to CloudWatch Logs. For more information about sending logs to CloudWatch Logs, see [Getting started with CloudWatch Logs](CWL_GettingStarted.md).

Queries in CloudWatch Logs Insights return either a set of fields from log events or the result of a mathematical aggregation or other operation performed on log events. This tutorial demonstrates a query that returns a list of log events.

## Run a sample query
<a name="CWL_AnalyzeLogData_RunQuerySample"></a>

**To run a CloudWatch Logs Insights sample query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

   On the **Logs Insights** page, the query editor contains a default query in Logs Insights QL that returns the 20 most recent log events.

1. In the **Select log group(s)** drop down, choose one or more log groups to query.

    If this is a monitoring account in CloudWatch cross-account observability, you can select log groups in the source accounts as well as the monitoring account. A single query can query logs from different accounts at once.

   You can filter the log groups by log group name, account ID, or account label.

   When you select a log group in the Standard log class, CloudWatch Logs Insights automatically detects data fields in the group. To see discovered fields, select the **Fields** menu near the top right of the page.
**Note**  
Discovered fields is supported only for log groups in the Standard log class. For more information about log classes, see [Log classes](CloudWatch_Logs_Log_Classes.md).

1. (Optional) Use the time interval selector to select a time period that you want to query.

   You can choose between 5 and 30-minute intervals; 1, 3, and 12-hour intervals; or a custom time frame.

1. Choose **Run** to view the results.

   For this tutorial, the results include the 20 most recently added log events.

   CloudWatch Logs displays a bar graph of log events in the log group over time. The bar graph shows not only the events in the table, but also the distribution of events in the log group that match the query and timeframe.

1. To see all fields for a returned log event, choose the triangular dropdown icon left of the numbered event.

## Modify the sample query
<a name="CWL_AnalyzeLogData_ModifySampleQuery"></a>

In this tutorial, you modify the sample query to show the 50 most recent log events.

If you haven't already run the previous tutorial, do that now. This tutorial starts where that previous tutorial ends.

**Note**  
Some sample queries provided with CloudWatch Logs Insights use `head` or `tail` commands instead of `limit`. These commands are being deprecated and have been replaced with `limit`. Use `limit` instead of `head` or `tail` in all queries that you write.

**To modify the CloudWatch Logs Insights sample query**

1. In the query editor, change **20** to **50**, and then choose **Run**.

   The results of the new query appear. Assuming there is enough data in the log group in the default time range, there are now 50 log events listed.

1. (Optional) You can save queries that you have created. To save this query, choose **Save**. For more information, see [Save and re-run CloudWatch Logs Insights queries](CWL_Insights-Saving-Queries.md).

## Add a filter command to the sample query
<a name="CWL_AnalyzeLogData_FilterQuery"></a>

This tutorial shows how to make a more powerful change to the query in the query editor. In this tutorial, you filter the results of the previous query based on a field in the retrieved log events.

If you haven't already run the previous tutorials, do that now. This tutorial starts where that previous tutorial ends.

**To add a filter command to the previous query**

1. Decide on a field to filter. To see the most common fields that CloudWatch Logs has detected in the log events contained in the selected log groups in the past 15 minutes, and the percentage of those log events in which each field appears, select **Fields** on the right side of the page.

   To see the fields contained in a particular log event, choose the icon to the left of that row.

   The **awsRegion** field might appear in your log event, depending on which events are in your logs. For the rest of this tutorial, we use **awsRegion** as the filter field, but you can use a different field if that field isn't available.

1. In the query editor box, place your cursor after **50** and press Enter.

1. On the new line, first enter \$1 (the pipe character) and a space. Commands in a CloudWatch Logs Insights query must be separated by the pipe character.

1. Enter **filter awsRegion="us-east-1"**.

1. Choose **Run**.

   The query runs again, and now displays the 50 most recent results that match the new filter.

   If you filtered on a different field and got an error result, you might need to escape the field name. If the field name includes non-alphanumeric characters, you must put backtick characters (`) before and after the field name (for example, **`error-code`="102"**).

   You must use the backtick characters for field names that contain non-alphanumeric characters, but not for values. Values are always contained in quotation marks (").

Logs Insights QL includes powerful query abilities, including several commands and support for regular expressions, mathematical, and statistical operations. For more information, see [CloudWatch Logs Insights language query syntax](CWL_QuerySyntax.md).

# Tutorial: Run a query with an aggregation function
<a name="CWL_AnalyzeLogData_AggregationQuery"></a>

You can use aggregation functions with the `stats` command and as arguments for other functions. In this tutorial, you run a query command that counts the number of log events containing a specified field. The query command returns a total count that's grouped by the specified field's value or values. For more information about aggregation functions, see [Supported operations and functions](https://docs.aws.amazon.com/en_us/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html#CWL_QuerySyntax-operations-functions) in the *Amazon CloudWatch Logs User Guide*.

**To run a query with an aggregation function**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. Confirm that the **Logs Insights QL** tab is selected.

1. In the **Select log group(s)** drop down, choose one or more log groups to query.

    If this is a monitoring account in CloudWatch cross-account observability, you can select log groups in the source accounts as well as the monitoring account. A single query can query logs from different accounts at once.

   You can filter the log groups by log group name, account ID, or account label.

   When you select a log group, CloudWatch Logs Insights automatically detects data fields in the log group if it is a Standard class log group. To see discovered fields, select the **Fields** menu near the top right of the page.

1. Delete the default query in the query editor, and enter the following command:

   ```
   stats count(*) by fieldName
   ```

1. Replace *fieldName* with a discovered field from the **Fields** menu.

   The **Fields** menu is located at the top right of the page and displays all of the discovered fields that CloudWatch Logs Insights detects in your log group.

1. Choose **Run** to view the query results.

   The query results show the number of records in your log group that match the query command and the total count that's grouped by the specified field's value or values.

# Tutorial: Run a query that produces a visualization grouped by log fields
<a name="CWL_AnalyzeLogData_VisualizationFieldQuery"></a>

When you run a query that uses the `stats` function to group the returned results by the values of one or more fields in the log entries, you can view the results as a bar chart, pie chart, line graph or stacked area graph. This helps you more efficiently visualize trends in your logs.

**To run a query for visualization**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. In the **Select log group(s)** drop down, choose one or more log groups to query.

    If this is a monitoring account in CloudWatch cross-account observability, you can select log groups in the source accounts as well as the monitoring account. A single query can query logs from different accounts at once.

   You can filter the log groups by log group name, account ID, or account label.

1. In the query editor, delete the current contents, enter the following `stats` function, and then choose **Run query**.

   ```
   stats count(*) by @logStream 
       | limit 100
   ```

   The results show the number of log events in the log group for each log stream. The results are limited to only 100 rows.

1. Choose the **Visualization** tab.

1. Select the arrow next to **Line**, and then choose **Bar**.

   The bar chart appears, showing a bar for each log stream in the log group.

# Tutorial: Run a query that produces a time series visualization
<a name="CWL_AnalyzeLogData_VisualizationQuery"></a>

When you run a query that uses the `bin()` function to group the returned results by a time period, you can view the results as a line graph, stacked area graph, pie chart, or bar chart. This helps you more efficiently visualize trends in log events over time.

**To run a query for visualization**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. Confirm that the **Logs Insights QL** tab is selected.

1. In the **Select log group(s)** drop down, choose one or more log groups to query.

    If this is a monitoring account in CloudWatch cross-account observability, you can select log groups in the source accounts as well as the monitoring account. A single query can query logs from different accounts at once.

   You can filter the log groups by log group name, account ID, or account label.

1. In the query editor, delete the current contents, enter the following `stats` function, and then choose **Run query**.

   ```
   stats count(*) by bin(30s)
   ```

   The results show the number of log events in the log group that were received by CloudWatch Logs for each 30-second period.

1. Choose the **Visualization** tab.

   The results are shown as a line graph. To switch to a bar chart, pie chart, or stacked area chart, choose the arrow next to **Line** at the upper left of the graph.

# Sample queries
<a name="CWL_QuerySyntax-examples"></a>

This section contains a list of general and useful query commands that you can run in the [CloudWatch console](https://console.aws.amazon.com/cloudwatch/). For information about how to run a query command, see [Tutorial: Run and modify a sample query](https://docs.aws.amazon.com/en_us/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_RunSampleQuery.html) in the *Amazon CloudWatch Logs User Guide*.

For more information about query syntax, see [CloudWatch Logs Insights language query syntax](CWL_QuerySyntax.md).

**Topics**
+ [

## General queries
](#CWL_QuerySyntax-examples-general)
+ [

## Queries for Lambda logs
](#CWL_QuerySyntax-examples-Lambda)
+ [

## Queries for Amazon VPC flow logs
](#CWL_QuerySyntax-examples-VPC)
+ [

## Queries for Route 53 logs
](#CWL_QuerySyntax-examples-Route53)
+ [

## Queries for CloudTrail logs
](#CWL_QuerySyntax-examples-CloudTrail)
+ [

## Queries for Amazon API Gateway
](#CWL_QuerySyntax-examples-APIGateway)
+ [

## Queries for NAT gateway
](#CWL_QuerySyntax-examples-NATGateway)
+ [

## Queries for Apache server logs
](#CWL_QuerySyntax-examples-Apache)
+ [

## Queries for Amazon EventBridge
](#CWL_QuerySyntax-examples-EventBridge)
+ [

## Examples of the parse command
](#CWL_QuerySyntax-examples-parse)

## General queries
<a name="CWL_QuerySyntax-examples-general"></a>

**Find the 25 most recently added log events.**

```
fields @timestamp, @message | sort @timestamp desc | limit 25
```

**Get a list of the number of exceptions per hour.** 

```
filter @message like /Exception/ 
    | stats count(*) as exceptionCount by bin(1h)
    | sort exceptionCount desc
```

**Get a list of log events that aren't exceptions.** 

```
fields @message | filter @message not like /Exception/
```

**Get the most recent log event for each unique value of the `server` field.** 

```
fields @timestamp, server, severity, message 
| sort @timestamp asc 
| dedup server
```

**Get the most recent log event for each unique value of the `server` field for each `severity` type.** 

```
fields @timestamp, server, severity, message 
| sort @timestamp desc 
| dedup server, severity
```

## Queries for Lambda logs
<a name="CWL_QuerySyntax-examples-Lambda"></a>

**Determine the amount of overprovisioned memory.**

```
filter @type = "REPORT"
    | stats max(@memorySize / 1000 / 1000) as provisonedMemoryMB,
        min(@maxMemoryUsed / 1000 / 1000) as smallestMemoryRequestMB,
        avg(@maxMemoryUsed / 1000 / 1000) as avgMemoryUsedMB,
        max(@maxMemoryUsed / 1000 / 1000) as maxMemoryUsedMB,
        provisonedMemoryMB - maxMemoryUsedMB as overProvisionedMB
```

**Create a latency report.**

```
filter @type = "REPORT" |
    stats avg(@duration), max(@duration), min(@duration) by bin(5m)
```

**Search for slow function invocations, and eliminate duplicate requests that can arise from retries or client-side code. In this query, `@duration` is in milliseconds.**

```
fields @timestamp, @requestId, @message, @logStream 
| filter @type = "REPORT" and @duration > 1000
| sort @timestamp desc
| dedup @requestId 
| limit 20
```

## Queries for Amazon VPC flow logs
<a name="CWL_QuerySyntax-examples-VPC"></a>

**Find the top 15 packet transfers across hosts:**

```
stats sum(packets) as packetsTransferred by srcAddr, dstAddr
    | sort packetsTransferred  desc
    | limit 15
```

**Find the top 15 byte transfers for hosts on a given subnet.**

```
filter isIpv4InSubnet(srcAddr, "192.0.2.0/24")
    | stats sum(bytes) as bytesTransferred by dstAddr
    | sort bytesTransferred desc
    | limit 15
```

**Find the IP addresses that use UDP as a data transfer protocol.**

```
filter protocol=17 | stats count(*) by srcAddr
```

**Find the IP addresses where flow records were skipped during the capture window.**

```
filter logStatus="SKIPDATA"
    | stats count(*) by bin(1h) as t
    | sort t
```

**Find a single record for each connection, to help troubleshoot network connectivity issues.**

```
fields @timestamp, srcAddr, dstAddr, srcPort, dstPort, protocol, bytes 
| filter logStream = 'vpc-flow-logs' and interfaceId = 'eni-0123456789abcdef0' 
| sort @timestamp desc 
| dedup srcAddr, dstAddr, srcPort, dstPort, protocol 
| limit 20
```

## Queries for Route 53 logs
<a name="CWL_QuerySyntax-examples-Route53"></a>

**Find the distribution of records per hour by query type.**

```
stats count(*) by queryType, bin(1h)
```

**Find the 10 DNS resolvers with the highest number of requests.**

```
stats count(*) as numRequests by resolverIp
    | sort numRequests desc
    | limit 10
```

**Find the number of records by domain and subdomain where the server failed to complete the DNS request.**

```
filter responseCode="SERVFAIL" | stats count(*) by queryName
```

## Queries for CloudTrail logs
<a name="CWL_QuerySyntax-examples-CloudTrail"></a>

**Find the number of log entries for each service, event type, and AWS Region.**

```
stats count(*) by eventSource, eventName, awsRegion
```

**Find the Amazon EC2 hosts that were started or stopped in a given AWS Region.**

```
filter (eventName="StartInstances" or eventName="StopInstances") and awsRegion="us-east-2"
```

**Find the AWS Regions, user names, and ARNs of newly created IAM users.**

```
filter eventName="CreateUser"
    | fields awsRegion, requestParameters.userName, responseElements.user.arn
```

**Find the number of records where an exception occurred while invoking the API `UpdateTrail`.**

```
filter eventName="UpdateTrail" and ispresent(errorCode)
    | stats count(*) by errorCode, errorMessage
```

**Find log entries where TLS 1.0 or 1.1 was used**

```
filter tlsDetails.tlsVersion in [ "TLSv1", "TLSv1.1" ]
| stats count(*) as numOutdatedTlsCalls by userIdentity.accountId, recipientAccountId, eventSource, eventName, awsRegion, tlsDetails.tlsVersion, tlsDetails.cipherSuite, userAgent
| sort eventSource, eventName, awsRegion, tlsDetails.tlsVersion
```

**Find the number of calls per service that used TLS versions 1.0 or 1.1**

```
filter tlsDetails.tlsVersion in [ "TLSv1", "TLSv1.1" ]
| stats count(*) as numOutdatedTlsCalls by eventSource
| sort numOutdatedTlsCalls desc
```

## Queries for Amazon API Gateway
<a name="CWL_QuerySyntax-examples-APIGateway"></a>

Find the last 10 4XX errors

```
fields @timestamp, status, ip, path, httpMethod
| filter status>=400 and status<=499
| sort @timestamp desc
| limit 10
```

Identify the 10 longest-running Amazon API Gateway requests in your Amazon API Gateway access log group

```
fields @timestamp, status, ip, path, httpMethod, responseLatency
| sort responseLatency desc
| limit 10
```

Return the list of the most popular API paths in your Amazon API Gateway access log group

```
stats count(*) as requestCount by path
| sort requestCount desc
| limit 10
```

Create an integration latency report for your Amazon API Gateway access log group

```
filter status=200
| stats avg(integrationLatency), max(integrationLatency), 
min(integrationLatency) by bin(1m)
```

## Queries for NAT gateway
<a name="CWL_QuerySyntax-examples-NATGateway"></a>

If you notice higher than normal costs in your AWS bill, you can use CloudWatch Logs Insights to find the top contributors. For more information about the following query commands, see [How can I find the top contributors to traffic through the NAT gateway in my VPC?](https://aws.amazon.com/premiumsupport/knowledge-center/vpc-find-traffic-sources-nat-gateway/) at the AWS premium support page.

**Note**  
In the following query commands, replace "x.x.x.x" with the private IP of your NAT gateway, and replace "y.y" with the first two octets of your VPC CIDR range.

**Find the instances that are sending the most traffic through your NAT gateway.**

```
filter (dstAddr like 'x.x.x.x' and srcAddr like 'y.y.') 
| stats sum(bytes) as bytesTransferred by srcAddr, dstAddr
| sort bytesTransferred desc
| limit 10
```

**Determine the traffic that's going to and from the instances in your NAT gateways.**

```
filter (dstAddr like 'x.x.x.x' and srcAddr like 'y.y.') or (srcAddr like 'xxx.xx.xx.xx' and dstAddr like 'y.y.')
| stats sum(bytes) as bytesTransferred by srcAddr, dstAddr
| sort bytesTransferred desc
| limit 10
```

**Determine the internet destinations that the instances in your VPC communicate with most often for uploads and downloads.**

*****For uploads*****

```
filter (srcAddr like 'x.x.x.x' and dstAddr not like 'y.y.') 
| stats sum(bytes) as bytesTransferred by srcAddr, dstAddr
| sort bytesTransferred desc
| limit 10
```

*****For downloads*****

```
filter (dstAddr like 'x.x.x.x' and srcAddr not like 'y.y.') 
| stats sum(bytes) as bytesTransferred by srcAddr, dstAddr
| sort bytesTransferred desc
| limit 10
```

## Queries for Apache server logs
<a name="CWL_QuerySyntax-examples-Apache"></a>

You can use CloudWatch Logs Insights to query Apache server logs. For more information about the following queries, see [Simplifying Apache server logs with CloudWatch Logs Insights](https://aws.amazon.com/blogs/mt/simplifying-apache-server-logs-with-amazon-cloudwatch-logs-insights/) at the AWS Cloud Operations & Migrations Blog.

**Find the most relevant fields, so you can review your access logs and check for traffic in the */admin* path of your application.**

```
fields @timestamp, remoteIP, request, status, filename| sort @timestamp desc
| filter filename="/var/www/html/admin"
| limit 20
```

**Find the number unique GET requests that accessed your main page with status code "200" (success).**

```
fields @timestamp, remoteIP, method, status
| filter status="200" and referrer= http://34.250.27.141/ and method= "GET"
| stats count_distinct(remoteIP) as UniqueVisits
| limit 10
```

**Find the number of times your Apache service restarted.**

```
fields @timestamp, function, process, message
| filter message like "resuming normal operations"
| sort @timestamp desc
| limit 20
```

## Queries for Amazon EventBridge
<a name="CWL_QuerySyntax-examples-EventBridge"></a>

Get the number of EventBridge events grouped by event detail type

```
fields @timestamp, @message
| stats count(*) as numberOfEvents by `detail-type`
| sort numberOfEvents desc
```

## Examples of the parse command
<a name="CWL_QuerySyntax-examples-parse"></a>

**Use a glob expression to extract the fields `@user`, `@method`, and `@latency` from the log field `@message` and return the average latency for each unique combination of `@method` and `@user`.** 

```
parse @message "user=*, method:*, latency := *" as @user,
    @method, @latency | stats avg(@latency) by @method,
    @user
```

**Use a regular expression to extract the fields `@user2`, `@method2`, and `@latency2` from the log field `@message` and return the average latency for each unique combination of `@method2` and `@user2`.**

```
parse @message /user=(?<user2>.*?), method:(?<method2>.*?),
    latency := (?<latency2>.*?)/ | stats avg(latency2) by @method2, 
    @user2
```

**Extracts the fields `loggingTime`, `loggingType` and `loggingMessage`, filters down to log events that contain `ERROR` or `INFO` strings, and then displays only the `loggingMessage` and `loggingType` fields for events that contain an `ERROR` string.**

```
FIELDS @message
    | PARSE @message "* [*] *" as loggingTime, loggingType, loggingMessage
    | FILTER loggingType IN ["ERROR", "INFO"]
    | DISPLAY loggingMessage, loggingType = "ERROR" as isError
```

# Compare (diff) with previous time ranges
<a name="CWL_AnalyzeLogData_Compare"></a>

You can use CloudWatch Logs Insights with the Logs Insights QL to compare changes in your log events over time. You can compare the log events ingested during a recent time range with the logs from the immediately previous time period. Alternatively, you can compare with similar past time periods. This can help you find whether an error in your logs was recently introduced or was already occurring, and can help you find other trends. 

Comparison queries return only patterns in the results, not raw log events. The patterns returned will help you quickly see the trends and changes in the log events over time. After you run a comparison query and have the pattern results, you can see sample raw log events for the patterns that you're interested in. For more information about log patterns, see [Pattern analysis](CWL_AnalyzeLogData_Patterns.md).

When you run a comparison query, your query is analyzed against two different time periods: the original query period that you select, and the comparison period. The comparison period is always of equal length to your original query period. The default time intervals for the comparisons are the following.
+ **Previous period**— Compares to the time period immediately before your query time period.
+ **Previous day**— Compares to the time period one day before your query time period.
+ **Previous week**— Compares to the time period one week before your query time period.
+ **Previous month**— Compares to the time period one month before your query time period.

**Note**  
Queries using comparisons incur charges similar to running a single CloudWatch Logs Insights query over the combined time range. For more information, see [Amazon CloudWatch Pricing](https://aws.amazon.com/cloudwatch/pricing/).

**To run a comparison query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, **Logs Insights**.

   A default query appears in the query box.

1. Confirm that the **Logs Insights QL** tab is selected.

1. Keep the default query or enter a different query. 

1. In the **Select log group(s)** drop-down, choose one or more log groups to query.

1. (Optional) Use the time interval selector to select a time period that you want to query. The default query is for the previous hour of log data.

1. By the time range selector, choose **Compare**. Then choose the previous time period that you want to compare the original logs with, and choose **Apply**.

1. Choose **Run query**.

   To cause the query to fetch the data from the comparison period, the `diff` command is appended to your query.

1. Choose the **Patterns** tab to see the results.

   The table displays the following information:
   + Each **Pattern**, with variable parts of the pattern replaced by the dynamic token symbol `<string-number>`. The *string* is a description of the type of data that the token represents. The *number* shows where in the pattern this token appears, compared to the other dynamic tokens. For more information, see [Pattern analysis](CWL_AnalyzeLogData_Patterns.md).
   + **Event count** is the number of log events with that pattern in the original, more current time period.
   + **Difference event count** is the difference between the number of matching log events in the current time period versus the comparison time period. A positive different means there are more such events in the current time period.
   + **Difference description** briefly summarizes the change in that pattern between the current time period and the comparison period.
   + **Severity type** is the probable severity of the logs events with this pattern, based on words found in the log events such as `FATAL`, `ERROR`, and `WARN`.

1. To further inspect one of the patterns in the list, choose the icon in the **Inspect** column for one of the patterns. 

   The **Pattern inspect** pane appears and displays the following: 
   + The **Pattern**. Select a token within the pattern to analyze that token's values.
   + A histogram showing the number of occurrences of the pattern over the queried time range. This can help you to identify interesting trends such as a sudden increase in occurrence of a pattern.
   + The **Log samples** tab displays a few of the log events that match the selected pattern.
   + The **Token Values** tab displays the values of the selected dynamic token, if you have selected one.
**Note**  
A maximum of 10 token values is captured for each token. Token counts might not be precise. CloudWatch Logs uses a probabilistic counter to generate the token count, not the absolute value.
   + The **Related patterns** tab displays other patterns that frequently occurred near the same time as the pattern that you are inspecting. For example, if a pattern for an `ERROR` message was usually accompanied by another log event marked as `INFO` with additional details, that pattern is displayed here.

# Visualize log data in graphs
<a name="CWL_Insights-Visualizing-Log-Data"></a>

You can use visualizations such as bar charts, line charts, and stacked area charts to more efficiently identify patterns in your log data. CloudWatch Logs Insights generates visualizations for queries that use the `stats` function and one or more aggregation functions. For more information, see [stats](CWL_QuerySyntax-Stats.md).

# OpenSearch Piped Processing Language (PPL)
<a name="CWL_AnalyzeLogData_PPL"></a>

This section contains a basic introduction to querying CloudWatch Logs using OpenSearch PPL. With PPL, you can retrieve, query, and analyze data using piped-together commands, making it easier to understand and compose complex queries. Its syntax is based on Unix pipes, and enables chaining of commands to transform and process data. With PPL, you can filter and aggregate data, and use a rich set of math, string, date, conditional, and other functions for analysis.

Including `SOURCE` in a PPL query is a useful way to specify the log groups field indexes, and data sources to include in a query when you are using the AWS CLI or API to create a query. The `SOURCE` command is supported only in the AWS CLI and API, not in the CloudWatch console. When you use the CloudWatch console to start a query, you use the console interface to specify the log groups and data source name and type.

Use `aws:fieldIndex` to return indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query. The relevant log groups are automatically selected, based on the fields specified in the `filterIndex` command. This reduces scanned volume by skipping log groups that do not have any log events containing the field specified in the query, and only scanning log groups that match the value specified in the query for this field index. Use `aws:fieldIndex` to specify the field name, along with the field name and value in the source command to query only indexed data containing the field and value specified. For more information, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md) 

You can use OpenSearch PPL for queries of log groups in the Standard Log Class. 

**Note**  
For information about all OpenSearch PPL query commands supported in CloudWatch Logs and detailed information about syntax and restrictions, see [Supported PPL commands](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-ppl.html) in the OpenSearch Service Developer Guide.  
 For information on other query languages you can use see, [CloudWatch Logs Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html), [OpenSearch Service SQL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_SQL.html), and [CloudWatch Metrics Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/query_with_cloudwatch-metrics-insights.html)


| Command or function | Example query | Description | 
| --- | --- | --- | 
|  `fields` |  `fields field1, field2`  |  Displays a set of fields which needs projection.  | 
|  `join` |  `LEFT JOIN left=l, right=r on l.id = r.id `join_right_lg` \| fields l.field_1, r.field_2`  |  Joins two datasets together.  | 
|  `where` |  `where field1="success" \| where field2 != "i-023fe0a90929d8822" \| fields field3, field4, field5,field6 \| head 1000`  |  Filters the data based on the conditions that you specify.  | 
|  `aws:fieldIndex` |  `source = [`aws:fieldIndex`="region", `region` = "us-west-2"] \| where status = 200 \| head 10`  |  Returns indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query.  | 
|  `stats` |  `stats count(), count(field1), min(field1), max(field1), avg(field1) by field2 \| head 1000`  |  Performs aggregations and calculations  | 
|  `parse` |  `parse field1 ".*/(?<field2>[^/]+$)" \| where field2 = "requestId" \| fields field1, field2 \| head 1000`  |  Extracts a regular expression (regex) pattern from a string and displays the extracted pattern. The extracted pattern can be further used to create new fields or filter data.  | 
|  `sort` |  `stats count(), count(field1), min(field1) as field1Alias, max(`field1`), avg(`field1`) by field2 \| sort -field1Alias \| head 1000`  |  Sort the displayed results by a field name. Use sort -FieldName to sort in descending order.  | 
|  `eval` |  `eval field2 = field1 * 2 \| fields field1, field2 \| head 20`  |  Modifies or processes the value of a field and stores it in a different field. This is useful to mathematically modify a column, apply string functions to a column, or apply date functions to a column.  | 
|  `rename` |  `rename field2 as field1 \| fields field1;`  |  Renames one or more fields in the search result.  | 
|  `head` |  `fields `@message` \| head 20`  |  Limits the displayed query results to the first N rows.  | 
|  `top` |  `top 2 field1 by field2`  |  Finds the most frequent values for a field.  | 
|  `dedup` |  `dedup field1 \| fields field1, field2, field3`  |  Removes duplicate entries based on the fields that you specify.  | 
|  `rare` |  `rare field1 by field2`  |  Finds the least frequent values of all fields in the field list.  | 
|  `subquery` |  `where field_1 IN [ search source= `subquery_lg` \| fields field_2 ] \| fields id, field_1 `  |  Performs complex, nested queries within your PPL statements.  | 
|  `trendline` |  `trendline sma(2, field1) as field1Alias`  |  Calculates the moving averages of fields.  | 
|  `eventStats` |  `eventstats sum(field1) by field2`  |  Enriches your event data with calculated summary statistics. It analyzes specified fields within your events, computes various statistical measures, and then appends these results to each original event as new fields.  | 
|  `expand` |  `eval tags_array_string = json_extract(`@message`, '$.tags')\| eval tags_array = json_array(json_extract(tags_string, '$[0]'), json_extract(tags_string, '$[1]'))\| expand tags_array as color_tags`  |  Breaks down a field containing multiple values into separate rows, creating a new row for each value in the specified field.  | 
|  `fillnull` |  `fields `@timestamp`, error_code, status_code \| fillnull using status_code = "UNKNOWN", error_code = "UNKNOWN"`  |  Fills null fields with the value that you provide. It can be used in one or more fields.  | 
|  `flatten` |  `eval metadata_struct = json_object('size', json_extract(metadata_string, '$.size'), 'color', json_extract(metadata_string, '$.color')) \| flatten metadata_struct as (meta_size, meta_color) `  |  Flattens a field. The field must be of this type: `struct<?,?>` or `array<struct<?,?>>`.  | 
|  `cidrmatch` |  `where cidrmatch(ip, '2003:db8::/32') \| fields ip `  |  Checks if the specified IP address is within the given CIDR range.  | 
|  `fieldsummary` |  `where field1 != 200 \| fieldsummary includefields= field1 nulls=true`  |  Calculates basic statistics for each field (count, distinct count, min, max, avg, stddev, and mean).  | 
|  `grok` |  `grok email '.+@%{HOSTNAME:host}' \| fields email, host`  |  Parses a text field with a grok pattern and appends the results to the search result.  | 
|  String functions |  `eval field1Len = LENGTH(field1) \| fields field1Len`  |  Built-in functions in PPL that can manipulate and transform string and text data within PPL queries. For example, converting case, combining strings, extracting parts, and cleaning text.  | 
|  Date-Time functions |  `eval newDate = ADDDATE(DATE('2020-08-26'), 1) \| fields newDate `  |  Built-in functions for handling and transforming date and timestamp data in PPL queries. For example, date\$1add, date\$1format, datediff, date-sub, timestampadd, timestampdiff, current\$1timezone, utc\$1timestamp, and current\$1date.  | 
|  Condition functions |  `eval field2 = isnull(field1) \| fields field2, field1, field3`  |  Built-in functions that check for specific field conditions, and evaluate expressions conditionally. For example, if field1 is null, return field2.  | 
|  Math functions |  `eval field2 = ACOS(field1) \| fields field1`  |  Built-in functions for performing mathematical calculations and transformations in PPL queries. For example, abs (absolute value), round (rounds numbers), sqrt (square root), pow (power calculation), and ceil (rounds up to nearest integer).  | 
|  CryptoGraphic functions |  `eval crypto = MD5(field)\| head 1000`  |  To calculate the hash of given field  | 
|  JSON functions |  `eval valid_json = json('[1,2,3,{"f1":1,"f2":[5,6]},4]') \| fields valid_json`  |  Built-in functions for handling JSON including arrays, extracting, and validation. For example, json\$1object, json\$1array, to\$1json\$1string, json\$1array\$1length, json\$1extract, json\$1keys, and json\$1valid.   | 

## Query scope
<a name="CWL_AnalyzeLogData_PPL-scope"></a>

Including SOURCE in a query is a useful way to specify the log groups to include in a query when you are using the AWS CLI or API to create a query. The SOURCE command is supported only in the AWS CLI and API, not in the CloudWatch console. When you use the CloudWatch console to start a query, you use the console interface to specify the log groups and data source name and type.

PPL's source command now support multiple ways to specify them:

1. Log group

1. Field indexes - New

1. Data source and type - New

### Log Group
<a name="CWL_AnalyzeLogData_PPL-scope-loggroup"></a>

Log Group source selection can be used when customers know which exact log group(s) need to be searched

```
source = [lg:`/aws/lambda/my-function`] | where status = 200 | head 10
```

### Field Indexes
<a name="CWL_AnalyzeLogData_PPL-scope-fieldindex"></a>

Field index-based source selection reduces the amount of data queried by limiting results to only indexed data when your filters target fields that have been indexed. The relevant log groups are automatically selected, based on the fields specified in the `filterIndex` command. For more information about field indexes and how to create them, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md).

Use `aws:fieldIndex` to return indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query. For these log groups that are indexed on this field, it further optimizes the query by skipping the log groups that do not have any log events containing the field specified in the query for the indexed field. It further reduces scanned volume by attempting to scan only log events from these log groups that match the value specified in the query for this field index. For more information about field indexes and how to create them, see Create field indexes to improve query performance and reduce scan volume.

In PPL, `aws:fieldIndex` is used to specify which key value pairs should be treated as indexes. The syntax is as follows

```
source = [`aws:fieldIndex`="region", `region` = "us-west-2"] | where status = 200 | head 10
```

where,

1. ``aws:fieldIndex`="region"` identifies region as field Index.

   1. Note: Instead of = customers can use IN to specify multiple indexes (example below)

1. ``region`="us-west-2"` identifies the filter condition to be applied

   1. Note: Instead of = customers can use IN to specify multiple values (example below)

Customers can specify multiple fieldIndexes as follows

```
source = [`aws:fieldIndex` IN ("status", "region"), `status` = 200, `region` IN ("us-west-2", "us-east-1")] | head 10
```

### Data Source and Type
<a name="CWL_AnalyzeLogData_PPL-scope-datasource"></a>

Data source and type based source selection can be used when customers know which exact data sources need to be queried. This query is executed over one or more log groups which contain the specified data source and type.

```
source = [ds:`data_source.type`] | where status = 200 | head 10
```

#### Supported PPL for data source queries
<a name="CWL_AnalyzeLogData_PPL-scope-datasource-supported"></a>

To support the use case for querying data sources in PPL, you can use the dynamic source selector clause. Using this syntax, you can query data sources by specifying them in the search command. You can specify up to 10 data sources.

**Syntax**

```
source=[ds:`DataSource1.Type1`, ds:`DataSource2.Type2`, ...ds:`DataSourcen.Typen`]
```

**Example query**

```
search source=[ds:`DataSource1.Type1`, ds:`DataSource2.Type2`] | fields field1, field2
```

### Combined example
<a name="CWL_AnalyzeLogData_PPL-scope-combined"></a>

Customers can specify all the source selection operators in any order & the results would be the intersection of the all the conditions applied.

For example, /aws/lambda/my-function-1 might contain multiple data source & types including wide variety of indexes, when the following query was ran, the results returned will only have events of source and type DataSource1.Type1 and matching the criteria of 'status' = 200.

```
search source=[
    ds:`DataSource1.Type1`, 
    lg:`/aws/lambda/my-function-1`, 
    `aws:fieldIndex` IN ("status"), `status` = 200 
]
```

## Restrictions
<a name="CWL_AnalyzeLogData_PPL-restrictions"></a>

The following restrictions apply when you use OpenSearch PPL to query in CloudWatch Logs Insights.
+ You cannot use join or subquery commands with data source queries.

# OpenSearch Structured Query Language (SQL)
<a name="CWL_AnalyzeLogData_SQL"></a>

This section contains a basic introduction to querying CloudWatch Logs using OpenSearch SQL. It provides a familiar option if you're used to working with relational databases. OpenSearch SQL offers a subset of SQL functionality, making it a good choice for performing ad-hoc queries and data analysis tasks. With OpenSearch SQL, you can use commands such as SELECT, FROM, WHERE, GROUP BY, HAVING, and various other SQL commands and functions. You can execute JOINs across log groups, correlate data across log groups using sub-queries, and use the rich set of JSON, mathematical, string, conditional, and other SQL functions to perform powerful analysis on log and security data.

Use `filterIndex` to return indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query. Reduce scanned volume by skipping log groups that do not have any log events containing the field specified in the query, and only scanning log groups that match the value specified in the query for this field index. Use `filterIndex` to specify the field name, along with the field name and value to query only indexed data containing the field and value specified.

You can use OpenSearch SQL for queries of log groups in the Standard Log Class. SQL also supports querying using data source name and data source type. 

**Note**  
The following table lists the SQL commands and functions supported in CloudWatch Logs For information about all OpenSearch SQL commands including syntax, see [Supported SQL commands](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/supported-directquery-sql.html) in the OpenSearch Service Developer Guide.  
For information on other query languages you can use, see[CloudWatch Logs Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html), [OpenSearch Service PPL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_PPL.html), and [CloudWatch Metrics Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/query_with_cloudwatch-metrics-insights.html).

## Supported SQL commands
<a name="CWL_AnalyzeLogData_SQL-table"></a>

**Note**  
In the example query column, replace `<logGroup>` as needed depending on which data source you're querying. 


| Command or function | Example query | Description | 
| --- | --- | --- | 
|  SELECT |  `SELECT `@message`, Operation FROM `LogGroupA``  |  Displays projected values.  | 
|  FROM |  `SELECT `@message`, Operation FROM `LogGroupA``  |  Built-in clause that specifies the source table(s) or view(s) from which to retrieve data, supporting various types of joins and subqueries.  | 
|  WHERE |  `SELECT * FROM `LogGroupA` WHERE Operation = 'x'`  |  Filters log events based on the provided field criteria.  | 
|  filterIndex |  `SELECT * FROM `filterIndex('region' = 'us-east-1')` WHERE status = 200 LIMIT 10;`  |  Returns indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query.  | 
|  GROUP BY |  `SELECT `@logStream`, COUNT(*) as log_count FROM `LogGroupA` GROUP BY `@logStream``  | Groups log events based on category and finds the average based on stats.  | 
|  HAVING |  `SELECT `@logStream`, COUNT(*) as log_count FROM `LogGroupA` GROUP BY `@logStream` HAVING log_count > 100`  |  Filters the results based on grouping conditions.  | 
|  ORDER BY |  `SELECT * FROM `LogGroupA` ORDER BY `@timestamp` DESC`  |  Orders the results based on fields in the ORDER BY clause. You can sort in either descending or ascending order.  | 
|  JOIN |  `SELECT A.`@message`, B.`@timestamp`FROM `LogGroupA` as A INNER JOIN `LogGroupB` as B ON A.`requestId` = B.`requestId``  |  Joins the results for two tables based on common fields. Inner JOIN or Left Outer Join must be specified  | 
|  LIMIT |  `Select * from `LogGroupA` limit 10`  |  Limits the displayed query results to the first N rows.  | 
|  String functions |  `SELECT upper(Operation) , lower(Operation), Operation FROM `LogGroupA``  |  Built-in functions in SQL that can manipulate and transform string and text data within SQL queries. For example, converting case, combining strings, extracting parts, and cleaning text.  | 
|  Date functions |  `SELECT current_date() as today, date_add(current_date(), 30) as thirty_days_later, last_day(current_date()) as month_end FROM `LogGroupA``  |  Built-in functions for handling and transforming date and timestamp data in SQL queries. For example, date\$1add, date\$1format, datediff, and current\$1date.  | 
|  Conditional functions |  `SELECT Operation, IF(Error > 0, 'High', 'Low') as error_category FROM `LogGroupA`;`  |  Built-in functions that perform actions based on specified conditions, or that evaluate expressions conditionally. For example, CASE and IF.  | 
|  Aggregate functions |  `SELECT AVG(bytes) as bytesWritten FROM `LogGroupA``  |  Built-in functions that perform calculations on multiple rows to produce a single summarized value. For example, SUM, COUNT, AVG, MAX, and MIN.  | 
|  JSON functions |  `SELECT get_json_object(json_column, '$.name') as name FROM `LogGroupA``  |  Built-in functions for parsing, extracting, modifying, and querying JSON-formatted data within SQL queries (e.g., from\$1json, to\$1json, get\$1json\$1object, json\$1tuple) allowing manipulation of JSON structures in datasets.  | 
|  Array functions |  `SELECT scores, size(scores) as length, array_contains(scores, 90) as has_90 FROM `LogGroupA`;`  |  Built-in functions for working with array-type columns in SQL queries, allowing operations like accessing, modifying, and analyzing array data (e.g., size, explode, array\$1contains).  | 
|  Window functions |  `SELECT field1, field2, RANK() OVER (ORDER BY field2 DESC) as field2Rank FROM `LogGroupA`;`  |  Built-in functions that perform calculations across a specified set of rows related to the current row (window), enabling operations like ranking, running totals, and moving averages. For example, ROW\$1NUMBER, RANK, LAG, and LEAD  | 
|  Conversion functions |  `SELECT CAST('123' AS INT) as converted_number, CAST(123 AS STRING) as converted_string FROM `LogGroupA``  |  Built-in functions for converting data from one type to another within SQL queries, enabling data type transformations and format conversions. For example, CAST, TO\$1DATE, TO\$1TIMESTAMP, and BINARY.  | 
|  Predicate functions |  `SELECT scores, size(scores) as length, array_contains(scores, 90) as has_90 FROM `LogGroupA`;`  |  Built-in functions that evaluate conditions and return boolean values (true/false) based on specified criteria or patterns. For example, IN, LIKE, BETWEEN, IS NULL, and EXISTS.  | 
|  Select multiple log groups |  `SELECT lg1.field1, lg1.field2 from `logGroups( logGroupIdentifier: ['LogGroup1', 'LogGroup2'])` as lg1 where lg1.field3= "Success"`  |  Enables you to specify multiple log groups in a SELECT statement  | 
|  Select multiple data sources |  `SELECT ds1.field1, ds1.field2 from `dataSource(['DataSource1', 'DataSource2'])` as ds1 where ds1.field3= "Success"`  |  Enables you to specify multiple data sources in a SELECT statement  | 

## Supported SQL for multi-log-group queries
<a name="CWL_AnalyzeLogData_SQL-multi"></a>

To support the use case for querying multiple log groups in SQL, you can use the `logGroups` command. Using this syntax, you can query multiple log groups by specifying them in the FROM command.

Syntax:

```
`logGroups(
    logGroupIdentifier: ['LogGroup1','LogGroup2', ...'LogGroupn']
)
```

In this syntax, you can specify up to 50 log groups in the `logGroupIdentifier` parameter. To reference log groups in a monitoring account, use ARNs instead of `LogGroup` names.

Example query:

```
SELECT LG1.Column1, LG1.Column2 from `logGroups(
    logGroupIdentifier: ['LogGroup1', 'LogGroup2']
)` as LG1 WHERE LG1.Column1 = 'ABC'
```

The following syntax involving multiple log groups after the `FROM` statement is NOT supported when querying CloudWatch Logs.

```
SELECT Column1, Column2 FROM 'LogGroup1', 'LogGroup2', ...'LogGroupn'
WHERE Column1 = 'ABC'
```

## Supported SQL for data source queries
<a name="CWL_AnalyzeLogData_SQL-data-source"></a>

 To support the use case for querying data sources in SQL, you can use the dataSource command. Using this syntax, you can query data sources by specifying them in the `FROM` command. You can specify up to 10 data sources. 

**Syntax**

```
`dataSource(
    ['DataSource1', 'DataSource2', ...'DataSourcen']
)`
```

**Example query **

```
SELECT DS1.Column1, DS1.Column2 from `dataSource(
    ['DataSource1', 'DataSource2']
)` as DS1 WHERE DS1.Column1 = 'ABC'
```

## Query scope
<a name="CWL_AnalyzeLogData_SQL-scope"></a>

In the AWS CLI and API, you can specify which logs to query by using the log group, data source and type, and field indexes.

### Log Group
<a name="CWL_AnalyzeLogData_SQL-scope-loggroup"></a>

Log Group source selection can be used when customers know which exact log group(s) need to be searched

```
SELECT * FROM `logGroups(logGroupIdentifier: ['/aws/lambda/my-function'])`;
```

### Data Source and Type
<a name="CWL_AnalyzeLogData_SQL-scope-datasource"></a>

Customers can query their logs using data source name and data source type.

Data source and type based source selection can be used when customers know which exact data sources need to be queried. This query is executed over one or more log groups which contain the specified data source and type.

To support the use case for querying data sources in SQL, you can use the dataSource command. Using this syntax, you can query data sources by specifying them in the FROM command. You can specify up to 10 data sources.

Syntax:

```
`dataSource(
    ['DataSource1.Type1', 'DataSource2.Type2', ...'DataSourcen.Typen']
)`
```

Example query:

```
SELECT DS1.Column1, DS1.Column2 from `dataSource(
    ['DataSource1.Type1', 'DataSource2.Type2']
)` as DS1 WHERE DS1.Column1 = 'ABC'
```

For more information on querying by data sources, see [Use facets to group and explore logs](CloudWatchLogs-Facets.md).

### Combined example
<a name="CWL_AnalyzeLogData_SQL-scope-combined"></a>

Customers can specify all the source selection operators within the backticks in any order and the results would be based on the intersection of the all the conditions applied.

For example, /aws/lambda/my-function-1 might contain multiple data source & types including wide variety of indexes, when the following query was ran, the results returned will only have events of source and type DataSource1.Type1 and matching the criteria of 'status' = 200.

```
SELECT * FROM `
   logGroups(logGroupIdentifier: ['/aws/lambda/my-function'])
   filterIndex('status' = 200)
   dataSource(['DataSource1.Type1'])
`;
```

### Field Indexes
<a name="CWL_AnalyzeLogData_SQL-scope-fieldindex"></a>

Field Index-based source selection automatically identifies relevant log groups when your filters target indexed fields, reducing scan volume and query runtime. 

Use `filterIndex` to return indexed data only, by forcing a query to scan only log groups that are indexed on a field that you specify in the query. For these log groups that are indexed on this field, it further optimizes the query by skipping the log groups that do not have any log events containing the field specified in the query for the indexed field. It further reduces scanned volume by attempting to scan only log events from these log groups that match the value specified in the query for this field index. For more information about field indexes and how to create them, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md).

In SQL, filterIndex is used to specify which key value pairs should be treated as indexes. The syntax is as follows

```
SELECT * FROM `filterIndex('region' = 'us-east-1')`;
```

where,

1. filterIndex(...) specifies, treat the key values within them as field indexes. Each key value pair is separated by a comma (example below)

1. 'region' = 'us-east-1' specifies the actual condition to be applied

   1. Note: Instead of = customers can use IN to specify multiple values (example below)

Using multiple filterIndex would combine the conditions using "AND". In the example, logs matching status=200 and region in us-east-1 or us-west-2 would be queried.

```
SELECT * FROM `filterIndex('status' = 200, 'region' IN ['us-east-1', 'us-west-2'])`;
```

## Restrictions
<a name="CWL_AnalyzeLogData_SQL-restrictions"></a>

The following restrictions apply when you use OpenSearch SQL to query in CloudWatch Logs Insights.
+ You can include only one JOIN in a SELECT statement.
+ You cannot use JOIN or subqueries with data source queries.
+ Only one level of nested subqueries is supported.
+ Multiple statement queries separated by semi-colons (;) aren't supported.
+ Queries containing field names that are identical but differ only in case (such as field1 and FIELD1) are not supported.

  For example, the following query isn't supported:

  ```
  Select AWSAccountId, AwsAccountId from LogGroup
  ```

  However, the following query is supported because the field name (`@logStream`) is identical in both log groups:

  ```
  Select a.`@logStream`, b.`@logStream` from Table A INNER Join Table B on a.id = b.id
  ```
+ Functions and expressions must operate on field names and be part of a SELECT statement with a log group specified in the FROM clause.

  For example, this query is not supported:

  ```
  SELECT cos(10) FROM LogGroup
  ```

  This query is supported:

  ```
  SELECT cos(field1) FROM LogGroup
  ```
+ When using SQL or PPL commands, enclose certain fields in backticks to successfully query them. Backticks are necessary for fields with special characters (non-alphabetic and non-numeric). For example, enclose `@message`, `Operation.Export`, and `Test::Field` in backticks. You don't need to enclose fields with purely alphabetic names in backticks.

  Example query with simple fields:

  ```
  SELECT SessionToken, Operation, StartTime  FROM `LogGroup-A`
  LIMIT 1000;
  ```

  Similar query with backticks appended:

  ```
  SELECT `@SessionToken`, `@Operation`, `@StartTime`  FROM `LogGroup-A` LIMIT 1000;
  ```

# Use natural language to generate and update CloudWatch Logs Insights queries
<a name="CloudWatchLogs-Insights-Query-Assist"></a>

CloudWatch Logs supports a natural language query capability to help you generate and update queries for [CloudWatch Logs Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html), [OpenSearch Service PPL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_PPL.html), [OpenSearch Service SQL](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_SQL.html), and [CloudWatch Metrics Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/query_with_cloudwatch-metrics-insights.html).

 With this capability, you can ask questions about or describe the CloudWatch Logs data you're looking for in plain English. The natural language capability generates a query based on a prompt that you enter and provides a line-by-line explanation of how the query works. You can also update your query to further investigate your data. 

 Depending on your environment, you can enter prompts like "What are the top 100 source IP addresses by bytes transferred?" and "Find the 10 slowest Lambda function requests." 

**Note**  
The natural-language query feature is a Regional service. For some Regions, the feature makes cross-Region calls to Regions in the United States to process the query prompts. For more information, see [Amazon CloudWatch expands region support for natural language query result summarization and query generation](https://aws.amazon.com/about-aws/whats-new/2025/08/amazon-cloudwatch-region-support-query-result-summarization-query-generation/) . 

 To generate a CloudWatch Logs Insights query with this capability, open the CloudWatch Logs Insights query editor, select the log group you want to query, and choose **Generate query**. 

**Important**  
 To use the natural language query capability, you must be signed in with the [CloudWatchLogsFullAccess](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/CloudWatchLogsFullAccess.html), [CloudWatchLogsReadOnlyAccess](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/CloudWatchLogsReadOnlyAccess.html), [AdministratorAccess](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.html), or [ReadOnlyAccess](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/ReadOnlyAccess.html) IAM policies, or have the `cloudwatch:GenerateQuery` permission. 

## Example queries
<a name="CloudWatchLogs-Insights-Query-Assist-examples"></a>

 The examples in this section describe how to generate and update queries using the natural language capability. 

**Note**  
 For more information on the CloudWatch Logs Insights query editor and syntax, see [CloudWatch Logs Insights query syntax](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html). 

### Examples: Generate a natural language query
<a name="CloudWatchLogs-Insights-Query-Assist-example-1"></a>

 To generate a query using natural language, enter a prompt and choose **Generate new query**. These example shows queries that perform a basic search. 

**Prompt**  
 The following is an example of a prompt that directs the capability to search for the 10 slowest Lambda function invocations. 

```
Find the 10 slowest requests
```

**Query**  
 The following is the query using the CloudWatch Logs Insights query language that the natural language capability generated based on the prompt. Notice how the prompt appears in a comment before the query. After the query, you can read an explanation that describes how the query works. 

```
# Find the 10 slowest requests
fields @timestamp, @message, @duration 
| sort @duration desc 
| limit 10
# This query retrieves the timestamp, message and duration fields from the logs and sorts them in descending order by duration to find the 10 slowest requests.
```

**Note**  
 To turn off the appearance of your prompt and the explanation of how the query works, use the gear icon in your editor. 

**Prompt**  
To generate an OpenSearch SQL query, select the OpenSearch SQL tab, then open the query generator prompt box to enter your natural language prompt. The following is an example of a prompt that uses the natural language capability to generate an OpenSearch SQL query. 

```
Give me the number of errors and exceptions per hour
```

**Query**  
The following is the SQL query generated by that prompt that you can use to find the number of errors and exceptions aggregated per hour:

```
SELECT DATE_FORMAT(`@timestamp`, 'yyyy-MM-dd HH') AS hour,
       COUNT(*) AS error_count
FROM `/aws/lambda/CloudWatchOdysseyQueryGen`
WHERE `@message` LIKE '%error%'
  OR `@message` LIKE '%exception%'
GROUP BY DATE_FORMAT(`@timestamp`, 'yyyy-MM-dd HH')
ORDER BY hour
```

**Prompt**  
To generate an OpenSearch PPL query, select the OpenSearch PPL tab, then open the query generator prompt box to enter your natural language prompt. The following is an example of a prompt that uses the natural language capability to generate an OpenSearch PPL query. 

```
Give me all unique exception messages
```

**Query**  
The following is the PPL query generated by that prompt that you can use to find the unique exception messages in your logs:

```
dedup @message 
| fields @message
```

### Example: Update a natural language query
<a name="CloudWatchLogs-Insights-Query-Assist-example-2"></a>

 You can update a query by editing the initial prompt and then choosing **Update query**. 

**Updated prompt**  
 The following example shows an updated version of the previous prompt. Instead of a prompt that searches for the 10 slowest Lambda function invocations, this prompt now directs the capability to search for the 20 slowest Lambda function invocations and include another column for additional log events. 

```
Show top 20 slowest requests instead and display requestId as a column
```

**Updated query**  
 The following is an example of the updated query using the CloudWatch Logs Insights query language. Notice how the updated prompt appears in a comment before the updated query. After the query, you can read an explanation that describes how the original query has been updated. 

```
# Show top 20 slowest requests instead and display requestId as a column
fields @timestamp, @message, @requestId, @duration 
| sort @duration desc 
| limit 20
# This query modifies the original query by replacing the @message field with the @requestId field and changing the limit from 10 to 20 to return the top 20 log events by duration instead of the top 10.
```

## Opting out of using your data for service improvement
<a name="CloudWatchLogs-Insights-Query-Assist-service-data"></a>

 The natural language prompt data you provide to train the AI model and generate relevant queries is used solely to provide and maintain your service. This data might be used to improve the quality of CloudWatch Logs Insights. Your trust and privacy, as well as the security of your content, is our highest priority. For more information, see [AWS Service Terms](https://aws.amazon.com/service-terms/) and [AWS responsible AI policy](https://aws.amazon.com/machine-learning/responsible-ai/policy/). 

 You can opt out of having your content used to develop or improve the quality of natural language queries by creating an AI service opt-out policy. To opt-out of data collection for all CloudWatch Logs AI features, including the query generation capability, you must create an opt-out policy for CloudWatch Logs. For more information, see [AI services opt-out policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_ai-opt-out.html) in the *AWS Organizations User Guide*. 

# Supported logs and discovered fields
<a name="CWL_AnalyzeLogData-discoverable-fields"></a>

CloudWatch Logs Insights supports different log types. For every log that's sent to a Standard class log group in Amazon CloudWatch Logs, CloudWatch Logs Insights automatically generates five system fields: 
+ `@message` contains the raw unparsed log event. This is the equivalent to the `message` field in [InputLogevent](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_InputLogEvent.html).
+ `@timestamp` contains the event timestamp in the log event's `timestamp` field. This is the equivalent to the `timestamp` field in [InputLogevent](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_InputLogEvent.html).
+ `@ingestionTime` contains the time when CloudWatch Logs received the log event.
+ `@logStream` contains the name of the log stream that the log event was added to. Log streams group logs through the same process that generated them.
+ `@log` is a log group identifier in the form of `account-id:log-group-name`. When querying multiple log groups, this can be useful to identify which log group a particular event belongs to.
+ `@entity` contains flattened JSON related to entities for the [Explore related telemetry](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ExploreRelated.html) feature.

  For example, this JSON can represent an entity.

  ```
  {
    "Entity": {
      "KeyAttributes": {
        "Type": "Service",
        "Name": "PetClinic"
      },
      "Attributes": {
        "PlatformType": "AWS::EC2",
        "EC2.InstanceId": "i-1234567890123"
      }
    }
  }
  ```

  For this entity, the extracted system fields would be the following:

  ```
  @entity.KeyAttributes.Type = Service
  @entity.KeyAttributes.Name = PetClinic
  @entity.Attributes.PlatformType = AWS::EC2
  @entity.Attributes.EC2.InstanceId = i-1234567890123
  ```

**Note**  
Field discovery is supported only for log groups in the Standard log class. For more information about log classes, see [Log classes](CloudWatch_Logs_Log_Classes.md).

CloudWatch Logs Insights inserts the **@** symbol at the start of fields that it generates.

For many log types, CloudWatch Logs also automatically discovers the log fields contained in the logs. These automatic discovery fields are shown in the following table.

For other types of logs with fields that CloudWatch Logs Insights doesn't automatically discover, you can use the `parse` command to extract and create extracted fields for use in that query. For more information, see [CloudWatch Logs Insights language query syntax](CWL_QuerySyntax.md).

If the name of a discovered log field starts with the `@` character, CloudWatch Logs Insights displays it with an additional `@` appended to the beginning. For example, if a log field name is `@example.com`, this field name is displayed as `@@example.com`.

**Note**  
Except for `@message`, `@timestamp`, or `@log`, you can create field indexes for discovered fields. For more information about field indexes, see [Create field indexes to improve query performance and reduce scan volume](CloudWatchLogs-Field-Indexing.md). 


| Log type | Discovered log fields | 
| --- | --- | 
|  Amazon VPC flow logs  |  `@timestamp`, `@logStream`, `@message`, `accountId`, `endTime`, `interfaceId`, `logStatus`, `startTime`, `version`, `action`, `bytes`, `dstAddr`, `dstPort`, `packets`, `protocol`, `srcAddr`, `srcPort`    | 
|  Route 53 logs  |  `@timestamp`, `@logStream`, `@message`, `edgeLocation`, `ednsClientSubnet`, `hostZoneId`, `protocol`, `queryName`, `queryTimestamp`, `queryType`, `resolverIp`, `responseCode`, `version`  | 
|  Lambda logs  |  `@timestamp`, `@logStream`, `@message`, `@requestId`, `@duration, ``@billedDuration`, `@type`, `@maxMemoryUsed`, `@memorySize` If a Lambda log line contains an X-Ray trace ID, it also includes the following fields: `@xrayTraceId` and `@xraySegmentId`. CloudWatch Logs Insights automatically discovers log fields in Lambda logs, but only for the first embedded JSON fragment in each log event. If a Lambda log event contains multiple JSON fragments, you can parse and extract the log fields by using the `parse` command. For more information, see [Fields in JSON logs](#CWL_AnalyzeLogData-discoverable-JSON-logs).  | 
|  CloudTrail logs Logs in JSON format  |  For more information, see [Fields in JSON logs](#CWL_AnalyzeLogData-discoverable-JSON-logs).  | 
|  Other log types  |  `@timestamp`, `@ingestionTime`, `@logStream`, `@message`, `@log`.  | 

## Fields in JSON logs
<a name="CWL_AnalyzeLogData-discoverable-JSON-logs"></a>

With CloudWatch Logs Insights, you use dot notation to represent JSON fields. This section contains an example JSON event and code snippet that show how you can access JSON fields using dot notation.

**Example: JSON event**

```
{
    "eventVersion": "1.0",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "EX_PRINCIPAL_ID",
        "arn": "arn: aws: iam: : 123456789012: user/Alice",
        "accessKeyId": "EXAMPLE_KEY_ID",
        "accountId": "123456789012",
        "userName": "Alice"
    },
    "eventTime": "2014-03-06T21: 22: 54Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "StartInstances",
    "awsRegion": "us-east-2",
    "sourceIPAddress": "192.0.2.255",
    "userAgent": "ec2-api-tools1.6.12.2",
    "requestParameters": {
        "instancesSet": {
            "items": [
                {
                    "instanceId": "i-abcde123"
                }
            ]
        }
    },
    "responseElements": {
        "instancesSet": {
            "items": [
                {
                    "instanceId": "i-abcde123",
                    "currentState": {
                        "code": 0,
                        "name": "pending"
                    },
                    "previousState": {
                        "code": 80,
                        "name": "stopped"
                    }
                }
            ]
        }
    }
}
```

The example JSON event contains an object that's named `userIdentity`. `userIdentity` contains a field that's named `type`. To represent value of `type` using dot notation, you use `userIdentity.type`.

The example JSON event contains arrays that flatten to lists of nested field names and values. To represent the value of `instanceId` for the first item in `requestParameters.instancesSet`, you use `requestParameters.instancesSet.items.0.instanceId`. The number `0` that's placed before the field `instanceID` refers to the position of values for the field `items`. The following example contains a code snippet that shows how you can access nested JSON fields in a JSON log event.

**Example: Query**

```
fields @timestamp, @message
| filter requestParameters.instancesSet.items.0.instanceId="i-abcde123"
| sort @timestamp desc
```

The code snippet shows a query that uses dot notation with the `filter` command to access the value of the nested JSON field `instanceId`. The query filters on messages where the value of `instanceId` equals `"i-abcde123"` and returns all of the log events that contain the specified value.

**Note**  
CloudWatch Logs Insights can extract a maximum of 200 log event fields from a JSON log. For additional fields that aren't extracted, you can use the `parse` command to extract the fields from the raw unparsed log event in the message field. For more information about the `parse` command, see [Query syntax](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html) in the Amazon CloudWatch User Guide.

# Create field indexes to improve query performance and reduce scan volume
<a name="CloudWatchLogs-Field-Indexing"></a>

You can create *field indexes* of fields in your log events for efficient equality-based searches. When you then use a field index in a CloudWatch Logs Insights query, the query attempts to skip processing log events that are known to not include the indexed field. This reduces the scan volume of your queries that use field indexes, making it possible to return results faster. This can help you quickly search petabytes of total logs across thousands of log groups, and hone in on relevant logs faster. Good fields to index are fields that you often need to query for. Fields that have high cardinality of values are also good candidates for field indexes because a query using these field indexes will complete faster because it limits the log events that are being matched to the target value.

For example, suppose you have created a field index for `requestId`. Then, any CloudWatch Logs Insights query on that log group that includes `requestId = value` or `requestId IN [value, value, ...]` will attempt to process only the log events that are known to contain that indexed field and the queried value, and that CloudWatch Logs has detected a value for that field in the past.

You can also leverage your field indexes to create efficient queries of larger numbers of log groups. When you use the `filterIndex` command in your query instead of the `filter` command, the query will run against selected log groups on log events that have field indexes. These queries can scan as many as 10,000 log groups which you choose by specifying as many as five log group name prefixes. If this is a monitoring account in CloudWatch cross-account observability, you can choose all the source accounts or specify individual source accounts to select the log groups”.

Indexed fields are case-sensitive. For example, a field index of `RequestId` won't match a log event containing `requestId`.

Fields indexes are supported only for the structured log formats of JSON and service logs.

CloudWatch Logs provides default field indexes for all log groups in the Standard log class. Default field indexes are automatically available for the following fields: 
+ `@logStream`
+ `@aws.region`
+ `@aws.account`
+ `@source.log`
+ `@data_source_name`
+ `@data_source_type`
+ `@data_format`
+ `traceId`
+ `severityText`
+ `attributes.session.id`

CloudWatch Logs provides default field indexes for certain data source name and type combinations as well. Default field indexes are automatically available for the following data source name and type combinations:


| Data Source Name and Type | Default Field Indexes | 
| --- | --- | 
|  `amazon_vpc.flow`  |  `action` `logStatus` `region` `flowDirection` `type`  | 
|  `amazon_route53.resolver_query`  |  `query_type` `transport` `rcode`  | 
|  `aws_waf.access`  |  `action` `httpRequest.country`  | 
|  `aws_cloudtrail.data` ` aws_cloudtrail.management`  |  `eventSource` `eventName` `awsRegion` `userAgent` `errorCode` `eventType` `managementEvent` `readOnly` `eventCategory` `requestId`  | 

Default field indexes are in addition to any custom field indexes you define within your policy. Default field indexes are not counted towards your [field index quota](CloudWatchLogs-Field-Indexing-Syntax.md). 

CloudWatch Logs indexes only the log events ingested after an index policy is created. It doesn't index log events ingested before the policy was created. After you create a field index, each matching log event remains indexed for 30 days from the log event's ingestion time.

**Note**  
If you create a field index policy in a monitoring account, that policy is not used for log groups in linked source accounts. A field index policy applies only in the account where it is created.

The rest of the topics in this section explain how to create field indexes. For information about referring to field indexes in your queries, see [filterIndex](CWL_QuerySyntax-FilterIndex.md) and [filter](CWL_QuerySyntax-Filter.md). 

**Topics**
+ [

# Field index syntax and quotas
](CloudWatchLogs-Field-Indexing-Syntax.md)
+ [

# Create an account-level field index policy
](CloudWatchLogs-Field-Indexing-CreateAccountLevel.md)
+ [

# Create a log-group level field index policy
](CloudWatchLogs-Field-Indexing-CreateLogGroupLevel.md)
+ [

# Log group selection options when creating a query
](Field-Indexing-Selection.md)
+ [

# Effects of deleting a field index policy
](CloudWatchLogs-Field-Indexing-Deletion.md)

# Field index syntax and quotas
<a name="CloudWatchLogs-Field-Indexing-Syntax"></a>

You create field indexes by creating *field index policies*. You can create account-level index policies that apply to your whole account, and you can also create policies that apply to only a single log group. For account-wide index policies, you can have one that applies to all log groups in the account. You can also create account-level index policies that apply to a subset of log groups in the account, selected by the prefixes of their log group names. If you have multiple account-level policies in the same account, the log group name prefixes for these policies can't overlap. Similarly, you can create account-level index policies that apply to a specific data source name and type combination. Only one account policy can be created per data source name and type combination. 

Log group-level field index policies override account-level field index policies: which apply to the log group as a whole (such as, account-level policies with no selection criteria or with log group name prefix based selection criteria). Account-level policies which match at the log event level (such as, for a given data source name and type combination) will apply in addition to policies which match the log group as a whole. If you create log-group level index policy, that log group does not use account-level policies that match at the log group level.

Matches of log events to the names of field indexes are case-sensitive. For example, a field index of `RequestId` won't match a log event containing `requestId`.

You can have as many as 40 account-level index policies, of these policies 20 can use log group name prefix selection criteria and 20 can use data source based selection criteria. If you have multiple account-level index policies filtered to log group name prefixes, no two of them can use the same or overlapping log group name prefixes. For example, if you have one policy filtered to log groups that start with `my-log`, you can't have another field index policy filtered to `my-logpprod` or `my-logging`. Similarly, if you have multiple account-level index policies filtered to data source name and type combinations, no two of them can use the same data source name and type. For example, if you have one policy filtered to the data source name `amazon_vpc` and data source type `flow` you cannot create another policy with this combination.

If you have an account-level index policy that has no name prefixes and applies to all log groups, then no other account-level index policy with log group name prefix filters can be created; you can create account-level index policies which use data source name and type filters.

Each index policy has the following quotas and restrictions:
+ As many as 20 fields can be included in the policy.
+ Each field name can include as many as 100 characters.
+ To create an index of a custom field in your log groups that starts with `@`, you must specify the field with an extra `@` at the beginning of the field name. For example, if your log events include a field named `@userId`, you must specify `@@userId` to create an index for this field.

For account-level index policies with data source name and type based selection criteria an additional restriction applies: all of the fields must be primitive data types, nested primitives are only supported for structs.

**Generated fields and reserved fields**

CloudWatch Logs Insights automatically generates system fields in each log event. These generated fields are prefixed with `@` For more information about generated fields, see [Supported logs and discovered fields](CWL_AnalyzeLogData-discoverable-fields.md).

Of these generated fields, the following are supported for use as field indexes:
+ `@logStream`
+ `@ingestionTime`
+ `@requestId`
+ `@type`
+ `@initDuration`
+ `@duration`
+ `@billedDuration`
+ `@memorySize`
+ `@maxMemoryUsed`
+ `@xrayTraceId`
+ `@xraySegmentId`

To index these generated fields, you don't need to add an extra `@` when specifying them, as you have to do for custom fields that start with `@`. For example, to create a field index for `@logStream`, just specify `@logStream` as the field index.

CloudWatch Logs provides default field indexes for all log groups in the Standard log class. Default field indexes are automatically available for the following fields: 
+ `@logStream`
+ `@aws.region`
+ `@aws.account`
+ `@source.log`
+ `@data_source_name`
+ `@data_source_type`
+ `@data_format`
+ `traceId`
+ `severityText`
+ `attributes.session.id`

CloudWatch Logs provides default field indexes for certain data source name and type combinations as well. Default field indexes are automatically available for the following data source name and type combinations:


| Data Source Name and Type | Default Field Indexes | 
| --- | --- | 
|  `amazon_vpc.flow`  |  `action` `logStatus` `region` `flowDirection` `type`  | 
|  `amazon_route53.resolver_query`  |  `query_type` `transport` `rcode`  | 
|  `aws_waf.access`  |  `action` `httpRequest.country`  | 
|  `aws_cloudtrail.data` ` aws_cloudtrail.management`  |  `eventSource` `eventName` `awsRegion` `userAgent` `errorCode` `eventType` `managementEvent` `readOnly` `eventCategory` `requestId`  | 

Default field indexes are in addition to any custom field indexes you define within your policy. Default field indexes are not counted towards your [field index quota](#CloudWatchLogs-Field-Indexing-Syntax). 

**Child fields and array fields in JSON logs**

You can index fields that are nested child fields or array fields in JSON logs.

For example, you can create an index of the `accessKeyId` child field within the `userIdentity` field within this log:

```
{
    "eventVersion": "1.0",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "EXAMPLE_PRINCIPAL_ID",
        "arn": "arn: aws: iam: : 123456789012: user/Alice",
        "accessKeyId": "11112222",
        "accountId": "123456789012",
        "userName": "Alice"
    },
    "eventTime": "2014-03-06T21: 22: 54Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "StartInstances",
    "awsRegion": "us-east-2",
    "sourceIPAddress": "192.0.2.255",
    "userAgent": "ec2-api-tools1.6.12.2",
    "requestParameters": {
        "instancesSet": {
            "items": [{
                "instanceId": "i-abcde123",
                "currentState": {
                    "code": 0,
                    "name": "pending"
                },
                "previousState": {
                    "code": 80,
                    "name": "stopped"
                }
            }]
        }
    }
}
```

To create this field, you refer to it using dot notation (`userIdentity.accessKeyId`) both when creating the field index and when specifying it in a query. The query could look like this:

```
fields @timestamp, @message 
| filterIndex userIdentity.accessKeyId = "11112222"
```

In the previous example event, the `instanceId` field is in an array within `requestParameters.instancesSet.items` To represent this field both when creating the field index and when querying, refer to it as `requestParameters.instancesSet.items.0.instanceId` The 0 refers to that field's place in the array.

Then a query for this field could be the following:

```
fields @timestamp, @message 
| filterIndex requestParameters.instancesSet.items.0.instanceId="i-abcde123"
```

# Create an account-level field index policy
<a name="CloudWatchLogs-Field-Indexing-CreateAccountLevel"></a>

Use the steps in this section to create a field index policy that applies to all log groups in the account, or to multiple log groups that have log group names that start with the same string.

**To create an account-level field index policy**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the left navigation pane, choose **Settings** and then choose the **Logs** tab.

1. In the **Account level index policies** section, choose **Manage**.

1. Choose **Create index policy**.

1. For **Policy name**, enter a name for your new policy.

1. For **Select scope of policy**, do one of the following:
   + Choose **All standard log groups** to have the index policy apply to all Standard Class log groups in the account.
   + Choose **Log groups by prefix match** to apply the policy to a subset of log groups that all have names that start with the same string. Then, enter the prefix for these log groups in **Enter a prefix name**.

     After you enter your prefix, you can choose **Preview prefix matched log groups** to confirm that your prefix matches the log groups that you expected.

     Choose **Logs Data by Data source** to apply the policy to a specific data source name and type combination. You can then select the **Data source** and **Data type** from the drop-down menu. 

     After you select the data source name and type you can select **Get fields** to populate the **Configure field indexes and facets** section with relevant information such as the fields available, included log groups, as well as default and custom field indexes.

1. For **Custom index field configuration**, choose **Add field path** to enter the first field to index.

   Then enter the string to use as the value of the field name or select a field from the drop-down menu. This must be an exact case match to what appears in the log events. For example, if your log events include `requestId`, you must enter `requestId` here. `RequestId`, `requestID`, and `request Id` wouldn't match.

   If you want to index a custom log field that starts with the `@` character, you must include an extra `@` character when you enter the index string. For example, if you have a custom log field `@emailname`, enter `@@emailname` in the **Add field path** box.

   You can also create indexes for the `@ingestionTime` and `@logStream` fields that CloudWatch Logs automatically generates. If you do, you don't need to add an extra `@` when specifying them.

1. (Optional)In addition to specifying the field path, you can select **Set as a facet** to create the field as a facet.

1. Repeat the previous step to add as many as 20 field indexes.

1. When you have finished, choose **Create**.

# Create a log-group level field index policy
<a name="CloudWatchLogs-Field-Indexing-CreateLogGroupLevel"></a>

Use the steps in this section to create a field index policy that applies to a single log group.

**To create a log-group level field index policy**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the left navigation pane, choose **Logs**, **Log groups**.

1. Choose the name of the log group.

1. Choose the **Field indexes** tab.

1. Choose **Manage field indexes for this log group**

1. For **Manage log group level field indexes**, choose **Add field path** to enter the first field to index.

   Then enter the string to use as the value of the field name. This must be an exact case match to what appears in the log events. For example, if your log events include `requestId`, you must enter `requestId` here. `RequestId`, `requestID`, and `request Id` would not match.

   If you want to index a custom log field that starts with the `@` character, you must include an extra `@` character when you enter the index string. For example, if you have a custom log field `@emailname`, enter `@@emailname` in the **Add field path** box.

   You can also create indexes for the `@ingestionTime` and `@logStream` fields that CloudWatch Logs automatically generates. If you do, do not need to add an extra `@` when specifying them.

1. (Optional) In addition to specifying the field path, you can select **Set as a facet** to create the field as a facet.

1. Repeat the previous step to add as many as 20 field indexes.

1. When you have finished, choose **Save**.

# Log group selection options when creating a query
<a name="Field-Indexing-Selection"></a>

This section explains the various ways that you can select log groups to include in a query.

**To select log groups for a query in the console**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, **Logs Insights**.

1. Select the query language you want to use for this query. You can choose either: **Logs Insights QL**, **OpenSearch PPL**, or **OpenSearch SQL**.

1. There are three ways to select log groups for the query:
   + Use the **Log group name** box. This is the default selection method. You can enter as many as 50 log group names with this method. If this is a monitoring account in CloudWatch cross-account observability, you can select log groups in the source accounts as well as the monitoring account. A single query can query logs from different accounts at once. 
   + Use the **Log group criteria** section. In this section, you can choose log groups based on the prefix of the log group names. You can include as many as five prefixes in one query. Log groups having these prefixes in their names will be selected. Alternatively, the **All log groups** option selects all the log groups from the account. 
   + If this is a monitoring account in CloudWatch cross-account observability, you can select **All accounts** in the account dropdown menu to select the log groups from all linked accounts. Alternatively, you can individually select which accounts should be included for this query.

   If your choices match more than 10,000 log groups, you'll see an error that prompts you to narrow your selection.

1. The default log class for a query is **Standard**. You can use **Log class** to change it to **Infrequent access**.

**Using the AWS CLI**

To make these types of selections when you start a query from the command line, you can use the `source` command in your query. For more information and examples, see [SOURCE](CWL_QuerySyntax-Source.md).

# Effects of deleting a field index policy
<a name="CloudWatchLogs-Field-Indexing-Deletion"></a>

If you delete a field index policy that has been in effect for a time, the following happens:
+ For up to 30 days after the policy is deleted, queries can still benefit from the indexed log events.
+ If you delete a log-group level index policy, and there is already an account-level policy in place that would apply to that log group, the account-level policy will eventually apply to that log group.

# Use facets to group and explore logs
<a name="CloudWatchLogs-Facets"></a>

Facets are useful for analyzing logs as they allow you to interactively filter and group your data without running queries. A facet is a field in your logs (such as `ServiceName` or `StatusCode`) that enables filtering, aggregation and analysis across log groups. You can view the list of faceted fields in the CloudWatch Logs Insights console, along with the count of log events for each facet value based on your selected time range. As you select different facets and values, the facet values and counts are updated in real-time, enabling you to interactively explore your logs.

Each facet shows available values and counts automatically extracted from fields in your logs based on the selected time range and query scope, and retained for 30 days. Facet counts shown are approximate. You can use the default facets such as data source name or data source type to explore your logs, or create custom facets on any of the fields in your logs. Data Source name is an AWS service or application that generates the logs (for example, Route 53, Amazon VPC, or CloudTrail) and Data Source type is the specific type of log generated by that service. Default facets are created by CloudWatch and include `@aws.region`, `@data_source_name`, `@data_source_type`, and `@data_format`. For more information, see [Log management](LogManagement.md). Facets are only available for logs that are ingested in the account. If you have set up cross account observability, the monitoring account cannot view facets based on logs from source accounts.

To create additional facets, select the fields in your logs that are relevant to your troubleshooting and configure them using the index policies. For custom facets, we recommend creating them on low-cardinality fields (fields having less than 100 unique values per day such as Status and ApplicationName). Facets with more than 100 unique values per day are classified as high-cardinality and values for these facets are not displayed. Select one or more facets and click to run queries across your logs.

To get started with facets in CloudWatch Logs Insights:

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, **Logs Insights**.

1. (Optional) Use the time range selector to select a time period that you want to analyze. For the selected time range, available facets and values are shown in the panel.

1. Select facets to explore your data and see real-time updates of the value distributions across the facets.

   Facets with more than 100 unique values are not displayed. To query specific values, use filters in your query instead.

## To run a facet-based query
<a name="CloudWatchLogs-Facets-RunQuery"></a>

1. Select one or more values across facets.

1. The event count will update based on the facets and values selected.

1. As facet values are selected, the query scope is updated to reflect the selection.

1. After selecting the facets values, click run to execute your query.

1. The maximum number of unique values supported per facet is 100. For example, if there are more than 100 values for a facet, then all the counts are displayed as "-", indicating that the values are unknown.

## To save a facet-based query
<a name="CloudWatchLogs-Facets-SaveQuery"></a>

1. Create your query using one or more facet values.

1. The rest of the steps are the same as saving a Logs Insights query. See [Saving CloudWatch Logs Insights queries](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_Insights-Saving-Queries.html).

1. Your saved queries are available in the Saved Queries section. When you retrieve a saved query, it will automatically include the facets and values used for the query, making it easy to analyze your logs.

## To create an account-level facet
<a name="CloudWatchLogs-Facets-CreateFacet"></a>

1. To create facets, you need to first create the field as an index and configure it as a facet. In the navigation pane, choose **Settings**, **Logs**, **Account level index policies**. Alternatively, you can select **Manage facets** on the facets panel.

1. Choose **Create new index policy**. For details on creating index policies, see [Create an account-level field index policy](CloudWatchLogs-Field-Indexing-CreateAccountLevel.md).

1. To create a facet, check **Set as facet** for the selected field in the index policy creation page.

## Facet Management using APIs
<a name="CloudWatchLogs-Facets-Management"></a>

Facet management can be done using the field index policy. See [https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_FieldIndex.html](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_FieldIndex.html) APIs for details.


**Field Index APIs**  

| No. | Name | Description | 
| --- | --- | --- | 
| 1 | PutIndexPolicy | Creates or updates a field index policy for the specific log group | 
| 2 | PutAccountPolicy | Creates an account-level data protection policy, subscription filter policy, field index policy, transformer policy, or metric extraction policy that applies to all log groups or a subset of log groups in the account | 
| 3 | DeleteIndexPolicy | Deletes a log-group level field index policy that was applied to a single log group | 
| 4 | DeleteAccountPolicy | Deletes a CloudWatch Logs account policy | 

# Pattern analysis
<a name="CWL_AnalyzeLogData_Patterns"></a>

CloudWatch Logs Insights uses machine learning algorithms to find *patterns* when you query your logs. A pattern is a shared text structure that recurs among your log fields. When you view the results of a query, you can choose the **Patterns** tab to see the patterns that CloudWatch Logs found based on a sample of your results. Alternatively, you can append the `pattern` command to your query to analyze the patterns in the entire set of matching log events. 

Patterns are useful for analyzing large log sets because a large number of log events can often be compressed into a few patterns.

Consider the following sample of three log events.

```
2023-01-01 19:00:01 [INFO] Calling DynamoDB to store for resource id 12342342k124-12345
2023-01-01 19:00:02 [INFO] Calling DynamoDB to store for resource id 324892398123-12345
2023-01-01 19:00:03 [INFO] Calling DynamoDB to store for resource id 3ff231242342-12345
```

In the previous sample, all three log events follow one pattern:

```
<Time-1> [INFO] Calling DynamoDB to store for resource id <ID-2>
```

Fields within a pattern are called *tokens*. Fields that vary within a pattern, such as a request ID or timestamp, are *dynamic tokens*. Each dynamic token is represented by `<string-number>`. The *string* is a description of the type of data that the token represents. The *number* shows where in the pattern this token appears, compared to the other dynamic tokens.

Common examples of dynamic tokens include error codes, timestamps, and request IDs. A *token value* represents a particular value of a dynamic token. For example, if a dynamic token represents an HTTP error code, then a token value could be `501`.

Pattern detection is also used in the CloudWatch Logs anomaly detector and compare features. For more information, see [Log anomaly detection](LogsAnomalyDetection.md) and [Compare (diff) with previous time ranges](CWL_AnalyzeLogData_Compare.md).

## Getting started with pattern analysis
<a name="CWL_AnalyzeLogData_Patterns-GetStarted"></a>

Pattern detection is automatically performed in any CloudWatch Logs Insights query. Queries that don't include the `pattern` command get both log events and patterns in the results.

If you include the `pattern` command in your query, pattern analysis is performed on the entire matched set of log events. This gives you more accurate pattern results, but the raw log events are not returned when you use the `pattern` command. When a query doesn't include `pattern`, the pattern results are based either on the first 1000 returned log events, or on the limit value you used in your query. If you include `pattern` in the query, then the results displayed in the **Patterns** tab are derived from all log events matched by the query.

**To get started with pattern analysis in CloudWatch Logs Insights**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, **Logs Insights**.

   On the **Logs Insights** page, the query editor contains a default query that returns the 20 most recent log events.

1. Remove the `| limit 20` line in the query box, so that the query looks like the following:

   ```
   fields @timestamp, @message, @logStream, @log
   | sort @timestamp desc
   ```

1. In the **Select log group(s)** drop-down, choose one or more log groups to query.

1. (Optional) Use the time interval selector to select a time period that you want to query.

   You can choose between 5-minute and 30-minute intervals; 1-hour, 3-hour, and 12-hour intervals; or a custom time frame.

1. Choose **Run query** to start the query.

   When the query finishes running, the **Logs** tab displays a table of log events returned by the query. Above the table is a message about how many records matched the query, similar to **Showing 10,000 of 71,101 records matched**.

1. Choose the **Patterns** tab.

1. The table now displays the patterns found in the query. Because the query did not include the `pattern` command, this tab displays only the patterns discovered among the 10,000 log events that were shown in the table in the **Logs** tab.

   For each pattern, the following information is displayed:
   + The **Pattern**, with each dynamic token displayed as `<string-number>`. The *string* is a description of the type of data that the token represents. The *number* shows where in the pattern this token appears, compared to the other dynamic tokens.
   + The **Event count**, which is the number of times that the pattern appeared in the queried log events. Choose the **Event count** column heading to sort the patterns by frequency.
   + The **Event ratio**, which is the percentage of the queried log events that contain this pattern. 
   + The **Severity type**, which will be one of the following:
     + **ERROR** if the pattern contains the word **Error**.
     + **WARN** if the pattern contains the word **Warn** but doesn't contain **Error**.
     + **INFO** if the pattern doesn't contain either **Warn** or **Error**.

     Choose the **Severity info** column heading to sort the patterns by severity.

1. Now change the query. Replace the `| sort @timestamp desc` line in the query with `| pattern @message`, so that the complete query is as follows:

   ```
   fields @timestamp, @message, @logStream, @log
   | pattern @message
   ```

1. Choose **Run query**.

   When the query finishes, there are no results in the **Logs** tab. However, the **Patterns** tab likely has a larger number of patterns listed, depending on the total number of log events that were queried.

1. Regardless of whether you included `pattern` in your query, you can further inspect the patterns that the query returns. To do so, choose the icon in the **Inspect** column for one of the patterns. 

   The **Pattern inspect** pane appears and displays the following: 
   + The **Pattern**. Select a token within the pattern to analyze that token's values.
   + A histogram showing the number of occurrences of the pattern over the queried time range. This can help you to identify interesting trends such as a sudden increase in occurrence of a pattern.
   + The **Log samples** tab displays a few of the log events that match the selected pattern.
   + The **Token Values** tab displays the values of the selected dynamic token, if you have selected one.
**Note**  
A maximum of 10 token values is captured for each token. Token counts might not be precise. CloudWatch Logs uses a probabilistic counter to generate the token count, not the absolute value.
   + The **Related patterns** tab displays other patterns that frequently occurred near the same time as the pattern that you are inspecting. For example, if a pattern for an `ERROR` message was usually accompanied by another log event marked as `INFO` with additional details, that pattern is displayed here.

## Details about the pattern command
<a name="CWL_AnalyzeLogData_Patterns-Details"></a>

This section contains more details about the `pattern` command and its uses.
+ In the previous tutorial, we removed the `sort` command when we added `pattern` because a query is not valid if it includes a `pattern` command after a `sort` command. It is valid to have a `pattern` before a `sort`.

   For more details about `pattern` syntax, see [pattern](CWL_QuerySyntax-Pattern.md).
+ When you use `pattern` in a query, `@message` must be one of the fields selected in the `pattern` command.
+ You can include the `filter` command before a `pattern` command to cause only the filtered set of log events to be used as input for pattern analysis.
+ To see pattern results for a particular field, such as a field derived from the `parse` command, use `pattern @fieldname`.
+ Queries with non-log output, such as queries with the `stats` command, do not return pattern results.



# Save and re-run CloudWatch Logs Insights queries
<a name="CWL_Insights-Saving-Queries"></a>

After you create a query, you can save it, and run it again later. Queries are saved in a folder structure, so you can organize them. You can save as many as 1000 queries per region and per account.

Queries are saved on a Region-specific level, not a user-specific level. If you create and save a query, other users with access to CloudWatch Logs in the same Region can see all saved queries and their folder structures in the Region.

To save a query, you must be logged into a role that has the permission `logs:PutQueryDefinition`. To see a list of your saved queries, you must be logged into a role that has the permission`logs:DescribeQueryDefinitions`.

**Note**  
You can create and save queries with parameters — reusable templates with named placeholders. Instead of saving multiple variations of the same query with different values, create one template and provide different parameter values when you run it. This functionality is currently supported for queries using Logs Insights query language only. For more information, see [Using saved queries with parameters](#CWL_Insights-Parameterized-Queries).

------
#### [ Console ]

**To save a query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. In the query editor, create a query.

1. Choose **Save**.

1. Enter a name for the query.

1. (Optional) Choose a folder where you want to save the query. Select **Create new** to create a folder. If you create a new folder, you can use slash (/) characters in the folder name to define a folder structure. For example, naming a new folder **folder-level-1/folder-level-2** creates a top-level folder called **folder-level-1**, with another folder called **folder-level-2** inside that folder. The query is saved in **folder-level-2**.

1. (Optional) Change the query's log groups or query text.

1. (Optional) To use parameters in your query, follow these additional steps:

   1. **Add parameters to your query.** Replace static values with placeholders using the `{{parameter}}` syntax (double braces before and after the parameter name).

      Example: Original query with static values:

      ```
      fields @timestamp, @message
      | filter level = "Error"
      | filter applicationName = "OrderService"
      ```

      Updated query with parameters:

      ```
      fields @timestamp, @message
      | filter level = {{logLevel}}
      | filter applicationName = {{applicationName}}
      ```

   1. **Define the parameters used in your query.** For each placeholder parameter, specify:
      + **Name**: Must exactly match the placeholder name (for example, `logLevel`, `applicationName`).
      + **Default value** (optional): The value to use if no parameter value is provided.
      + **Description** (optional): Explains the parameter's purpose.

   1. Queries with parameters can be run by using the query name with a `$` prefix and passing the parameter names as key-value pairs. See **To run a saved query** for details.

1. Choose **Save**.

------
#### [ AWS CLI ]

**To save a query**, use `put-query-definition`:

```
aws logs put-query-definition \
  --name "ErrorsByLevel" \
  --query-string "fields @timestamp, @message | filter level = \"ERROR\"" \
  --log-group-names "/aws/lambda/my-function" \
  --region us-east-1
```

(Optional) To save a query with parameters, add the `--parameters` option and use `{{parameterName}}` placeholders in the query string:

```
aws logs put-query-definition \
  --name "ErrorsByLevel" \
  --query-string "fields @timestamp, @message | filter level = {{logLevel}} | filter applicationName = {{applicationName}}" \
  --parameters '[{"name":"logLevel","defaultValue":"ERROR","description":"Log level to filter"},{"name":"applicationName","defaultValue":"OrderService","description":"Application name to filter"}]' \
  --log-group-names "/aws/lambda/my-function" \
  --region us-east-1
```

To save a query in a folder, prefix the query name with the folder path:

```
aws logs put-query-definition \
  --name "my-folder/ErrorsByLevel" \
  --query-string "fields @timestamp, @message | filter level = {{logLevel}}" \
  --parameters '[{"name":"logLevel","defaultValue":"ERROR","description":"Log level to filter"}]' \
  --log-group-names "/aws/lambda/my-function" \
  --region us-east-1
```

------
#### [ API ]

**To save a query**, call [PutQueryDefinition](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutQueryDefinition.html):

```
{
  "name": "ErrorsByLevel",
  "queryString": "fields @timestamp, @message | filter level = \"ERROR\"",
  "logGroupNames": ["/aws/lambda/my-function"]
}
```

(Optional) To save a query with parameters, include the `parameters` field and use `{{parameterName}}` placeholders in the query string:

```
{
  "name": "ErrorsByLevel",
  "queryString": "fields @timestamp, @message | filter level = {{logLevel}} | filter applicationName = {{applicationName}}",
  "logGroupNames": ["/aws/lambda/my-function"],
  "parameters": [
    {
      "name": "logLevel",
      "defaultValue": "ERROR",
      "description": "Log level to filter"
    },
    {
      "name": "applicationName",
      "defaultValue": "OrderService",
      "description": "Application name to filter"
    }
  ]
}
```

------

**Tip**  
 You can create a folder for saved queries with `PutQueryDefinition`. To create a folder for your saved queries, use a forward slash (/) to prefix your desired query name with your desired folder name: `<folder-name>/<query-name>`. For more information about this action, see [PutQueryDefinition](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutQueryDefinition.html). 

------
#### [ Console ]

**To run a saved query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. On the right, choose **Queries**.

1. Select your query from the **Saved queries** list. The query text appears in the query editor.

1. (Optional) To use a query with parameters:

   1. Choose the **\$1** icon next to the query name in the **Saved queries** side panel.

   1. The query with parameters appears in the query editor. For example, if you choose the **\$1** icon next to `ErrorsByLevel`, the query editor is populated with: `$ErrorsByLevel(level=, applicationName=)`

   1. Provide the values for the parameters (level, applicationName) and run the query. For example: `$ErrorsByLevel(level= "ERROR", applicationName= "OrderService")`

1. Choose **Run**.

------
#### [ AWS CLI ]

**To run a saved query with parameters**

Use `start-query` with the `$QueryName()` syntax:

```
aws logs start-query \
  --log-group-names "/aws/lambda/my-function" \
  --start-time 1707566400 --end-time 1707570000 \
  --query-string '$ErrorsByLevel(level= "ERROR", applicationName= "OrderService")' \
  --region us-east-1
```

------
#### [ API ]

**To run a saved query with parameters**

Call [StartQuery](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_StartQuery.html) with the `$QueryName()` syntax in the `queryString` field:

```
{
  "logGroupNames": ["/aws/lambda/my-function"],
  "startTime": 1707566400,
  "endTime": 1707570000,
  "queryString": "$ErrorsByLevel(level=\"ERROR\", applicationName= \"OrderService\")"
}
```

------

**To save a new version of a saved query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. On the right, choose **Queries**.

1. Select your query from **Saved queries** list. It appears in the query editor.

1. Modify the query. If you need to run it to check your work, choose **Run query**.

1. When you are ready to save the new version, choose **Actions**, **Save as**.

1. Enter a name for the query.

1. (Optional) Choose a folder where you want to save the query. Select **Create new** to create a folder. If you create a new folder, you can use slash (/) characters in the folder name to define a folder structure. For example, naming a new folder **folder-level-1/folder-level-2** creates a top-level folder called **folder-level-1**, with another folder called **folder-level-2** inside that folder. The query is saved in **folder-level-2**.

1. (Optional) Change the query's log groups or query text.

1. Choose **Save**.

To delete a query, you must be logged in to a role that has the `logs:DeleteQueryDefinition` permission.

**To edit or delete a saved query**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. On the right, choose **Queries**.

1. Select your query from **Saved queries** list. It appears in the query editor.

1. Choose **Actions**, **Edit** or **Actions**, **Delete**.

## Using saved queries with parameters
<a name="CWL_Insights-Parameterized-Queries"></a>

Saved queries with parameters are reusable query templates with named placeholders. Instead of maintaining multiple copies of nearly identical queries, you can save a template and supply different parameter values when running the query. Parameters are only supported in the CloudWatch Logs Insights query language.

 **How it works** 

When saving a query, placeholders identify the values which you can provide at query execution time. Placeholders use the `{{parameterName}}` syntax. The following is an example of a saved query named `ErrorsByLevel` with two parameters `logLevel` and `applicationName`.

```
fields @timestamp, @message
| filter level = {{logLevel}}
| filter applicationName = {{applicationName}}
```

To run a saved query, you can invoke it using the query name prefixed with `$` and passing the parameter values. The CloudWatch Logs Insights query engine replaces each placeholder. If a parameter contains default values, then those values are used if no other values are provided.

```
# Run query by using query name and passing parameter values explicitly
$ErrorsByLevel(logLevel = "WARN", applicationName = "OrderService")

# Run query without specifying parameter values - default values are used in this case.
$ErrorsByLevel()
```

Saved query names containing spaces or special characters need to be enclosed with backticks:

```
$`Errors By Level`(logLevel = "WARN")
```

### Sample saved queries with parameters
<a name="CWL_Insights-Parameterized-Queries-Examples"></a>

 **Adding a result limit as a parameter** 

Query name: `ErrorsByLevel` with parameters `logLevel` (default: `"ERROR"`), `applicationName` (default: `"OrderService"`), and `maxResults` (default: `50`)

```
fields @timestamp, @message, @logStream
| filter level = {{logLevel}}
| filter applicationName = {{applicationName}}
| sort @timestamp desc
| limit {{maxResults}}
```

```
# Run the query using the query name and passing parameter values
$ErrorsByLevel(logLevel = "WARN", applicationName = "OrderService", maxResults = 100)
```

 **Using multiple saved queries with parameters** 

 The example below uses `ErrorsByLevel` and a second saved query `RecentN` which is defined as `sort @timestamp desc | limit {{count}}` (with parameter `count`, default `20`). The CloudWatch Logs Insights query engine expands each query before running it.

```
# Using multiple queries with parameters in sequence
$ErrorsByLevel(logLevel = "WARN", applicationName = "OrderService")
| $RecentN(count = 10)

# Each of the queries is expanded, resulting in the following query when it is run.
fields @timestamp, @message
| filter level = "WARN"
| filter applicationName = "OrderService"
| sort @timestamp desc
| limit 10
```

### Quotas and error handling
<a name="CWL_Insights-Parameterized-Queries-Quotas"></a>

**Note**  
Each saved query can have a maximum of 20 parameters.

The expanded query string cannot exceed 10,000 characters. Parameter names must start with a letter or underscore. A saved query cannot reference another saved query (nested invocations are not supported).


**Common errors**  

| Error | Cause | 
| --- | --- | 
| Parameters are only supported for CWLI query language | Parameters are only supported in the CloudWatch Logs Insights query language. | 
| Required parameters not found in queryString | A parameter name in `--parameters` does not have a matching `{{placeholder}}` in the query string. | 
| Parameter count exceeds the maximum of 20 | Saved queries currently only support 20 parameters. | 
| Duplicate parameter name | The query definition has duplicate parameters in `parameters`. | 

**Note**  
To create or update a saved query with parameters, you need the `logs:PutQueryDefinition` permission. To run one, you need `logs:StartQuery` and `logs:DescribeQueryDefinitions`.

# Add query to dashboard or export query results
<a name="CWL_ExportQueryResults"></a>

After you run a query, you can add the query to a CloudWatch dashboard or copy the results to the clipboard.

Queries added to dashboards run every time you load the dashboard and every time that the dashboard refreshes. These queries count toward your limit of 100 concurrent CloudWatch Logs Insights queries.

**To add query results to a dashboard**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. Choose one or more log groups and run a query.

1. Choose **Add to dashboard**.

1. Select the dashboard, or choose **Create new** to create a dashboard for the query results.

1. Select the widget type to use for the query results.

1. Enter a name for the widget.

1. Choose **Add to dashboard**.

**To copy query results to the clipboard or download the query results**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. Choose one or more log groups and run a query.

1. Choose **Export results**, and then choose the option you want.

# View running queries or query history
<a name="CloudWatchLogs-Insights-Query-History"></a>

You can view the queries currently in progress as well as your recent query history.

Queries currently running includes queries you have added to a dashboard. You are limited to 100 concurrent CloudWatch Logs Insights queries per account, including queries added to dashboards. Additionally, You can run 15 concurrent queries for either OpenSearch Service PPL or OpenSearch Service SQL.

**To view your recent query history**

1. Open the CloudWatch console at [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).

1. In the navigation pane, choose **Logs**, and then choose **Logs Insights**.

1. Choose **History**, if you are using the new design for the CloudWatch Logs console. If you are using the old design, choose **Actions**, **View query history for this account**.

   A list of your recent queries appears. You can run any of them again by selecting the query and choosing **Run**.

   Under **Status**, CloudWatch Logs displays **In progress** for any queries that are currently running.

# Encrypt query results with AWS Key Management Service
<a name="CloudWatchLogs-Insights-Query-Encrypt"></a>

By default, CloudWatch Logs encrypts the stored results of your CloudWatch Logs Insights queries using the default CloudWatch Logs server-side encryption method. You can choose to use a AWS KMS key to encrypt these results instead. If you associate a AWS KMS key with your encryption results, then CloudWatch Logs uses that key to encrypt the stored results of all queries in the account. 

If you later disassociate a the key from your query results, CloudWatch Logs goes back to the default encryption method for later queries. But the queries that ran while the key was associated are still encrypted with that key. CloudWatch Logs can still return those results after the KMS key is disassociated, because CloudWatch Logs can still continue to reference the key. However, if the key is later disabled, then CloudWatch Logs is unable to read the query results that were encrypted with that key.

**Important**  
CloudWatch Logs supports only symmetric KMS keys. Do not use an asymmetric key to encrypt your query results. For more information, see [Using Symmetric and Asymmetric Keys](https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html).

## Limits
<a name="encryption-limits-queries"></a>
+ To perform the following steps, you must have the following permissions: `kms:CreateKey`, `kms:GetKeyPolicy`, and `kms:PutKeyPolicy`.
+ After you associate or disassociate a key from your query results, it can take up to five minutes for the operation to take effect.
+ If you revoke CloudWatch Logs access to an associated key or delete an associated KMS key, your encrypted data in CloudWatch Logs can no longer be retrieved.
+ You can't use the CloudWatch console to associate a key, you must use the AWS CLI or CloudWatch Logs API.

## Step 1: Create an AWS KMS key
<a name="create-cmk"></a>

To create a KMS key use the following [create-key](https://docs.aws.amazon.com/cli/latest/reference/kms/create-key.html) command:

```
aws kms create-key
```

The output contains the key ID and Amazon Resource Name (ARN) of the key. The following is example output:

```
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "1234abcd-12ab-34cd-56ef-1234567890ab",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "Enabled": true,
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1478910250.94,
        "Arn": "arn:aws:kms:us-west-2:123456789012:key/6f815f63-e628-448c-8251-e40cb0d29f59",
        "AWSAccountId": "123456789012",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ]
    }
}
```

## Step 2: Set permissions on the KMS key
<a name="cmk-permissions"></a>

By default, all KMS keys are private. Only the resource owner can use it to encrypt and decrypt data. However, the resource owner can grant permissions to access the key to other users and resources. With this step, you give the CloudWatch Logs service principal permission to use the key. This service principal must be in the same AWS Region where the key is stored.

As a best practice, we recommend that you restrict the use of the key to only those AWS accounts that you specify.

First, save the default policy for your KMS key as `policy.json` using the following [get-key-policy](https://docs.aws.amazon.com/cli/latest/reference/kms/get-key-policy.html) command:

```
aws kms get-key-policy --key-id key-id --policy-name default --output text > ./policy.json
```

Open the `policy.json` file in a text editor and add the section in bold from one of the following statements. Separate the existing statement from the new statement with a comma. These statements use `Condition` sections to enhance the security of the AWS KMS key. For more information, see [AWS KMS keys and encryption context](encrypt-log-data-kms.md#encrypt-log-data-kms-policy).

The `Condition` section in this example limits the use of the AWS KMS key to the CloudWatch Logs Insights query results in the specified account.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Id": "key-default-1",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111122223333:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.region.amazonaws.com"
            },
            "Action": [
                "kms:Encrypt*",
                "kms:Decrypt*",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:Describe*"
            ],
            "Resource": "*",
            "Condition": {
                "ArnEquals": {
                "aws:SourceArn": "arn:aws:logs:us-east-1:111122223333:query-result:*"
                },
                "StringEquals": {
                "aws:SourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

------

Finally, add the updated policy using the following [put-key-policy](https://docs.aws.amazon.com/cli/latest/reference/kms/put-key-policy.html) command:

```
aws kms put-key-policy --key-id key-id --policy-name default --policy file://policy.json
```

## Step 3: Associate a KMS key with your query results
<a name="associate-cmk-query"></a>

**To associate the KMS key with the query results in the account**  
Use the [disassociate-kms-key](https://docs.aws.amazon.com/cli/latest/reference/logs/disassociate-kms-key.html) command as follows:

```
aws logs associate-kms-key --resource-identifier "arn:aws:logs:region:account-id:query-result:*" --kms-key-id "key-arn"
```

## Step 4: Disassociate a key from query results in the account
<a name="disassociate-cmk-query"></a>

To disassociate the KMS key associated with query results, use the following [disassociate-kms-key](https://docs.aws.amazon.com/cli/latest/reference/logs/disassociate-kms-key.html) command:

```
aws logs disassociate-kms-key --resource-identifier "arn:aws:logs:region:account-id:query-result:*"
```

# Generate a natural language summary from CloudWatch Logs Insights query results
<a name="CloudWatchLogs-Insights-Query-Results-Summary"></a>

Analyzing log data is crucial for understanding your applications' behavior, but interpreting large volumes of log entries can be time-consuming. CloudWatch Logs Insights now offers a natural language summarization capability that transforms complex query results into clear, concise summaries. This capability helps you quickly identify issues and gain actionable insights from your log data. 

## How it works
<a name="how-it-works"></a>

CloudWatch Logs Insights can generate a human-readable summary from your query results using Amazon Bedrock. The feature supports all CloudWatch Logs Insights query languages and provides clear, actionable insights from your log data.

## Regional availability and data processing
<a name="regional-availability"></a>

**Important**  
When you use this feature, your query results might be processed in a different AWS Region. For example, if you run a query in US East (N. Virginia), the summarization might occur in US West (Oregon).

The following table lists the possible processing AWS Region for the different geographies in which the query results feature is available:


| Supported CloudWatch Logs geography | Possible Processing Region | 
| --- | --- | 
| United States (US) | US East (N. Virginia) Region US East (Ohio) Region US West (Oregon) Region | 
| Europe | Europe (Frankfurt) Region Europe (Ireland) Region Europe (Paris) Region Europe (Stockholm) Region Europe (London) Region | 
| Asia Pacific |  US East (N. Virginia) Region US East (Ohio) Region US West (Oregon) Region  | 
| South America |  US East (N. Virginia) Region US East (Ohio) Region US West (Oregon) Region  | 

## Getting started
<a name="getting-started"></a>

**To generate a natural language summary**

1. Run your CloudWatch Logs Insights query.

1. After the query completes, select **Summarize results**.

## Permissions
<a name="permissions"></a>

You must have one of the following:
+ `CloudWatchLogsFullAccess` permission
+ `CloudWatchLogsReadOnlyAccess` permission
+ Custom IAM policy including the `cloudwatch:GenerateQueryResultsSummary`, `logs:GetQueryResults`, `logs:DescribeQueries` and `logs:FilterLogEvents` actions

## Data privacy
<a name="data-privacy"></a>

Your query results are processed securely and aren't used to train or improve CloudWatch Logs Insights or Amazon Bedrock. If you choose to provide feedback on the query results summary using the feedback buttons, your feedback indicates your level of satisfaction with the capability provided in CloudWatch Logs Insights.