Testing 25 New Commands and Functions Added to CloudWatch Logs Insights (July 2026 Edition)

Testing 25 New Commands and Functions Added to CloudWatch Logs Insights (July 2026 Edition)

I tested 25 new CloudWatch Logs Insights commands and functions added in July 2026, including hex conversion, datetime parsing, cumulative sums, and sessionization, and summarize the behavior and caveats observed.
2026.07.17

This page has been translated by machine translation. View original

Introduction

On July 15, 2026, 25 new commands and functions were added to CloudWatch Logs Insights.

https://aws.amazon.com/jp/about-aws/whats-new/2026/7/amazon-cloudwatch-logs-insights-ql/

This is the third installment, following the May release (13 items) and the June release (23 items), bringing the three-month total to 61. This time the focus is on analysis-oriented features such as row-level sequence operations, sessionization, outlier detection, and CIDR lookup.

https://dev.classmethod.jp/articles/cloudwatch-logs-insights-new-commands-functions-2026/

https://dev.classmethod.jp/articles/cloudwatch-logs-insights-new-commands-functions-2026-june/

Here is the list of added features.

Category Function/Command Purpose
Type conversion hexToAscii Convert a hex string to ASCII
Type conversion hexToDec Convert a hex string to a decimal number
Type conversion decToHex Convert a decimal number to a hex string
Date/time parseDate Parse a date string into epoch milliseconds
Date/time formatDate Format a timestamp in strftime format
Date/time queryStartTime Return the query window start time
Date/time queryEndTime Return the query window end time
Date/time queryTimeRange Return the query window width in milliseconds
Row sequence autoregress Generate previous-row values as lag fields
Row sequence accum Calculate the cumulative sum of a numeric field
Row sequence filldown Forward-fill missing values with the last non-null value
Row sequence fillmissing Insert a specified value into empty time bins
Session sessionize Sessionize by identity + inactivity gap
Statistics variance Calculate population variance
Statistics topk Return the top k most frequent values
Statistics countFrequent Return approximate counts of field values in descending order
String messageSize Return the byte length of a field
JSON jsonArraySize Return the number of elements in a JSON array string
JSON jsonArrayContains Determine whether a JSON array contains a specified value
Condition isNumeric Determine whether a field value is numeric
Query composition where Alias of the filter command
Analysis outlier IQR-based outlier detection
Time comparison logcompare Compare the current and past time windows
Query composition appendcols Join subquery columns by row position
Lookup cidrlookup Match an IP against a lookup table by CIDR range

Comparing the additions over the three months, the direction of the features differs from month to month.

Period Items added Trend
May 2026 13 Reading and formatting (parse extensions, display, string functions)
June 2026 23 Aggregation and judgment (conditional branching, statistical functions, IP checks)
July 2026 25 Analysis, sessionization, and joins (row operations, outlier, lookup)

In this article, I actually ran all 25 of these against the log group /test/insights-new-2026-07 (60 test data entries) in the us-east-1 region. I summarize the behavior I was able to confirm and practical points to note. The verification date is 2026-07-17.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-operations-functions.html

Verification

Type conversion and encoding

These are the three functions hexToAscii, hexToDec, and decToHex, which convert between hexadecimal and ASCII strings or decimal numbers.

filter ispresent(hex_ascii)
| display hex_ascii, hexToAscii(hex_ascii) as ascii_text, hex_num, hexToDec(hex_num) as dec_val, decimal, decToHex(decimal) as hex_out
hex_ascii ascii_text hex_num dec_val decimal hex_out
436c6f7564576174636820496e736967687473 CloudWatch Insights 7fff 32767 32767 0x7fff
576f726c64 World 1a 26 26 0x1a
48656c6c6f Hello ff 255 255 0xff

hexToAscii converts a hex string into an ASCII string. "CloudWatch Insights" was restored from a 38-digit (19-byte) input, so it handles variable-length input. hexToDec accepts lowercase hex without the 0x prefix as input and returns a decimal number. The reverse, decToHex, returned lowercase hex with the 0x prefix in its output.

Date/time functions

parseDate and formatDate, which convert between date strings and timestamps, were added, along with queryStartTime, queryEndTime, and queryTimeRange, which reference the times of the query window itself. I verify all five functions together.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-timeseries-functions.html

Here are the verification results for parseDate and formatDate.

