@astroscope/opentelemetry 0.1.0 → 0.1.1
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/dist/{chunk-BQFWPPEO.js → chunk-45TY3U7U.js} +2 -8
- package/dist/{chunk-DPYEL3WF.js → chunk-JU6FJKLT.js} +1 -2
- package/dist/{chunk-7RBJ7XB3.js → chunk-PCCKGEEG.js} +60 -80
- package/dist/fetch-Z2DBQPE2.js +7 -0
- package/dist/index.js +15 -38
- package/dist/middleware-entrypoint.js +3 -5
- package/package.json +3 -3
- package/dist/chunk-63MOS4WA.js +0 -146
- package/dist/chunk-CEPTXEJV.js +0 -89
- package/dist/chunk-FEC4ETRL.js +0 -70
- package/dist/chunk-KLGWLEAU.js +0 -123
- package/dist/chunk-OFMO3ZKX.js +0 -124
- package/dist/chunk-QIWOBUML.js +0 -89
- package/dist/chunk-QTSNLOSC.js +0 -70
- package/dist/chunk-UPNRPRAW.js +0 -72
- package/dist/chunk-VHXZF2FP.js +0 -124
- package/dist/chunk-WTUM3JRA.js +0 -155
- package/dist/fetch-55MNQVLN.js +0 -7
- package/dist/fetch-FUKHXS77.js +0 -6
- package/dist/fetch-JGQFPQSL.js +0 -6
- package/dist/fetch-RERXGIJA.js +0 -7
- package/dist/fetch-SVGRNFLY.js +0 -7
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
recordFetchRequestDuration
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JU6FJKLT.js";
|
|
4
4
|
|
|
5
5
|
// src/fetch.ts
|
|
6
|
-
import {
|
|
7
|
-
SpanKind,
|
|
8
|
-
SpanStatusCode,
|
|
9
|
-
context,
|
|
10
|
-
propagation,
|
|
11
|
-
trace
|
|
12
|
-
} from "@opentelemetry/api";
|
|
6
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
13
7
|
var LIB_NAME = "@astroscope/opentelemetry";
|
|
14
8
|
function instrumentFetch() {
|
|
15
9
|
const originalFetch = globalThis.fetch;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/metrics.ts
|
|
2
|
-
import {
|
|
2
|
+
import { ValueType, metrics } from "@opentelemetry/api";
|
|
3
3
|
var LIB_NAME = "@astroscope/opentelemetry";
|
|
4
4
|
var httpRequestDuration = null;
|
|
5
5
|
var httpActiveRequests = null;
|
|
@@ -50,7 +50,6 @@ function getActionDuration() {
|
|
|
50
50
|
return actionDuration;
|
|
51
51
|
}
|
|
52
52
|
function recordHttpRequestStart(attributes) {
|
|
53
|
-
const startTime = performance.now();
|
|
54
53
|
getHttpActiveRequests().add(1, {
|
|
55
54
|
"http.request.method": attributes.method,
|
|
56
55
|
"http.route": attributes.route
|
|
@@ -2,16 +2,10 @@ import {
|
|
|
2
2
|
recordActionDuration,
|
|
3
3
|
recordHttpRequestDuration,
|
|
4
4
|
recordHttpRequestStart
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JU6FJKLT.js";
|
|
6
6
|
|
|
7
7
|
// src/middleware.ts
|
|
8
|
-
import {
|
|
9
|
-
SpanKind,
|
|
10
|
-
SpanStatusCode,
|
|
11
|
-
context,
|
|
12
|
-
propagation,
|
|
13
|
-
trace
|
|
14
|
-
} from "@opentelemetry/api";
|
|
8
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
15
9
|
import { RPCType, setRPCMetadata } from "@opentelemetry/core";
|
|
16
10
|
var LIB_NAME = "@astroscope/opentelemetry";
|
|
17
11
|
var ACTIONS_PREFIX = "/_actions/";
|
|
@@ -29,11 +23,10 @@ function shouldExclude(ctx, exclude) {
|
|
|
29
23
|
if (typeof exclude === "function") {
|
|
30
24
|
return exclude(ctx);
|
|
31
25
|
}
|
|
32
|
-
|
|
33
|
-
return exclude.some((pattern) => matchesPattern(path, pattern));
|
|
26
|
+
return exclude.some((pattern) => matchesPattern(ctx.url.pathname, pattern));
|
|
34
27
|
}
|
|
35
28
|
function getClientIp(request) {
|
|
36
|
-
return request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? request.headers.get("x-real-ip") ?? request.headers.get("cf-connecting-ip") ?? //
|
|
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
|
|
37
30
|
void 0;
|
|
38
31
|
}
|
|
39
32
|
function createOpenTelemetryMiddleware(options = {}) {
|
|
@@ -42,21 +35,18 @@ function createOpenTelemetryMiddleware(options = {}) {
|
|
|
42
35
|
if (shouldExclude(ctx, options.exclude)) {
|
|
43
36
|
return next();
|
|
44
37
|
}
|
|
38
|
+
const startTime = performance.now();
|
|
45
39
|
const { request, url } = ctx;
|
|
46
|
-
const input = {
|
|
47
|
-
traceparent: request.headers.get("traceparent"),
|
|
48
|
-
tracestate: request.headers.get("tracestate")
|
|
49
|
-
};
|
|
40
|
+
const input = { traceparent: request.headers.get("traceparent"), tracestate: request.headers.get("tracestate") };
|
|
50
41
|
const parentContext = propagation.extract(context.active(), input);
|
|
51
|
-
const clientIp = getClientIp(request);
|
|
52
42
|
const contentLength = request.headers.get("content-length");
|
|
43
|
+
const clientIp = getClientIp(request);
|
|
53
44
|
const spanOptions = {
|
|
54
45
|
attributes: {
|
|
55
46
|
"http.request.method": request.method,
|
|
56
47
|
"url.full": request.url,
|
|
57
48
|
"url.path": url.pathname,
|
|
58
49
|
"url.query": url.search.slice(1),
|
|
59
|
-
// Remove leading "?"
|
|
60
50
|
"url.scheme": url.protocol.replace(":", ""),
|
|
61
51
|
"server.address": url.hostname,
|
|
62
52
|
"server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80,
|
|
@@ -72,76 +62,66 @@ function createOpenTelemetryMiddleware(options = {}) {
|
|
|
72
62
|
const span = tracer.startSpan(spanName, spanOptions, parentContext);
|
|
73
63
|
const spanContext = trace.setSpan(parentContext, span);
|
|
74
64
|
const rpcMetadata = { type: RPCType.HTTP, span };
|
|
75
|
-
const startTime = performance.now();
|
|
76
65
|
const endActiveRequest = recordHttpRequestStart({ method: request.method, route: url.pathname });
|
|
77
|
-
return context.with(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
span.setAttribute("http.response.body.size", responseSize);
|
|
83
|
-
if (status >= 400) {
|
|
84
|
-
span.setStatus({
|
|
85
|
-
code: SpanStatusCode.ERROR,
|
|
86
|
-
message: `HTTP ${status}`
|
|
87
|
-
});
|
|
88
|
-
} else {
|
|
89
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
90
|
-
}
|
|
91
|
-
span.end();
|
|
92
|
-
endActiveRequest();
|
|
93
|
-
const duration = performance.now() - startTime;
|
|
94
|
-
recordHttpRequestDuration(
|
|
95
|
-
{ method: request.method, route: url.pathname, status },
|
|
96
|
-
duration
|
|
97
|
-
);
|
|
98
|
-
if (isAction) {
|
|
99
|
-
recordActionDuration({ name: actionName, status }, duration);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
const response = await next();
|
|
104
|
-
if (!response.body) {
|
|
105
|
-
finalize(response.status, 0);
|
|
106
|
-
return response;
|
|
107
|
-
}
|
|
108
|
-
const [measureStream, clientStream] = response.body.tee();
|
|
109
|
-
let responseSize = 0;
|
|
110
|
-
(async () => {
|
|
111
|
-
const reader = measureStream.getReader();
|
|
112
|
-
try {
|
|
113
|
-
while (true) {
|
|
114
|
-
const { done, value } = await reader.read();
|
|
115
|
-
if (done) break;
|
|
116
|
-
responseSize += value.length;
|
|
117
|
-
}
|
|
118
|
-
} finally {
|
|
119
|
-
finalize(response.status, responseSize);
|
|
120
|
-
}
|
|
121
|
-
})();
|
|
122
|
-
return new Response(clientStream, {
|
|
123
|
-
status: response.status,
|
|
124
|
-
headers: response.headers
|
|
125
|
-
});
|
|
126
|
-
} catch (e) {
|
|
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) {
|
|
127
71
|
span.setStatus({
|
|
128
72
|
code: SpanStatusCode.ERROR,
|
|
129
|
-
message:
|
|
73
|
+
message: `HTTP ${status}`
|
|
130
74
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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);
|
|
140
104
|
}
|
|
141
|
-
|
|
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);
|
|
142
121
|
}
|
|
122
|
+
throw e;
|
|
143
123
|
}
|
|
144
|
-
);
|
|
124
|
+
});
|
|
145
125
|
};
|
|
146
126
|
}
|
|
147
127
|
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createOpenTelemetryMiddleware
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PCCKGEEG.js";
|
|
4
4
|
import {
|
|
5
5
|
instrumentFetch
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-45TY3U7U.js";
|
|
7
|
+
import "./chunk-JU6FJKLT.js";
|
|
8
8
|
|
|
9
9
|
// src/integration.ts
|
|
10
10
|
import fs from "fs";
|
|
@@ -18,10 +18,7 @@ var DEV_EXCLUDES = [
|
|
|
18
18
|
{ prefix: "/src/" },
|
|
19
19
|
{ prefix: "/node_modules/" }
|
|
20
20
|
];
|
|
21
|
-
var ASTRO_STATIC_EXCLUDES = [
|
|
22
|
-
{ prefix: "/_astro/" },
|
|
23
|
-
{ prefix: "/_image" }
|
|
24
|
-
];
|
|
21
|
+
var ASTRO_STATIC_EXCLUDES = [{ prefix: "/_astro/" }, { prefix: "/_image" }];
|
|
25
22
|
var STATIC_EXCLUDES = [
|
|
26
23
|
{ exact: "/favicon.ico" },
|
|
27
24
|
{ exact: "/robots.txt" },
|
|
@@ -31,26 +28,13 @@ var STATIC_EXCLUDES = [
|
|
|
31
28
|
{ exact: "/manifest.webmanifest" },
|
|
32
29
|
{ prefix: "/.well-known/" }
|
|
33
30
|
];
|
|
34
|
-
var RECOMMENDED_EXCLUDES = [
|
|
35
|
-
...DEV_EXCLUDES,
|
|
36
|
-
...ASTRO_STATIC_EXCLUDES,
|
|
37
|
-
...STATIC_EXCLUDES
|
|
38
|
-
];
|
|
31
|
+
var RECOMMENDED_EXCLUDES = [...DEV_EXCLUDES, ...ASTRO_STATIC_EXCLUDES, ...STATIC_EXCLUDES];
|
|
39
32
|
|
|
40
33
|
// src/integration.ts
|
|
41
34
|
var VIRTUAL_MODULE_ID = "virtual:@astroscope/opentelemetry/config";
|
|
42
|
-
var RESOLVED_VIRTUAL_MODULE_ID =
|
|
35
|
+
var RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
43
36
|
function serializeExcludePatterns(patterns) {
|
|
44
|
-
|
|
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(", ")}]`;
|
|
37
|
+
return `[${patterns.map((p) => "pattern" in p ? `{ pattern: ${p.pattern.toString()} }` : JSON.stringify(p)).join(", ")}]`;
|
|
54
38
|
}
|
|
55
39
|
function opentelemetry(options = {}) {
|
|
56
40
|
const httpConfig = options.instrumentations?.http ?? {
|
|
@@ -64,12 +48,7 @@ function opentelemetry(options = {}) {
|
|
|
64
48
|
return {
|
|
65
49
|
name: "@astroscope/opentelemetry",
|
|
66
50
|
hooks: {
|
|
67
|
-
"astro:config:setup": ({
|
|
68
|
-
command,
|
|
69
|
-
updateConfig,
|
|
70
|
-
logger,
|
|
71
|
-
addMiddleware
|
|
72
|
-
}) => {
|
|
51
|
+
"astro:config:setup": ({ command, updateConfig, logger, addMiddleware }) => {
|
|
73
52
|
isBuild = command === "build";
|
|
74
53
|
if (httpConfig.enabled) {
|
|
75
54
|
addMiddleware({
|
|
@@ -93,7 +72,6 @@ function opentelemetry(options = {}) {
|
|
|
93
72
|
}
|
|
94
73
|
}
|
|
95
74
|
},
|
|
96
|
-
// Only add fetch instrumentation plugin if enabled
|
|
97
75
|
...fetchConfig.enabled ? [
|
|
98
76
|
{
|
|
99
77
|
name: "@astroscope/opentelemetry/fetch",
|
|
@@ -101,7 +79,7 @@ function opentelemetry(options = {}) {
|
|
|
101
79
|
if (isBuild) return;
|
|
102
80
|
server.httpServer?.once("listening", async () => {
|
|
103
81
|
try {
|
|
104
|
-
const { instrumentFetch: instrumentFetch2 } = await import("./fetch-
|
|
82
|
+
const { instrumentFetch: instrumentFetch2 } = await import("./fetch-Z2DBQPE2.js");
|
|
105
83
|
instrumentFetch2();
|
|
106
84
|
logger.info("fetch instrumentation enabled");
|
|
107
85
|
} catch (error) {
|
|
@@ -118,15 +96,14 @@ function opentelemetry(options = {}) {
|
|
|
118
96
|
if (!outDir) return;
|
|
119
97
|
const entryPath = path.join(outDir, "entry.mjs");
|
|
120
98
|
if (!fs.existsSync(entryPath)) return;
|
|
121
|
-
|
|
122
|
-
|
|
99
|
+
const content = fs.readFileSync(entryPath, "utf-8");
|
|
100
|
+
fs.writeFileSync(
|
|
101
|
+
entryPath,
|
|
102
|
+
`import { instrumentFetch } from '@astroscope/opentelemetry';
|
|
123
103
|
instrumentFetch();
|
|
124
|
-
|
|
125
|
-
content = instrumentCode + content;
|
|
126
|
-
fs.writeFileSync(entryPath, content);
|
|
127
|
-
logger.info(
|
|
128
|
-
"injected fetch instrumentation into entry.mjs"
|
|
104
|
+
${content}`
|
|
129
105
|
);
|
|
106
|
+
logger.info("injected fetch instrumentation into entry.mjs");
|
|
130
107
|
}
|
|
131
108
|
}
|
|
132
109
|
] : []
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createOpenTelemetryMiddleware
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-PCCKGEEG.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.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "OpenTelemetry tracing middleware for Astro SSR",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,14 +55,14 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@opentelemetry/api": "^1.9.0",
|
|
58
|
-
"@opentelemetry/core": "^
|
|
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
64
|
"@opentelemetry/api": "^1.0.0",
|
|
65
|
-
"@opentelemetry/core": "^
|
|
65
|
+
"@opentelemetry/core": "^2.0.0",
|
|
66
66
|
"astro": "^5.0.0"
|
|
67
67
|
}
|
|
68
68
|
}
|
package/dist/chunk-63MOS4WA.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
recordHttpRequestDuration,
|
|
3
|
-
recordHttpRequestStart
|
|
4
|
-
} from "./chunk-UPNRPRAW.js";
|
|
5
|
-
|
|
6
|
-
// src/middleware.ts
|
|
7
|
-
import {
|
|
8
|
-
SpanKind,
|
|
9
|
-
SpanStatusCode,
|
|
10
|
-
context,
|
|
11
|
-
propagation,
|
|
12
|
-
trace
|
|
13
|
-
} from "@opentelemetry/api";
|
|
14
|
-
import { RPCType, setRPCMetadata } from "@opentelemetry/core";
|
|
15
|
-
var LIB_NAME = "@astroscope/opentelemetry";
|
|
16
|
-
var ACTIONS_PREFIX = "/_actions/";
|
|
17
|
-
function matchesPattern(path, pattern) {
|
|
18
|
-
if ("pattern" in pattern) {
|
|
19
|
-
return pattern.pattern.test(path);
|
|
20
|
-
}
|
|
21
|
-
if ("prefix" in pattern) {
|
|
22
|
-
return path.startsWith(pattern.prefix);
|
|
23
|
-
}
|
|
24
|
-
return path === pattern.exact;
|
|
25
|
-
}
|
|
26
|
-
function shouldExclude(ctx, exclude) {
|
|
27
|
-
if (!exclude) return false;
|
|
28
|
-
if (typeof exclude === "function") {
|
|
29
|
-
return exclude(ctx);
|
|
30
|
-
}
|
|
31
|
-
const path = ctx.url.pathname;
|
|
32
|
-
return exclude.some((pattern) => matchesPattern(path, pattern));
|
|
33
|
-
}
|
|
34
|
-
function getClientIp(request) {
|
|
35
|
-
return request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? request.headers.get("x-real-ip") ?? request.headers.get("cf-connecting-ip") ?? // Cloudflare
|
|
36
|
-
void 0;
|
|
37
|
-
}
|
|
38
|
-
function createOpenTelemetryMiddleware(options = {}) {
|
|
39
|
-
const tracer = trace.getTracer(LIB_NAME);
|
|
40
|
-
return async (ctx, next) => {
|
|
41
|
-
if (shouldExclude(ctx, options.exclude)) {
|
|
42
|
-
return next();
|
|
43
|
-
}
|
|
44
|
-
const { request, url } = ctx;
|
|
45
|
-
const input = {
|
|
46
|
-
traceparent: request.headers.get("traceparent"),
|
|
47
|
-
tracestate: request.headers.get("tracestate")
|
|
48
|
-
};
|
|
49
|
-
const parentContext = propagation.extract(context.active(), input);
|
|
50
|
-
const clientIp = getClientIp(request);
|
|
51
|
-
const contentLength = request.headers.get("content-length");
|
|
52
|
-
const spanOptions = {
|
|
53
|
-
attributes: {
|
|
54
|
-
"http.request.method": request.method,
|
|
55
|
-
"url.full": request.url,
|
|
56
|
-
"url.path": url.pathname,
|
|
57
|
-
"url.query": url.search.slice(1),
|
|
58
|
-
// Remove leading "?"
|
|
59
|
-
"url.scheme": url.protocol.replace(":", ""),
|
|
60
|
-
"server.address": url.hostname,
|
|
61
|
-
"server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80,
|
|
62
|
-
"user_agent.original": request.headers.get("user-agent") ?? "",
|
|
63
|
-
...contentLength && { "http.request.body.size": parseInt(contentLength) },
|
|
64
|
-
...clientIp && { "client.address": clientIp }
|
|
65
|
-
},
|
|
66
|
-
kind: SpanKind.SERVER
|
|
67
|
-
};
|
|
68
|
-
const isAction = url.pathname.startsWith(ACTIONS_PREFIX);
|
|
69
|
-
const actionName = url.pathname.slice(ACTIONS_PREFIX.length).replace(/\/$/, "");
|
|
70
|
-
const spanName = isAction ? `ACTION ${actionName}` : `${request.method} ${url.pathname}`;
|
|
71
|
-
const span = tracer.startSpan(spanName, spanOptions, parentContext);
|
|
72
|
-
const spanContext = trace.setSpan(parentContext, span);
|
|
73
|
-
const rpcMetadata = { type: RPCType.HTTP, span };
|
|
74
|
-
const metricsEnabled = options.metrics ?? false;
|
|
75
|
-
const startTime = metricsEnabled ? performance.now() : 0;
|
|
76
|
-
const endActiveRequest = metricsEnabled ? recordHttpRequestStart({ method: request.method, route: url.pathname }) : void 0;
|
|
77
|
-
return context.with(
|
|
78
|
-
setRPCMetadata(spanContext, rpcMetadata),
|
|
79
|
-
async () => {
|
|
80
|
-
const finalize = (status, responseSize) => {
|
|
81
|
-
span.setAttribute("http.response.status_code", status);
|
|
82
|
-
span.setAttribute("http.response.body.size", responseSize);
|
|
83
|
-
if (status >= 400) {
|
|
84
|
-
span.setStatus({
|
|
85
|
-
code: SpanStatusCode.ERROR,
|
|
86
|
-
message: `HTTP ${status}`
|
|
87
|
-
});
|
|
88
|
-
} else {
|
|
89
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
90
|
-
}
|
|
91
|
-
span.end();
|
|
92
|
-
if (metricsEnabled) {
|
|
93
|
-
endActiveRequest?.();
|
|
94
|
-
recordHttpRequestDuration(
|
|
95
|
-
{ method: request.method, route: url.pathname, status },
|
|
96
|
-
performance.now() - startTime
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
try {
|
|
101
|
-
const response = await next();
|
|
102
|
-
if (!response.body) {
|
|
103
|
-
finalize(response.status, 0);
|
|
104
|
-
return response;
|
|
105
|
-
}
|
|
106
|
-
const [measureStream, clientStream] = response.body.tee();
|
|
107
|
-
let responseSize = 0;
|
|
108
|
-
(async () => {
|
|
109
|
-
const reader = measureStream.getReader();
|
|
110
|
-
try {
|
|
111
|
-
while (true) {
|
|
112
|
-
const { done, value } = await reader.read();
|
|
113
|
-
if (done) break;
|
|
114
|
-
responseSize += value.length;
|
|
115
|
-
}
|
|
116
|
-
} finally {
|
|
117
|
-
finalize(response.status, responseSize);
|
|
118
|
-
}
|
|
119
|
-
})();
|
|
120
|
-
return new Response(clientStream, {
|
|
121
|
-
status: response.status,
|
|
122
|
-
headers: response.headers
|
|
123
|
-
});
|
|
124
|
-
} catch (e) {
|
|
125
|
-
span.setStatus({
|
|
126
|
-
code: SpanStatusCode.ERROR,
|
|
127
|
-
message: e instanceof Error ? e.message : "Unknown error"
|
|
128
|
-
});
|
|
129
|
-
span.end();
|
|
130
|
-
if (metricsEnabled) {
|
|
131
|
-
endActiveRequest?.();
|
|
132
|
-
recordHttpRequestDuration(
|
|
133
|
-
{ method: request.method, route: url.pathname, status: 500 },
|
|
134
|
-
performance.now() - startTime
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
throw e;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
);
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export {
|
|
145
|
-
createOpenTelemetryMiddleware
|
|
146
|
-
};
|
package/dist/chunk-CEPTXEJV.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
recordFetchRequestDuration
|
|
3
|
-
} from "./chunk-DPYEL3WF.js";
|
|
4
|
-
|
|
5
|
-
// src/fetch.ts
|
|
6
|
-
import {
|
|
7
|
-
SpanKind,
|
|
8
|
-
SpanStatusCode,
|
|
9
|
-
context,
|
|
10
|
-
propagation,
|
|
11
|
-
trace
|
|
12
|
-
} from "@opentelemetry/api";
|
|
13
|
-
var LIB_NAME = "@astroscope/opentelemetry";
|
|
14
|
-
var metricsEnabled = false;
|
|
15
|
-
function instrumentFetch(options) {
|
|
16
|
-
metricsEnabled = options?.metrics ?? false;
|
|
17
|
-
const originalFetch = globalThis.fetch;
|
|
18
|
-
async function instrumentedFetch(input, init) {
|
|
19
|
-
const tracer = trace.getTracer(LIB_NAME);
|
|
20
|
-
const activeContext = context.active();
|
|
21
|
-
const request = new Request(input, init);
|
|
22
|
-
const url = new URL(request.url);
|
|
23
|
-
const span = tracer.startSpan(
|
|
24
|
-
`FETCH ${request.method}`,
|
|
25
|
-
{
|
|
26
|
-
kind: SpanKind.CLIENT,
|
|
27
|
-
attributes: {
|
|
28
|
-
"http.request.method": request.method,
|
|
29
|
-
"url.full": request.url,
|
|
30
|
-
"url.path": url.pathname,
|
|
31
|
-
"url.scheme": url.protocol.replace(":", ""),
|
|
32
|
-
"server.address": url.hostname,
|
|
33
|
-
"server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
activeContext
|
|
37
|
-
);
|
|
38
|
-
const headers = new Headers(request.headers);
|
|
39
|
-
const carrier = {};
|
|
40
|
-
propagation.inject(trace.setSpan(activeContext, span), carrier);
|
|
41
|
-
for (const [key, value] of Object.entries(carrier)) {
|
|
42
|
-
headers.set(key, value);
|
|
43
|
-
}
|
|
44
|
-
const startTime = metricsEnabled ? performance.now() : 0;
|
|
45
|
-
try {
|
|
46
|
-
const response = await originalFetch(request.url, {
|
|
47
|
-
...init,
|
|
48
|
-
method: request.method,
|
|
49
|
-
headers,
|
|
50
|
-
body: request.body
|
|
51
|
-
});
|
|
52
|
-
span.setAttribute("http.response.status_code", response.status);
|
|
53
|
-
if (response.status >= 400) {
|
|
54
|
-
span.setStatus({
|
|
55
|
-
code: SpanStatusCode.ERROR,
|
|
56
|
-
message: `HTTP ${response.status}`
|
|
57
|
-
});
|
|
58
|
-
} else {
|
|
59
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
60
|
-
}
|
|
61
|
-
span.end();
|
|
62
|
-
if (metricsEnabled) {
|
|
63
|
-
recordFetchRequestDuration(
|
|
64
|
-
{ method: request.method, host: url.hostname, status: response.status },
|
|
65
|
-
performance.now() - startTime
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
return response;
|
|
69
|
-
} catch (error) {
|
|
70
|
-
span.setStatus({
|
|
71
|
-
code: SpanStatusCode.ERROR,
|
|
72
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
73
|
-
});
|
|
74
|
-
span.end();
|
|
75
|
-
if (metricsEnabled) {
|
|
76
|
-
recordFetchRequestDuration(
|
|
77
|
-
{ method: request.method, host: url.hostname, status: 0 },
|
|
78
|
-
performance.now() - startTime
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
globalThis.fetch = Object.assign(instrumentedFetch, originalFetch);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export {
|
|
88
|
-
instrumentFetch
|
|
89
|
-
};
|
package/dist/chunk-FEC4ETRL.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// src/fetch.ts
|
|
2
|
-
import {
|
|
3
|
-
SpanKind,
|
|
4
|
-
SpanStatusCode,
|
|
5
|
-
context,
|
|
6
|
-
propagation,
|
|
7
|
-
trace
|
|
8
|
-
} from "@opentelemetry/api";
|
|
9
|
-
var LIB_NAME = "@astroscope/opentelemetry";
|
|
10
|
-
function instrumentFetch() {
|
|
11
|
-
const originalFetch = globalThis.fetch;
|
|
12
|
-
async function instrumentedFetch(input, init) {
|
|
13
|
-
const tracer = trace.getTracer(LIB_NAME);
|
|
14
|
-
const activeContext = context.active();
|
|
15
|
-
const request = new Request(input, init);
|
|
16
|
-
const url = new URL(request.url);
|
|
17
|
-
const span = tracer.startSpan(
|
|
18
|
-
`FETCH ${request.method}`,
|
|
19
|
-
{
|
|
20
|
-
kind: SpanKind.CLIENT,
|
|
21
|
-
attributes: {
|
|
22
|
-
"http.request.method": request.method,
|
|
23
|
-
"url.full": request.url,
|
|
24
|
-
"url.path": url.pathname,
|
|
25
|
-
"url.scheme": url.protocol.replace(":", ""),
|
|
26
|
-
"server.address": url.hostname,
|
|
27
|
-
"server.port": url.port ? parseInt(url.port) : url.protocol === "https:" ? 443 : 80
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
activeContext
|
|
31
|
-
);
|
|
32
|
-
const headers = new Headers(request.headers);
|
|
33
|
-
const carrier = {};
|
|
34
|
-
propagation.inject(trace.setSpan(activeContext, span), carrier);
|
|
35
|
-
for (const [key, value] of Object.entries(carrier)) {
|
|
36
|
-
headers.set(key, value);
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
const response = await originalFetch(request.url, {
|
|
40
|
-
...init,
|
|
41
|
-
method: request.method,
|
|
42
|
-
headers,
|
|
43
|
-
body: request.body
|
|
44
|
-
});
|
|
45
|
-
span.setAttribute("http.response.status_code", response.status);
|
|
46
|
-
if (response.status >= 400) {
|
|
47
|
-
span.setStatus({
|
|
48
|
-
code: SpanStatusCode.ERROR,
|
|
49
|
-
message: `HTTP ${response.status}`
|
|
50
|
-
});
|
|
51
|
-
} else {
|
|
52
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
53
|
-
}
|
|
54
|
-
span.end();
|
|
55
|
-
return response;
|
|
56
|
-
} catch (error) {
|
|
57
|
-
span.setStatus({
|
|
58
|
-
code: SpanStatusCode.ERROR,
|
|
59
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
60
|
-
});
|
|
61
|
-
span.end();
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
globalThis.fetch = Object.assign(instrumentedFetch, originalFetch);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export {
|
|
69
|
-
instrumentFetch
|
|
70
|
-
};
|