Azure Blob Storage
Overview
Azure Blob Storage exports logs, metrics, and traces to containers in an Azure Storage account. Each batch is written as one blob in OpenTelemetry Protocol JSON or protobuf format, with optional gzip or zstd compression.
Use it for low-cost long-term retention, or as a hand-off point for an Azure-side consumer such as Synapse, Data Explorer, Microsoft Fabric, or an Azure Function blob trigger. If you want telemetry queryable in Sentinel, use Microsoft Sentinel instead — blobs are not indexed by Log Analytics.
Supported types: Logs · Metrics · Traces
Note: The container you configure must already exist in the storage account. This destination writes blobs; it never creates containers.
Authentication Configuration
All authentication lives in the attached Azure Blob Storage credential — the destination node itself has no auth fields and stores no secret. Pick the Authentication Type on the credential:
| Auth Type | What it needs | Stores a secret? |
|---|---|---|
connection_string | Connection string (embeds the account key) | Yes |
service_principal | Storage Account URL, Tenant ID, Client ID, Client Secret | Yes |
system_managed_identity | Storage Account URL only | No |
user_managed_identity | Storage Account URL, Client ID | No |
workload_identity | Storage Account URL, Tenant ID, Client ID, Federated Token File | No |
The credential form shows only the fields the chosen type needs.
Storage Account URL is the blob service endpoint, e.g.
https://myaccount.blob.core.windows.net/. It is required for every type except
connection_string, where the endpoint is read from the connection string.
Prefer a managed identity where the collector runs inside Azure. Those three types store no key at all — the collector resolves a short-lived token from Entra ID — so there is nothing to rotate or leak. Use
connection_stringwhen the collector runs outside Azure, and note that some organizations disable account-key access entirely (allowSharedKeyAccess), which rules it out.
Note: Whichever identity you use must hold Storage Blob Data Contributor (or equivalent write permission) on the container scope. A missing role assignment surfaces as a 403 on upload, not a configuration error. Assigning it requires Owner or User Access Administrator — the Contributor role cannot grant it.
Configuration
| Parameter | Type | Default Value | Required | Description |
|---|---|---|---|---|
| url | string | none | Cond. | Blob service endpoint, e.g. https://myaccount.blob.core.windows.net/. Required unless auth type is connection_string. |
| container | string | none | Yes | Container that receives the blobs. Must already exist. |
| folder_name | string | none | No | Optional folder inside the container to store blobs under. |
| blob_prefix | string | none | No | Optional prefix to prepend to all stored blob names. |
| partition | string | minute | No | Time-based partitioning scheme (minute, hour, day, month, year). |
Container names follow Azure's rule: 3–63 characters, lowercase letters, digits and single hyphens, starting and ending with a letter or digit.
Note: Logs, metrics and traces share the one container — the blob name carries the signal (
logs,metrics,traces), so the three streams stay distinguishable. Hand-written collector config can still target a different container per signal.
Blob Naming
Blobs are written to:
[folder_name/]year=YYYY/month=MM/day=DD/hour=HH/minute=MM/[blob_prefix]<signal>_<serial>.json[.gz]
The key=value folder layout is what Synapse, Microsoft Fabric and Databricks recognise for partition pruning, so a query filtered to one day reads only that day's prefix.
partition controls how deep the folder tree goes:
| partition | Path |
|---|---|
year | year=2026/ |
month | year=2026/month=09/ |
day | year=2026/month=09/day=15/ |
hour | year=2026/month=09/day=15/hour=07/ |
minute | year=2026/month=09/day=15/hour=07/minute=32/ |
Coarser partitions produce fewer, larger blobs. Timestamps are UTC.
A random serial number is appended before the extension (logs_4821.json) so two batches landing in the same second cannot overwrite each other.
Note:
folder_nameandblob_prefixare passed through literally. A folder namedarchive2006or a prefix of01-stays exactly as typed — only the generatedyear=/month=/… portion is date-formatted.
Advanced Configuration
| Parameter | Type | Default Value | Description |
|---|---|---|---|
| format | string | json | Encoded telemetry format: json (OTLP JSON) or proto (OTLP protobuf). |
| compression | string | gzip | Compress each blob before upload: none, gzip, or zstd. The matching .gz / .zst suffix is appended to the blob name. |
| timeout | int | 60 | Maximum time in seconds to wait for a single upload attempt. Raise it if large batches fail with context deadline exceeded. |
| retry_on_failure | bool | true | Enables automatic retry when an upload fails. |
| backpressure_queue | bool | true | Enables an internal queue to manage high volume and reduce data loss. |
Retry Settings
If retry on failure is enabled, the following fields are available:
| Parameter | Type | Default Value | Required | Description |
|---|---|---|---|---|
| initial_interval | duration | 5 | Yes | Initial wait time after a failure before the first retry. |
| max_interval | duration | 30 | Yes | Maximum wait time between any two retries. |
| max_time_elapsed | duration | 300 | Yes | Total maximum time to keep retrying for a single batch. |
Sending Queue Settings
If Enable Backpressure Queue is enabled, the following fields are available:
| Parameter | Type | Default Value | Required | Description |
|---|---|---|---|---|
| number_of_consumers | int | 10 | Yes | Number of parallel workers uploading from the queue. |
| queue_size | int | 1000 | Yes | Maximum number of batches to hold in the queue. |
| enable_disk_backed_queue | bool | true | Yes | Saves the queue to disk so buffered blobs survive restarts. |
Example Configuration
{
"auth": {
"type": "connection_string", // default: "connection_string"
// tenant_id / client_id / client_secret / federated_token_file
// apply to the other auth types only.
},
"url": "", // required unless type is "connection_string"
"container": "praxis-logs", // required, must already exist
"folder_name": "", // default: none
"blob_prefix": "", // default: none
"partition": "minute", // default: "minute"
"advanced": {
"format": "json", // default: "json"
"compression": "gzip", // default: "gzip"
"timeout": 60, // default: 60
"append_blob": {
"enabled": false, // default: false
"separator": "\n", // default: "\n"
},
"retry_on_failure": true,
"retry_on_failure_settings": {
"initial_interval": 5, // required, default: 5
"max_interval": 30, // required, default: 30
"max_time_elapsed": 300, // required, default: 300
},
"backpressure_queue": true,
"backpressure_queue_settings": {
"number_of_consumers": 10, // required, default: 10
"queue_size": 1000, // required, default: 1000
"enable_disk_backed_queue": true, // required, default: true
},
},
}
Troubleshooting
| Symptom | Cause |
|---|---|
| Every upload fails with 404 | The container does not exist. Create it in the storage account — this destination does not. |
| Every upload fails with 403 | The identity lacks Storage Blob Data Contributor on the container scope. |
| 403 only with a managed identity | The role assignment is missing or still propagating; assigning it needs Owner, not Contributor. |
| Connection string rejected by Azure | The account has allowSharedKeyAccess disabled by policy — switch the credential to a managed identity. |
| Config rejected when saving the pipeline | No Azure Blob Storage credential is attached — one is always required. |
| Writes stop after a long run | advanced.append_blob is enabled and the blob hit the 50,000-block ceiling. |
| DNS failure on the account hostname | The storage account name in the connection string is wrong, or the account is in a different Azure cloud (Gov / China need a different EndpointSuffix). |