Skip to main content

Azure Data Explorer

Overview​

Azure Data Explorer ingests logs, metrics and traces into an Azure Data Explorer (Kusto) database as JSON, one table per signal. Records are gzip-compressed and submitted through the Kusto ingestion service, then queried with KQL.

This is a different product surface from the other Azure destinations: Microsoft Sentinel writes OCSF records into Log Analytics custom tables through a Data Collection Rule, Azure Monitor sends Application Insights envelopes, and Azure Blob Storage writes OTLP objects to a container. This node writes rows into a Kusto database you own.

Supported platforms

  • Linux: Logs, Metrics, Traces
  • Windows: Logs, Metrics, Traces
  • macOS: Logs, Metrics, Traces

Prerequisite: the database, the three tables, and any ingestion mappings must already exist on the cluster. This node issues no DDL — see Table schemas for the expected column layout.

Authentication​

Attach an Azure credential. Its Authentication Type selects how the collector authenticates to the cluster:

Authentication TypeWhat the node sendsCredential fields used
service_principalEntra ID application keytenant_id, client_id, client_secret
system_managed_identityThe VM's system-assigned identitynone
user_managed_identityA user-assigned identityclient_id (must be the identity's client ID, as a UUID)
defaultThe ambient Azure default credential chainnone

workload_identity is not supported by this destination — the Kusto SDK has no workload-identity path — and is rejected when the pipeline is saved.

Whichever identity you use needs the Database Ingestor role on the target database (and Database Viewer if you also want to query from the same principal).

Note: service_principal is the only type that puts a secret into the pipeline configuration. Prefer a managed identity when the collector runs inside Azure — those types leave this node holding no secret at all.

Basic Configuration​

ParameterTypeDefaultRequiredDescription
cluster_uristring—YesCluster endpoint, e.g. https://mycluster.westus2.kusto.windows.net. Must be https.
db_namestringoteldbYesDatabase holding the destination tables.
ingestion_typestringqueuedNoqueued or managed. See Ingestion modes.
logs_table_namestringOTELLogsYesTable receiving log records.
metrics_table_namestringOTELMetricsYesTable receiving metric points.
traces_table_namestringOTELTracesYesTable receiving spans.

All three table names are required even if the pipeline only carries one signal: the exporter resolves every table name when it starts, and a blank one would ingest into a table literally named "".

Ingestion modes​

ModeBehaviour
queuedBatches through the Data Management service. Durable, higher latency (typically minutes), and available on every cluster.
managedUses streaming ingestion for lower latency, falling back to queued when streaming is unavailable. Streaming ingestion must be enabled on the cluster and the table.

Advanced Configuration​

ParameterTypeDefaultRequiredDescription
timeoutstring30sNoMaximum time to wait for an ingestion request. Empty means no timeout.
logs_table_json_mappingstring—NoName of a pre-created JSON ingestion mapping for the logs table.
metrics_table_json_mappingstring—NoName of a pre-created JSON ingestion mapping for the metrics table.
traces_table_json_mappingstring—NoName of a pre-created JSON ingestion mapping for the traces table.
retry_on_failureobject—NoExponential backoff for failed ingestion requests.
sending_queueobject—NoBackpressure queue size, consumers, and optional disk backing.

Ingestion mappings​

Leave the mapping fields empty to ingest against the table's own schema — that works when the table columns match the layout below. Name a mapping when your table's column names differ, or when you want to drop or reshape fields on ingest. The mapping must already exist on the cluster; create it with .create table <T> ingestion json mapping ....

Example Configuration​

{
"cluster_uri": "https://mycluster.westus2.kusto.windows.net",
"db_name": "oteldb", // default: "oteldb"
"ingestion_type": "queued", // default: "queued"

"logs_table_name": "OTELLogs", // default: "OTELLogs"
"metrics_table_name": "OTELMetrics", // default: "OTELMetrics"
"traces_table_name": "OTELTraces", // default: "OTELTraces"

"advanced": {
"timeout": "30s", // default: "30s"
"logs_table_json_mapping": "", // default: none (use the table schema)
"retry_on_failure": {
"enabled": true, // default: true
"initial_interval": "5s", // default: "5s"
"max_interval": "30s", // default: "30s"
"max_elapsed_time": "300s", // default: "300s"
},
"sending_queue": {
"queue_size": 1000, // default: 1000
"num_consumers": 10, // default: 10
"enable_disk_backed_queue": true,
},
},
}

Table schemas​

Create the three tables before pointing a pipeline at them. These are the columns the exporter writes.

Logs (OTELLogs)

ColumnType
Timestampdatetime
ObservedTimestampdatetime
TraceIDstring
SpanIDstring
SeverityTextstring
SeverityNumberint
Bodystring
ResourceAttributesdynamic
LogsAttributesdynamic

Metrics (OTELMetrics)

ColumnType
Timestampdatetime
MetricNamestring
MetricTypestring
MetricUnitstring
MetricDescriptionstring
MetricValuereal
Hoststring
ResourceAttributesdynamic
MetricAttributesdynamic

Traces (OTELTraces)

ColumnType
TraceIDstring
SpanIDstring
ParentIDstring
SpanNamestring
SpanStatusstring
SpanStatusMessagestring
SpanKindstring
StartTimedatetime
EndTimedatetime
ResourceAttributesdynamic
TraceAttributesdynamic
Eventsdynamic
Linksdynamic

Example DDL for the logs table:

.create table OTELLogs (
Timestamp: datetime,
ObservedTimestamp: datetime,
TraceID: string,
SpanID: string,
SeverityText: string,
SeverityNumber: int,
Body: string,
ResourceAttributes: dynamic,
LogsAttributes: dynamic
)