feat(outputs.snowpipe_streaming): Add plugin#18721
feat(outputs.snowpipe_streaming): Add plugin#18721aleksclark wants to merge 5 commits intoinfluxdata:masterfrom
Conversation
Add a dedicated Snowflake output plugin that streams metrics directly into
Snowflake tables using gosnowflake's efficient batch inserts with array
binding, which leverages Snowpipe Streaming internally.
Features:
- Key-pair authentication via RSA private keys
- Go template-based table routing (e.g. metrics_{{.Name}})
- Configurable batch size with multi-row INSERT VALUES
- Exponential backoff retry on transient errors
- Tag/field column filtering
- Auto table creation and schema evolution (ALTER TABLE ADD COLUMN)
- Table schema caching with configurable TTL
- NaN/Inf sanitization to NULL
- Thread-safe concurrent writes
🐮 Generated with Crush
Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
|
Thanks so much for the pull request! |
|
!signed-cla |
🐮 Generated with Crush Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
🐾 Generated with Crush Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
- Omit unused receiver names instead of using underscore - Remove stale //nolint:revive directives - Add //nolint:gosec for G201 (quoteIdent sanitises identifier) - Check s.Write error in goroutine with assert.NoError
|
Download PR build artifacts for linux_amd64.tar.gz, darwin_arm64.tar.gz, and windows_amd64.zip. 📦 Click here to get additional PR build artifactsArtifact URLs |
|
@aleksclark can you please restore the PR description template, especially the AI section, as we cannot review your PR otherwise! |
|
@srebhan sure thing, sorry about that! |
srebhan
left a comment
There was a problem hiding this comment.
Thanks for your contribution @aleksclark! I started reviewing and added some comments but the real question is why this plugin is needed.
There already is a SQL output plugin and I don't see any reason on why you can't add Snowpipe support there!?
| [snowflake]: https://www.snowflake.com/ | ||
| [gosnowflake]: https://github.com/snowflakedb/gosnowflake | ||
|
|
||
| ⭐ Telegraf v1.35.0 |
There was a problem hiding this comment.
I think this is
| ⭐ Telegraf v1.35.0 | |
| ⭐ Telegraf v1.39.0 |
;-)
| inserts via the [gosnowflake][gosnowflake] driver with array binding, which | ||
| leverages Snowpipe Streaming internally for low-latency, high-throughput | ||
| ingest without staging files. |
There was a problem hiding this comment.
These are implementation / developer-targeted oriented details so we should remove them as this documentation is user-focused.
| inserts via the [gosnowflake][gosnowflake] driver with array binding, which | |
| leverages Snowpipe Streaming internally for low-latency, high-throughput | |
| ingest without staging files. | |
| inserts. |
| ## Prerequisites | ||
|
|
||
| 1. A Snowflake account with a database and schema already created. | ||
| 2. Key-pair authentication configured for the Snowflake user: | ||
| - Generate an RSA key pair: | ||
|
|
||
| ```bash | ||
| openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt | ||
| openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub | ||
| ``` | ||
|
|
||
| - Assign the public key to the user: | ||
|
|
||
| ```sql | ||
| ALTER USER my_user SET RSA_PUBLIC_KEY='<public key contents>'; | ||
| ``` | ||
|
|
||
| 3. The user must have INSERT privileges on the target table(s). | ||
| 4. If `create_table = true`, the user must also have CREATE TABLE privileges. |
There was a problem hiding this comment.
Please cut this down to really Telegraf related details. For the key-pair generation please link to the upstream documentation as nobody will maintain this here if things change in the database.
| 3. The user must have INSERT privileges on the target table(s). | ||
| 4. If `create_table = true`, the user must also have CREATE TABLE privileges. | ||
|
|
||
| ## Global configuration options |
There was a problem hiding this comment.
Please keep the inclusion "comment" which is used to auto-insert the global configuration section so we can change it in one common place
| ## Global configuration options | |
| ## Global configuration options <!-- @/docs/includes/plugin_config.md --> |
| ## {{.Name}} - metric name | ||
| ## {{.Tag "key"}} - tag value | ||
| ## Example: "metrics_{{.Name}}" routes each metric name to a separate table | ||
| table = "" |
There was a problem hiding this comment.
Can we please have the metric name as default here?
|
|
||
| ### NaN/Inf field values | ||
|
|
||
| Fields containing NaN or Inf float values are inserted as NULL to avoid |
There was a problem hiding this comment.
| Fields containing NaN or Inf float values are inserted as NULL to avoid | |
| Fields containing `NaN` or infinite float values are inserted as `NULL` to avoid |
| @@ -0,0 +1,588 @@ | |||
| //go:generate ../../../tools/readme_config_includer/generator | |||
| package snowpipe_streaming | |||
There was a problem hiding this comment.
How about just naming this snowpipe?
| import ( | ||
| "crypto/rsa" | ||
| "crypto/x509" | ||
| gosql "database/sql" |
| if strings.Contains(s.Table, "{{") { | ||
| tmpl, err := template.New("table").Parse(s.Table) | ||
| if err != nil { | ||
| return fmt.Errorf("parsing table template: %w", err) | ||
| } | ||
| s.tableTmpl = tmpl | ||
| s.tableHasTmpl = true | ||
| } |
There was a problem hiding this comment.
Why do you use this fragile setup? Wouldn't it be better to always use the template?
Or even better avoid this altogether and always use the metric name and let the user adapt this using processor plugins.
| ## Number of rows per insert batch | ||
| # batch_size = 1000 |
There was a problem hiding this comment.
The metric_batch_size is a global setting that should determine the batch-size instead of adding another parameter!
Summary
Add a dedicated Snowflake Snowpipe Streaming output plugin for low-latency, high-throughput metric ingestion directly into Snowflake tables.
The existing SQL output plugin supports Snowflake via gosnowflake, but it is a generic SQL driver — no batch optimization, no schema management, no Snowpipe Streaming awareness. This dedicated plugin provides production-grade Snowflake ingestion with:
metrics_{{.Name}})Features
Configuration
Tests
Dependencies
Uses gosnowflake which is already in go.mod (used by the SQL output plugin). No new dependencies.
Files Added
plugins/outputs/snowpipe_streaming/snowpipe_streaming.go(595 lines)plugins/outputs/snowpipe_streaming/snowpipe_streaming_test.go(785 lines)plugins/outputs/snowpipe_streaming/sample.confplugins/outputs/snowpipe_streaming/README.md(197 lines)plugins/outputs/all/snowpipe_streaming.go(registration)Checklist
Related issues
resolves #18735