@ogcio/o11y-sdk-node 0.1.0-beta.4 → 0.1.0-beta.7
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/CHANGELOG.md +22 -1
- package/README.md +59 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -0
- package/dist/lib/exporter/console.d.ts +3 -0
- package/dist/lib/exporter/console.js +16 -0
- package/dist/lib/exporter/grpc.d.ts +3 -0
- package/dist/lib/{grpc.js → exporter/grpc.js} +9 -5
- package/dist/lib/exporter/http.d.ts +3 -0
- package/dist/lib/{http.js → exporter/http.js} +9 -5
- package/dist/lib/index.d.ts +28 -5
- package/dist/lib/instrumentation.node.js +37 -7
- package/dist/lib/options.d.ts +5 -3
- package/dist/lib/processor/enrich-span-processor.d.ts +11 -0
- package/dist/lib/processor/enrich-span-processor.js +22 -0
- package/dist/lib/traces.d.ts +1 -0
- package/dist/lib/traces.js +4 -0
- package/dist/lib/url-sampler.d.ts +10 -0
- package/dist/lib/url-sampler.js +25 -0
- package/dist/lib/utils.d.ts +4 -2
- package/dist/lib/utils.js +8 -3
- package/dist/package.json +20 -17
- package/dist/vitest.config.js +15 -1
- package/index.ts +2 -2
- package/lib/exporter/console.ts +27 -0
- package/lib/{grpc.ts → exporter/grpc.ts} +13 -7
- package/lib/{http.ts → exporter/http.ts} +13 -7
- package/lib/index.ts +36 -4
- package/lib/instrumentation.node.ts +59 -9
- package/lib/options.ts +5 -3
- package/lib/processor/enrich-span-processor.ts +39 -0
- package/lib/traces.ts +5 -0
- package/lib/url-sampler.ts +52 -0
- package/lib/utils.ts +16 -4
- package/package.json +20 -17
- package/test/enrich-span-processor.test.ts +105 -0
- package/test/index.test.ts +9 -0
- package/test/integration/README.md +26 -0
- package/test/integration/integration.test.ts +58 -0
- package/test/integration/run.sh +85 -0
- package/test/node-config.test.ts +49 -36
- package/test/url-sampler.test.ts +215 -0
- package/test/utils/alloy-log-parser.ts +46 -0
- package/vitest.config.ts +15 -1
- package/coverage/cobertura-coverage.xml +0 -310
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sdk-node/index.html +0 -116
- package/coverage/lcov-report/sdk-node/index.ts.html +0 -112
- package/coverage/lcov-report/sdk-node/lib/console.ts.html +0 -130
- package/coverage/lcov-report/sdk-node/lib/grpc.ts.html +0 -178
- package/coverage/lcov-report/sdk-node/lib/http.ts.html +0 -190
- package/coverage/lcov-report/sdk-node/lib/index.html +0 -221
- package/coverage/lcov-report/sdk-node/lib/index.ts.html +0 -256
- package/coverage/lcov-report/sdk-node/lib/instrumentation.node.ts.html +0 -334
- package/coverage/lcov-report/sdk-node/lib/metrics.ts.html +0 -295
- package/coverage/lcov-report/sdk-node/lib/options.ts.html +0 -106
- package/coverage/lcov-report/sdk-node/lib/utils.ts.html +0 -115
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -312
- package/dist/lib/console.d.ts +0 -3
- package/dist/lib/console.js +0 -12
- package/dist/lib/grpc.d.ts +0 -3
- package/dist/lib/http.d.ts +0 -3
- package/lib/console.ts +0 -15
- package/test-report.xml +0 -71
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
BUILD_ID=$1
|
|
2
|
+
ROOT_PATH=$2
|
|
3
|
+
|
|
4
|
+
NETWORK_NAME="${BUILD_ID}_testnetwork"
|
|
5
|
+
ALLOY_CONTAINER_NAME="integrationalloy"
|
|
6
|
+
NODE_CONTAINER_NAME="${BUILD_ID}_fastify_app"
|
|
7
|
+
ERROR_CODE=0
|
|
8
|
+
|
|
9
|
+
docker build -t ${NODE_CONTAINER_NAME}:${BUILD_ID} -f $ROOT_PATH/examples/fastify/Dockerfile $ROOT_PATH/
|
|
10
|
+
|
|
11
|
+
docker network create $NETWORK_NAME
|
|
12
|
+
|
|
13
|
+
docker run -d \
|
|
14
|
+
-v "$ROOT_PATH/alloy/integration-test.alloy:/etc/alloy/config.alloy:ro" \
|
|
15
|
+
--network $NETWORK_NAME \
|
|
16
|
+
--name $ALLOY_CONTAINER_NAME \
|
|
17
|
+
-p 4317:4317 \
|
|
18
|
+
-p 4318:4318 \
|
|
19
|
+
grafana/alloy \
|
|
20
|
+
run --server.http.listen-addr=0.0.0.0:12345 --stability.level=experimental /etc/alloy/config.alloy
|
|
21
|
+
|
|
22
|
+
MAX_RETRIES=10
|
|
23
|
+
COUNTER=0
|
|
24
|
+
echo "$ALLOY_CONTAINER_NAME container status"
|
|
25
|
+
until [ "$(docker inspect -f {{.State.Running}} $ALLOY_CONTAINER_NAME)" = true ]; do
|
|
26
|
+
sleep 2
|
|
27
|
+
docker inspect -f {{.State.Running}} $ALLOY_CONTAINER_NAME
|
|
28
|
+
COUNTER=$((COUNTER + 1))
|
|
29
|
+
if [ $COUNTER -ge $MAX_RETRIES ]; then
|
|
30
|
+
echo "Exceeded maximum retries. Exiting."
|
|
31
|
+
ERROR_CODE=1
|
|
32
|
+
break
|
|
33
|
+
fi
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
if [[ $ERROR_CODE -eq 0 ]]; then
|
|
37
|
+
docker run --detach \
|
|
38
|
+
--network $NETWORK_NAME \
|
|
39
|
+
--name $NODE_CONTAINER_NAME \
|
|
40
|
+
--health-cmd="curl -f http://${NODE_CONTAINER_NAME}:9091/api/health > /dev/null || exit 1" \
|
|
41
|
+
--health-start-period=1s \
|
|
42
|
+
--health-retries=10 \
|
|
43
|
+
--health-interval=1s \
|
|
44
|
+
-p 9091:9091 \
|
|
45
|
+
${NODE_CONTAINER_NAME}:${BUILD_ID}
|
|
46
|
+
|
|
47
|
+
COUNTER=0
|
|
48
|
+
echo "$NODE_CONTAINER_NAME container status"
|
|
49
|
+
until [ "$(docker inspect -f {{.State.Health.Status}} $NODE_CONTAINER_NAME)" = "healthy" ]; do
|
|
50
|
+
sleep 1
|
|
51
|
+
docker inspect -f {{.State.Health.Status}} $NODE_CONTAINER_NAME
|
|
52
|
+
COUNTER=$((COUNTER + 1))
|
|
53
|
+
if [ $COUNTER -ge $MAX_RETRIES ]; then
|
|
54
|
+
echo "Exceeded maximum retries. Exiting."
|
|
55
|
+
ERROR_CODE=1
|
|
56
|
+
break
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if [[ $ERROR_CODE -eq 0 ]]; then
|
|
62
|
+
sleep 2
|
|
63
|
+
curl -X GET -f http://localhost:9091/api/dummy -H 'Content-Type: application/json'
|
|
64
|
+
sleep 2
|
|
65
|
+
curl -X GET -f http://localhost:9091/api/dummy -H 'Content-Type: application/json'
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# sleep N seconds to await instrumentation flow send and receiving signals
|
|
69
|
+
sleep 10
|
|
70
|
+
|
|
71
|
+
# Copy logs from container to file
|
|
72
|
+
docker container logs $ALLOY_CONTAINER_NAME >&$ROOT_PATH/packages/sdk-node/test/integration/logs.txt
|
|
73
|
+
echo "log file at $ROOT_PATH/packages/sdk-node/test/integration/logs.txt"
|
|
74
|
+
|
|
75
|
+
docker container stop $ALLOY_CONTAINER_NAME
|
|
76
|
+
docker container stop $NODE_CONTAINER_NAME
|
|
77
|
+
|
|
78
|
+
docker container rm -f $ALLOY_CONTAINER_NAME
|
|
79
|
+
docker container rm -f $NODE_CONTAINER_NAME
|
|
80
|
+
|
|
81
|
+
docker image rm ${NODE_CONTAINER_NAME}:${BUILD_ID}
|
|
82
|
+
|
|
83
|
+
docker network rm $NETWORK_NAME
|
|
84
|
+
|
|
85
|
+
exit $ERROR_CODE
|
package/test/node-config.test.ts
CHANGED
|
@@ -9,7 +9,17 @@ import { OTLPTraceExporter as HTTP_OTLPTraceExporter } from "@opentelemetry/expo
|
|
|
9
9
|
import { OTLPMetricExporter as HTTP_OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
10
10
|
import { OTLPLogExporter as HTTP_OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
11
11
|
import { NodeSDKConfig } from "../lib/index.js";
|
|
12
|
-
import buildHttpExporters from "../lib/http.js";
|
|
12
|
+
import buildHttpExporters from "../lib/exporter/http.js";
|
|
13
|
+
import {
|
|
14
|
+
BatchSpanProcessor,
|
|
15
|
+
ConsoleSpanExporter,
|
|
16
|
+
SimpleSpanProcessor,
|
|
17
|
+
} from "@opentelemetry/sdk-trace-base";
|
|
18
|
+
import {
|
|
19
|
+
BatchLogRecordProcessor,
|
|
20
|
+
SimpleLogRecordProcessor,
|
|
21
|
+
} from "@opentelemetry/sdk-logs";
|
|
22
|
+
import { EnrichSpanProcessor } from "../lib/processor/enrich-span-processor.js";
|
|
13
23
|
|
|
14
24
|
describe("verify config settings", () => {
|
|
15
25
|
const commonConfig = {
|
|
@@ -21,6 +31,7 @@ describe("verify config settings", () => {
|
|
|
21
31
|
const config: NodeSDKConfig = {
|
|
22
32
|
...commonConfig,
|
|
23
33
|
protocol: "grpc",
|
|
34
|
+
collectorMode: "batch",
|
|
24
35
|
diagLogLevel: "NONE",
|
|
25
36
|
};
|
|
26
37
|
|
|
@@ -31,20 +42,21 @@ describe("verify config settings", () => {
|
|
|
31
42
|
const _configuration = sdk["_configuration"];
|
|
32
43
|
assert.equal(_configuration.serviceName, commonConfig.serviceName);
|
|
33
44
|
|
|
34
|
-
const
|
|
45
|
+
const logs = _configuration.logRecordProcessors;
|
|
35
46
|
|
|
36
|
-
assert.
|
|
47
|
+
assert.equal(logs.length, 1);
|
|
48
|
+
assert.ok(logs[0] instanceof BatchLogRecordProcessor);
|
|
49
|
+
|
|
50
|
+
const spans = _configuration.spanProcessors;
|
|
51
|
+
|
|
52
|
+
assert.equal(spans.length, 2);
|
|
53
|
+
assert.ok(spans[0] instanceof BatchSpanProcessor);
|
|
54
|
+
assert.ok(spans[1] instanceof EnrichSpanProcessor);
|
|
37
55
|
|
|
38
|
-
const logRecordProcessors = _configuration.logRecordProcessors;
|
|
39
|
-
assert.equal(logRecordProcessors.length, 1);
|
|
40
|
-
// assert default signals sending mode
|
|
41
|
-
assert.ok(logRecordProcessors[0] instanceof logs.BatchLogRecordProcessor);
|
|
42
56
|
assert.ok(
|
|
43
|
-
|
|
57
|
+
_configuration.metricReader instanceof
|
|
58
|
+
metrics.PeriodicExportingMetricReader,
|
|
44
59
|
);
|
|
45
|
-
|
|
46
|
-
const metricReader = _configuration.metricReader;
|
|
47
|
-
assert.ok(metricReader._exporter instanceof GRPC_OTLPMetricExporter);
|
|
48
60
|
});
|
|
49
61
|
|
|
50
62
|
test("http config", () => {
|
|
@@ -60,19 +72,21 @@ describe("verify config settings", () => {
|
|
|
60
72
|
const _configuration = sdk["_configuration"];
|
|
61
73
|
assert.equal(_configuration.serviceName, commonConfig.serviceName);
|
|
62
74
|
|
|
63
|
-
const
|
|
64
|
-
|
|
75
|
+
const logs = _configuration.logRecordProcessors;
|
|
76
|
+
|
|
77
|
+
assert.equal(logs.length, 1);
|
|
78
|
+
assert.ok(logs[0] instanceof BatchLogRecordProcessor);
|
|
79
|
+
|
|
80
|
+
const spans = _configuration.spanProcessors;
|
|
81
|
+
|
|
82
|
+
assert.equal(spans.length, 2);
|
|
83
|
+
assert.ok(spans[0] instanceof BatchSpanProcessor);
|
|
84
|
+
assert.ok(spans[1] instanceof EnrichSpanProcessor);
|
|
65
85
|
|
|
66
|
-
const logRecordProcessors = _configuration.logRecordProcessors;
|
|
67
|
-
assert.equal(logRecordProcessors.length, 1);
|
|
68
|
-
// assert default signals sending mode
|
|
69
|
-
assert.ok(logRecordProcessors[0] instanceof logs.BatchLogRecordProcessor);
|
|
70
86
|
assert.ok(
|
|
71
|
-
|
|
87
|
+
_configuration.metricReader instanceof
|
|
88
|
+
metrics.PeriodicExportingMetricReader,
|
|
72
89
|
);
|
|
73
|
-
|
|
74
|
-
const metricReader = _configuration.metricReader;
|
|
75
|
-
assert.ok(metricReader._exporter instanceof HTTP_OTLPMetricExporter);
|
|
76
90
|
});
|
|
77
91
|
|
|
78
92
|
test("console - console config", () => {
|
|
@@ -82,30 +96,29 @@ describe("verify config settings", () => {
|
|
|
82
96
|
diagLogLevel: "NONE",
|
|
83
97
|
};
|
|
84
98
|
|
|
85
|
-
const sdk: NodeSDK
|
|
99
|
+
const sdk: NodeSDK = buildNodeInstrumentation(config)!;
|
|
86
100
|
assert.ok(sdk);
|
|
87
101
|
|
|
88
102
|
const _configuration = sdk["_configuration"];
|
|
89
103
|
assert.equal(_configuration.serviceName, commonConfig.serviceName);
|
|
90
104
|
|
|
91
|
-
const
|
|
105
|
+
const logs = _configuration.logRecordProcessors;
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
assert.
|
|
107
|
+
// verify simple log processor for instant console logging
|
|
108
|
+
assert.equal(logs.length, 1);
|
|
109
|
+
assert.ok(logs[0] instanceof SimpleLogRecordProcessor);
|
|
95
110
|
|
|
96
|
-
const
|
|
97
|
-
|
|
111
|
+
const spans = _configuration.spanProcessors;
|
|
112
|
+
|
|
113
|
+
assert.equal(spans.length, 2);
|
|
114
|
+
// verify simple span for instant console logging
|
|
115
|
+
assert.ok(spans[0] instanceof SimpleSpanProcessor);
|
|
116
|
+
assert.ok(spans[1] instanceof EnrichSpanProcessor);
|
|
98
117
|
|
|
99
|
-
assert.ok(logRecordProcessors[0] instanceof logs.SimpleLogRecordProcessor);
|
|
100
118
|
assert.ok(
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
_configuration.metricReader instanceof
|
|
120
|
+
metrics.PeriodicExportingMetricReader,
|
|
103
121
|
);
|
|
104
|
-
assert.isUndefined(logRecordProcessors[0]["_exporter"]._transport);
|
|
105
|
-
|
|
106
|
-
const metricReader = _configuration.metricReader;
|
|
107
|
-
assert.ok(metricReader._exporter instanceof metrics.ConsoleMetricExporter);
|
|
108
|
-
assert.isUndefined(metricReader._exporter._transport);
|
|
109
122
|
});
|
|
110
123
|
|
|
111
124
|
test("single log sending config", () => {
|
|
@@ -124,7 +137,7 @@ describe("verify config settings", () => {
|
|
|
124
137
|
|
|
125
138
|
const logRecordProcessors = _configuration.logRecordProcessors;
|
|
126
139
|
assert.equal(logRecordProcessors.length, 1);
|
|
127
|
-
assert.ok(logRecordProcessors[0] instanceof
|
|
140
|
+
assert.ok(logRecordProcessors[0] instanceof SimpleLogRecordProcessor);
|
|
128
141
|
});
|
|
129
142
|
|
|
130
143
|
test("check if clear base endpoint final slash", () => {
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Context } from "@opentelemetry/api";
|
|
2
|
+
import {
|
|
3
|
+
SamplingDecision,
|
|
4
|
+
SamplingResult,
|
|
5
|
+
} from "@opentelemetry/sdk-trace-base";
|
|
6
|
+
import { describe, expect, test, vi } from "vitest";
|
|
7
|
+
import { UrlSampler } from "../lib/url-sampler";
|
|
8
|
+
|
|
9
|
+
describe("url sampler", () => {
|
|
10
|
+
// mock sampler to be sure every trace after UrlSamper has RECORD status
|
|
11
|
+
const mockSampler = {
|
|
12
|
+
shouldSample: vi
|
|
13
|
+
.fn()
|
|
14
|
+
.mockImplementation(
|
|
15
|
+
(_context, _traceId, _spanName, _spanKind, attributes, _links) => {
|
|
16
|
+
return {
|
|
17
|
+
decision: SamplingDecision.RECORD,
|
|
18
|
+
attributes: attributes,
|
|
19
|
+
} as SamplingResult;
|
|
20
|
+
},
|
|
21
|
+
),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
test("should add custom span attributes to trace", async () => {
|
|
25
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
26
|
+
[
|
|
27
|
+
{
|
|
28
|
+
type: "endsWith",
|
|
29
|
+
url: "/health",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
mockSampler,
|
|
33
|
+
{
|
|
34
|
+
"signal.namespace": "unittest",
|
|
35
|
+
"signal.callback.result": () => "test",
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
expect(sampler).not.toBeNull();
|
|
40
|
+
|
|
41
|
+
const result = sampler.shouldSample(
|
|
42
|
+
{} as Context,
|
|
43
|
+
"traceId",
|
|
44
|
+
"span",
|
|
45
|
+
0,
|
|
46
|
+
{ "http.target": "/track" },
|
|
47
|
+
[],
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
51
|
+
expect(result.decision).toBe(SamplingDecision.RECORD);
|
|
52
|
+
expect(result.attributes).not.toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("should not record trace about /health api", async () => {
|
|
56
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
57
|
+
[
|
|
58
|
+
{
|
|
59
|
+
type: "endsWith",
|
|
60
|
+
url: "/health",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
mockSampler,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const result = sampler.shouldSample(
|
|
67
|
+
{} as Context,
|
|
68
|
+
"traceId",
|
|
69
|
+
"span",
|
|
70
|
+
0,
|
|
71
|
+
{ "http.target": "/health" },
|
|
72
|
+
[],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
76
|
+
expect(result.decision).toBe(SamplingDecision.NOT_RECORD);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("should record every other trace which is not /health api", async () => {
|
|
80
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
81
|
+
[
|
|
82
|
+
{
|
|
83
|
+
type: "endsWith",
|
|
84
|
+
url: "/health",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
mockSampler,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
let result = sampler.shouldSample(
|
|
91
|
+
{} as Context,
|
|
92
|
+
"traceId",
|
|
93
|
+
"span",
|
|
94
|
+
0,
|
|
95
|
+
{ "http.target": "/test" },
|
|
96
|
+
[],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(result.decision).toBe(SamplingDecision.RECORD);
|
|
100
|
+
|
|
101
|
+
result = sampler.shouldSample(
|
|
102
|
+
{} as Context,
|
|
103
|
+
"traceId",
|
|
104
|
+
"span",
|
|
105
|
+
0,
|
|
106
|
+
{ "http.target": "/another/url" },
|
|
107
|
+
[],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(result.decision).toBe(SamplingDecision.RECORD);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("operator 'includes', should not record every trace which include /block in url", async () => {
|
|
114
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
115
|
+
[
|
|
116
|
+
{
|
|
117
|
+
type: "includes",
|
|
118
|
+
url: "/block",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
mockSampler,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(sampler).not.toBeNull();
|
|
125
|
+
|
|
126
|
+
const result = sampler.shouldSample(
|
|
127
|
+
{} as Context,
|
|
128
|
+
"traceId",
|
|
129
|
+
"span",
|
|
130
|
+
0,
|
|
131
|
+
{ "http.target": "/namespace/block/example/12" },
|
|
132
|
+
[],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
136
|
+
expect(result.decision).toBe(SamplingDecision.NOT_RECORD);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("operator 'endsWith', should not record only trace which ends with /block in url", async () => {
|
|
140
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
141
|
+
[
|
|
142
|
+
{
|
|
143
|
+
type: "endsWith",
|
|
144
|
+
url: "/block",
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
mockSampler,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
expect(sampler).not.toBeNull();
|
|
151
|
+
|
|
152
|
+
// expect traced with block in the URL middle
|
|
153
|
+
let result = sampler.shouldSample(
|
|
154
|
+
{} as Context,
|
|
155
|
+
"traceId",
|
|
156
|
+
"span",
|
|
157
|
+
0,
|
|
158
|
+
{ "http.target": "/namespace/block/example/12" },
|
|
159
|
+
[],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
163
|
+
expect(result.decision).toBe(SamplingDecision.RECORD);
|
|
164
|
+
|
|
165
|
+
// should stop trace with block at the end
|
|
166
|
+
result = sampler.shouldSample(
|
|
167
|
+
{} as Context,
|
|
168
|
+
"traceId",
|
|
169
|
+
"span",
|
|
170
|
+
0,
|
|
171
|
+
{ "http.target": "/namespace/example/block" },
|
|
172
|
+
[],
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
176
|
+
expect(result.decision).toBe(SamplingDecision.NOT_RECORD);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("operator 'equals', should not record trace which is equal to /block in url", async () => {
|
|
180
|
+
const sampler: UrlSampler = new UrlSampler(
|
|
181
|
+
[
|
|
182
|
+
{
|
|
183
|
+
type: "equals",
|
|
184
|
+
url: "/block",
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
mockSampler,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(sampler).not.toBeNull();
|
|
191
|
+
|
|
192
|
+
let result = sampler.shouldSample(
|
|
193
|
+
{} as Context,
|
|
194
|
+
"traceId",
|
|
195
|
+
"span",
|
|
196
|
+
0,
|
|
197
|
+
{ "http.target": "/namespace/block/example/12" },
|
|
198
|
+
[],
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(sampler.toString()).toBe("UrlSampler");
|
|
202
|
+
expect(result.decision).toBe(SamplingDecision.RECORD);
|
|
203
|
+
|
|
204
|
+
result = sampler.shouldSample(
|
|
205
|
+
{} as Context,
|
|
206
|
+
"traceId",
|
|
207
|
+
"span",
|
|
208
|
+
0,
|
|
209
|
+
{ "http.target": "/block" },
|
|
210
|
+
[],
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
expect(result.decision).toBe(SamplingDecision.NOT_RECORD);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function parseLog(
|
|
2
|
+
log: string,
|
|
3
|
+
): Record<string, object | string | number> {
|
|
4
|
+
const logArray = log
|
|
5
|
+
.split("\\n")
|
|
6
|
+
.map((line) => line.trim())
|
|
7
|
+
.filter((line) => line);
|
|
8
|
+
|
|
9
|
+
const jsonObject: Record<string, object | string | number> = {};
|
|
10
|
+
let currentSection: Record<string, object | string | number> = jsonObject;
|
|
11
|
+
const sectionStack: Record<string, object | string | number>[] = [];
|
|
12
|
+
|
|
13
|
+
logArray.forEach((line) => {
|
|
14
|
+
line = line.trim();
|
|
15
|
+
|
|
16
|
+
if (line.startsWith("->")) {
|
|
17
|
+
const match = line.match(/->\s+([^:]+):\s+(Str|Int)\((.+)\)/);
|
|
18
|
+
if (match) {
|
|
19
|
+
const [, key, type, value] = match;
|
|
20
|
+
const parsedValue = type === "Int" ? parseInt(value, 10) : value;
|
|
21
|
+
|
|
22
|
+
if (typeof currentSection === "object") {
|
|
23
|
+
currentSection[key] = parsedValue;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} else if (line.endsWith(":")) {
|
|
27
|
+
// new section
|
|
28
|
+
const sectionName = line
|
|
29
|
+
.slice(0, -1)
|
|
30
|
+
.trim()
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(" ", "_");
|
|
33
|
+
jsonObject[sectionName] = {};
|
|
34
|
+
currentSection = jsonObject[sectionName] as Record<
|
|
35
|
+
string,
|
|
36
|
+
object | string | number
|
|
37
|
+
>;
|
|
38
|
+
sectionStack.push(currentSection);
|
|
39
|
+
} else if (line.startsWith('"')) {
|
|
40
|
+
// Additional metadata at the end, store it separately
|
|
41
|
+
jsonObject["metadata"] = line;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return jsonObject;
|
|
46
|
+
}
|
package/vitest.config.ts
CHANGED
|
@@ -4,7 +4,6 @@ export default defineConfig({
|
|
|
4
4
|
test: {
|
|
5
5
|
globals: true,
|
|
6
6
|
watch: false,
|
|
7
|
-
include: ["**/test/*.test.ts"],
|
|
8
7
|
exclude: ["**/fixtures/**", "**/dist/**"],
|
|
9
8
|
poolOptions: {
|
|
10
9
|
threads: {
|
|
@@ -22,5 +21,20 @@ export default defineConfig({
|
|
|
22
21
|
},
|
|
23
22
|
reporters: ["default", ["junit", { outputFile: "test-report.xml" }]],
|
|
24
23
|
environment: "node",
|
|
24
|
+
pool: "threads",
|
|
25
|
+
workspace: [
|
|
26
|
+
{
|
|
27
|
+
test: {
|
|
28
|
+
include: ["**/test/*.test.ts"],
|
|
29
|
+
name: "unit",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
test: {
|
|
34
|
+
include: ["**/test/integration/*.test.ts"],
|
|
35
|
+
name: "integration",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
25
39
|
},
|
|
26
40
|
});
|