Files
traefik-llmgateway/vendor/github.com/lukaszraczylo/oss-telemetry
lukaszraczylo 9dc67dedbb feat: add anonymous usage reporting, matching traefikoidc
Release builds send one anonymous "plugin loaded" ping per process, so
the project can see roughly how many installs exist and which versions
are in use. The payload is project name, version and timestamp. Nothing
else leaves the pod: no identifiers, no hostname, no configuration, no
provider names, no keys, no request data.

Three things keep it from firing when it should not. Builds from source
carry the devPluginVersion sentinel and stay silent, so developer
checkouts and every test run never phone home. The ping is sent only
after the plugin constructs successfully, so a rejected configuration is
never counted as an install. A sync.Once holds it to one per process,
because Traefik calls New once per route and oss-telemetry does not
deduplicate on the client side.

Operators of a release build opt out with DO_NOT_TRACK=1,
OSS_TELEMETRY_DISABLED=1, or TRAEFIK_LLMGATEWAY_DISABLE_TELEMETRY=1.
README.md documents the full payload and the opt-out; a plugin that
phones home without saying so in its own README would be indefensible.

oss-telemetry is the plugin's first non-stdlib RUNTIME dependency, which
has consequences for the Yaegi gate:

- vendor/ is no longer excluded from yaegi-check's GOPATH copy. It was
  excluded on the reasoning that it held only test-only testify and
  _test.go files are never interpreted. That reasoning no longer holds:
  leaving vendor out would make the interpreted copy fail to resolve an
  import the real plugin tree resolves fine, so the gate would stop
  representing production.

- yaegi-check now stamps a fake release version into its GOPATH copy so
  New's telemetry gate is PASSED rather than short-circuited, and the
  vendored package is actually called under the interpreter. Import
  resolution alone is not coverage; a cross-package call into interpreted
  third-party code is its own risk. Telemetry is suppressed by env vars
  set before anything is interpreted, so the gate never emits a real
  ping.

- A new assertion reads the version back through GET /admin/api/overview.
  Without it a silently failed stamp would leave the dev sentinel in
  place and the harness would still print OK while covering nothing.
  Verified by disabling the stamp and watching the gate fail.

shouldSendTelemetry is split out from sendStartupTelemetry so the
decision is table-testable without a network, since oss-telemetry's
endpoint is deliberately not overridable from consuming code.

Also brings the version-gated documentation up to date, since the same
README edit touches it. The latest release is v1.0.3, so the pre-1.0
experimental warning has met its own stated condition and is replaced by
a semver stability statement in README.md and dropped from
.traefik.yml's catalog summary. The catalog now serves the released tags
(verified: the v1.0.3 download endpoint returns 200), so the "not yet
published" and "analyzer has not been run" claims are corrected, the
catalog form of the static config is documented as usable, and
examples/kubernetes.yaml pins v1.0.3 instead of v0.1.0.
2026-08-22 18:45:36 +01:00
..

oss-telemetry

A tiny Go client that fires one anonymous "this binary started" ping at a central ingest endpoint. Designed to be embedded in your own open-source projects so you can see approximate adoption and version spread without collecting anything that could identify a user.

This is the client library only. The ingest endpoint, server-side deduplication, rate limiting, and metrics are out of scope here.

What it sends

A single HTTP POST per call to Send:

{
  "project": "my-tool",
  "version": "1.2.3",
  "ts": 1747782200
}

No identifiers, no IP, no machine info, no user data. The server dedupes incoming requests; the client just fires and forgets.

Failproof by design

  • Never blocks the caller — work runs in a goroutine.
  • Never panics — the goroutine recovers internally.
  • Never returns errors — bad input and network failures are silently dropped.
  • Never retries, never persists state, never reads back.
  • 2-second hard timeout on every request.
  • Zero third-party dependencies (Go stdlib only).

The endpoint is hardcoded and not overridable from consuming code, by design.

Install

go get github.com/lukaszraczylo/oss-telemetry

Requires Go 1.22+.

Usage

package main

import (
    "time"

    telemetry "github.com/lukaszraczylo/oss-telemetry"
)

const version = "1.2.3"

func main() {
    telemetry.Send("my-tool", version)

    // ... your program runs ...

    // Only needed for short-lived CLIs that may exit before the goroutine
    // finishes its POST. Long-running services do not need this.
    telemetry.Wait(2 * time.Second)
}

Call Send once at boot. Calling it more often just sends more pings; the server deduplicates.

Disabling telemetry

If you ship a binary that imports this library, link your users to this section (https://github.com/lukaszraczylo/oss-telemetry#disabling-telemetry) so they can find the opt-out paths.

Any one of these turns it off:

Mechanism How
Universal opt-out DO_NOT_TRACK=1
Library-wide opt-out OSS_TELEMETRY_DISABLED=1
Project-specific opt-out <UPPER_PROJECT>_DISABLE_TELEMETRY=1
Programmatic (e.g. behind a --no-telemetry flag) telemetry.Disable() before the first Send

Project-specific env var derivation: uppercase the project name and replace - with _. For my-tool the variable is MY_TOOL_DISABLE_TELEMETRY.

Truthy values: 1, true, yes, on (case-insensitive). Anything else is treated as "not set".

Validation rules (silently dropped if violated)

  • project: matches ^[a-z0-9-]+$, length 1–64.
  • version: matches ^[A-Za-z0-9.+_-]+$, length 1–32.

Bad input is a no-op — the library never logs, never errors, never crashes.

API

// Fire a single ping in the background. Returns immediately.
func Send(project, version string)

// Suppress all subsequent Send calls in this process. Idempotent.
func Disable()

// Block until in-flight pings complete or timeout elapses, whichever first.
// Useful for short-lived CLI processes.
func Wait(timeout time.Duration)

Testing

go test -race ./...

License

Pick one before publishing. None bundled.