Cosmos DB Monitoring Scripts
New 7.12
An Azure Cosmos DB account can be reachable and still be in trouble: orders that never get processed, a container that nobody writes to any more, or documents that should have been cleaned up months ago. Monitoring Scripts (custom script monitoring) let the Nodinite Azure Agent watch the data itself. Each script is a read-only query that runs on every monitoring cycle and becomes its own Resource in your Monitor Views, with a state of OK, Warning, or Error.
- ✅ Turn any business rule you can express as a Cosmos DB SQL query into a monitored resource
- ✅ Choose how the result is judged: a number against thresholds, a health value, or a return code
- ✅ Put your own explanation in the log text with a
Messagefield - ✅ Change thresholds from the Monitor View with the Edit Remote Action, without touching the agent configuration
Monitoring Scripts complement the built-in Monitoring Cosmos DB, which checks that databases and containers are reachable, and the Approved Queries, which let users run read-only queries on demand.
How Monitoring Scripts Work
read-only query"] C{"fa:fa-scale-balanced Evaluation"} D["fa:fa-check OK"] E["fa:fa-triangle-exclamation Warning"] F["fa:fa-xmark Error"] G["fa:fa-bell Alarm Plugins"] B -->|"every monitoring cycle"| A A -->|"exactly one row"| C C --> D C --> E C --> F E --> G F --> G style B fill:#2678BD,color:#fff style D fill:#93d16d style E fill:#FFD525 style F fill:#c33d34,color:#fff
Diagram: The Azure Agent runs each enabled script (blue) against its container on every monitoring cycle. The evaluation turns the single returned row into OK (green), Warning (yellow), or Error (red), and Alarm Plugins notify your team of the changes.
- Each enabled script is monitored as its own Resource in the Cosmos DB - Script Category. The resource name is the script's Display Name.
- The script runs on every monitoring cycle, not when somebody opens the resource. Its latest outcome is the resource's state and log text.
- The query must return exactly one row: either a single value, or one object with a single numeric field. No rows, more than one row, more than one numeric field, or a query that fails puts the resource in Error. A query that runs longer than 30 seconds is stopped and is an Error too.
- An object may include a
Messagefield. Its text becomes the resource's log text, so the alert can say what is wrong. - Cosmos DB SQL is not T-SQL:
DECLARE,IF, andTHROWare not available. The query only returns a value, and the Evaluation decides the state. - Every run consumes request units (RU), on every cycle. Keep the queries cheap.
Configure Monitoring Scripts
Monitoring Scripts belong to a Cosmos DB configuration of the Azure Agent. Open the agent's Configuration and expand the Cosmos DB configuration.

The General tab of a Cosmos DB configuration. Its tabs also hold the Throughputs, the Queries, and the Monitoring Scripts.
The Monitoring Scripts (n) tab lists the scripts of the configuration; the number is how many there are. It sits next to the Queries (n) tab, which is a different list: the Approved Queries that users run on demand, while Monitoring Scripts run on every monitoring cycle. Click Add to create a script, click a script to expand it, and click the red minus button to delete it.

Each enabled script in the list becomes one monitored resource; a disabled script shows a ban icon.
Each script has these fields:
| Field | Description |
|---|---|
| Enabled | When checked, the script runs on every monitoring cycle and is monitored as a resource |
| Display Name | The name of the script, used as the resource name |
| Database | The database that holds the container the script runs against |
| Container | The container the script runs against. A Cosmos DB SQL query runs against a single container |
| Query | The read-only SELECT query; see How Monitoring Scripts Work for what it must return |
| Evaluation | How the returned row decides the state: Thresholds, Health, or Return code (see below) |
| Warning Threshold | Only with Thresholds; hidden for the other evaluations. A result greater than or equal to this number is a Warning. Must not be greater than the Error Threshold. Leave empty to never raise a Warning |
| Error Threshold | Only with Thresholds; hidden for the other evaluations. A result greater than or equal to this number is an Error. Must not be lower than the Warning Threshold. Leave empty to never raise an Error |
Save checks the scripts: Display Name, Database, Container, and Query are required, the query must be a SELECT, the Display Name must be unique within the configuration, thresholds can't be negative, the Warning Threshold can't be greater than the Error Threshold, and Thresholds needs at least one threshold.
A script you remove or disable is no longer monitored, and its resource is removed from Nodinite after three monitoring cycles, like any other Azure resource.
Evaluation Types
| Evaluation | The query returns | State |
|---|---|---|
| Thresholds | A number: a single value, or the single numeric field of an object | ❌ Error when the number is at or above the Error Threshold, ⚠️ Warning when it is at or above the Warning Threshold, otherwise ✅ OK |
| Health | An object with a Health field set to OK, Warning, or Error |
The state the query names |
| Return code | A number: a single value, or the Status field of an object |
✅ OK for 0, ❌ Error below 0, ⚠️ Warning above 0 |
The examples below are the scripts in the screenshots. Replace the field names (Type, Processed, CreatedAt, CustomerId, Items) with the ones in your documents.
Thresholds: Messages Stuck with a Failed Line Item
Count the messages that have waited more than 15 minutes without being processed and have at least one failed line item, leaving out test customers. Two such messages are a Warning, three or more an Error.
SELECT VALUE COUNT(1)
FROM c
WHERE c.Type = "Message"
AND c.Processed = false
AND DateTimeDiff("minute", c.CreatedAt, GetCurrentDateTime()) > 15
AND NOT STARTSWITH(c.CustomerId, "TEST-", true)
AND EXISTS (SELECT VALUE i FROM i IN c.Items WHERE i.Status = "Failed")
SELECT VALUE returns the count as a single value, which the thresholds judge. When the count is 0, the log text reads The script returned 0.

