feat(azure_blob source): add Azure Blob Storage source - #26107
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf4fa5c72d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 305ccd6b3a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 97be5b4f10
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Summary
Adds an
azure_blobsource: the S3/SQS pattern fromaws_s3, ported to Azure.An Event Grid subscription publishes
Microsoft.Storage.BlobCreatednotifications to an Azure Storage Queue, which Vector polls. Each notification is resolved to a blob, downloaded, optionally decompressed, decoded with any codec, and its queue message deleted once the events are durably accepted by the pipeline (end-to-end acknowledgements).compression: autoinfers gzip/zstd fromContent-Encoding,Content-Type, or blob suffix, then verifies that guess against the stream's magic bytes. On a mismatch it reads the blob raw and logs which signal disagreed. An explicitly configured codec is never second-guessed.azure_commonfrom theazure_blobsink unchanged, so a config that works for the sink works here: connection string (account key or SAS), oraccount_name/blob_endpointplus any Azure token credential.blob_endpoint/queue_endpointoverrides for sovereign clouds, private endpoints, and Azurite.dequeue_countis logged so poison messages are visible.New metrics:
azure_blob_event_ignored_total,azure_blob_processing_{succeeded,failed}_duration_seconds,azure_queue_message_{delete,processing,receive}_succeeded_total,azure_queue_message_received_messages_total.Relationship to the
aws_s3sourceWhere
aws_s3had a precedent I copied it: file layout, type visibility, config field names, decoding pipeline, metric naming,#[allow]s.aws_s3azure_blobsources/aws_s3/mod.rs+sqs.rssources/azure_blob/mod.rs+queue.rsStrategy::Sqs(default, sole variant)Strategy::StorageQueue(default, sole variant)sqs::Config(pub(super))queue::Config(pub(super))Ingestor/IngestorProcess/StateProcessingError(pub),IngestorNewError(pub(super))Compression+determine_compressionobject_key_→blob_name_s3_object_processing_{succeeded,failed}_duration_secondsazure_blob_processing_{…}sqs_message_{delete,processing,receive}_succeeded_totalazure_queue_message_{…}Six of the seven queue options keep their
aws_s3names and defaults:poll_secs,visibility_timeout_secs,max_number_of_messages,client_concurrency,delete_message,delete_failed_message.queue_urlbecomesqueue_namebecause the Azure SDK derives the URL from the service endpoint.deferred,timeout, andtls_optionsare not ported.Where Azure forced a divergence:
QueueEventenum anddecode_message_text.delete_failed_messagematters more here, and why a compression mismatch downgrades to reading raw rather than failing the blob.aws_s3'spoll_secsis the SQS long-poll wait time; Azure'sGetMessagesreturns immediately, so the same name and default (15s) instead caps a client-side backoff between empty polls. Same knob, different mechanism.Content-Lengthto the transport, which runs after the signing policy, so aContentLengthPolicyis pushed ahead of it. Noaws_s3analogue; the AWS SDK signs its own requests.References
Vector configuration
Connection string:
Managed Identity, tuned queue options, gzip blobs decoded as JSON:
Azurite, which is what the integration tests run against. Endpoints are explicit because a local address cannot be derived from the account name:
How did you test this PR?
Real Azure environment. Ran the source against a live storage account with an Event Grid subscription delivering
Microsoft.Storage.BlobCreatednotifications to a Storage Queue, ingesting both uncompressed blobs and gzip (.gz) blobs under the defaultcompression: auto.Unit tests (50): endpoint resolution (public cloud, development storage,
DevelopmentStorageProxyUriport rewriting including IPv6 literals, explicit overrides, SAS appending); notification parsing for both schemas and the array-wrapped form; base64 vs raw bodies; subject/URL blob resolution and percent-decoding precedence; compression detection and magic-byte verification; theazure_core::Errorsource-chain renderer; config validation.cargo nextest run --no-default-features \ --features sources-azure_blob,sinks-azure_blob \ -E 'test(azure_blob)'Integration tests (14) against Azurite's blob and queue services. Azurite does not run Event Grid, so the tests enqueue synthetic notifications themselves.
cargo vdev int start azure cargo vdev int test azureCovers all three notification formats (Event Grid base64, Event Grid raw JSON, CloudEvents base64); JSON and bytes decoding; the Vector log namespace; blob names with spaces; a blob over the SDK's 4 MiB download partition size, which takes the partitioned path and requires the
azure_core/tokiofeature; gzip, multipart gzip, multipart zstd; multiline aggregation; rejected batches with and withoutdelete_failed_message; non-BlobCreatedevents ignored and deleted. Each test asserts the resulting queue depth. The 13 that go through the shared test_event helper also run under assert_source_compliance(&SOURCE_TAGS, ...); the ignored-event-type test does not, since it deliberately produces no events and so emits none of the telemetry that check requires.Checks:
The source uses
azure_commonfromsrc/sinks/, sosrc/sinks/mod.rsgates that module onsources-azure_blobtoo. Declaringsinks-azure_blobas a Cargo dependency instead would register theazure_blobsink in source-only builds.Is this a breaking change?
New source behind a new sources-azure_blob feature. Existing files are touched only for registration: module declarations (src/sources/mod.rs, src/internal_events/mod.rs), feature definitions (Cargo.toml), metric-name enums (lib/vector-common/src/internal_event/metric_name.rs), and docs. The only change affecting existing behavior is one added #[cfg] feature on the already-shared azure_common module; azure_common itself is unmodified.
Does this PR include user facing changes?
no-changeloglabel to this PR.Fragment added at
changelog.d/azure_blob_source.feature.md.Cargo.lockchanged (azure_storage_queue, plus theazure_core/tokiofeature).LICENSE-3rdparty.csvgains oneazure_storage_queueentry; its transitive dependencies (async-trait,azure_core,serde,time) were already listed.