> For the complete documentation index, see [llms.txt](https://docs.devolutions.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.devolutions.net/server/knowledge-base/how-to-articles/send-devolutions-server-logs-to-azure-log-analytics.md).

# Send Devolutions Server logs to Azure Log Analytics

Send Devolutions Server activity and administration logs to Azure Log Analytics with an app registration, a DCE, a custom table, and a DCR transformation.

Devolutions Server can send its activity and administration logs to an Azure Log Analytics workspace through the Azure Monitor Logs ingestion API. This article describes how to create the Azure components, how to configure Devolutions Server, and how to verify the result: a custom table in which each log entry is a row with its user, entry, vault, and machine in separate columns.

## Before you begin

* An Azure subscription with a Log Analytics workspace.
* In Azure, the permissions to:
  * Register an application in Microsoft Entra ID.
  * Create tables in the Log Analytics workspace (at least contributor rights on the workspace).
  * Create data collection endpoints and data collection rules (for example, the ***Monitoring Contributor*** role).
  * Assign roles on the data collection rule.
* A Devolutions Server administrator account, or a user with the administrative permission to edit the ***Logging*** server settings.

## Logs sent to Azure

Devolutions Server sends the entries of the connection logs only:

* ***Activity*** entries, which are linked to an entry, such as opening a session or viewing a password.
* ***Administration*** entries, which are not linked to an entry.

Entries of user vaults are sent only when ***Log user vault activities*** is enabled in ***Administration*** – ***System settings*** – ***General***. Other logs of Devolutions Server are not sent. If you have audit requirements, confirm that this subset covers them before using it as your only audit trail.

## How the components fit together

Devolutions Server authenticates with an Azure app registration, then posts the logs to a Data Collection Endpoint (DCE). The Data Collection Rule (DCR) receives them in its stream, transforms them with a KQL query, and writes the result in the custom table of the Log Analytics workspace.

Each field of the ***Azure log analytics*** section of Devolutions Server takes a value from Azure:

| Devolutions Server field                | Value to enter                                               | Where to find it in Azure                                                                  |
| --------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| ***Azure endpoint***                    | ***Logs ingestion*** URI of the DCE                          | ***Monitor*** – ***Data Collection Endpoints*** – the DCE – ***Overview***                 |
| ***Immutable ID***                      | `immutableId` of the DCR, which starts with `dcr-`           | ***Monitor*** – ***Data collection rules*** – the DCR – ***Overview*** – ***JSON View***   |
| ***Azure log analytics stream name***   | Name of the DCR stream, such as `Custom-Devolutions_Logs_CL` | ***JSON View*** of the DCR, under `streamDeclarations`                                     |
| ***Azure log analytics tenant ID***     | ***Directory (tenant) ID***                                  | ***Microsoft Entra ID*** – ***App registrations*** – the application – ***Overview***      |
| ***Azure log analytics client ID***     | ***Application (client) ID***                                | ***Microsoft Entra ID*** – ***App registrations*** – the application – ***Overview***      |
| ***Azure log analytics client secret*** | ***Value*** of the client secret                             | ***Certificates & secrets*** of the application, displayed only when the secret is created |

## Log format sent by Devolutions Server

Devolutions Server sends each log entry with three top-level fields only:

* `TimeGenerated` (datetime): The time at which the entry was sent.
* `Event` (dynamic): The log entry itself, with the event time (`@t`), `ReportType` (`Activity` or `Administration`), `MachineName` (the Devolutions Server machine), and a `Properties` object that holds the details of the entry. Empty values are left out of `Properties`.
* `Message` (string): The rendered log message.

The stream of the DCR must declare these three fields, and the transformation must read the values inside `Event`. Otherwise, rows are created in the table, but all their fields are empty.

## Set up Azure Log Analytics

### Register an application

1. In the Azure portal, go to ***Microsoft Entra ID*** – ***App registrations***.
2. Click ***New registration***.
3. Enter a name for the application.
4. Under ***Supported account types***, keep ***Accounts in this organizational directory only***.
5. Click ***Register***. A redirect URI is not required.
6. On the ***Overview*** page of the application, copy the ***Application (client) ID*** and the ***Directory (tenant) ID***.

### Create a client secret

1. In the application, go to ***Certificates & secrets***.
2. Click ***New client secret***.
3. Enter a description and select an ***Expires*** duration.
4. Click ***Add***.
5. Copy the ***Value*** of the secret, not its ***Secret ID***. The value cannot be displayed again after you leave the page.

### Create a Data Collection Endpoint

1. In the Azure portal, go to ***Monitor*** – ***Data Collection Endpoints***.
2. Click ***Create***.
3. Enter a name, and select the subscription, the resource group, and the region of the Log Analytics workspace.
4. Click ***Create***.
5. Open the DCE.
6. On its ***Overview*** page, copy the ***Logs ingestion*** URI.

### Create the table and the Data Collection Rule

The ***New custom log (DCR based)*** wizard creates the table and the DCR together. It builds the stream of the DCR from a sample file, so the sample must have the format sent by Devolutions Server.

1. Save the following content in a file named `sample.json`:

   ```json
   [{"TimeGenerated":"2026-10-21T12:00:00Z","Event":{"@t":"2026-10-21T12:00:00Z","ReportType":"Activity","MachineName":"SERVER01","Properties":{"User":"user@domain.com","ConnectionName":"Sample","ConnectionId":"","VaultName":"Default","VaultId":"","Message":"Sample","LogDate":"","ConnectionType":"","ConnectionUsername":"","Machine":"","Ticket#":"","ActiveTime":"","OnOpenComment":"","OnCloseComment":""}},"Message":"Sample"}]
   ```
2. In the Azure portal, go to ***Log Analytics workspaces*** and open the workspace.
3. Go to ***Tables***.
4. Click ***Create*** – ***New custom log (DCR based)***.
5. Enter a table name, such as `Devolutions_Logs`. The portal adds the `_CL` suffix.
6. Click ***Create a new data collection rule***.
7. Select the ***Subscription*** and the ***Resource group***, and enter a ***Name*** for the DCR.
8. Select the DCE in the data collection endpoint list.
9. Click ***Next***.
10. Click ***Browse for files*** and select `sample.json`.
11. Confirm that the preview contains exactly the `TimeGenerated`, `Event`, and `Message` columns.
12. Click ***Transformation editor***.
13. Replace the query with the following transformation:

    ```kql
    source
    | extend e = parse_json(tostring(Event))
    | extend p = parse_json(tostring(e.Properties))
    | project TimeGenerated = todatetime(e['@t']),
        ReportType = tostring(e.ReportType),
        MachineName = tostring(e.MachineName),
        User = tostring(p.User),
        ConnectionName = tostring(p.ConnectionName),
        ConnectionId = tostring(p.ConnectionId),
        VaultName = tostring(p.VaultName),
        VaultId = tostring(p.VaultId),
        Message = tostring(p.Message),
        LogDate = tostring(p.LogDate),
        ConnectionType = tostring(p.ConnectionType),
        ConnectionUsername = tostring(p.ConnectionUsername),
        Machine = tostring(p.Machine),
        Ticket = tostring(p['Ticket#']),
        ActiveTime = tostring(p.ActiveTime),
        OnOpenComment = tostring(p.OnOpenComment),
        OnCloseComment = tostring(p.OnCloseComment)
    ```
14. Click ***Run*** and confirm that the `ReportType` and `User` columns contain values.
15. Click ***Apply***.
16. Click ***Next***.
17. Click ***Create***.

The transformation starts with `source`, which represents the incoming stream, and uses the event time of the log entry as `TimeGenerated`. The table is created with the following columns:

| Column             | Type     | Content                                        |
| ------------------ | -------- | ---------------------------------------------- |
| TimeGenerated      | datetime | Time of the event                              |
| ReportType         | string   | `Activity` or `Administration`                 |
| MachineName        | string   | Devolutions Server machine that sent the entry |
| User               | string   | User who performed the action                  |
| ConnectionName     | string   | Name of the entry                              |
| ConnectionId       | string   | ID of the entry                                |
| VaultName          | string   | Name of the vault                              |
| VaultId            | string   | ID of the vault                                |
| Message            | string   | Log message                                    |
| LogDate            | string   | Creation date of the log entry                 |
| ConnectionType     | string   | Type of the entry                              |
| ConnectionUsername | string   | Username of the entry                          |
| Machine            | string   | Machine of the user                            |
| Ticket             | string   | Ticket number                                  |
| ActiveTime         | string   | Active time of the session                     |
| OnOpenComment      | string   | Comment entered when the session was opened    |
| OnCloseComment     | string   | Comment entered when the session was closed    |

### Copy the immutable ID and the stream name

The immutable ID and the stream name are properties of the DCR, not of the table.

1. In the Azure portal, go to ***Monitor*** – ***Data collection rules***.
2. Open the DCR created with the table.
3. On its ***Overview*** page, click ***JSON View***.
4. Copy the value of `immutableId`.
5. Copy the name of the stream declared under `streamDeclarations`, such as `Custom-Devolutions_Logs_CL`.

{% hint style="warning" %}
The stream name entered in Devolutions Server must match the stream of the DCR exactly, including the `Custom-` prefix. The table name does not have this prefix. When the stream name does not match, Azure rejects the logs, the table stays empty, and Devolutions Server does not display an error.
{% endhint %}

### Assign the role on the Data Collection Rule

1. In the DCR, go to ***Access control (IAM)***.
2. Click ***Add role assignment***.
3. Select ***Monitoring Metrics Publisher***.
4. Click ***Next***.
5. For ***Assign access to***, select ***User, group, or service principal***.
6. Click ***Select members***.
7. Select the registered application.
8. Click ***Select***.
9. Click ***Review + assign***.

Microsoft indicates that a role assignment can take up to 30 minutes to apply. For more information, consult the [Microsoft tutorial on the Logs ingestion API](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/tutorial-logs-ingestion-portal).

## Configure Devolutions Server

1. In the Devolutions Server web interface, go to ***Administration*** – ***Server settings*** – ***Logging***.
2. In the ***Azure log analytics*** section, check ***Enable Azure logging***.
3. In ***Azure endpoint***, enter the ***Logs ingestion*** URI of the DCE.
4. In ***Immutable ID***, enter the `immutableId` of the DCR.
5. In ***Azure log analytics stream name***, enter the stream name of the DCR, with its `Custom-` prefix.
6. In ***Azure log analytics tenant ID***, enter the ***Directory (tenant) ID*** of the application.
7. In ***Azure log analytics client ID***, enter the ***Application (client) ID*** of the application.
8. In ***Azure log analytics client secret***, enter the ***Value*** of the client secret.
9. Click ***Test connection***.
10. Click ***Save*** at the top right of the page.

The settings apply when they are saved, without restarting Devolutions Server. Unchecking ***Enable Azure logging*** and saving clears all the values of the ***Azure log analytics*** section.

{% hint style="warning" %}
***Test connection*** only validates the tenant ID, the client ID, and the client secret by requesting a token from Microsoft. It does not use the endpoint, the immutable ID, or the stream name, and it does not send a log entry. A successful test does not confirm that the DCE, the DCR, the stream name, the role assignment, or the transformation are configured correctly.
{% endhint %}

## Verify that the logs are received

1. Generate an activity entry, for example by opening an entry of the Devolutions Server data source from Remote Desktop Manager, or by viewing the password of an entry in the Devolutions Server web interface.
2. In the Azure portal, go to ***Log Analytics workspaces*** and open the workspace.
3. Go to ***Logs***.
4. Run the following query, with the name of the table:

   ```kql
   Devolutions_Logs_CL | take 5
   ```
5. Confirm that the `ReportType` and `User` columns contain values.

New rows can take a few minutes to appear, and the first rows of a new table can take longer.

## Troubleshooting

| Symptom                                                                          | Cause                                                                                                                                                                                                                    | Fix                                                                                                                                                                                                                |
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| The table stays empty, even though ***Test connection*** succeeds.               | The stream name, the immutable ID, or the endpoint entered in Devolutions Server does not match the DCR and the DCE. ***Test connection*** does not check these values.                                                  | Copy the `immutableId` and the stream name again from the ***JSON View*** of the DCR, and the ***Logs ingestion*** URI from the DCE. The stream name includes the `Custom-` prefix. Click ***Save***.              |
| The table stays empty, and the values entered in Devolutions Server are correct. | The registered application does not have the ***Monitoring Metrics Publisher*** role on the DCR, or the role assignment is not applied yet.                                                                              | In the DCR, verify the role assignment in ***Access control (IAM)***. Wait up to 30 minutes after assigning the role.                                                                                              |
| The table stays empty, and no action generated a log entry.                      | Only connection log entries are sent. User vault entries are sent only when ***Log user vault activities*** is enabled.                                                                                                  | Open an entry from Remote Desktop Manager or view a password in the web interface. For user vault entries, enable ***Log user vault activities*** in ***Administration*** – ***System settings*** – ***General***. |
| Rows are created, but all their fields are empty.                                | The DCR stream does not declare `TimeGenerated`, `Event`, and `Message`, or the transformation reads flat columns instead of the values inside `Event`. This happens when the table was created from a different sample. | Replace the stream columns and the `transformKql` of the DCR through its ***Export template***, or recreate the table and the DCR from `sample.json`.                                                              |
| Some columns are empty on some rows only.                                        | Devolutions Server leaves empty values out of `Properties`. ***Administration*** entries are not linked to an entry, so the entry columns are empty.                                                                     | No fix is required.                                                                                                                                                                                                |
| ***Test connection*** fails.                                                     | The tenant ID, the client ID, or the client secret is incorrect, or the client secret has expired. The client secret field expects the ***Value*** of the secret, not its ***Secret ID***.                               | Verify the IDs on the ***Overview*** page of the application. Create a new client secret if needed, enter its ***Value***, and click ***Save***.                                                                   |
| Logs stopped arriving after working for some time.                               | The client secret has expired, so Devolutions Server can no longer authenticate.                                                                                                                                         | Create a new client secret in the application, enter its ***Value*** in ***Azure log analytics client secret***, and click ***Save***.                                                                             |

To check whether the DCR receives data, consult the DCR metrics, such as `Logs Rows Received per Min` and `Logs Transformation Errors per Min`. For more information, consult the [Microsoft documentation on DCR monitoring](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-monitor).

## Fix an existing configuration

A table and a DCR created with a different sample or transformation can be corrected without being recreated. The ***JSON View*** of the DCR is read-only, so the DCR is modified through its template:

1. In the Azure portal, open the DCR.
2. Click ***Export template***.
3. Click ***Deploy***.
4. Click ***Edit template***.
5. In `streamDeclarations`, set the columns of the stream to `TimeGenerated` (datetime), `Event` (dynamic), and `Message` (string):

   ```json
   "columns": [
     { "name": "TimeGenerated", "type": "datetime" },
     { "name": "Event", "type": "dynamic" },
     { "name": "Message", "type": "string" }
   ]
   ```
6. In `dataFlows`, replace the value of `transformKql` with the transformation, on a single line:

   ```json
   "transformKql": "source | extend e = parse_json(tostring(Event)) | extend p = parse_json(tostring(e.Properties)) | project TimeGenerated = todatetime(e['@t']), ReportType = tostring(e.ReportType), MachineName = tostring(e.MachineName), User = tostring(p.User), ConnectionName = tostring(p.ConnectionName), ConnectionId = tostring(p.ConnectionId), VaultName = tostring(p.VaultName), VaultId = tostring(p.VaultId), Message = tostring(p.Message), LogDate = tostring(p.LogDate), ConnectionType = tostring(p.ConnectionType), ConnectionUsername = tostring(p.ConnectionUsername), Machine = tostring(p.Machine), Ticket = tostring(p['Ticket#']), ActiveTime = tostring(p.ActiveTime), OnOpenComment = tostring(p.OnOpenComment), OnCloseComment = tostring(p.OnCloseComment)"
   ```
7. Click ***Save***. Do not change the parameter values.
8. Click ***Review + create***.
9. Click ***Create***.

The table must contain every column produced by the transformation: `TimeGenerated` (datetime) and the other 16 columns (string). Add any missing column to the table schema. The DCR can also be deployed from a JSON file with the Azure CLI (`az monitor data-collection rule create`) or PowerShell (`New-AzDataCollectionRule`). For more information, consult the [Microsoft documentation on editing a DCR](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-rule-create-edit). Changes to a DCR can take several minutes to apply.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.devolutions.net/server/knowledge-base/how-to-articles/send-devolutions-server-logs-to-azure-log-analytics.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