The script runs against the Messages container of the Orders database.

With Thresholds, the two threshold fields decide the state.
Health: Retention of the Oldest Document
Check how old the oldest document in the container is: older than 90 days is an Error, older than 30 days a Warning. The query names the state itself, and the Message field tells which document it is.
SELECT TOP 1
(GetCurrentTimestamp() / 1000 - c._ts > 90 * 86400 ? "Error"
: GetCurrentTimestamp() / 1000 - c._ts > 30 * 86400 ? "Warning"
: "OK") AS Health,
CONCAT("Oldest document ", c.id, " dates from ", TimestampToDateTime(c._ts * 1000),
" (", ToString(FLOOR((GetCurrentTimestamp() / 1000 - c._ts) / 86400)), " days)") AS Message
FROM c
ORDER BY c._ts ASC
_ts is the time Cosmos DB last wrote the document, in seconds; GetCurrentTimestamp() is in milliseconds, hence the division by 1000.

With Health, the query names the state, and the threshold fields are not shown.
Return Code: Documents Written Today Versus the Working Day
Check that the container receives documents every working day. Before 06:00 everything is OK. After that, the newest document must be from today: if it isn't, the resource is a Warning until 12:00 and an Error after that.
SELECT TOP 1
(DateTimePart("hour", GetCurrentDateTime()) < 6 ? 0
: LEFT(TimestampToDateTime(c._ts * 1000), 10) = LEFT(GetCurrentDateTime(), 10) ? 0
: DateTimePart("hour", GetCurrentDateTime()) >= 12 ? -1
: 1) AS Status,
CONCAT("Newest document ", c.id, " written ", TimestampToDateTime(c._ts * 1000),
", now ", GetCurrentDateTime()) AS Message
FROM c
ORDER BY c._ts DESC

With Return code, the query returns the state as a number, and the threshold fields are not shown.
Cosmos DB SQL works in UTC: GetCurrentDateTime() returns UTC time, so the hours in this example are UTC hours.
Monitoring Scripts in a Monitor View
Each script appears as a resource in the Cosmos DB - Script Category. The description names the account, database, and container the script runs on, and the log text shows the latest result.

The scripts sit in the same Application as the database and its containers. The Faulty Script is in Error because the query has a syntax error; the log text shows the error.
Each script resource belongs to the Application Subscription/Configuration/Database, the same Application as the containers of that database. The log text of a Thresholds script reads, for example, The script returned 5, which is greater than or equal to the Error threshold (4).; a Message field replaces it.
The state tells you where the problem is:
| State | Cause | Log text |
|---|---|---|
| Error | The account is reachable, but the script fails: a Cosmos DB error (syntax, a missing container), no row or more than one row, a result the evaluation can't use, or a run longer than 30 seconds | The script could not be executed. followed by the reason, or The script did not complete within 30 seconds. |
| Unavailable | The account can't be reached (an invalid connection string, the network, or a firewall), so no script of the configuration can run | The connection string is invalid or the account is unreachable. followed by the reason Cosmos DB reported; the database resource shows the same text |
Fix a failing query in the Monitoring Scripts tab of the configuration, and an unreachable account in its General tab.
Use the Expected State of the resource to override the evaluation, and the Resource State History to see when the state changed.
Remote Actions
Under Control Center, the Action menu of a script resource has two Remote Actions: Details and Edit.

The agent's actions come last, under Control Center, after the Monitor View and Administration entries.
Details
Details shows where the script runs (tenant, subscription, resource group, database, container, and endpoint) and how its result is evaluated, with the thresholds. It never shows the query text and never runs the script, so opening it costs no request units; the latest result is the resource's state and log text.

Details shows the evaluation and its thresholds next to the location of the script.
Edit
Edit changes the Container, the Evaluation, and the thresholds of the script from the Monitor View. The container name is case-sensitive and must exist in the database. A saved change takes effect on the next monitoring cycle.

Edit changes the container, the evaluation, and the thresholds; the query stays in the configuration.
The query, the database, and the name of the script are changed only in the Monitoring Scripts tab of the Cosmos DB configuration. The threshold fields show only for Thresholds. A changed container is checked to exist before the change is saved.
Permissions: Details and Edit need no extra right: every user whose Role has the action rights of the Monitor View can use them, and Save in Edit writes the agent's settings, the same settings the configuration writes. Unlike creating containers, changing throughput, or deleting containers, there is no switch in the configuration that turns these actions off.
Frequently Asked Questions
What happens if my query returns more than one row?
The resource goes to Error. Use SELECT VALUE COUNT(1) or SELECT TOP 1 so the query always returns exactly one row.
Why does my script cost request units?
Every enabled script runs on every monitoring cycle, and each run is a query against the container. Filter on indexed fields, avoid scanning the whole container, and disable scripts you don't need.
Can I write to the database from a script?
No. Monitoring Scripts are read-only SELECT queries. To write a document, use the Post Document Remote Action.