Understand event filtering for Event Grid subscriptions
This article describes the different ways to filter which events are sent to your endpoint. When creating an event subscription, you have three options for filtering:
- Event types
- Subject begins with or ends with
- Advanced fields and operators
Azure Resource Manager template
The examples shown in this article are JSON snippets for defining filters in Azure Resource Manager (ARM) templates. For an example of a complete ARM template and deploying an ARM template, see Quickstart: Route Blob storage events to web endpoint by using an ARM template. Here's some more sections around the filter
section from the example in the quickstart. The ARM template defines the following resources.
- Azure storage account
- System topic for the storage account
- Event subscription for the system topic. You'll see the
filter
subsection in the event subscription section.
In the following example, the event subscription filters for Microsoft.Storage.BlobCreated
and Microsoft.Storage.BlobDeleted
events.
{
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-08-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot"
}
},
{
"type": "Microsoft.EventGrid/systemTopics",
"apiVersion": "2021-12-01",
"name": "[parameters('systemTopicName')]",
"location": "[parameters('location')]",
"properties": {
"source": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
"topicType": "Microsoft.Storage.StorageAccounts"
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
]
},
{
"type": "Microsoft.EventGrid/systemTopics/eventSubscriptions",
"apiVersion": "2021-12-01",
"name": "[format('{0}/{1}', parameters('systemTopicName'), parameters('eventSubName'))]",
"properties": {
"destination": {
"properties": {
"endpointUrl": "[parameters('endpoint')]"
},
"endpointType": "WebHook"
},
"filter": {
"includedEventTypes": [
"Microsoft.Storage.BlobCreated",
"Microsoft.Storage.BlobDeleted"
]
}
},
"dependsOn": [
"[resourceId('Microsoft.EventGrid/systemTopics', parameters('systemTopicName'))]"
]
}
]
}
Event type filtering
By default, all event types for the event source are sent to the endpoint. You can decide to send only certain event types to your endpoint. For example, you can get notified of updates to your resources, but not notified for other operations like deletions. In that case, filter by the Microsoft.Resources.ResourceWriteSuccess
event type. Provide an array with the event types, or specify All
to get all event types for the event source.
The JSON syntax for filtering by event type is:
"filter": {
"includedEventTypes": [
"Microsoft.Resources.ResourceWriteFailure",
"Microsoft.Resources.ResourceWriteSuccess"
]
}
Subject filtering
For simple filtering by subject, specify a starting or ending value for the subject. For example, you can specify the subject ends with .txt
to only get events related to uploading a text file to storage account. Or, you can filter the subject begins with /blobServices/default/containers/testcontainer
to get all events for that container but not other containers in the storage account.
When publishing events to custom topics, create subjects for your events that make it easy for subscribers to know whether they're interested in the event. Subscribers use the subject property to filter and route events. Consider adding the path for where the event happened, so subscribers can filter by segments of that path. The path enables subscribers to narrowly or broadly filter events. If you provide a three segment path like /A/B/C
in the subject, subscribers can filter by the first segment /A
to get a broad set of events. Those subscribers get events with subjects like /A/B/C
or /A/D/E
. Other subscribers can filter by /A/B
to get a narrower set of events.
Examples (Blob Storage events)
Blob events can be filtered by the event type, container name, or name of the object that was created or deleted.
The subject of Blob storage events uses the format:
/blobServices/default/containers/<containername>/blobs/<blobname>
To match all events for a storage account, you can leave the subject filters empty.
To match events from blobs created in a set of containers sharing a prefix, use a subjectBeginsWith
filter like:
/blobServices/default/containers/containerprefix
To match events from blobs created in specific container, use a subjectBeginsWith
filter like:
/blobServices/default/containers/containername/
To match events from blobs created in specific container sharing a blob name prefix, use a subjectBeginsWith
filter like:
/blobServices/default/containers/containername/blobs/blobprefix
To match events from blobs create in a specific subfolder of a container, use a subjectBeginsWith
filter like:
/blobServices/default/containers/{containername}/blobs/{subfolder}/
To match events from blobs created in specific container sharing a blob suffix, use a subjectEndsWith
filter like ".log" or ".jpg".
Advanced filtering
To filter by values in the data fields and specify the comparison operator, use the advanced filtering option. In advanced filtering, you specify the:
- operator type - The type of comparison.
- key - The field in the event data that you're using for filtering. It can be a number, boolean, string, or an array.
- values - The value or values to compare to the key.
Key
Key is the field in the event data that you're using for filtering. It can be one of the following types:
Number
Boolean
String
Array. You need to set the
enableAdvancedFilteringOnArrays
property to true to use this feature."filter": { "subjectBeginsWith": "/blobServices/default/containers/mycontainer/blobs/log", "subjectEndsWith": ".jpg", "enableAdvancedFilteringOnArrays": true }
For events in Cloud Events schema, use the following values for the key: eventid
, source
, eventtype
, eventtypeversion
, or event data (like data.key1
).
If you're using Event Grid basic tier, for events in the Event Grid schema, use the following values for the key: ID
, Topic
, Subject
, EventType
, DataVersion
, or event data (like data.key1
). For custom input schema, use the event data fields (like data.key1
). To access fields in the data section, use the .
(dot) notation. For example, data.siteName
, data.appEventTypeDetail.action
to access siteName
or action
for the following sample event.
"data": {
"appEventTypeDetail": {
"action": "Started"
},
"siteName": "<site-name>",
"clientRequestId": "None",
"correlationRequestId": "None",
"requestId": "292f499d-04ee-4066-994d-c2df57b99198",
"address": "None",
"verb": "None"
},
Note
Event Grid doesn't support filtering on an array of objects. It only allows String, Boolean, Numbers, and Array of the same types (like integer array or string array).
Values
The values can be: number, string, boolean, or array
Operators
The available operators for numbers are:
NumberIn
The NumberIn operator evaluates to true if the key value is one of the specified filter values. In the following example, it checks whether the value of the counter
attribute in the data
section is 5 or 1.
"advancedFilters": [{
"operatorType": "NumberIn",
"key": "data.counter",
"values": [
5,
1
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a, b, c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF filter == key
MATCH
NumberNotIn
The NumberNotIn evaluates to true if the key value is not any of the specified filter values. In the following example, it checks whether the value of the counter
attribute in the data
section isn't 41 and 0.
"advancedFilters": [{
"operatorType": "NumberNotIn",
"key": "data.counter",
"values": [
41,
0
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a, b, c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF filter == key
FAIL_MATCH
NumberLessThan
The NumberLessThan operator evaluates to true if the key value is less than the specified filter value. In the following example, it checks whether the value of the counter
attribute in the data
section is less than 100.
"advancedFilters": [{
"operatorType": "NumberLessThan",
"key": "data.counter",
"value": 100
}]
If the key is an array, all the values in the array are checked against the filter value. Here's the pseudo code with the key: [v1, v2, v3]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH key IN (v1, v2, v3)
IF key < filter
MATCH
NumberGreaterThan
The NumberGreaterThan operator evaluates to true if the key value is greater than the specified filter value. In the following example, it checks whether the value of the counter
attribute in the data
section is greater than 20.
"advancedFilters": [{
"operatorType": "NumberGreaterThan",
"key": "data.counter",
"value": 20
}]
If the key is an array, all the values in the array are checked against the filter value. Here's the pseudo code with the key: [v1, v2, v3]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH key IN (v1, v2, v3)
IF key > filter
MATCH
NumberLessThanOrEquals
The NumberLessThanOrEquals operator evaluates to true if the key value is less than or equal to the specified filter value. In the following example, it checks whether the value of the counter
attribute in the data
section is less than or equal to 100.
"advancedFilters": [{
"operatorType": "NumberLessThanOrEquals",
"key": "data.counter",
"value": 100
}]
If the key is an array, all the values in the array are checked against the filter value. Here's the pseudo code with the key: [v1, v2, v3]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH key IN (v1, v2, v3)
IF key <= filter
MATCH
NumberGreaterThanOrEquals
The NumberGreaterThanOrEquals operator evaluates to true if the key value is greater than or equal to the specified filter value. In the following example, it checks whether the value of the counter
attribute in the data
section is greater than or equal to 30.
"advancedFilters": [{
"operatorType": "NumberGreaterThanOrEquals",
"key": "data.counter",
"value": 30
}]
If the key is an array, all the values in the array are checked against the filter value. Here's the pseudo code with the key: [v1, v2, v3]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH key IN (v1, v2, v3)
IF key >= filter
MATCH
NumberInRange
The NumberInRange operator evaluates to true if the key value is in one of the specified filter ranges. In the following example, it checks whether the value of the key1
attribute in the data
section is in one of the two ranges: 3.14159 - 999.95, 3000 - 4000.
{
"operatorType": "NumberInRange",
"key": "data.key1",
"values": [[3.14159, 999.95], [3000, 4000]]
}
The values
property is an array of ranges. In the previous example, it's an array of two ranges. Here's an example of an array with one range to check.
Array with one range:
{
"operatorType": "NumberInRange",
"key": "data.key1",
"values": [[3000, 4000]]
}
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: an array of ranges. In this pseudo code, a
and b
are low and high values of each range in the array. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH (a,b) IN filter.Values
FOR_EACH key IN (v1, v2, v3)
IF key >= a AND key <= b
MATCH
NumberNotInRange
The NumberNotInRange operator evaluates to true if the key value is not in any of the specified filter ranges. In the following example, it checks whether the value of the key1
attribute in the data
section is in one of the two ranges: 3.14159 - 999.95, 3000 - 4000. If it's, the operator returns false.
{
"operatorType": "NumberNotInRange",
"key": "data.key1",
"values": [[3.14159, 999.95], [3000, 4000]]
}
The values
property is an array of ranges. In the previous example, it's an array of two ranges. Here's an example of an array with one range to check.
Array with one range:
{
"operatorType": "NumberNotInRange",
"key": "data.key1",
"values": [[3000, 4000]]
}
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: an array of ranges. In this pseudo code, a
and b
are low and high values of each range in the array. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH (a,b) IN filter.Values
FOR_EACH key IN (v1, v2, v3)
IF key >= a AND key <= b
FAIL_MATCH
The available operator for booleans is:
BoolEquals
The BoolEquals operator evaluates to true if the key value is the specified boolean value filter. In the following example, it checks whether the value of the isEnabled
attribute in the data
section is true
.
"advancedFilters": [{
"operatorType": "BoolEquals",
"key": "data.isEnabled",
"value": true
}]
If the key is an array, all the values in the array are checked against the filter boolean value. Here's the pseudo code with the key: [v1, v2, v3]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH key IN (v1, v2, v3)
IF filter == key
MATCH
The available operators for strings are:
StringContains
The StringContains evaluates to true if the key value contains any of the specified filter values (as substrings). In the following example, it checks whether the value of the key1
attribute in the data
section contains one of the specified substrings: microsoft
or azure
. For example, azure data factory
has azure
in it.
"advancedFilters": [{
"operatorType": "StringContains",
"key": "data.key1",
"values": [
"microsoft",
"azure"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key CONTAINS filter
MATCH
StringNotContains
The StringNotContains operator evaluates to true if the key does not contain the specified filter values as substrings. If the key contains one of the specified values as a substring, the operator evaluates to false. In the following example, the operator returns true only if the value of the key1
attribute in the data
section doesn't have contoso
and fabrikam
as substrings.
"advancedFilters": [{
"operatorType": "StringNotContains",
"key": "data.key1",
"values": [
"contoso",
"fabrikam"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key CONTAINS filter
FAIL_MATCH
See Limitations section for current limitation of this operator.
StringBeginsWith
The StringBeginsWith operator evaluates to true if the key value begins with any of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section begins with event
or message
. For example, event hubs
begins with event
.
"advancedFilters": [{
"operatorType": "StringBeginsWith",
"key": "data.key1",
"values": [
"event",
"message"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key BEGINS_WITH filter
MATCH
StringNotBeginsWith
The StringNotBeginsWith operator evaluates to true if the key value does not begin with any of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section doesn't begin with event
or message
.
"advancedFilters": [{
"operatorType": "StringNotBeginsWith",
"key": "data.key1",
"values": [
"event",
"message"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key BEGINS_WITH filter
FAIL_MATCH
StringEndsWith
The StringEndsWith operator evaluates to true if the key value ends with one of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section ends with jpg
or jpeg
or png
. For example, eventgrid.png
ends with png
.
"advancedFilters": [{
"operatorType": "StringEndsWith",
"key": "data.key1",
"values": [
"jpg",
"jpeg",
"png"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key ENDS_WITH filter
MATCH
StringNotEndsWith
The StringNotEndsWith operator evaluates to true if the key value does not end with any of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section doesn't end with jpg
or jpeg
or png
.
"advancedFilters": [{
"operatorType": "StringNotEndsWith",
"key": "data.key1",
"values": [
"jpg",
"jpeg",
"png"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF key ENDS_WITH filter
FAIL_MATCH
StringIn
The StringIn operator checks whether the key value exactly matches one of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section is contoso
or fabrikam
or factory
.
"advancedFilters": [{
"operatorType": "StringIn",
"key": "data.key1",
"values": [
"contoso",
"fabrikam",
"factory"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF filter == key
MATCH
StringNotIn
The StringNotIn operator checks whether the key value does not match any of the specified filter values. In the following example, it checks whether the value of the key1
attribute in the data
section isn't aws
and bridge
.
"advancedFilters": [{
"operatorType": "StringNotIn",
"key": "data.key1",
"values": [
"aws",
"bridge"
]
}]
If the key is an array, all the values in the array are checked against the array of filter values. Here's the pseudo code with the key: [v1, v2, v3]
and the filter: [a,b,c]
. Any key values with data types that don’t match the filter’s data type are ignored.
FOR_EACH filter IN (a, b, c)
FOR_EACH key IN (v1, v2, v3)
IF filter == key
FAIL_MATCH
All string comparisons aren't case-sensitive.
Note
If the event JSON doesn't contain the advanced filter key, filter is evaluated as not matched for the following operators: NumberGreaterThan, NumberGreaterThanOrEquals, NumberLessThan, NumberLessThanOrEquals, NumberIn, BoolEquals, StringContains, StringNotContains, StringBeginsWith, StringNotBeginsWith, StringEndsWith, StringNotEndsWith, StringIn.
The filter is evaluated as matched for the following operators: NumberNotIn, StringNotIn.
IsNullOrUndefined
The IsNullOrUndefined operator evaluates to true if the key's value is NULL or undefined.
{
"operatorType": "IsNullOrUndefined",
"key": "data.key1"
}
In the following example, key1 is missing, so the operator would evaluate to true.
{
"data":
{
"key2": 5
}
}
In the following example, key1 is set to null, so the operator would evaluate to true.
{
"data":
{
"key1": null
}
}
If key1 has any other value in these examples, the operator would evaluate to false.
IsNotNull
The IsNotNull operator evaluates to true if the key's value isn't NULL or undefined.
{
"operatorType": "IsNotNull",
"key": "data.key1"
}
OR and AND
If you specify a single filter with multiple values, an OR operation is performed, so the value of the key field must be one of these values. Here's an example:
"advancedFilters": [
{
"operatorType": "StringContains",
"key": "Subject",
"values": [
"/providers/microsoft.devtestlab/",
"/providers/Microsoft.Compute/virtualMachines/"
]
}
]
If you specify multiple different filters, an AND operation is done, so each filter condition must be met. Here's an example:
"advancedFilters": [
{
"operatorType": "StringContains",
"key": "Subject",
"values": [
"/providers/microsoft.devtestlab/"
]
},
{
"operatorType": "StringContains",
"key": "Subject",
"values": [
"/providers/Microsoft.Compute/virtualMachines/"
]
}
]
CloudEvents
For events in the CloudEvents schema, use the following values for the key: eventid
, source
, eventtype
, eventtypeversion
, or event data (like data.key1
).
You can also use extension context attributes in CloudEvents 1.0. In the following example, comexampleextension1
and comexampleothervalue
are extension context attributes.
{
"specversion" : "1.0",
"type" : "com.example.someevent",
"source" : "/mycontext",
"id" : "C234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"subject": null,
"comexampleextension1" : "value",
"comexampleothervalue" : 5,
"datacontenttype" : "application/json",
"data" : {
"appinfoA" : "abc",
"appinfoB" : 123,
"appinfoC" : true
}
}
Here's an example of using an extension context attribute in a filter.
"advancedFilters": [{
"operatorType": "StringBeginsWith",
"key": "comexampleothervalue",
"values": [
"5",
"1"
]
}]
Limitations
Advanced filtering has the following limitations:
- 25 advanced filters and 25 filter values across all the filters per Event Grid subscription
- 512 characters per string value
- Keys with
.
(dot) character in them. For example:http://schemas.microsoft.com/claims/authnclassreference
orjohn.doe@contoso.com
. Currently, there's no support for escape characters in keys.
The same key can be used in more than one filter.
Next steps
- To learn about filtering events with PowerShell and Azure CLI, see Filter events for Event Grid.
- To quickly get started using Event Grid, see Create and route custom events with Azure Event Grid.