filter ispresent(date_str)
| display event, date_str, parseDate(date_str, "yyyy-MM-dd", "UTC") as parsed, formatDate(@timestamp, "%Y-%m-%d %H:%M:%S", "UTC") as fmt
event date_str parsed fmt
rollback 2026-07-01 2026-07-01 00:00:00.000 2026-07-16 18:09:23
release 2026-07-10 2026-07-10 00:00:00.000 2026-07-16 18:09:18
deploy 2026-07-15 2026-07-15 00:00:00.000 2026-07-16 18:09:13

parseDate takes a Java DateTimeFormatter pattern as the second argument and specifies the time zone in the third argument. The return value is epoch milliseconds, but it is rendered in timestamp format on the Logs Insights console. formatDate uses a strftime-style format string, and the official documentation states that it can also be called with the alias strftime.

Next are the three functions that return the times of the query window.

fields queryStartTime() as qst, queryEndTime() as qet, queryTimeRange() as qtr | limit 1
qst qet qtr
2026-07-16 16:13:38.000 2026-07-16 18:14:38.999 7260999

queryTimeRange returns the width of the query window in milliseconds. For a window of about two hours, 7260999 ms was returned, and it can be used within a query as a reference value for aggregation and normalization.

Row sequences and null handling

autoregress, accum, and filldown were added as operations that depend on row ordering, and fillmissing was added as an operation that fills gaps in time bins. For the first three commands, you need to specify sort @timestamp asc earlier in the pipeline (behavior confirmed during verification).

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Autoregress.html

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Accum.html

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Filldown.html

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Fillmissing.html

autoregress expands previous-row values into new columns as lag fields.

filter ispresent(metric) | sort @timestamp asc | fields @timestamp, value | autoregress value p=1-2
@timestamp value value_p1 value_p2
2026-07-16 18:09:43.682 10
2026-07-16 18:09:48.682 12 10
2026-07-16 18:09:53.682 11 12 10
2026-07-16 18:09:58.682 13 11 12
2026-07-16 18:10:03.682 12 13 11

Specifying p=1-2 automatically generates value_p1, holding the value from one row before, and value_p2, holding the value from two rows before. The leading rows are empty because there are not enough preceding rows for the lag. Since previous-row values become available, it can also be used to create derived columns, such as taking a difference with value - value_p1.

accum calculates the cumulative sum of a numeric field.

filter ispresent(metric) | sort @timestamp asc | fields @timestamp, value | accum value AS running_total
@timestamp value running_total
2026-07-16 18:09:43.682 10 10
2026-07-16 18:09:48.682 12 22
2026-07-16 18:09:53.682 11 33
2026-07-16 18:09:58.682 13 46
2026-07-16 18:10:03.682 12 58

filldown forward-fills missing values with the last non-null value.

filter ispresent(sensor) | sort @timestamp asc | fields @timestamp, sensor, region, reading | filldown region
@timestamp sensor region reading
2026-07-16 18:11:23.682 temp-1 us-east-1 22.5
2026-07-16 18:11:28.682 temp-1 us-east-1 23.1
2026-07-16 18:11:33.682 temp-1 us-east-1 22.8
2026-07-16 18:11:38.682 temp-1 eu-west-1 19.2
2026-07-16 18:11:43.682 temp-1 eu-west-1 19.5

In the original data, region was missing in rows 2, 3, and 5, but filldown filled them with the last non-null value. This is useful for sensor data and event logs where context information is recorded in only some of the records.

fillmissing is used after stats ... by bin() and inserts a specified value into time bins that have no data.

filter metric = "cpu_usage" | stats avg(value) as avg_val by bin(10s) | fillmissing with 0 for avg_val
bin(10s) avg_val
2026-07-16 18:27:50.000 0
2026-07-16 18:27:40.000 0
2026-07-16 18:27:30.000 0

All three displayed rows are bins with no data, and fillmissing inserted 0. In this verification data, no bins with actual data were included in the displayed range, so everything is 0.

Sessionization

sessionize is a command that splits a sequence of events into sessions based on an identity field and an inactivity gap (maxspan).

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Sessionize.html

filter ispresent(userId) | sort @timestamp asc | fields @timestamp, userId, action, deviceId | sessionize userId, deviceId maxspan 20s
@timestamp userId action deviceId session_id
2026-07-16 18:11:48.682 user-A login mobile user-A\x1fmobile-1
2026-07-16 18:11:53.682 user-A view_page mobile user-A\x1fmobile-1
2026-07-16 18:11:58.682 user-B login desktop user-B\x1fdesktop-1
2026-07-16 18:12:03.682 user-A click mobile user-A\x1fmobile-1
2026-07-16 18:12:08.682 user-B view_page desktop user-B\x1fdesktop-1
2026-07-16 18:12:13.682 user-B logout desktop user-B\x1fdesktop-1
2026-07-16 18:12:18.682 user-A login mobile user-A\x1fmobile-1
2026-07-16 18:12:23.682 user-A purchase mobile user-A\x1fmobile-1

