autotel-tanstack 1.13.35 → 1.13.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -5
- package/src/auto.test.ts +0 -114
- package/src/auto.ts +0 -60
- package/src/browser/context.ts +0 -88
- package/src/browser/debug-headers.ts +0 -19
- package/src/browser/error-reporting.ts +0 -64
- package/src/browser/handlers.ts +0 -23
- package/src/browser/index.ts +0 -66
- package/src/browser/loaders.ts +0 -62
- package/src/browser/metrics.ts +0 -86
- package/src/browser/middleware.ts +0 -77
- package/src/browser/server-functions.ts +0 -31
- package/src/browser/testing.ts +0 -130
- package/src/browser/types.ts +0 -100
- package/src/context.test.ts +0 -90
- package/src/context.ts +0 -145
- package/src/debug-headers.ts +0 -109
- package/src/env.ts +0 -56
- package/src/error-reporting.ts +0 -204
- package/src/handlers.ts +0 -306
- package/src/index.ts +0 -97
- package/src/instrument.test.ts +0 -131
- package/src/instrument.ts +0 -97
- package/src/loaders.test.ts +0 -123
- package/src/loaders.ts +0 -356
- package/src/metrics.ts +0 -184
- package/src/middleware.test.ts +0 -198
- package/src/middleware.ts +0 -435
- package/src/route-filter.test.ts +0 -28
- package/src/route-filter.ts +0 -40
- package/src/server-functions.test.ts +0 -86
- package/src/server-functions.ts +0 -188
- package/src/testing.test.ts +0 -205
- package/src/testing.ts +0 -430
- package/src/types.test.ts +0 -46
- package/src/types.ts +0 -182
package/src/error-reporting.ts
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error reporting utilities for TanStack Start
|
|
3
|
-
*
|
|
4
|
-
* Provides basic error reporting without external dependencies,
|
|
5
|
-
* following the patterns from TanStack Start observability guide.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Error report data structure
|
|
10
|
-
*/
|
|
11
|
-
export interface ErrorReport {
|
|
12
|
-
id: string;
|
|
13
|
-
count: number;
|
|
14
|
-
lastSeen: Date;
|
|
15
|
-
error: {
|
|
16
|
-
name: string;
|
|
17
|
-
message: string;
|
|
18
|
-
stack?: string;
|
|
19
|
-
context?: unknown;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Error store for in-memory error tracking
|
|
25
|
-
*
|
|
26
|
-
* Stores error reports with deduplication by error name + message.
|
|
27
|
-
* Thread-safe for concurrent access.
|
|
28
|
-
*/
|
|
29
|
-
class ErrorStore {
|
|
30
|
-
private errors = new Map<string, ErrorReport>();
|
|
31
|
-
private readonly maxErrors = 100; // Limit memory usage
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Report an error
|
|
35
|
-
*/
|
|
36
|
-
reportError(error: Error, context?: unknown): string {
|
|
37
|
-
const key = `${error.name}:${error.message}`;
|
|
38
|
-
const existing = this.errors.get(key);
|
|
39
|
-
|
|
40
|
-
if (existing) {
|
|
41
|
-
existing.count++;
|
|
42
|
-
existing.lastSeen = new Date();
|
|
43
|
-
if (context) {
|
|
44
|
-
// Merge context
|
|
45
|
-
existing.error.context = {
|
|
46
|
-
...(existing.error.context as Record<string, unknown>),
|
|
47
|
-
...(context as Record<string, unknown>),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
return key;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Add new error
|
|
54
|
-
const report: ErrorReport = {
|
|
55
|
-
id: key,
|
|
56
|
-
count: 1,
|
|
57
|
-
lastSeen: new Date(),
|
|
58
|
-
error: {
|
|
59
|
-
name: error.name,
|
|
60
|
-
message: error.message,
|
|
61
|
-
stack: error.stack,
|
|
62
|
-
context,
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
this.errors.set(key, report);
|
|
67
|
-
|
|
68
|
-
// Limit stored errors
|
|
69
|
-
if (this.errors.size > this.maxErrors) {
|
|
70
|
-
// Remove oldest error
|
|
71
|
-
const entries = [...this.errors.entries()];
|
|
72
|
-
const oldest = entries.toSorted(
|
|
73
|
-
(a: [string, ErrorReport], b: [string, ErrorReport]) =>
|
|
74
|
-
a[1].lastSeen.getTime() - b[1].lastSeen.getTime(),
|
|
75
|
-
)[0];
|
|
76
|
-
this.errors.delete(oldest[0]);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Log immediately
|
|
80
|
-
console.error('[ERROR REPORTED]:', {
|
|
81
|
-
error: error.message,
|
|
82
|
-
count: 1,
|
|
83
|
-
context,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
return key;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get all error reports
|
|
91
|
-
*/
|
|
92
|
-
getAllErrors(): ErrorReport[] {
|
|
93
|
-
return [...this.errors.values()];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Get a specific error by ID
|
|
98
|
-
*/
|
|
99
|
-
getError(id: string): ErrorReport | undefined {
|
|
100
|
-
return this.errors.get(id);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Clear all errors
|
|
105
|
-
*/
|
|
106
|
-
clear(): void {
|
|
107
|
-
this.errors.clear();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Clear a specific error
|
|
112
|
-
*/
|
|
113
|
-
clearError(id: string): void {
|
|
114
|
-
this.errors.delete(id);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Global error store instance
|
|
120
|
-
*/
|
|
121
|
-
export const errorStore = new ErrorStore();
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Report an error to the error store
|
|
125
|
-
*
|
|
126
|
-
* @example
|
|
127
|
-
* ```typescript
|
|
128
|
-
* import { reportError } from 'autotel-tanstack/error-reporting';
|
|
129
|
-
*
|
|
130
|
-
* try {
|
|
131
|
-
* await riskyOperation();
|
|
132
|
-
* } catch (error) {
|
|
133
|
-
* reportError(error as Error, {
|
|
134
|
-
* userId: context.userId,
|
|
135
|
-
* operation: 'riskyOperation',
|
|
136
|
-
* });
|
|
137
|
-
* throw error;
|
|
138
|
-
* }
|
|
139
|
-
* ```
|
|
140
|
-
*/
|
|
141
|
-
export function reportError(error: Error, context?: unknown): string {
|
|
142
|
-
return errorStore.reportError(error, context);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Create an error reporting endpoint handler
|
|
147
|
-
*
|
|
148
|
-
* Returns a handler that exposes error reports in JSON format.
|
|
149
|
-
* Use this to create an `/admin/errors` endpoint.
|
|
150
|
-
*
|
|
151
|
-
* @example
|
|
152
|
-
* ```typescript
|
|
153
|
-
* // routes/admin/errors.ts
|
|
154
|
-
* import { createFileRoute } from '@tanstack/react-router';
|
|
155
|
-
* import { json } from '@tanstack/react-start';
|
|
156
|
-
* import { createErrorReportingHandler } from 'autotel-tanstack/error-reporting';
|
|
157
|
-
*
|
|
158
|
-
* export const Route = createFileRoute('/admin/errors')({
|
|
159
|
-
* server: {
|
|
160
|
-
* handlers: {
|
|
161
|
-
* GET: createErrorReportingHandler(),
|
|
162
|
-
* },
|
|
163
|
-
* },
|
|
164
|
-
* });
|
|
165
|
-
* ```
|
|
166
|
-
*/
|
|
167
|
-
export function createErrorReportingHandler() {
|
|
168
|
-
return async () => {
|
|
169
|
-
const { json } = await import('@tanstack/react-start');
|
|
170
|
-
|
|
171
|
-
return json({
|
|
172
|
-
errors: errorStore.getAllErrors(),
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Wrap a function with automatic error reporting
|
|
179
|
-
*
|
|
180
|
-
* Automatically reports errors to the error store.
|
|
181
|
-
*
|
|
182
|
-
* @example
|
|
183
|
-
* ```typescript
|
|
184
|
-
* import { withErrorReporting } from 'autotel-tanstack/error-reporting';
|
|
185
|
-
*
|
|
186
|
-
* const riskyOperation = createServerFn()
|
|
187
|
-
* .handler(withErrorReporting(async () => {
|
|
188
|
-
* return await performOperation();
|
|
189
|
-
* }, { operation: 'riskyOperation' }));
|
|
190
|
-
* ```
|
|
191
|
-
*/
|
|
192
|
-
export function withErrorReporting<TArgs extends unknown[], TReturn>(
|
|
193
|
-
fn: (...args: TArgs) => Promise<TReturn>,
|
|
194
|
-
context?: Record<string, unknown>,
|
|
195
|
-
): (...args: TArgs) => Promise<TReturn> {
|
|
196
|
-
return async (...args: TArgs): Promise<TReturn> => {
|
|
197
|
-
try {
|
|
198
|
-
return await fn(...args);
|
|
199
|
-
} catch (error) {
|
|
200
|
-
reportError(error as Error, context);
|
|
201
|
-
throw error;
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
}
|
package/src/handlers.ts
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { context, SpanStatusCode } from '@opentelemetry/api';
|
|
2
|
-
import { trace, init, type TraceContext } from 'autotel';
|
|
3
|
-
import { extractContextFromRequest } from './context';
|
|
4
|
-
import { isExcludedPath } from './route-filter';
|
|
5
|
-
import {
|
|
6
|
-
type WrapStartHandlerConfig,
|
|
7
|
-
DEFAULT_CONFIG,
|
|
8
|
-
SPAN_ATTRIBUTES,
|
|
9
|
-
} from './types';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Request handler type (compatible with TanStack Start handlers)
|
|
13
|
-
*/
|
|
14
|
-
type RequestHandler = (
|
|
15
|
-
request: Request,
|
|
16
|
-
opts?: { context?: Record<string, unknown> },
|
|
17
|
-
) => Promise<Response> | Response;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Wrap a TanStack Start handler with OpenTelemetry tracing
|
|
21
|
-
*
|
|
22
|
-
* This function wraps the entire request handler to automatically create
|
|
23
|
-
* spans for all incoming requests. It initializes OpenTelemetry and
|
|
24
|
-
* provides comprehensive request tracing.
|
|
25
|
-
*
|
|
26
|
-
* @param config - Configuration options including OTLP endpoint and headers
|
|
27
|
-
* @returns Function that wraps a request handler
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // server.ts
|
|
32
|
-
* import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server';
|
|
33
|
-
* import { wrapStartHandler } from 'autotel-tanstack/handlers';
|
|
34
|
-
*
|
|
35
|
-
* export default wrapStartHandler({
|
|
36
|
-
* service: 'my-app',
|
|
37
|
-
* endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
38
|
-
* headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
|
|
39
|
-
* })(createStartHandler(defaultStreamHandler));
|
|
40
|
-
* ```
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```typescript
|
|
44
|
-
* // With env var configuration (recommended for production)
|
|
45
|
-
* // Set OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS
|
|
46
|
-
* export default wrapStartHandler()(createStartHandler(defaultStreamHandler));
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
export function wrapStartHandler(
|
|
50
|
-
config: WrapStartHandlerConfig = {},
|
|
51
|
-
): (handler: RequestHandler) => RequestHandler {
|
|
52
|
-
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
53
|
-
|
|
54
|
-
// Initialize autotel with provided configuration
|
|
55
|
-
const service =
|
|
56
|
-
config.service || process.env.OTEL_SERVICE_NAME || 'tanstack-start';
|
|
57
|
-
const endpoint = config.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
58
|
-
|
|
59
|
-
// Parse headers from env if not provided
|
|
60
|
-
let headers = config.headers;
|
|
61
|
-
if (!headers && process.env.OTEL_EXPORTER_OTLP_HEADERS) {
|
|
62
|
-
headers = {};
|
|
63
|
-
const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(',');
|
|
64
|
-
for (const pair of pairs) {
|
|
65
|
-
const [key, value] = pair.split('=');
|
|
66
|
-
if (key && value) {
|
|
67
|
-
headers[key.trim()] = value.trim();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Initialize OpenTelemetry
|
|
73
|
-
init({
|
|
74
|
-
service,
|
|
75
|
-
endpoint,
|
|
76
|
-
headers,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return function wrapHandler(handler: RequestHandler): RequestHandler {
|
|
80
|
-
return async function tracedHandler(
|
|
81
|
-
request: Request,
|
|
82
|
-
opts?: { context?: Record<string, unknown> },
|
|
83
|
-
): Promise<Response> {
|
|
84
|
-
const url = new URL(request.url);
|
|
85
|
-
|
|
86
|
-
// Check if path should be excluded
|
|
87
|
-
if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {
|
|
88
|
-
return handler(request, opts);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Extract parent context from request headers
|
|
92
|
-
const parentContext = extractContextFromRequest(request);
|
|
93
|
-
|
|
94
|
-
// Run within parent context
|
|
95
|
-
return context.with(parentContext, async () => {
|
|
96
|
-
const spanName = `${request.method} ${url.pathname}`;
|
|
97
|
-
|
|
98
|
-
return trace(spanName, async (ctx: TraceContext) => {
|
|
99
|
-
// Set HTTP semantic attributes
|
|
100
|
-
ctx.setAttributes({
|
|
101
|
-
[SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
|
|
102
|
-
[SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
|
|
103
|
-
[SPAN_ATTRIBUTES.URL_FULL]: request.url,
|
|
104
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'request',
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
if (url.search) {
|
|
108
|
-
ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Capture configured headers
|
|
112
|
-
if (mergedConfig.captureHeaders) {
|
|
113
|
-
for (const header of mergedConfig.captureHeaders) {
|
|
114
|
-
const value = request.headers.get(header);
|
|
115
|
-
if (value) {
|
|
116
|
-
ctx.setAttribute(
|
|
117
|
-
`http.request.header.${header.toLowerCase()}`,
|
|
118
|
-
value,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Add custom attributes
|
|
125
|
-
if (config.customAttributes) {
|
|
126
|
-
const customAttrs = config.customAttributes({
|
|
127
|
-
type: 'request',
|
|
128
|
-
name: spanName,
|
|
129
|
-
request,
|
|
130
|
-
});
|
|
131
|
-
ctx.setAttributes(
|
|
132
|
-
customAttrs as Record<string, string | number | boolean>,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const startTime = Date.now();
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
const response = await handler(request, opts);
|
|
140
|
-
const duration = Date.now() - startTime;
|
|
141
|
-
|
|
142
|
-
ctx.setAttribute(
|
|
143
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
144
|
-
duration,
|
|
145
|
-
);
|
|
146
|
-
ctx.setAttribute(
|
|
147
|
-
SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,
|
|
148
|
-
response.status,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
// Set status based on HTTP status code
|
|
152
|
-
if (response.status >= 400) {
|
|
153
|
-
ctx.setStatus({
|
|
154
|
-
code: SpanStatusCode.ERROR,
|
|
155
|
-
message: `HTTP ${response.status}`,
|
|
156
|
-
});
|
|
157
|
-
} else {
|
|
158
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return response;
|
|
162
|
-
} catch (error) {
|
|
163
|
-
const duration = Date.now() - startTime;
|
|
164
|
-
ctx.setAttribute(
|
|
165
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
166
|
-
duration,
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
if (mergedConfig.captureErrors) {
|
|
170
|
-
ctx.recordError(error);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
throw error;
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
};
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Create a traced handler without auto-initialization
|
|
183
|
-
*
|
|
184
|
-
* Use this when you want to initialize autotel separately
|
|
185
|
-
* (e.g., with more advanced configuration).
|
|
186
|
-
*
|
|
187
|
-
* @param config - Configuration options (excluding endpoint/headers)
|
|
188
|
-
* @returns Function that wraps a request handler
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```typescript
|
|
192
|
-
* import { init } from 'autotel';
|
|
193
|
-
* import { createTracedHandler } from 'autotel-tanstack/handlers';
|
|
194
|
-
*
|
|
195
|
-
* // Initialize autotel with custom configuration
|
|
196
|
-
* init({
|
|
197
|
-
* service: 'my-app',
|
|
198
|
-
* endpoint: 'https://api.honeycomb.io',
|
|
199
|
-
* instrumentations: [/* custom instrumentations *\/],
|
|
200
|
-
* });
|
|
201
|
-
*
|
|
202
|
-
* // Wrap handler without re-initializing
|
|
203
|
-
* export default createTracedHandler({
|
|
204
|
-
* captureHeaders: ['x-request-id'],
|
|
205
|
-
* })(createStartHandler(defaultStreamHandler));
|
|
206
|
-
* ```
|
|
207
|
-
*/
|
|
208
|
-
export function createTracedHandler(
|
|
209
|
-
config: Omit<WrapStartHandlerConfig, 'endpoint' | 'headers' | 'service'> = {},
|
|
210
|
-
): (handler: RequestHandler) => RequestHandler {
|
|
211
|
-
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
212
|
-
|
|
213
|
-
return function wrapHandler(handler: RequestHandler): RequestHandler {
|
|
214
|
-
return async function tracedHandler(
|
|
215
|
-
request: Request,
|
|
216
|
-
opts?: { context?: Record<string, unknown> },
|
|
217
|
-
): Promise<Response> {
|
|
218
|
-
const url = new URL(request.url);
|
|
219
|
-
|
|
220
|
-
// Check if path should be excluded
|
|
221
|
-
if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {
|
|
222
|
-
return handler(request, opts);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const parentContext = extractContextFromRequest(request);
|
|
226
|
-
|
|
227
|
-
return context.with(parentContext, async () => {
|
|
228
|
-
const spanName = `${request.method} ${url.pathname}`;
|
|
229
|
-
|
|
230
|
-
return trace(spanName, async (ctx: TraceContext) => {
|
|
231
|
-
ctx.setAttributes({
|
|
232
|
-
[SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
|
|
233
|
-
[SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
|
|
234
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'request',
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
if (url.search) {
|
|
238
|
-
ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (mergedConfig.captureHeaders) {
|
|
242
|
-
for (const header of mergedConfig.captureHeaders) {
|
|
243
|
-
const value = request.headers.get(header);
|
|
244
|
-
if (value) {
|
|
245
|
-
ctx.setAttribute(
|
|
246
|
-
`http.request.header.${header.toLowerCase()}`,
|
|
247
|
-
value,
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (config.customAttributes) {
|
|
254
|
-
const customAttrs = config.customAttributes({
|
|
255
|
-
type: 'request',
|
|
256
|
-
name: spanName,
|
|
257
|
-
request,
|
|
258
|
-
});
|
|
259
|
-
ctx.setAttributes(
|
|
260
|
-
customAttrs as Record<string, string | number | boolean>,
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const startTime = Date.now();
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
const response = await handler(request, opts);
|
|
268
|
-
const duration = Date.now() - startTime;
|
|
269
|
-
|
|
270
|
-
ctx.setAttribute(
|
|
271
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
272
|
-
duration,
|
|
273
|
-
);
|
|
274
|
-
ctx.setAttribute(
|
|
275
|
-
SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,
|
|
276
|
-
response.status,
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
if (response.status >= 400) {
|
|
280
|
-
ctx.setStatus({
|
|
281
|
-
code: SpanStatusCode.ERROR,
|
|
282
|
-
message: `HTTP ${response.status}`,
|
|
283
|
-
});
|
|
284
|
-
} else {
|
|
285
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return response;
|
|
289
|
-
} catch (error) {
|
|
290
|
-
const duration = Date.now() - startTime;
|
|
291
|
-
ctx.setAttribute(
|
|
292
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
293
|
-
duration,
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
if (mergedConfig.captureErrors) {
|
|
297
|
-
ctx.recordError(error);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
throw error;
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
};
|
|
305
|
-
};
|
|
306
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* autotel-tanstack
|
|
3
|
-
*
|
|
4
|
-
* OpenTelemetry instrumentation for TanStack Start applications.
|
|
5
|
-
* Provides automatic tracing for server functions, middleware, and route loaders.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* // Quick start with middleware
|
|
10
|
-
* import { createStart } from '@tanstack/react-start';
|
|
11
|
-
* import { tracingMiddleware } from 'autotel-tanstack';
|
|
12
|
-
*
|
|
13
|
-
* export const startInstance = createStart(() => ({
|
|
14
|
-
* requestMiddleware: [tracingMiddleware()],
|
|
15
|
-
* }));
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```typescript
|
|
20
|
-
* // Zero-config auto-init
|
|
21
|
-
* import 'autotel-tanstack/auto';
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* @packageDocumentation
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
// Types
|
|
28
|
-
export type {
|
|
29
|
-
TanStackInstrumentationConfig,
|
|
30
|
-
TracingMiddlewareConfig,
|
|
31
|
-
TraceServerFnConfig,
|
|
32
|
-
TraceLoaderConfig,
|
|
33
|
-
WrapStartHandlerConfig,
|
|
34
|
-
} from './types';
|
|
35
|
-
export { DEFAULT_CONFIG, SPAN_ATTRIBUTES } from './types';
|
|
36
|
-
|
|
37
|
-
// Middleware
|
|
38
|
-
export {
|
|
39
|
-
createTracingMiddleware,
|
|
40
|
-
tracingMiddleware,
|
|
41
|
-
functionTracingMiddleware,
|
|
42
|
-
createTracingServerHandler,
|
|
43
|
-
type MiddlewareHandler,
|
|
44
|
-
} from './middleware';
|
|
45
|
-
|
|
46
|
-
// Server Functions
|
|
47
|
-
export { traceServerFn, createTracedServerFnFactory } from './server-functions';
|
|
48
|
-
|
|
49
|
-
// Loaders
|
|
50
|
-
export { traceLoader, traceBeforeLoad, createTracedRoute } from './loaders';
|
|
51
|
-
|
|
52
|
-
// Handlers
|
|
53
|
-
export { wrapStartHandler, createTracedHandler } from './handlers';
|
|
54
|
-
|
|
55
|
-
// Context
|
|
56
|
-
export {
|
|
57
|
-
extractContextFromRequest,
|
|
58
|
-
injectContextToHeaders,
|
|
59
|
-
createTracedHeaders,
|
|
60
|
-
runInContext,
|
|
61
|
-
getActiveContext,
|
|
62
|
-
} from './context';
|
|
63
|
-
|
|
64
|
-
// Debug Headers
|
|
65
|
-
export {
|
|
66
|
-
debugHeadersMiddleware,
|
|
67
|
-
type DebugHeadersConfig,
|
|
68
|
-
} from './debug-headers';
|
|
69
|
-
|
|
70
|
-
// Metrics
|
|
71
|
-
export {
|
|
72
|
-
metricsCollector,
|
|
73
|
-
createMetricsHandler,
|
|
74
|
-
recordTiming,
|
|
75
|
-
type TimingStats,
|
|
76
|
-
} from './metrics';
|
|
77
|
-
|
|
78
|
-
// Error Reporting
|
|
79
|
-
export {
|
|
80
|
-
errorStore,
|
|
81
|
-
reportError,
|
|
82
|
-
createErrorReportingHandler,
|
|
83
|
-
withErrorReporting,
|
|
84
|
-
type ErrorReport,
|
|
85
|
-
} from './error-reporting';
|
|
86
|
-
|
|
87
|
-
// Configurable TanStack Start tracing setup (the configurable form of the
|
|
88
|
-
// zero-config `autotel-tanstack/auto` import).
|
|
89
|
-
export { instrument, type InstrumentOptions } from './instrument';
|
|
90
|
-
|
|
91
|
-
// Re-export autotel core utilities for convenience
|
|
92
|
-
// Note: These should only be used on the server side
|
|
93
|
-
// They use Node.js APIs (AsyncLocalStorage) that don't exist in the browser
|
|
94
|
-
export { trace, span, init, shutdown, flush } from 'autotel';
|
|
95
|
-
|
|
96
|
-
// Export environment utilities
|
|
97
|
-
export { isBrowser, isNode, isServerSide } from './env';
|