ExDataSketch emits structured telemetry events at meaningful operation boundaries, enabling production observability without impacting hot-path performance.
Why Telemetry Matters
Individual update/2 calls can run at billions per second -- emitting events
for each would cripple throughput. Instead, ExDataSketch emits events at
compound operation boundaries:
from_enumerable/2-- batch ingestionmerge_many/1-- bulk mergeserialize/1/deserialize/1-- serialization (HLL only in this release)- Storage operations -- save, load, merge, delete
- Stream operations -- partition merge
Configuration
Telemetry is enabled by default. Disable globally:
config :ex_data_sketch, telemetry_enabled: falseDisable specific categories:
config :ex_data_sketch, telemetry: [
sketch: true,
persistence: true,
stream: true,
pipeline: false
]Event Reference
Sketch Events
| Event | Measurements | Metadata |
|---|---|---|
[:ex_data_sketch, :sketch, :ingest] | duration, size_bytes | sketch_type |
[:ex_data_sketch, :sketch, :merge] | duration, merge_count | sketch_type |
[:ex_data_sketch, :sketch, :serialize] | duration, size_bytes | sketch_type |
[:ex_data_sketch, :sketch, :deserialize] | duration, size_bytes | sketch_type |
Note: The
:ingestevent'ssize_bytesmeasurement reflects the serialized size of the resulting sketch. Since the sketch is fully constructed before this measurement is taken, it is always available regardless of sketch type.
Persistence Events
| Event | Measurements | Metadata |
|---|---|---|
[:ex_data_sketch, :persistence, :save] | duration, size_bytes | sketch_type, backend, key |
[:ex_data_sketch, :persistence, :load] | duration | sketch_type, backend, key |
[:ex_data_sketch, :persistence, :merge] | duration | sketch_type, backend, key |
[:ex_data_sketch, :persistence, :delete] | duration | backend, key |
Note: The
:deleteevent does not includesketch_typebecause the sketch struct is no longer available at deletion time. The:loadevent does not includesize_bytesbecause the binary size is only known after deserialization completes.
Stream Events
| Event | Measurements | Metadata |
|---|---|---|
[:ex_data_sketch, :stream, :reduce] | (none) | sketch_type |
[:ex_data_sketch, :stream, :partition_merge] | duration, partition_count | sketch_type |
Note: The
:reduceevent is a completion signal emitted fromFlow.on_trigger/2. Because the reduce runs inside the Flow runtime, no timing measurement is available.
Pipeline Events
| Event | Measurements | Metadata |
|---|---|---|
[:ex_data_sketch, :pipeline, :accumulate] | duration, count | sketch_type, batch_size |
[:ex_data_sketch, :pipeline, :periodic_flush] | duration | sketch_type |
Note: The
:periodic_flushdurationmeasures time since the previous flush (or process start), not the time taken to perform the flush itself.
All Event Names
To get a list of all event names programmatically:
ExDataSketch.Telemetry.all_event_names()
# => [[:ex_data_sketch, :sketch, :ingest],
# [:ex_data_sketch, :sketch, :merge],
# [:ex_data_sketch, :sketch, :serialize],
# [:ex_data_sketch, :sketch, :deserialize],
# [:ex_data_sketch, :persistence, :save],
# [:ex_data_sketch, :persistence, :load],
# [:ex_data_sketch, :persistence, :merge],
# [:ex_data_sketch, :persistence, :delete],
# [:ex_data_sketch, :stream, :reduce],
# [:ex_data_sketch, :stream, :partition_merge],
# [:ex_data_sketch, :pipeline, :accumulate],
# [:ex_data_sketch, :pipeline, :periodic_flush]]Attaching Handlers
Use :telemetry.attach/4 to listen for events:
:telemetry.attach("my-handler", [:ex_data_sketch, :sketch, :ingest], fn _name, measurements, metadata, _config ->
Logger.info("Ingested \#{metadata.sketch_type}: \#{measurements.size_bytes} bytes in \#{measurements.duration} ns")
end, nil)Measurement Details
All duration measurements use native time units (as returned by
System.monotonic_time/0). Convert to milliseconds with:
System.convert_time_unit(duration, :native, :millisecond)The sketch_type metadata field uses atoms: :hll, :cms, :theta, :ull,
:kll, :ddsketch, :req, :frequent_items, :misra_gries, :bloom,
:quotient, :cqf, :iblt, :cuckoo, :xor_filter, :filter_chain.
The backend metadata field uses atoms: :ets, :dets, :cubdb, :mnesia,
:ecto.
OpenTelemetry Integration
When the :opentelemetry_api dependency is available, bridge telemetry events
to OTEL spans:
ExDataSketch.Telemetry.OpenTelemetry.setup()This attaches handlers that create OpenTelemetry spans for each ExDataSketch
telemetry event. Call this in your application's start/2 callback.
To disable:
config :ex_data_sketch, :integrations, opentelemetry: false