Skip to content

Commit 2e792d2

Browse files
authored
feat: inject config from server (#27)
1 parent 09c73e2 commit 2e792d2

File tree

15 files changed

+296
-179
lines changed

15 files changed

+296
-179
lines changed

apps/dev-playground/client/vite.config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import path from "node:path";
2-
import { appKitTypesPlugin } from "@databricks/app-kit";
32
import { tanstackRouter } from "@tanstack/router-plugin/vite";
43
import react from "@vitejs/plugin-react";
54
import { defineConfig } from "vite";
@@ -8,7 +7,6 @@ import { defineConfig } from "vite";
87
export default defineConfig({
98
plugins: [
109
react(),
11-
appKitTypesPlugin(),
1210
tanstackRouter({
1311
target: "react",
1412
autoCodeSplitting: process.env.NODE_ENV !== "development",

apps/dev-playground/server/reconnect-plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class ReconnectPlugin extends Plugin {
1919

2020
injectRoutes(router: IAppRouter): void {
2121
this.route<ReconnectResponse>(router, {
22+
name: "reconnect",
2223
method: "get",
2324
path: "/",
2425
handler: async (_req, res) => {
@@ -27,6 +28,7 @@ export class ReconnectPlugin extends Plugin {
2728
});
2829

2930
this.route<ReconnectStreamResponse>(router, {
31+
name: "stream",
3032
method: "get",
3133
path: "/stream",
3234
handler: async (req, res) => {

apps/dev-playground/server/telemetry-example-plugin.ts

Lines changed: 118 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -41,118 +41,125 @@ class TelemetryExamples extends Plugin {
4141
}
4242

4343
private registerTelemetryExampleRoutes(router: Router) {
44-
router.post("/combined", async (req: Request, res: Response) => {
45-
const startTime = Date.now();
46-
47-
return this.telemetry.startActiveSpan(
48-
"combined-example",
49-
{
50-
attributes: {
51-
"example.type": "combined",
52-
"example.version": "v2",
44+
this.route(router, {
45+
name: "combined",
46+
method: "post",
47+
path: "/combined",
48+
handler: async (req: Request, res: Response) => {
49+
const startTime = Date.now();
50+
51+
return this.telemetry.startActiveSpan(
52+
"combined-example",
53+
{
54+
attributes: {
55+
"example.type": "combined",
56+
"example.version": "v2",
57+
},
5358
},
54-
},
55-
async (span: Span) => {
56-
try {
57-
const userId =
58-
req.body?.userId || req.query.userId || "demo-user-123";
59-
60-
this.telemetry.emit({
61-
severityNumber: SeverityNumber.INFO,
62-
severityText: "INFO",
63-
body: "Processing telemetry example request",
64-
attributes: {
65-
"user.id": userId,
66-
"request.type": "combined-example",
67-
},
68-
});
69-
70-
const result = await this.complexOperation(userId);
71-
72-
const duration = Date.now() - startTime;
73-
this.requestCounter.add(1, { status: "success" });
74-
this.durationHistogram.record(duration);
75-
76-
this.telemetry.emit({
77-
severityNumber: SeverityNumber.INFO,
78-
severityText: "INFO",
79-
body: "Request completed successfully",
80-
attributes: {
81-
"user.id": userId,
82-
"duration.ms": duration,
83-
"result.fields": Object.keys(result).length,
84-
},
85-
});
86-
87-
span.setStatus({ code: SpanStatusCode.OK });
88-
89-
res.json({
90-
success: true,
91-
result,
92-
duration_ms: duration,
93-
tracing: {
94-
hint: "Open Grafana at http://localhost:3000",
95-
services: [
96-
"app-template (main service)",
97-
"user-operations (complex operation)",
98-
"auth-validation (user validation)",
99-
"data-access (database operations - with cache!)",
100-
"auth-service (permissions)",
101-
"external-api (external HTTP calls)",
102-
"data-processing (transformation)",
103-
],
104-
expectedSpans: [
105-
"HTTP POST (SDK auto-instrumentation)",
106-
"combined-example (custom tracer: custom-telemetry-example)",
107-
" └─ complex-operation (custom tracer: user-operations)",
108-
" ├─ validate-user (100ms, custom tracer: auth-validation)",
109-
" ├─ fetch-user-data (200ms first call / cached on repeat, custom tracer: data-access) [parallel]",
110-
" │ └─ cache.hit attribute set by SDK (false on first call, true on repeat)",
111-
" ├─ fetch-external-resource (custom tracer: external-api) [parallel]",
112-
" │ └─ HTTP GET https://example.com (SDK auto-instrumentation)",
113-
" ├─ fetch-permissions (150ms, custom tracer: auth-service) [parallel]",
114-
" └─ transform-data (80ms, custom tracer: data-processing)",
115-
],
116-
},
117-
metrics: {
118-
recorded: ["app.requests.total", "app.request.duration"],
119-
},
120-
logs: {
121-
emitted: [
122-
"Starting complex operation workflow",
123-
"Data fetching completed successfully",
124-
"Data transformation completed",
125-
"Permissions retrieved",
126-
"External API call completed",
127-
],
128-
},
129-
});
130-
} catch (error) {
131-
span.recordException(error as Error);
132-
span.setStatus({ code: SpanStatusCode.ERROR });
133-
this.requestCounter.add(1, { status: "error" });
134-
135-
this.telemetry.emit({
136-
severityNumber: SeverityNumber.ERROR,
137-
severityText: "ERROR",
138-
body: error instanceof Error ? error.message : "Unknown error",
139-
attributes: {
140-
"error.type": error instanceof Error ? error.name : "Unknown",
141-
"error.stack": error instanceof Error ? error.stack : undefined,
142-
"request.path": req.path,
143-
},
144-
});
145-
146-
res.status(500).json({
147-
error: true,
148-
message: error instanceof Error ? error.message : "Unknown error",
149-
});
150-
} finally {
151-
span.end();
152-
}
153-
},
154-
{ name: "custom-telemetry-example" },
155-
);
59+
async (span: Span) => {
60+
try {
61+
const userId =
62+
req.body?.userId || req.query.userId || "demo-user-123";
63+
64+
this.telemetry.emit({
65+
severityNumber: SeverityNumber.INFO,
66+
severityText: "INFO",
67+
body: "Processing telemetry example request",
68+
attributes: {
69+
"user.id": userId,
70+
"request.type": "combined-example",
71+
},
72+
});
73+
74+
const result = await this.complexOperation(userId);
75+
76+
const duration = Date.now() - startTime;
77+
this.requestCounter.add(1, { status: "success" });
78+
this.durationHistogram.record(duration);
79+
80+
this.telemetry.emit({
81+
severityNumber: SeverityNumber.INFO,
82+
severityText: "INFO",
83+
body: "Request completed successfully",
84+
attributes: {
85+
"user.id": userId,
86+
"duration.ms": duration,
87+
"result.fields": Object.keys(result).length,
88+
},
89+
});
90+
91+
span.setStatus({ code: SpanStatusCode.OK });
92+
93+
res.json({
94+
success: true,
95+
result,
96+
duration_ms: duration,
97+
tracing: {
98+
hint: "Open Grafana at http://localhost:3000",
99+
services: [
100+
"app-template (main service)",
101+
"user-operations (complex operation)",
102+
"auth-validation (user validation)",
103+
"data-access (database operations - with cache!)",
104+
"auth-service (permissions)",
105+
"external-api (external HTTP calls)",
106+
"data-processing (transformation)",
107+
],
108+
expectedSpans: [
109+
"HTTP POST (SDK auto-instrumentation)",
110+
"combined-example (custom tracer: custom-telemetry-example)",
111+
" └─ complex-operation (custom tracer: user-operations)",
112+
" ├─ validate-user (100ms, custom tracer: auth-validation)",
113+
" ├─ fetch-user-data (200ms first call / cached on repeat, custom tracer: data-access) [parallel]",
114+
" │ └─ cache.hit attribute set by SDK (false on first call, true on repeat)",
115+
" ├─ fetch-external-resource (custom tracer: external-api) [parallel]",
116+
" │ └─ HTTP GET https://example.com (SDK auto-instrumentation)",
117+
" ├─ fetch-permissions (150ms, custom tracer: auth-service) [parallel]",
118+
" └─ transform-data (80ms, custom tracer: data-processing)",
119+
],
120+
},
121+
metrics: {
122+
recorded: ["app.requests.total", "app.request.duration"],
123+
},
124+
logs: {
125+
emitted: [
126+
"Starting complex operation workflow",
127+
"Data fetching completed successfully",
128+
"Data transformation completed",
129+
"Permissions retrieved",
130+
"External API call completed",
131+
],
132+
},
133+
});
134+
} catch (error) {
135+
span.recordException(error as Error);
136+
span.setStatus({ code: SpanStatusCode.ERROR });
137+
this.requestCounter.add(1, { status: "error" });
138+
139+
this.telemetry.emit({
140+
severityNumber: SeverityNumber.ERROR,
141+
severityText: "ERROR",
142+
body: error instanceof Error ? error.message : "Unknown error",
143+
attributes: {
144+
"error.type": error instanceof Error ? error.name : "Unknown",
145+
"error.stack":
146+
error instanceof Error ? error.stack : undefined,
147+
"request.path": req.path,
148+
},
149+
});
150+
151+
res.status(500).json({
152+
error: true,
153+
message:
154+
error instanceof Error ? error.message : "Unknown error",
155+
});
156+
} finally {
157+
span.end();
158+
}
159+
},
160+
{ name: "custom-telemetry-example" },
161+
);
162+
},
156163
});
157164
}
158165

packages/app-kit/src/analytics/analytics.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class AnalyticsPlugin extends Plugin {
4242

4343
injectRoutes(router: IAppRouter) {
4444
this.route(router, {
45+
name: "arrow",
4546
method: "get",
4647
path: "/arrow-result/:jobId",
4748
handler: async (req: Request, res: Response) => {
@@ -50,6 +51,7 @@ export class AnalyticsPlugin extends Plugin {
5051
});
5152

5253
this.route(router, {
54+
name: "arrowAsUser",
5355
method: "get",
5456
path: "/users/me/arrow-result/:jobId",
5557
handler: async (req: Request, res: Response) => {
@@ -58,6 +60,7 @@ export class AnalyticsPlugin extends Plugin {
5860
});
5961

6062
this.route<AnalyticsQueryResponse>(router, {
63+
name: "queryAsUser",
6164
method: "post",
6265
path: "/users/me/query/:query_key",
6366
handler: async (req: Request, res: Response) => {
@@ -66,6 +69,7 @@ export class AnalyticsPlugin extends Plugin {
6669
});
6770

6871
this.route<AnalyticsQueryResponse>(router, {
72+
name: "query",
6973
method: "post",
7074
path: "/query/:query_key",
7175
handler: async (req: Request, res: Response) => {

packages/app-kit/src/core/tests/databricks.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class CoreTestPlugin implements BasePlugin {
5353
asUser() {
5454
return this;
5555
}
56+
57+
getEndpoints() {
58+
return {};
59+
}
5660
}
5761

5862
class NormalTestPlugin implements BasePlugin {
@@ -80,6 +84,10 @@ class NormalTestPlugin implements BasePlugin {
8084
asUser() {
8185
return this;
8286
}
87+
88+
getEndpoints() {
89+
return {};
90+
}
8391
}
8492

8593
class DeferredTestPlugin implements BasePlugin {
@@ -109,6 +117,10 @@ class DeferredTestPlugin implements BasePlugin {
109117
asUser(): any {
110118
return this;
111119
}
120+
121+
getEndpoints() {
122+
return {};
123+
}
112124
}
113125

114126
class SlowSetupPlugin implements BasePlugin {
@@ -133,6 +145,10 @@ class SlowSetupPlugin implements BasePlugin {
133145
asUser(): any {
134146
return this;
135147
}
148+
149+
getEndpoints() {
150+
return {};
151+
}
136152
}
137153

138154
class FailingPlugin implements BasePlugin {
@@ -152,6 +168,10 @@ class FailingPlugin implements BasePlugin {
152168
asUser(): any {
153169
return this;
154170
}
171+
172+
getEndpoints() {
173+
return {};
174+
}
155175
}
156176

157177
describe("AppKit", () => {

0 commit comments

Comments
 (0)