Commit cc942b5
authored
feat(appkit): send internal telemetry via AppkitLog schema (#332)
* feat(appkit): send internal telemetry via AppkitLog schema
Introduce the AppkitLog event family (APP_STARTUP, HEARTBEAT,
REQUEST_METRICS) and a TelemetryReporter singleton that owns the
shared dispatch state, periodic heartbeat, and request metrics
aggregation. The server plugin records each matched route via
res.on('finish') middleware; the reporter flushes one event per
endpoint on a periodic timer. The legacy observability_log
APP_STARTUP is kept as a fallback until the AppkitLog schema is
deployed end-to-end on the telemetry backend.
Errors propagate from the inner senders so consumers can see
exactly what was POSTed and how the endpoint responded; the only
catches live at the SDK's outermost boundaries (fire-and-forget
startup + interval timers).
Adds an Internal Telemetry tab in dev-playground that lets you
trigger each event on demand and renders the request, response,
and an equivalent curl command. Disable with
disableInternalTelemetry: true or APPKIT_TELEMETRY_DISABLED=true.
Also unblocks the pre-commit knip hook by ignoring the @cyclonedx/cdxgen
dependency, which is invoked dynamically via pnpm exec from the
release:sbom script.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* fix(playground): bind DATABRICKS_JOB_ID in app.yaml
The dev-playground registers the jobs() plugin, whose manifest
requires DATABRICKS_JOB_ID, but app.yaml never declared a binding
for it. As a result, deploying the playground to a fresh
Databricks App fails AppKit's startup resource validation with
"Missing required resources: job:Job [jobs]".
Add the missing entry alongside the other resource bindings.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* fix(appkit): use /telemetry-ext and resolve redirect locations
The bare /telemetry endpoint rejects SP bearer tokens and 302s to
/login.html?next_url=..., which the previous code tried to follow
verbatim — but a relative location is not a valid fetch URL and
threw a "Failed to parse URL" error that the legacy try/catch
silently swallowed. Switch the dispatch URL to the SP-friendly
/telemetry-ext endpoint, and harden redirect handling by resolving
the location against the original request URL.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* refactor(appkit): drop legacy observability_log startup telemetry
Now that the AppkitLog dispatch path is verified end-to-end against
/telemetry-ext, the observability_log fallback is no longer needed.
Remove sendStartupTelemetry, the dead StartupTelemetryParams /
buildEntityId / buildLegacyStartupPayload helpers, and the second
fire-and-forget block in createApp's bootstrap. Migrate the sender
test suite to cover sendAppkitLogs (which retains all the URL,
auth, redirect, and error-propagation guarantees) and rewrite the
core internal-telemetry tests against the reporter mock.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* fix(appkit): read app_id from DATABRICKS_CLIENT_ID
Databricks Apps injects DATABRICKS_CLIENT_ID (the app's OAuth
client UUID) into the runtime env, not DATABRICKS_APP_ID, so the
old lookup always resolved to "" and the AppkitLog.app_id field
went out empty. Switch the bootstrap to read DATABRICKS_CLIENT_ID
so logs carry the actual per-app identifier.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* refactor(appkit): rename internal telemetry kill-switch env var
Rename APPKIT_TELEMETRY_DISABLED to DISABLE_APPKIT_INTERNAL_TELEMETRY.
The new name makes it explicit that this controls AppKit's
internal/anonymized telemetry, not the user-facing OpenTelemetry
config exposed via createApp({ telemetry }).
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* refactor(appkit): inline sender.ts into reporter
sender.ts only wrapped postTelemetry with buildAppkitPayload — one
caller, no shared logic worth a dedicated file. Have the reporter's
#send call postTelemetry directly and rename the test file from
sender.test.ts to client.test.ts so the wire-format coverage
(URL, auth, redirects, error propagation) clearly targets
postTelemetry.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* docs: add public internal-telemetry page
Document exactly what AppKit collects (event_name, app_id,
appkit_version, plus per-event bodies for APP_STARTUP, HEARTBEAT,
and REQUEST_METRICS), how it's sent, and the two ways to disable —
disableInternalTelemetry on createApp and the
DISABLE_APPKIT_INTERNAL_TELEMETRY env var. Bump faq.md's sidebar
position to 8 to make room. Add a one-paragraph header in the
package's index.ts pointing at the public doc.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* fix(appkit): harden telemetry dispatch + revert knip cdxgen change
- Refuse cross-origin redirects from /telemetry-ext so the live SP
Authorization header cannot be replayed against a third party.
- Fall back to serviceCtx.client.config.host when DATABRICKS_HOST
is unset so the dispatch URL still resolves correctly when the
SDK was given a pre-configured WorkspaceClient.
- Redact Authorization / Cookie / Set-Cookie when surfacing the
request in the dev-playground debug UI and in the printed curl,
so the sensitive headers don't leak via the response or get
copy-pasted into shared logs.
- Revert the knip.json @cyclonedx/cdxgen exception. Earlier
diagnosis was wrong — the warnings are notices, not errors, and
the original pre-commit failures came from this branch's own
unused exports (now trimmed). With the branch rebased on origin/
main, knip exits 0 against the unmodified config.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* refactor(appkit): hoist redirect body.cancel() out of the branch
Both branches in fetchWithRedirect (cross-origin throw + same-origin
follow) want to release the redirect's response body before moving
on. Run the cancel once after we've parsed the target URL, before
deciding what to do, instead of repeating it on each side.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): drop redirect-follow logic to test endpoint behavior
The /telemetry-ext endpoint may not actually issue redirects in
practice; the follow logic was added defensively. Inline a single
fetch with redirect: "manual" so any 3xx surfaces directly to the
caller (and the dev-playground UI), making it easy to verify
whether the redirect path is exercised on real traffic.
If the deployed app never produces a 3xx response, the helper
function and its tests stay deleted; if it does, restore them.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): drop redirect handling and dev-playground doc section
The /telemetry-ext endpoint does not actually redirect under normal
SP-authenticated traffic, so the redirect-follow logic, the
redirect: "manual" hint on fetch, and the corresponding tests were
all dead weight. Inline a plain fetch and remove the related test.
Also drop the "Inspecting events locally" section from the public
internal-telemetry doc — the dev-playground harness is internal
tooling and isn't relevant to library consumers.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): drop public TelemetryReporter exports + dev-playground debug
The dev-playground debug plugin was the only consumer of
TelemetryReporter, TelemetrySendRequest, TelemetrySendResponse, and
TelemetrySendResult outside the package. Since dev-playground is
internal tooling for AppKit maintainers, exporting infrastructure
types via the public surface only to feed it isn't justified.
Drop:
- TelemetryReporter and the TelemetrySend* types from the public
@databricks/appkit exports
- The TelemetrySend* re-exports from internal-telemetry/index.ts
(no remaining consumer)
- The internal-telemetry-debug plugin and its routes
- The /internal-telemetry route, home-page card, and nav link in
dev-playground
The reporter and types remain available intra-package for the
core/server wiring; nothing about the dispatch behavior changes.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* docs(appkit): rename internal-telemetry page to Privacy + DO_NOT_TRACK
- Rename docs/docs/internal-telemetry.mdx to privacy.mdx so library
consumers don't confuse it with the user-facing OpenTelemetry
config exposed via createApp({ telemetry }).
- Move the page to the bottom of the sidebar (sidebar_position: 99).
- Honor the cross-tool DO_NOT_TRACK=1 convention
(https://consoledonottrack.com) alongside the AppKit-specific
DISABLE_APPKIT_INTERNAL_TELEMETRY env var.
- Document the new opt-out path on the Privacy page and update the
in-source comment that pointed at the old doc location.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): drop .js suffixes from internal-telemetry imports
The project uses moduleResolution: "bundler", which doesn't require
explicit .js extensions on relative imports. The rest of appkit
imports without them; only internal-telemetry/ added them, by
mistake on my part. Strip them to match the surrounding codebase.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* docs(appkit): trim Privacy page
Drop the "we do not send X, Y, Z" paragraph — committing to a
non-collection list ties our hands if the schema later changes.
Also drop the "How it's sent" section; the dispatch endpoint and
fire-and-forget semantics are implementation details users don't
need to track.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(playground): drop appkit.plugins.json
The dev-playground no longer needs the aggregated plugin manifest;
the file is generated by `appkit plugin sync` and isn't read by
any current dev-playground flow.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): send empty bodies for APP_STARTUP and HEARTBEAT
Drop the placeholder: true field from app_startup_event and
heartbeat_event payloads; an empty object is enough to identify
the oneof variant on the wire.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* refactor(appkit): send telemetry via client.apiClient.request
The SDK's apiClient.request already does host resolution,
authentication, query string handling, and User-Agent setting that
client.ts was reimplementing by hand. Drop client.ts (and its
tests), inline a single apiClient.request call inside reporter's
#send, and remove the now-unused workspaceHost from the reporter
constructor.
Tests for the reporter switch to mocking apiClient.request on the
WorkspaceClient mock instead of stubbing global fetch.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* fix(appkit): stop telemetry reporter on graceful shutdown + cover middleware
- Call TelemetryReporter.getInstance()?.stop() in the server
plugin's _gracefulShutdown so heartbeat/metric timers don't keep
firing during the 15s shutdown grace window.
- Export requestMetricsMiddleware as @internal and add unit tests
for the integration point: matched routes, baseUrl + route
template assembly, no-op when req.route is unset, no-op when the
reporter is uninitialized, and 4xx/5xx status pass-through.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore(appkit): remove dead consoledonottrack.com link
Drop the link from the config.ts comment and from the Privacy
page; the URL doesn't resolve. The DO_NOT_TRACK env var stays —
the convention itself is fine, just the canonical site reference
isn't useful.
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
* chore: drop .superset/config.json from gitignore
Co-authored-by: Isaac
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>
---------
Signed-off-by: Jorge Calvar <jorge.calvar@databricks.com>1 parent 9d2920c commit cc942b5
14 files changed
Lines changed: 869 additions & 1 deletion
File tree
- apps/dev-playground
- docs/docs
- api/appkit
- packages/appkit/src
- core
- tests
- internal-telemetry
- tests
- plugins/server
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
8 | 10 | | |
9 | 11 | | |
10 | 12 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
33 | | - | |
| 34 | + | |
34 | 35 | | |
35 | 36 | | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
13 | 18 | | |
14 | 19 | | |
15 | 20 | | |
| |||
191 | 196 | | |
192 | 197 | | |
193 | 198 | | |
| 199 | + | |
194 | 200 | | |
195 | 201 | | |
196 | 202 | | |
| |||
233 | 239 | | |
234 | 240 | | |
235 | 241 | | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
236 | 246 | | |
237 | 247 | | |
238 | 248 | | |
| |||
241 | 251 | | |
242 | 252 | | |
243 | 253 | | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
244 | 266 | | |
245 | 267 | | |
246 | 268 | | |
| |||
300 | 322 | | |
301 | 323 | | |
302 | 324 | | |
| 325 | + | |
303 | 326 | | |
304 | 327 | | |
305 | 328 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
9 | 27 | | |
10 | 28 | | |
11 | 29 | | |
| |||
629 | 647 | | |
630 | 648 | | |
631 | 649 | | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
632 | 704 | | |
633 | 705 | | |
634 | 706 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
0 commit comments