Using the combination of userId and deviceId as the identity, events occurring consecutively within a maxspan of 20s were grouped into the same session. The session_id field is generated automatically. In this verification, it was displayed in a form like user-A\x1fmobile-1, where the values of the identifier fields are joined with the control character \x1f (Unit Separator) and a sequence number is appended at the end. Since this format is not stated in the official documentation, it may be implementation-dependent. According to the official documentation, the default value of maxspan is 30 minutes. Session analysis of user behavior can now be done with Logs Insights alone.

Statistics commands

On the statistics side, variance (population variance), topk (top-k frequent values), and countFrequent (approximate frequency count) have been added.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Stats.html

I checked variance alongside the existing stddev and avg.

filter ispresent(response_time) | stats variance(response_time) as v, stddev(response_time) as sd, avg(response_time) as avg_rt
v sd avg_rt
4788776.5156 2188.3273 1017.4667

variance returns the population variance. Squaring the stddev value almost exactly matches variance (2188.3273² ≒ 4788776), which was consistent with the standard deviation.

topk returns the top k frequent values and their occurrence counts.

filter ispresent(status) | stats topk(3, status)
status count
200 10
403 2
500 2

The official documentation states that it cannot be used together with a by clause.

countFrequent calculates approximate counts for each combination of field values and returns them in descending order.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-CountFrequent.html

filter ispresent(method) | countFrequent method, status
method status _approxcount
GET 200 5
POST 200 5
GET 500 2
GET 403 2
POST 401 1

The _approxcount field is generated automatically.

String functions

messageSize is a function that returns the byte length of a field.

fields messageSize(@message) as sz, @message | sort sz desc | limit 5
sz @message (excerpt)
147 {"level": "INFO", "service": "payment-service"...}
146 {"level": "INFO", "service": "payment-service"...}
145 {"level": "INFO", "service": "payment-service"...}

JSON functions

jsonArraySize and jsonArrayContains are functions that operate on JSON array strings.

filter ispresent(role_list)
| display user, role_list, jsonArraySize(role_list) as role_count, jsonArrayContains(role_list, "admin") as is_admin
user role_list role_count is_admin
charlie ["admin","viewer"] 2 1
bob ["viewer"] 1 0
alice ["admin","editor","viewer"] 3 1

jsonArraySize returned the number of elements in the array, and jsonArrayContains returned 1 if the specified value was included and 0 if not. These functions cannot be used on arrays that have been expanded by automatic parsing into forms like roles.0; they must be applied to fields that are kept as strings.

Conditional validation

isNumeric determines whether a field value can be interpreted as a number.

filter ispresent(field_a)
| display field_a, isNumeric(field_a) as a_num, field_b, isNumeric(field_b) as b_num
field_a a_num field_b b_num
0 1 99.9 1
not_number 0 100 1
42 1 hello 0

Query composition (where)

where is an alias of the filter command ("grammar alias for the filter command" in the official documentation), aimed at users familiar with SQL.

where response_time > 1000 | display service, response_time
service response_time
notification 1100
notification 2045
api-gateway 8901
auth-service 1523

Data analysis (outlier)

outlier is a statistical outlier detection command based on the IQR (interquartile range). The official documentation describes it as "Detects statistical outliers based on the interquartile range (IQR)".

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Outlier.html

filter metric = "cpu_usage" | sort @timestamp asc | fields @timestamp, value | outlier mark=true param=1.5 value

The command was accepted and matched=20, but I observed that the output was limited to a single record. The cause is unconfirmed. For practical use, I recommend re-verifying with a larger dataset. According to the official documentation, specifying mark=true adds a boolean marker field indicating the outlier determination result. In this verification environment, this field was displayed as _is_outlier. The available options are action=remove/transform, mark=true, and param (IQR coefficient).

logcompare

logcompare is a command that compares the current time window with a past window.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Logcompare.html

I verified it with a two-hour query window and timeshift 1h. The error "Diff doesn't support overlap between two time ranges we compare" occurs. If timeshift is smaller than the width of the query window, the time ranges being compared overlap, resulting in this error. This is behavior confirmed during verification, and I could not find this constraint stated in the official documentation I referred to. For it to work correctly, you need to specify a timeshift larger than the query window.

appendcols

appendcols is a command that joins the result columns of a subquery to the main query by row position.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Appendcols.html

