Telemetry
dfmt reports one anonymous event per run. This page lists every field it contains, how to see exactly what your machine would send, and how to turn it off.
We collect it for two reasons: to know how many people use dfmt and on what, and to find out
where the parser and formatter fail in real projects so we can fix them. Nothing on this page is
a summary — the event has no fields beyond the ones listed here, and --telemetry-preview shows
you the literal payload before it is sent.
What is never sent
- File names, paths, directory names, or your project's name
- SQL, Jinja, or any other file content — not even fragments from error messages
- Your IP address, hostname, user name, or any account identifier
- Git remote URLs, branch names, or commit hashes
Events are anonymous in PostHog's sense: no person profile is created, and geolocation from the connection is disabled. Data is stored in PostHog's EU cloud.
How to turn it off
Any one of these disables reporting; there is no setting that forces it on.
| Method | Scope |
|---|---|
DLAB_TELEMETRY=0 in the environment | This shell / this user |
"telemetry": false at the root of dlab.json | Everyone working in that project, including CI |
DO_NOT_TRACK=1 in the environment | This shell / this user |
DO_NOT_TRACK=1 is the convention shared by many command-line
tools, so a machine already opted out of everything is opted out of dfmt too.
Only a binary built at a release tag reports at all. A build from a source checkout carries a
git describe version such as 0.0.1-M5-12-gabc1234-dirty, and sends nothing — so working on
dfmt itself needs no opt-out. --telemetry-preview names the reason it is off.
Deleting ~/.config/dlab/telemetry-id ($XDG_CONFIG_HOME/dlab/telemetry-id, or
%APPDATA%\dlab\telemetry-id on Windows) resets the installation id.
How to see what would be sent
dfmt check --telemetry-preview
prints the full event as JSON on stderr, followed by whether it was sent, and why not if it was not.
The event
Event name: dlab:dfmt_run. One per invocation, sent after the run's own output. The binary hands
the event to a short-lived background process of itself and exits at once, so your prompt never
waits on the network; that process gives up after a few seconds if the network is blocked. With
--telemetry-preview the event is sent before exit instead, so the outcome can be printed. A
failed send is never reported outside --telemetry-preview — nothing about formatting depends on
it.
The event carries the identity and environment blocks below, product, and then the run, file,
error and timing sections, which are specific to dfmt.
Identity
| Field | Meaning |
|---|---|
install_id | A random UUID minted the first time dfmt runs on this machine, stored in the file above. Derived from nothing about the machine. |
project_id | A truncated salted SHA-256 of the git origin URL with credentials stripped. Lets runs in the same repository be counted together across machines; the URL itself is not recoverable from it. Absent outside a git checkout. |
distinct_id | install_id locally; project:<project_id> in CI, where runners are ephemeral and an install id would count every run as a new installation. |
Environment
| Field | Meaning |
|---|---|
$lib_version | The dfmt version: the release tag this binary was built at, e.g. 0.0.1-M5. Always a tag, because a build that is not at one does not report. |
$os, $os_version | Operating system family (macos, linux, windows, other) and its major.minor version |
arch | CPU architecture, e.g. aarch64 |
cpu_count | Number of processors |
is_native | Whether the native binary or a JVM ran |
is_interactive | Whether stderr is a terminal |
is_ci, ci_provider | Whether a CI environment was detected, and which one (github, gitlab, buildkite, circleci, travis, jenkins, azure, teamcity, bitbucket, codebuild, drone, other) |
The run
| Field | Meaning |
|---|---|
product | dfmt |
mode | check, write, or print |
dialect | The SQL dialect the run used |
has_config_file | Whether a dlab.json was found |
has_changed_since, has_model_flag, is_no_jinja, is_verbose | Which of those options were used |
is_dbt, dbt_adapter, dbt_model_count, dbt_macro_count, dbt_init_ms | Whether a dbt project was detected, its adapter type, its size, and how long loading it took |
is_dbt_init_failed | Present when a dbt project was found but could not be loaded, and the run fell back to plain SQL |
exit_code | The process exit code |
exit_reason | Present only when the run stopped before formatting. One of usage, no_config, no_dialect, missing_packages, model_requires_dbt, model_not_found, no_changed_files, no_files, scan_failed, uncaught |
exception_class | With exit_reason: uncaught: the Java class name of what crashed dfmt, e.g. OutOfMemoryError. Never the message. |
Files
| Field | Meaning |
|---|---|
file_count | Files the run looked at |
written_file_count | Files dfmt write changed |
changed_file_count | Files dfmt check would have changed |
unchanged_file_count | Files already formatted |
failed_file_count | Files that errored |
warned_file_count | Files that produced at least one warning |
skipped_file_count | Files returned untouched by decision: disabled dbt models, Jinja files outside a dbt project |
jinja_file_count | Files that went through the template pipeline |
source_char_count, file_char_count_p50, file_char_count_max | Total and per-file size of what was formatted |
Errors
| Field | Meaning |
|---|---|
warning_count | All warnings across all files |
sql_parse_error_count | SQL the parser could not fully read |
jinja_error_count | Jinja syntax or evaluation failures |
runtime_dependent_count | Models that need a live warehouse to compile |
reconstruction_failure_count | Cases where dfmt's own template layer gave up — bugs in dfmt |
parse_error_kind_counts | SQL parse errors by kind: missing_keyword, missing_punct, skipped, node |
parse_error_production_counts | The ten grammar rules that failed most often, by our internal rule names, with counts |
failure_kind_counts | Why files failed, by kind: empty_output, destructive_write_refused, write_failed, or the class name of the exception (StackOverflowError, IOException, …). Never a message. |
The error fields are why the telemetry earns its keep: knowing that Expression fails ten
times more often than SelectStatement under snowflake tells us what to fix next, and no
example of your SQL is needed to know it.
Timing
| Field | Meaning |
|---|---|
cpu_ms | Parse and format time summed over files, with file IO excluded |
batch_ms | Wall time of the batch, IO included |
wall_ms | Wall time of the whole process |
source_char_count / cpu_ms is a throughput independent of how many files a project has or how
large they are; cpu_ms / batch_ms is how much parallelism the machine gave.