@astroscope/opentelemetry 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -74,7 +74,7 @@ Note, since this integration creates spans directly, you don't need to
74
74
  // astro.config.ts
75
75
  import { defineConfig } from "astro/config";
76
76
  import boot from "@astroscope/boot";
77
- import { opentelemetry } from "@astroscope/opentelemetry";
77
+ import opentelemetry from "@astroscope/opentelemetry";
78
78
 
79
79
  export default defineConfig({
80
80
  integrations: [opentelemetry(), boot()], // opentelemetry() should come as early as possible in the list
@@ -336,10 +336,8 @@ exclude: [
336
336
  | `STATIC_EXCLUDES` | Common static files (`/assets/`, `/favicon.ico`, etc.) |
337
337
 
338
338
  ```ts
339
- import {
340
- opentelemetry,
341
- RECOMMENDED_EXCLUDES,
342
- } from "@astroscope/opentelemetry";
339
+ import opentelemetry from "@astroscope/opentelemetry";
340
+ import { RECOMMENDED_EXCLUDES } from "@astroscope/excludes";
343
341
 
344
342
  opentelemetry({
345
343
  instrumentations: {
@@ -0,0 +1,77 @@
1
+ import {
2
+ recordFetchRequestDuration
3
+ } from "./chunk-JU6FJKLT.js";
4
+
5
+ // src/fetch.ts
6
+ import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
+ var LIB_NAME = "@astroscope/opentelemetry";
8
+ function instrumentFetch() {
9
+ const originalFetch = globalThis.fetch;
10
+ async function instrumentedFetch(input, init) {
11
+ const tracer = trace.getTracer(LIB_NAME);
12
+ const activeContext = context.active();
13
+ const request = new Request(input, init);
14
+ const url = new URL(request.url);
15
+ const span = tracer.startSpan(
16
+ `FETCH ${request.method}`,
17
+ {
18
+ kind: SpanKind.CLIENT,
19
+ attributes: {
20
+ "http.request.method": request.method,
21
+ "url.full": request.url,
22
+ "url.path": url.pathname,
23
+ "url.scheme": url.protocol.replace(":", ""),
24
+ "server.address": url.hostname,
25
+ "server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80
26
+ }
27
+ },
28
+ activeContext
29
+ );
30
+ const headers = new Headers(request.headers);
31
+ const carrier = {};
32
+ propagation.inject(trace.setSpan(activeContext, span), carrier);
33
+ for (const [key, value] of Object.entries(carrier)) {
34
+ headers.set(key, value);
35
+ }
36
+ const startTime = performance.now();
37
+ try {
38
+ const response = await originalFetch(request.url, {
39
+ ...init,
40
+ method: request.method,
41
+ headers,
42
+ body: request.body
43
+ });
44
+ span.setAttribute("http.response.status_code", response.status);
45
+ if (response.status >= 400) {
46
+ span.setStatus({
47
+ code: SpanStatusCode.ERROR,
48
+ message: `HTTP ${response.status}`
49
+ });
50
+ } else {
51
+ span.setStatus({ code: SpanStatusCode.OK });
52
+ }
53
+ span.end();
54
+ recordFetchRequestDuration(
55
+ { method: request.method, host: url.hostname, status: response.status },
56
+ performance.now() - startTime
57
+ );
58
+ return response;
59
+ } catch (error) {
60
+ span.setStatus({
61
+ code: SpanStatusCode.ERROR,
62
+ message: error instanceof Error ? error.message : "Unknown error"
63
+ });
64
+ span.end();
65
+ recordFetchRequestDuration(
66
+ { method: request.method, host: url.hostname, status: 0 },
67
+ performance.now() - startTime
68
+ );
69
+ throw error;
70
+ }
71
+ }
72
+ globalThis.fetch = Object.assign(instrumentedFetch, originalFetch);
73
+ }
74
+
75
+ export {
76
+ instrumentFetch
77
+ };
@@ -0,0 +1,90 @@
1
+ // src/metrics.ts
2
+ import { ValueType, metrics } from "@opentelemetry/api";
3
+ var LIB_NAME = "@astroscope/opentelemetry";
4
+ var httpRequestDuration = null;
5
+ var httpActiveRequests = null;
6
+ var fetchRequestDuration = null;
7
+ var actionDuration = null;
8
+ function getHttpRequestDuration() {
9
+ if (!httpRequestDuration) {
10
+ const meter = metrics.getMeter(LIB_NAME);
11
+ httpRequestDuration = meter.createHistogram("http.server.request.duration", {
12
+ description: "Duration of HTTP server requests",
13
+ unit: "s",
14
+ valueType: ValueType.DOUBLE
15
+ });
16
+ }
17
+ return httpRequestDuration;
18
+ }
19
+ function getHttpActiveRequests() {
20
+ if (!httpActiveRequests) {
21
+ const meter = metrics.getMeter(LIB_NAME);
22
+ httpActiveRequests = meter.createUpDownCounter("http.server.active_requests", {
23
+ description: "Number of active HTTP server requests",
24
+ unit: "{request}",
25
+ valueType: ValueType.INT
26
+ });
27
+ }
28
+ return httpActiveRequests;
29
+ }
30
+ function getFetchRequestDuration() {
31
+ if (!fetchRequestDuration) {
32
+ const meter = metrics.getMeter(LIB_NAME);
33
+ fetchRequestDuration = meter.createHistogram("http.client.request.duration", {
34
+ description: "Duration of HTTP client requests (fetch)",
35
+ unit: "s",
36
+ valueType: ValueType.DOUBLE
37
+ });
38
+ }
39
+ return fetchRequestDuration;
40
+ }
41
+ function getActionDuration() {
42
+ if (!actionDuration) {
43
+ const meter = metrics.getMeter(LIB_NAME);
44
+ actionDuration = meter.createHistogram("astro.action.duration", {
45
+ description: "Duration of Astro action executions",
46
+ unit: "s",
47
+ valueType: ValueType.DOUBLE
48
+ });
49
+ }
50
+ return actionDuration;
51
+ }
52
+ function recordHttpRequestStart(attributes) {
53
+ getHttpActiveRequests().add(1, {
54
+ "http.request.method": attributes.method,
55
+ "http.route": attributes.route
56
+ });
57
+ return () => {
58
+ getHttpActiveRequests().add(-1, {
59
+ "http.request.method": attributes.method,
60
+ "http.route": attributes.route
61
+ });
62
+ };
63
+ }
64
+ function recordHttpRequestDuration(attributes, durationMs) {
65
+ getHttpRequestDuration().record(durationMs / 1e3, {
66
+ "http.request.method": attributes.method,
67
+ "http.route": attributes.route,
68
+ "http.response.status_code": attributes.status
69
+ });
70
+ }
71
+ function recordFetchRequestDuration(attributes, durationMs) {
72
+ getFetchRequestDuration().record(durationMs / 1e3, {
73
+ "http.request.method": attributes.method,
74
+ "server.address": attributes.host,
75
+ "http.response.status_code": attributes.status
76
+ });
77
+ }
78
+ function recordActionDuration(attributes, durationMs) {
79
+ getActionDuration().record(durationMs / 1e3, {
80
+ "astro.action.name": attributes.name,
81
+ "http.response.status_code": attributes.status
82
+ });
83
+ }
84
+
85
+ export {
86
+ recordHttpRequestStart,
87
+ recordHttpRequestDuration,
88
+ recordFetchRequestDuration,
89
+ recordActionDuration
90
+ };
@@ -0,0 +1,115 @@
1
+ import {
2
+ recordActionDuration,
3
+ recordHttpRequestDuration,
4
+ recordHttpRequestStart
5
+ } from "./chunk-JU6FJKLT.js";
6
+
7
+ // src/middleware.ts
8
+ import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
9
+ import { RPCType, setRPCMetadata } from "@opentelemetry/core";
10
+ import { shouldExclude } from "@astroscope/excludes";
11
+ var LIB_NAME = "@astroscope/opentelemetry";
12
+ var ACTIONS_PREFIX = "/_actions/";
13
+ function getClientIp(request) {
14
+ return request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? request.headers.get("x-real-ip") ?? request.headers.get("cf-connecting-ip") ?? // no native ip address access in Astro available
15
+ void 0;
16
+ }
17
+ function createOpenTelemetryMiddleware(options = {}) {
18
+ const tracer = trace.getTracer(LIB_NAME);
19
+ return async (ctx, next) => {
20
+ if (shouldExclude(ctx, options.exclude)) {
21
+ return next();
22
+ }
23
+ const startTime = performance.now();
24
+ const { request, url } = ctx;
25
+ const input = { traceparent: request.headers.get("traceparent"), tracestate: request.headers.get("tracestate") };
26
+ const parentContext = propagation.extract(context.active(), input);
27
+ const contentLength = request.headers.get("content-length");
28
+ const clientIp = getClientIp(request);
29
+ const spanOptions = {
30
+ attributes: {
31
+ "http.request.method": request.method,
32
+ "url.full": request.url,
33
+ "url.path": url.pathname,
34
+ "url.query": url.search.slice(1),
35
+ "url.scheme": url.protocol.replace(":", ""),
36
+ "server.address": url.hostname,
37
+ "server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80,
38
+ "user_agent.original": request.headers.get("user-agent") ?? "",
39
+ ...contentLength && { "http.request.body.size": parseInt(contentLength) },
40
+ ...clientIp && { "client.address": clientIp }
41
+ },
42
+ kind: SpanKind.SERVER
43
+ };
44
+ const isAction = url.pathname.startsWith(ACTIONS_PREFIX);
45
+ const actionName = url.pathname.slice(ACTIONS_PREFIX.length).replace(/\/$/, "");
46
+ const spanName = isAction ? `ACTION ${actionName}` : `${request.method} ${url.pathname}`;
47
+ const span = tracer.startSpan(spanName, spanOptions, parentContext);
48
+ const spanContext = trace.setSpan(parentContext, span);
49
+ const rpcMetadata = { type: RPCType.HTTP, span };
50
+ const endActiveRequest = recordHttpRequestStart({ method: request.method, route: url.pathname });
51
+ return context.with(setRPCMetadata(spanContext, rpcMetadata), async () => {
52
+ const finalize = (status, responseSize) => {
53
+ span.setAttribute("http.response.status_code", status);
54
+ span.setAttribute("http.response.body.size", responseSize);
55
+ if (status >= 400) {
56
+ span.setStatus({
57
+ code: SpanStatusCode.ERROR,
58
+ message: `HTTP ${status}`
59
+ });
60
+ } else {
61
+ span.setStatus({ code: SpanStatusCode.OK });
62
+ }
63
+ span.end();
64
+ endActiveRequest();
65
+ const duration = performance.now() - startTime;
66
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status }, duration);
67
+ if (isAction) {
68
+ recordActionDuration({ name: actionName, status }, duration);
69
+ }
70
+ };
71
+ try {
72
+ const response = await next();
73
+ if (!response.body) {
74
+ finalize(response.status, 0);
75
+ return response;
76
+ }
77
+ const [measureStream, clientStream] = response.body.tee();
78
+ let responseSize = 0;
79
+ (async () => {
80
+ const reader = measureStream.getReader();
81
+ try {
82
+ while (true) {
83
+ const { done, value } = await reader.read();
84
+ if (done) break;
85
+ responseSize += value.length;
86
+ }
87
+ } finally {
88
+ finalize(response.status, responseSize);
89
+ }
90
+ })();
91
+ return new Response(clientStream, {
92
+ status: response.status,
93
+ headers: response.headers
94
+ });
95
+ } catch (e) {
96
+ span.setStatus({
97
+ code: SpanStatusCode.ERROR,
98
+ message: e instanceof Error ? e.message : "Unknown error"
99
+ });
100
+ span.end();
101
+ endActiveRequest();
102
+ const duration = performance.now() - startTime;
103
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status: 500 }, duration);
104
+ if (isAction) {
105
+ recordActionDuration({ name: actionName, status: 500 }, duration);
106
+ }
107
+ throw e;
108
+ }
109
+ });
110
+ };
111
+ }
112
+
113
+ export {
114
+ createOpenTelemetryMiddleware
115
+ };
@@ -0,0 +1,130 @@
1
+ import {
2
+ recordActionDuration,
3
+ recordHttpRequestDuration,
4
+ recordHttpRequestStart
5
+ } from "./chunk-JU6FJKLT.js";
6
+
7
+ // src/middleware.ts
8
+ import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
9
+ import { RPCType, setRPCMetadata } from "@opentelemetry/core";
10
+ var LIB_NAME = "@astroscope/opentelemetry";
11
+ var ACTIONS_PREFIX = "/_actions/";
12
+ function matchesPattern(path, pattern) {
13
+ if ("pattern" in pattern) {
14
+ return pattern.pattern.test(path);
15
+ }
16
+ if ("prefix" in pattern) {
17
+ return path.startsWith(pattern.prefix);
18
+ }
19
+ return path === pattern.exact;
20
+ }
21
+ function shouldExclude(ctx, exclude) {
22
+ if (!exclude) return false;
23
+ if (typeof exclude === "function") {
24
+ return exclude(ctx);
25
+ }
26
+ return exclude.some((pattern) => matchesPattern(ctx.url.pathname, pattern));
27
+ }
28
+ function getClientIp(request) {
29
+ return request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? request.headers.get("x-real-ip") ?? request.headers.get("cf-connecting-ip") ?? // no native ip address access in Astro available
30
+ void 0;
31
+ }
32
+ function createOpenTelemetryMiddleware(options = {}) {
33
+ const tracer = trace.getTracer(LIB_NAME);
34
+ return async (ctx, next) => {
35
+ if (shouldExclude(ctx, options.exclude)) {
36
+ return next();
37
+ }
38
+ const startTime = performance.now();
39
+ const { request, url } = ctx;
40
+ const input = { traceparent: request.headers.get("traceparent"), tracestate: request.headers.get("tracestate") };
41
+ const parentContext = propagation.extract(context.active(), input);
42
+ const contentLength = request.headers.get("content-length");
43
+ const clientIp = getClientIp(request);
44
+ const spanOptions = {
45
+ attributes: {
46
+ "http.request.method": request.method,
47
+ "url.full": request.url,
48
+ "url.path": url.pathname,
49
+ "url.query": url.search.slice(1),
50
+ "url.scheme": url.protocol.replace(":", ""),
51
+ "server.address": url.hostname,
52
+ "server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80,
53
+ "user_agent.original": request.headers.get("user-agent") ?? "",
54
+ ...contentLength && { "http.request.body.size": parseInt(contentLength) },
55
+ ...clientIp && { "client.address": clientIp }
56
+ },
57
+ kind: SpanKind.SERVER
58
+ };
59
+ const isAction = url.pathname.startsWith(ACTIONS_PREFIX);
60
+ const actionName = url.pathname.slice(ACTIONS_PREFIX.length).replace(/\/$/, "");
61
+ const spanName = isAction ? `ACTION ${actionName}` : `${request.method} ${url.pathname}`;
62
+ const span = tracer.startSpan(spanName, spanOptions, parentContext);
63
+ const spanContext = trace.setSpan(parentContext, span);
64
+ const rpcMetadata = { type: RPCType.HTTP, span };
65
+ const endActiveRequest = recordHttpRequestStart({ method: request.method, route: url.pathname });
66
+ return context.with(setRPCMetadata(spanContext, rpcMetadata), async () => {
67
+ const finalize = (status, responseSize) => {
68
+ span.setAttribute("http.response.status_code", status);
69
+ span.setAttribute("http.response.body.size", responseSize);
70
+ if (status >= 400) {
71
+ span.setStatus({
72
+ code: SpanStatusCode.ERROR,
73
+ message: `HTTP ${status}`
74
+ });
75
+ } else {
76
+ span.setStatus({ code: SpanStatusCode.OK });
77
+ }
78
+ span.end();
79
+ endActiveRequest();
80
+ const duration = performance.now() - startTime;
81
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status }, duration);
82
+ if (isAction) {
83
+ recordActionDuration({ name: actionName, status }, duration);
84
+ }
85
+ };
86
+ try {
87
+ const response = await next();
88
+ if (!response.body) {
89
+ finalize(response.status, 0);
90
+ return response;
91
+ }
92
+ const [measureStream, clientStream] = response.body.tee();
93
+ let responseSize = 0;
94
+ (async () => {
95
+ const reader = measureStream.getReader();
96
+ try {
97
+ while (true) {
98
+ const { done, value } = await reader.read();
99
+ if (done) break;
100
+ responseSize += value.length;
101
+ }
102
+ } finally {
103
+ finalize(response.status, responseSize);
104
+ }
105
+ })();
106
+ return new Response(clientStream, {
107
+ status: response.status,
108
+ headers: response.headers
109
+ });
110
+ } catch (e) {
111
+ span.setStatus({
112
+ code: SpanStatusCode.ERROR,
113
+ message: e instanceof Error ? e.message : "Unknown error"
114
+ });
115
+ span.end();
116
+ endActiveRequest();
117
+ const duration = performance.now() - startTime;
118
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status: 500 }, duration);
119
+ if (isAction) {
120
+ recordActionDuration({ name: actionName, status: 500 }, duration);
121
+ }
122
+ throw e;
123
+ }
124
+ });
125
+ };
126
+ }
127
+
128
+ export {
129
+ createOpenTelemetryMiddleware
130
+ };
@@ -0,0 +1,115 @@
1
+ import {
2
+ recordActionDuration,
3
+ recordHttpRequestDuration,
4
+ recordHttpRequestStart
5
+ } from "./chunk-JU6FJKLT.js";
6
+
7
+ // src/middleware.ts
8
+ import { shouldExclude } from "@astroscope/excludes";
9
+ import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
10
+ import { RPCType, setRPCMetadata } from "@opentelemetry/core";
11
+ var LIB_NAME = "@astroscope/opentelemetry";
12
+ var ACTIONS_PREFIX = "/_actions/";
13
+ function getClientIp(request) {
14
+ return request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? request.headers.get("x-real-ip") ?? request.headers.get("cf-connecting-ip") ?? // no native ip address access in Astro available
15
+ void 0;
16
+ }
17
+ function createOpenTelemetryMiddleware(options = {}) {
18
+ const tracer = trace.getTracer(LIB_NAME);
19
+ return async (ctx, next) => {
20
+ if (shouldExclude(ctx, options.exclude)) {
21
+ return next();
22
+ }
23
+ const startTime = performance.now();
24
+ const { request, url } = ctx;
25
+ const input = { traceparent: request.headers.get("traceparent"), tracestate: request.headers.get("tracestate") };
26
+ const parentContext = propagation.extract(context.active(), input);
27
+ const contentLength = request.headers.get("content-length");
28
+ const clientIp = getClientIp(request);
29
+ const spanOptions = {
30
+ attributes: {
31
+ "http.request.method": request.method,
32
+ "url.full": request.url,
33
+ "url.path": url.pathname,
34
+ "url.query": url.search.slice(1),
35
+ "url.scheme": url.protocol.replace(":", ""),
36
+ "server.address": url.hostname,
37
+ "server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80,
38
+ "user_agent.original": request.headers.get("user-agent") ?? "",
39
+ ...contentLength && { "http.request.body.size": parseInt(contentLength) },
40
+ ...clientIp && { "client.address": clientIp }
41
+ },
42
+ kind: SpanKind.SERVER
43
+ };
44
+ const isAction = url.pathname.startsWith(ACTIONS_PREFIX);
45
+ const actionName = url.pathname.slice(ACTIONS_PREFIX.length).replace(/\/$/, "");
46
+ const spanName = isAction ? `ACTION ${actionName}` : `${request.method} ${url.pathname}`;
47
+ const span = tracer.startSpan(spanName, spanOptions, parentContext);
48
+ const spanContext = trace.setSpan(parentContext, span);
49
+ const rpcMetadata = { type: RPCType.HTTP, span };
50
+ const endActiveRequest = recordHttpRequestStart({ method: request.method, route: url.pathname });
51
+ return context.with(setRPCMetadata(spanContext, rpcMetadata), async () => {
52
+ const finalize = (status, responseSize) => {
53
+ span.setAttribute("http.response.status_code", status);
54
+ span.setAttribute("http.response.body.size", responseSize);
55
+ if (status >= 400) {
56
+ span.setStatus({
57
+ code: SpanStatusCode.ERROR,
58
+ message: `HTTP ${status}`
59
+ });
60
+ } else {
61
+ span.setStatus({ code: SpanStatusCode.OK });
62
+ }
63
+ span.end();
64
+ endActiveRequest();
65
+ const duration = performance.now() - startTime;
66
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status }, duration);
67
+ if (isAction) {
68
+ recordActionDuration({ name: actionName, status }, duration);
69
+ }
70
+ };
71
+ try {
72
+ const response = await next();
73
+ if (!response.body) {
74
+ finalize(response.status, 0);
75
+ return response;
76
+ }
77
+ const [measureStream, clientStream] = response.body.tee();
78
+ let responseSize = 0;
79
+ (async () => {
80
+ const reader = measureStream.getReader();
81
+ try {
82
+ while (true) {
83
+ const { done, value } = await reader.read();
84
+ if (done) break;
85
+ responseSize += value.length;
86
+ }
87
+ } finally {
88
+ finalize(response.status, responseSize);
89
+ }
90
+ })();
91
+ return new Response(clientStream, {
92
+ status: response.status,
93
+ headers: response.headers
94
+ });
95
+ } catch (e) {
96
+ span.setStatus({
97
+ code: SpanStatusCode.ERROR,
98
+ message: e instanceof Error ? e.message : "Unknown error"
99
+ });
100
+ span.end();
101
+ endActiveRequest();
102
+ const duration = performance.now() - startTime;
103
+ recordHttpRequestDuration({ method: request.method, route: url.pathname, status: 500 }, duration);
104
+ if (isAction) {
105
+ recordActionDuration({ name: actionName, status: 500 }, duration);
106
+ }
107
+ throw e;
108
+ }
109
+ });
110
+ };
111
+ }
112
+
113
+ export {
114
+ createOpenTelemetryMiddleware
115
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ instrumentFetch
3
+ } from "./chunk-45TY3U7U.js";
4
+ import "./chunk-JU6FJKLT.js";
5
+ export {
6
+ instrumentFetch
7
+ };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,6 @@
1
1
  import { APIContext, MiddlewareHandler, AstroIntegration } from 'astro';
2
+ import { ExcludePattern } from '@astroscope/excludes';
2
3
 
3
- type ExcludePattern = {
4
- pattern: RegExp;
5
- } | {
6
- prefix: string;
7
- } | {
8
- exact: string;
9
- };
10
4
  interface OpenTelemetryMiddlewareOptions {
11
5
  /**
12
6
  * Paths to exclude from tracing.
@@ -86,7 +80,7 @@ interface OpenTelemetryIntegrationOptions {
86
80
  * ```ts
87
81
  * // astro.config.ts
88
82
  * import { defineConfig } from "astro/config";
89
- * import { opentelemetry } from "@astroscope/opentelemetry";
83
+ * import opentelemetry from "@astroscope/opentelemetry";
90
84
  *
91
85
  * export default defineConfig({
92
86
  * integrations: [opentelemetry()],
@@ -121,32 +115,4 @@ interface OpenTelemetryIntegrationOptions {
121
115
  */
122
116
  declare function opentelemetry(options?: OpenTelemetryIntegrationOptions): AstroIntegration;
123
117
 
124
- /**
125
- * Vite/Astro dev server paths - only relevant in development.
126
- */
127
- declare const DEV_EXCLUDES: ExcludePattern[];
128
- /**
129
- * Astro internal paths for static assets and image optimization.
130
- */
131
- declare const ASTRO_STATIC_EXCLUDES: ExcludePattern[];
132
- /**
133
- * Common static asset paths.
134
- */
135
- declare const STATIC_EXCLUDES: ExcludePattern[];
136
- /**
137
- * Recommended excludes for OpenTelemetry middleware.
138
- * Includes dev paths, Astro internals, and common static assets.
139
- *
140
- * @example
141
- * ```ts
142
- * createOpenTelemetryMiddleware({
143
- * exclude: [
144
- * ...RECOMMENDED_EXCLUDES,
145
- * { exact: "/health" }, // your health endpoint
146
- * ],
147
- * })
148
- * ```
149
- */
150
- declare const RECOMMENDED_EXCLUDES: ExcludePattern[];
151
-
152
- export { ASTRO_STATIC_EXCLUDES, DEV_EXCLUDES, type ExcludePattern, type OpenTelemetryIntegrationOptions, type OpenTelemetryMiddlewareOptions, RECOMMENDED_EXCLUDES, STATIC_EXCLUDES, createOpenTelemetryMiddleware, instrumentFetch, opentelemetry };
118
+ export { type OpenTelemetryIntegrationOptions, type OpenTelemetryMiddlewareOptions, createOpenTelemetryMiddleware, opentelemetry as default, instrumentFetch };
package/dist/index.js CHANGED
@@ -1,57 +1,17 @@
1
1
  import {
2
2
  createOpenTelemetryMiddleware
3
- } from "./chunk-7RBJ7XB3.js";
3
+ } from "./chunk-SNVIK2H6.js";
4
4
  import {
5
5
  instrumentFetch
6
- } from "./chunk-BQFWPPEO.js";
7
- import "./chunk-DPYEL3WF.js";
6
+ } from "./chunk-45TY3U7U.js";
7
+ import "./chunk-JU6FJKLT.js";
8
8
 
9
9
  // src/integration.ts
10
10
  import fs from "fs";
11
11
  import path from "path";
12
-
13
- // src/excludes.ts
14
- var DEV_EXCLUDES = [
15
- { prefix: "/@id/" },
16
- { prefix: "/@fs/" },
17
- { prefix: "/@vite/" },
18
- { prefix: "/src/" },
19
- { prefix: "/node_modules/" }
20
- ];
21
- var ASTRO_STATIC_EXCLUDES = [
22
- { prefix: "/_astro/" },
23
- { prefix: "/_image" }
24
- ];
25
- var STATIC_EXCLUDES = [
26
- { exact: "/favicon.ico" },
27
- { exact: "/robots.txt" },
28
- { exact: "/sitemap.xml" },
29
- { exact: "/browserconfig.xml" },
30
- { exact: "/manifest.json" },
31
- { exact: "/manifest.webmanifest" },
32
- { prefix: "/.well-known/" }
33
- ];
34
- var RECOMMENDED_EXCLUDES = [
35
- ...DEV_EXCLUDES,
36
- ...ASTRO_STATIC_EXCLUDES,
37
- ...STATIC_EXCLUDES
38
- ];
39
-
40
- // src/integration.ts
12
+ import { RECOMMENDED_EXCLUDES, serializeExcludePatterns } from "@astroscope/excludes";
41
13
  var VIRTUAL_MODULE_ID = "virtual:@astroscope/opentelemetry/config";
42
- var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
43
- function serializeExcludePatterns(patterns) {
44
- const items = patterns.map((p) => {
45
- if ("pattern" in p) {
46
- return `{ pattern: ${p.pattern.toString()} }`;
47
- } else if ("prefix" in p) {
48
- return `{ prefix: ${JSON.stringify(p.prefix)} }`;
49
- } else {
50
- return `{ exact: ${JSON.stringify(p.exact)} }`;
51
- }
52
- });
53
- return `[${items.join(", ")}]`;
54
- }
14
+ var RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
55
15
  function opentelemetry(options = {}) {
56
16
  const httpConfig = options.instrumentations?.http ?? {
57
17
  enabled: true,
@@ -64,12 +24,7 @@ function opentelemetry(options = {}) {
64
24
  return {
65
25
  name: "@astroscope/opentelemetry",
66
26
  hooks: {
67
- "astro:config:setup": ({
68
- command,
69
- updateConfig,
70
- logger,
71
- addMiddleware
72
- }) => {
27
+ "astro:config:setup": ({ command, updateConfig, logger, addMiddleware }) => {
73
28
  isBuild = command === "build";
74
29
  if (httpConfig.enabled) {
75
30
  addMiddleware({
@@ -93,7 +48,6 @@ function opentelemetry(options = {}) {
93
48
  }
94
49
  }
95
50
  },
96
- // Only add fetch instrumentation plugin if enabled
97
51
  ...fetchConfig.enabled ? [
98
52
  {
99
53
  name: "@astroscope/opentelemetry/fetch",
@@ -101,7 +55,7 @@ function opentelemetry(options = {}) {
101
55
  if (isBuild) return;
102
56
  server.httpServer?.once("listening", async () => {
103
57
  try {
104
- const { instrumentFetch: instrumentFetch2 } = await import("./fetch-RERXGIJA.js");
58
+ const { instrumentFetch: instrumentFetch2 } = await import("./fetch-Z2DBQPE2.js");
105
59
  instrumentFetch2();
106
60
  logger.info("fetch instrumentation enabled");
107
61
  } catch (error) {
@@ -118,15 +72,14 @@ function opentelemetry(options = {}) {
118
72
  if (!outDir) return;
119
73
  const entryPath = path.join(outDir, "entry.mjs");
120
74
  if (!fs.existsSync(entryPath)) return;
121
- let content = fs.readFileSync(entryPath, "utf-8");
122
- const instrumentCode = `import { instrumentFetch } from '@astroscope/opentelemetry';
75
+ const content = fs.readFileSync(entryPath, "utf-8");
76
+ fs.writeFileSync(
77
+ entryPath,
78
+ `import { instrumentFetch } from '@astroscope/opentelemetry';
123
79
  instrumentFetch();
124
- `;
125
- content = instrumentCode + content;
126
- fs.writeFileSync(entryPath, content);
127
- logger.info(
128
- "injected fetch instrumentation into entry.mjs"
80
+ ${content}`
129
81
  );
82
+ logger.info("injected fetch instrumentation into entry.mjs");
130
83
  }
131
84
  }
132
85
  ] : []
@@ -138,11 +91,7 @@ instrumentFetch();
138
91
  };
139
92
  }
140
93
  export {
141
- ASTRO_STATIC_EXCLUDES,
142
- DEV_EXCLUDES,
143
- RECOMMENDED_EXCLUDES,
144
- STATIC_EXCLUDES,
145
94
  createOpenTelemetryMiddleware,
146
- instrumentFetch,
147
- opentelemetry
95
+ opentelemetry as default,
96
+ instrumentFetch
148
97
  };
@@ -1,13 +1,11 @@
1
1
  import {
2
2
  createOpenTelemetryMiddleware
3
- } from "./chunk-7RBJ7XB3.js";
4
- import "./chunk-DPYEL3WF.js";
3
+ } from "./chunk-SNVIK2H6.js";
4
+ import "./chunk-JU6FJKLT.js";
5
5
 
6
6
  // src/middleware-entrypoint.ts
7
7
  import { excludePatterns } from "virtual:@astroscope/opentelemetry/config";
8
- var onRequest = createOpenTelemetryMiddleware({
9
- exclude: excludePatterns
10
- });
8
+ var onRequest = createOpenTelemetryMiddleware({ exclude: excludePatterns });
11
9
  export {
12
10
  onRequest
13
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astroscope/opentelemetry",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "OpenTelemetry tracing middleware for Astro SSR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,14 +55,15 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@opentelemetry/api": "^1.9.0",
58
- "@opentelemetry/core": "^1.30.0",
58
+ "@opentelemetry/core": "^2.2.0",
59
59
  "astro": "^5.1.0",
60
60
  "tsup": "^8.5.1",
61
61
  "typescript": "^5.9.3"
62
62
  },
63
63
  "peerDependencies": {
64
+ "@astroscope/excludes": "workspace:*",
64
65
  "@opentelemetry/api": "^1.0.0",
65
- "@opentelemetry/core": "^1.0.0",
66
+ "@opentelemetry/core": "^2.0.0",
66
67
  "astro": "^5.0.0"
67
68
  }
68
69
  }