filter ispresent(service)
| stats count(*) as cnt by service
| appendcols ( SOURCE '/test/insights-new-2026-07' | filter ispresent(response_time) | stats avg(response_time) as avg_rt by service )
service cnt avg_rt
notification 3 1070.6667
search-service 3 212.6667
api-gateway 3 3145
payment-service 3 84.3333
auth-service 3 574.6667

The SOURCE clause is required in the subquery. Omitting SOURCE causes a MalformedQueryException. The join is done by positional row matching rather than key matching. In this verification, the results of the main query and the subquery were returned in the same order, and the corresponding values were joined correctly. For practical use, I recommend specifying sort in both the main query and the subquery to explicitly align the row order.

cidrlookup

cidrlookup is a command that matches an IP address against a lookup table by CIDR range and retrieves the corresponding values.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Cidrlookup.html

You need to create a lookup table in advance. You can create it from the CloudWatch console via Settings → Logs tab → Lookup tables → Create lookup table. There is also a method of uploading a CSV directly with the CreateLookupTable API.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax-Lookup.html

The CSV used this time is as follows. The IP addresses shown are dummy values for verification, including documentation addresses defined in RFC 5737.

cidr,region,owner,network_type
198.51.100.0/24,us-west-2,external,public
10.0.0.0/8,us-east-1,internal,private
172.16.0.0/12,ap-northeast-1,internal,private
192.168.0.0/16,eu-west-1,internal,private
203.0.113.0/24,documentation,example,reserved
filter ispresent(ip)
| fields @timestamp, ip, service
| cidrlookup net_table ip AS cidr OUTPUT region, owner, network_type
| display ip, region, owner, network_type
ip region owner network_type
198.51.100.10 us-west-2 external public
10.0.2.101 us-east-1 internal private
192.168.1.11 eu-west-1 internal private
172.16.0.6 ap-northeast-1 internal private
203.0.113.50 documentation example reserved

AS cidr specifies the CIDR column name in the lookup table, and OUTPUT lists the columns to retrieve. To display the results, I had to explicitly specify the OUTPUT columns in display.

Summary

The 25 commands and functions added in July 2026 further broaden the range of log analysis you can do with CloudWatch Logs Insights.

In particular, time-series data processing with autoregress, accum, filldown, and fillmissing, sessionization of user behavior with sessionize, and outlier detection with outlier look useful for incident investigation and trend analysis. In addition, logcompare enables comparison with past time periods, cidrlookup enables attaching attributes to IP addresses, and appendcols enables analysis that places multiple aggregation results side by side.

These are things that previously might have required forwarding logs to a database or an external analytics service for processing. With this feature addition, some of that can now be run within Logs Insights queries. For example, it can be used for log investigations like the following.

  • Check differences from previous metric values and cumulative values
  • Fill in missing time-series data and context information
  • Sessionize a series of operations per user or device
  • Extract outliers in response time or processing volume
  • Compare current log trends with past time periods
  • Attach information such as network and management categories to IP addresses

Some features require caution when used, such as commands that depend on row position or time range, but this update increases the situations in which aggregation and processing during an investigation can be completed entirely within Logs Insights.

Test data structure and ingestion example (excerpt)

This shows the log group used for verification and how the test data was ingested. The following is an excerpt of the setup and is not complete code that generates all 60 entries used in the main text. I used the us-east-1 region.

Create the log group and log stream.

aws logs create-log-group --log-group-name /test/insights-new-2026-07 --region us-east-1
aws logs create-log-stream --log-group-name /test/insights-new-2026-07 --log-stream-name test-stream --region us-east-1

The following is an excerpt of the code that generated the 60 JSON logs, covering the time-series metrics and the hex conversion data.

import json, time

now = int(time.time() * 1000)
events = []

# Example: time-series metrics (20 entries)
for i, v in enumerate([10, 12, 11, 13, 12]):  # excerpt
    events.append({
        "timestamp": now + i * 5000,
        "message": json.dumps({"metric": "cpu_usage", "value": v})
    })

# Example: for hex conversion
events.append({
    "timestamp": now,
    "message": json.dumps({
        "hex_ascii": "436c6f7564576174636820496e736967687473",
        "hex_num": "7fff", "decimal": 32767
    })
})

# After that, add logs for dates, JSON arrays, sessions, and CIDR in the same way
with open("events.json", "w") as f:
    json.dump(events, f)

Ingest the generated logs with put-log-events.

aws logs put-log-events \
  --log-group-name /test/insights-new-2026-07 \
  --log-stream-name test-stream \
  --log-events file://events.json \
  --region us-east-1

Share this article

AWSのお困り事はクラスメソッドへ