Azure Event Hub
Overview
Azure Event Hub consumes events from an Azure Event Hubs instance. Event Hubs is the delivery point almost every Azure service writes to: point a diagnostic setting at a hub and the platform streams that resource's logs and metrics into it continuously, with no agent on the resource itself. This source reads that stream and turns it into pipeline records.
Supported types: Logs
Supported platforms
- Linux:
Logs - Windows:
Logs - macOS:
Logs
Typical uses:
- Azure resource diagnostics — activity logs, NSG flow logs, Key Vault audit, App Service logs, AKS control-plane logs. Anything with a diagnostic setting.
Requires collector v0.5.43 or later. Earlier releases do not build the Event Hub receiver at all, and the node will not be offered for older agents.
Authentication Configuration
The node holds no secret. Attach one of two credential types — which one you pick decides how the collector authenticates:
| Credential | Use when | Node must also supply |
|---|---|---|
Connection String (connection_string) | You have a connection string | nothing — the string carries both |
Azure Auth (azureauth) | You want an Entra ID identity | Namespace and Event Hub Name |
azureauth is the shared Azure identity credential — the same one the Microsoft Sentinel
destination uses — and offers default (the Azure SDK credential chain), service_principal,
system_managed_identity, user_managed_identity and workload_identity. Only
service_principal stores a secret.
A connection string is a shared-access-key secret rather than an identity, which is why it is a
separate credential type: azureauth resolves to a token and has no connection-string mode.
connection_string is deliberately vendor-neutral — every service has its own connection-string
shape, so the credential holds the opaque secret and each node validates the shape it needs.
The connection string must contain
EntityPath=<event hub name>. Copy it from the Event Hub instance's shared access policy, not the namespace's. A namespace-levelRootManageSharedAccessKeystring has noEntityPath, so there is no way to tell which hub in the namespace to read. Praxis rejects such a string when the pipeline is saved.
With
azureauthyou must fill in Namespace and Event Hub Name on the node. An Entra ID token is scoped to a namespace, not to a single entity, so there is noEntityPathto fall back on. Namespace must be fully qualified —my-namespace.servicebus.windows.net.
Prefer a managed identity where the collector runs inside Azure. Those types store no key at all — the collector resolves a short-lived token from Entra ID.
Note: Whichever identity you use must hold Azure Event Hubs Data Receiver on the hub (or namespace) scope. A missing role assignment surfaces as a 401 at start-up, not a configuration error.
Basic Configuration
| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
| namespace | string | none | Cond. | Fully qualified namespace, e.g. my-namespace.servicebus.windows.net. Required for every auth type except connection_string. An sb:// or https:// prefix is stripped for you. |
| event_hub_name | string | none | Cond. | The hub to read. Required for every auth type except connection_string, which carries it in EntityPath. |
| group | string | $Default | No | Consumer group. Each group tracks its own position in the hub. |
| format | string | azure | No | Body parser. azure unpacks the Azure Monitor records[] envelope; raw passes message bodies through untouched (Enum: azure, raw). |
| persist_offsets | boolean | true | No | Checkpoint each partition to disk so a restart resumes where it left off. |
Give the collector its own consumer group where you can. Two readers sharing
$Defaultcompete for partition ownership. Create one on the hub (Event Hub → Consumer groups → + Consumer group) and name it here. Note the Basic tier allows only one consumer group — on Basic you are stuck with$Default, which also means the portal's Data Explorer competes with the collector whenever you use it to inspect the hub. Standard allows 20.
Leave
persist_offsetson. With it off, checkpoints live in memory only: a restart resumes from the latest event and everything published while the collector was down is silently skipped. When on, checkpoints are written under<collector home>/metadata/azure_event_hub_offsets/<node name>, one directory per node, so two Event Hub sources never overwrite each other's positions.
Format: azure vs raw
azure is the right choice for anything Azure Monitor produced. It parses the records[]
envelope and maps the standard fields onto OpenTelemetry:
| Azure field | Becomes |
|---|---|
resourceId | resource attribute azure.resource.id |
operationName | azure.operation.name |
Level | severity number and severity text |
time | record timestamp |
raw passes the message body through unparsed and lifts the AMQP application properties onto
log attributes. Use it for applications publishing their own payloads to the hub.
azureneeds the Azure Monitor envelope. The body must be JSON with a top-levelrecords[]array whose entries carry at leasttime(ortimeStamp) andresourceId:{"records":[{"time":"2026-09-18T09:30:00Z","resourceId":"/SUBSCRIPTIONS/…","category":"AuditLogs","operationName":"Sign-in","Level":"Informational"}]}A body that is valid JSON but has no
records[]produces zero records, with no error and no warning — the pipeline simply stays empty. A record insiderecords[]whose timestamp will not parse is dropped with anUnable to convert timestamp from logwarning. Events you send by hand from the portal's Data Explorer blade are not in this shape; userawto see them.
This node reads logs only
Three separate reasons converge on it:
- The receiver is a shared component. Every pipeline referencing one node gets a single receiver instance, bound to whichever pipeline the collector builds first — and rebound on every restart. Advertising more than one signal would leave two of them silently empty, with the working one changing across restarts.
- The two Azure translators are asymmetric. The metrics translator correctly ignores a
resource-log record, but the logs translator turns a platform-metric record into a log line,
because a metric record also carries
timeandresourceId. One hub feeding both would count every metric twice. - The traces translator does not discriminate at all. It emits a span for any
records[]entry whose timestamp parses, so ordinary resource logs come out as spans with an empty trace ID, span ID, name and attributes.
Reading metrics from an Event Hub therefore needs a separate node definition with its own consumer group. That is not built today.
Advanced Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
| partition | string | none | Read a single partition instead of all of them. Leave empty in normal use — pinning one partition means the rest are never read. |
| offset | string | none | Starting sequence number. Only valid together with partition. |
| apply_semantic_conventions | boolean | false | Rename the Azure-specific attributes to their OpenTelemetry semantic-convention equivalents. |
| poll_rate | integer | 5 | Seconds to wait for a full batch before returning a partial one. Lower means fresher data and more calls. |
| max_poll_events | integer | 100 | Events fetched per poll cycle. |
| enable_prefetch | boolean | true | Read ahead from each partition into a local buffer so polls return without waiting on the network. |
| prefetch_count | integer | 300 | Events buffered per partition, when prefetching is on. Higher uses more memory for fewer round trips. |
Example Configuration
Connection string — the namespace and hub come from the string, so the node needs neither:
{
"group": "praxis", // dedicated consumer group
"format": "azure", // default
"persist_offsets": true // default
}
Managed identity — the node supplies what the connection string would have carried:
{
"namespace": "my-namespace.servicebus.windows.net", // required for Entra ID auth
"event_hub_name": "insights-logs-auditlogs", // required for Entra ID auth
"group": "praxis",
"format": "azure",
"persist_offsets": true,
"advanced": {
"max_poll_events": 500,
"poll_rate": 2
}
}
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Start-up fails complaining about the connection string | The string has no EntityPath — it came from the namespace's shared access policy rather than the hub's. |
| Start-up fails with an authorization error | The identity lacks Azure Event Hubs Data Receiver on the hub, or the client secret has expired. |
| No events, but the hub shows incoming messages | Another reader owns the partitions under the same consumer group. Give the collector its own group. |
| A gap in the data after a restart | persist_offsets was off, so the receiver resumed from the latest event. Turn it on. |
| Pipeline looks healthy but the destination stays empty | Switch format to raw and resend. raw turns every event into exactly one record, so if data appears the body simply is not an Azure Monitor envelope. Note the collector's Log Records debug line prints logs: {} whether it holds zero records or thousands — plog.Logs has no exported fields — so that line is not evidence either way. |
| Events arrive but parse oddly | The publisher is not Azure Monitor, so the records[] envelope is absent. Switch format to raw. |
Related
- Microsoft Sentinel — send the processed result back into Sentinel.
- Azure Blob Storage — archive it instead.
- Apache Kafka — the equivalent source for a Kafka-based bus.