Wasm Stats Filter Sink
The WasmFilterStatsSinkConfig configuration specifies a stats sink middleware that runs a WebAssembly (WASM) plugin to filter, transform, and enrich metrics before delegating to an inner stats sink.
This is useful when you need custom, programmable logic to decide which metrics are exported – for example, dropping high-cardinality metrics by name pattern, injecting tags from node metadata, renaming metrics, or adding synthetic metrics. It replaces centralized metric processing services with distributed in-proxy logic.
This extension should be configured with the type URL
type.googleapis.com/envoy.extensions.stat_sinks.wasm_filter.v3.WasmFilterStatsSinkConfig.
Attention
The Wasm stats filter sink is only included in contrib images
Attention
The Wasm stats filter sink is experimental and is currently under active development. Capabilities will be expanded over time and the configuration structures are likely to change.
How it works
The wasm_filter sink wraps any existing stats sink (the inner sink) and
interposes a WASM plugin on each flush cycle:
Envoy’s flush timer fires and passes the full
MetricSnapshotto thewasm_filtersink.The sink serializes all counters and gauges into a compact binary buffer and invokes the WASM plugin’s
onStatsUpdate()callback.The plugin iterates the metrics and applies custom logic. It may call foreign functions to:
Get additional data: histogram names, per-metric tags
Set global tags: applied to all metrics on every flush
Rename metrics: override the name of specific counters/gauges/histograms
Inject synthetic metrics: add new counters/gauges to the snapshot
Emit kept indices: declare which metrics to keep
The host builds an enriched snapshot: filtered metrics wrapped with tag/name overrides, plus any injected synthetic metrics.
The enriched snapshot is flushed to the inner sink.
Text readouts and host counters/gauges pass through unfiltered.
Capabilities
Capability |
Foreign Function |
Description |
|---|---|---|
Filter |
|
Declare which counters, gauges, and histograms to keep. |
Global tag injection |
|
Set tags (e.g. datacenter, pod) applied to ALL metrics. Called once at
startup from |
Metric renaming |
|
Override the name of specific metrics (e.g. prefix with |
Synthetic metrics |
|
Inject new counters/gauges with custom names, values, and tags. Called per flush. |
Histogram discovery |
|
Get the list of histogram names (not in the standard |
Per-metric tags |
|
Get tags for a single metric by type and index. |
Bulk tags |
|
Get tags for all metrics in one call. |
Configuration example
stats_flush_interval: 10s
stats_sinks:
- name: envoy.stat_sinks.wasm_filter
typed_config:
"@type": type.googleapis.com/envoy.extensions.stat_sinks.wasm_filter.v3.WasmFilterStatsSinkConfig
wasm_config:
name: "my_stats_filter"
root_id: "stats_filter"
vm_config:
runtime: "envoy.wasm.runtime.v8"
code:
local:
filename: "/etc/envoy/stats_filter_plugin.wasm"
configuration:
"@type": type.googleapis.com/google.protobuf.StringValue
value: '{"exclude_prefixes": ["server.compilation", "runtime."], "rename_with_prefix": true}'
inner_sink:
name: envoy.stat_sinks.kafka
typed_config:
"@type": type.googleapis.com/envoy.extensions.stat_sinks.kafka.v3.KafkaStatsSinkConfig
broker_list: "kafka:9092"
topic: "envoy-metrics"
format: PROTOBUF
emit_tags_as_labels: true
Wire format reference
stats_filter_emit
[counter_count] [counter_idx_0] ... [counter_idx_N]
[gauge_count] [gauge_idx_0] ... [gauge_idx_M]
[hist_count] [hist_idx_0] ... [hist_idx_K] (optional)
stats_filter_set_name_overrides
[count: uint32]
For each override:
[type: uint32 (1=counter, 2=gauge, 3=histogram)]
[index: uint32]
[new_name_len: uint32] [new_name bytes]
stats_filter_inject_metrics
[counter_count: uint32]
For each counter:
[name_len: uint32] [name bytes] [value: uint64]
[tag_count: uint32] for each tag: [name_len][name][value_len][value]
[gauge_count: uint32]
For each gauge:
[name_len: uint32] [name bytes] [value: uint64]
[tag_count: uint32] for each tag: [name_len][name][value_len][value]
stats_filter_get_histograms
Input: empty. Output:
[count: uint32] for each: [name_len: uint32] [name bytes]
Reading node metadata
The plugin can read Envoy’s node metadata during onConfigure() using
getProperty() / getValue() with paths like:
["xds", "node", "id"]– node ID (hostname)["xds", "node", "cluster"]– cluster name["xds", "node", "metadata", "datacenter"]– custom metadata["xds", "node", "locality", "region"]– locality region
These are used to compute global tags via stats_filter_set_global_tags.
Performance considerations
Global tags: set once at startup, zero per-flush overhead.
Metric filtering: single WASM boundary crossing for the serialized buffer.
Bulk tag lookup:
stats_filter_get_all_metric_tags– one crossing vs N.Name overrides and injection: one crossing each per flush.
Current limitations
Text readouts are not filterable – they pass through to the inner sink.
Value transformation is not supported – the plugin can rename and tag metrics but cannot modify counter/gauge values.