Plugins
A plugin changes every run from one place: where tasks run, where the
cache lives, what keys hold, who sees the results. Install it and list it
in .vx/workspace.ts.
bun add -d @vzn/vx-lockfile @vzn/vx-otelimport { defineWorkspace } from '@vzn/vx/config'import { bun } from '@vzn/vx-lockfile'import { otel } from '@vzn/vx-otel'
export default defineWorkspace({ plugins: [bun(), otel({ serviceName: 'my-monorepo' })],})vx applies no plugin by default. With none, it runs and caches on this machine. A plugin that declines a task hands it back to this machine.
Plugins that ship
Section titled “Plugins that ship”| Package | Hooks it fills |
|---|---|
@vzn/vx-reapi |
cache, executor (Remote cache, Remote execution) |
@vzn/vx-migrate |
config, discover, project, fingerprint (turbo(), nx()), cache (turboCache(), nxCache()) (Migrate) |
@vzn/vx-lockfile |
discover, project, fingerprint, key (Lockfiles) |
@vzn/vx-history |
schedule, admit, commands |
@vzn/vx-otel |
telemetry (below) |
@vzn/vx-ci |
config, telemetry, commands (GitHub Actions, GitLab CI) |
@vzn/vx-cache |
cache, on a @vzn/vx-cache-server |
@vzn/vx-cache-server |
none: the cache server you host |
@vzn/vx-history-server |
none: the timings server vxHistory() reads |
@vzn/vx-devtools |
none: the CI token check the servers share |
One plugin can fill several: @vzn/vx-history fills three at once.
OpenTelemetry
Section titled “OpenTelemetry”@vzn/vx-otel exports every run as OTLP traces, metrics and logs, with no
OpenTelemetry SDK: one trace per run, one span per task. Install it
(bun add -d @vzn/vx-otel) and point it at your collector
(OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318). Without any
endpoint it declines; a signal’s own endpoint alone exports that signal.
import { defineWorkspace } from '@vzn/vx/config'import { otel } from '@vzn/vx-otel'
export default defineWorkspace({ plugins: [otel({ serviceName: 'my-monorepo', headers: { authorization: 'Bearer …' } })],})| Option | Env var | Default |
|---|---|---|
endpoint |
OTEL_EXPORTER_OTLP_ENDPOINT |
none |
tracesEndpoint |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
<endpoint>/v1/traces |
metricsEndpoint |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
<endpoint>/v1/metrics |
logsEndpoint |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT |
<endpoint>/v1/logs |
serviceName |
OTEL_SERVICE_NAME |
vx |
headers |
OTEL_EXPORTER_OTLP_HEADERS (k=v,…) |
{} |
metrics |
OTEL_METRICS_EXPORTER=none turns it off |
true |
logs |
OTEL_LOGS_EXPORTER=none turns it off |
true |
timeoutMs |
OTEL_EXPORTER_OTLP_TIMEOUT |
15000 |
compression |
OTEL_EXPORTER_OTLP_COMPRESSION (and _<SIGNAL>_) |
'none' |
live |
none: send each task as it ends | true |
| Signal | Carries |
|---|---|
vx.run span |
vx.run.task_count, vx.run.failed_count, vx.run.aborted_count, vx.run.hit_local_count, vx.run.hit_remote_count, vx.run.up_to_date_count, vx.run.restored_local_count, vx.run.restored_remote_count, vx.run.exit_ok, vx.cache.upload.* (remote uploads, once settled), vx.workspace.id, vx.default_branch, vx.telemetry.schema |
vx.task span |
vx.cache.source, vx.cache.restored (on a hit), vx.task.hash, vx.task.attempts, vx.task.blocked_by, vx.task.timed_out, vx.task.sandbox_violations, vx.task.not_ready, vx.task.command, vx.task.flaky.*, vx.cache.stored_* (on a hit), vx.task.admission_held_ms, vx.task.queued_ms, vx.task.input_files, vx.cache.miss.change_count and vx.cache.miss.changes (what a miss’s key changed since the last saved entry), vx.cache.artifact_bytes, vx.cache.save_ms, vx.cache.fetch_ms; links to the tasks it waited on; vx.task.retry, vx.task.timeout and vx.sandbox.violation events |
| a span per stage | startup, load configs, classify + probe, run graph, … (the VX_DEBUG_TIMING stages), with vx.stage.name |
| metrics | vx.tasks.total, vx.tasks.failed, vx.tasks.cache_hits, vx.tasks.cache_restored, vx.tasks.cache_up_to_date, vx.run.duration_ms, vx.run.time_saved_ms |
| metrics per task | vx.task.duration, vx.task.cpu_time, vx.task.peak_memory, vx.task.time_saved, vx.task.admission_held, vx.task.queued, vx.task.artifact_size, vx.task.cache_save, vx.task.cache_fetch at its end; vx.task.cpu_usage and vx.task.memory each second while it runs; each point names its span as an exemplar |
| a log per task | the task’s output at its end, linked to its span; vx.log.chars_full says when it was cut |
| every resource | service.instance.id (the run id), host.name, host.arch, os.type, vcs.ref.head.*, vcs.repository.*, vx.workspace.path (the workspace root in its repository), and on CI cicd.pipeline.run.url.full, cicd.pipeline.name, vcs.change.id (the pull request), vx.ci.job, vx.ci.attempt: one key joins a run’s traces, metrics and logs |
Each task is sent as it ends, so a dashboard follows a CI run live;
live: false sends it all at the end. A failed task’s span is ERROR.
A failed or slow export warns, and the run still exits green.
To see it locally, run otel-desktop-viewer:
brew tap ctrlspice/otel-desktop-viewerbrew install --cask otel-desktop-viewerotel-desktop-viewerOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 vx run build --all