Skip to content

Commit 1c85ced

Browse files
authored
Add UDP Exporter release workflow and test sample app (#162)
*Issue #, if available:* *Description of changes:* Add Sample App for testing UDP Exporter Add a release workflow for UDP Exporter to publish the UDP exporter release to NPM. The release workflow will: 1. Compile the UDP exporter JS files and run unit tests. 2. Set up and run an instance of X-Ray daemon. 3. Run a validation app to send traces to X-Ray daemon via UDP exporter of the latest commit. 4. Validation step to verify that daemon received the traces. 5. (Currently commented out) Publish UDP Exporter to NPM. *Testing:* https://github.com/jj22ee/aws-otel-js-instrumentation/actions/runs/13665992607 By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent b542192 commit 1c85ced

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Release ADOT OTLP UDP Exporter
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
version:
6+
description: The version to tag the release with, e.g., 1.2.0
7+
required: true
8+
9+
jobs:
10+
build:
11+
environment: Release
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout Contrib Repo @ SHA - ${{ github.sha }}
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Node and run Unit Tests
18+
uses: ./.github/actions/set_up
19+
with:
20+
node_version: "20"
21+
package_name: "@aws/aws-otel-otlp-udp-exporter"
22+
os: ubuntu-latest
23+
run_unit_tests: true
24+
25+
# Project dependencies and compilation are already done in the previous step
26+
- name: Install Dependencies, Compile, and Build Tarball
27+
id: staging_tarball_build
28+
shell: bash
29+
run: |
30+
cd exporters/aws-otel-otlp-udp-exporter
31+
npm pack
32+
33+
- name: Download and run X-Ray Daemon
34+
run: |
35+
mkdir xray-daemon
36+
cd xray-daemon
37+
wget https://s3.us-west-2.amazonaws.com/aws-xray-assets.us-west-2/xray-daemon/aws-xray-daemon-linux-3.x.zip
38+
unzip aws-xray-daemon-linux-3.x.zip
39+
./xray -o -n us-west-2 -f ./daemon-logs.log --log-level debug &
40+
41+
- name: Setup Sample App
42+
run: |
43+
cd sample-applications/integ-test-http-server
44+
npm install
45+
npm install ../../exporters/aws-otel-otlp-udp-exporter/aws-aws-otel-otlp-udp-exporter-*.tgz
46+
47+
- name: Run Sample App in Background
48+
run: |
49+
cd sample-applications/integ-test-http-server
50+
node udp-exporter-test-server.js &
51+
# Wait for test server to initialize
52+
sleep 5
53+
54+
- name: Call Sample App Endpoint
55+
id: call-endpoint
56+
run: |
57+
echo "traceId=$(curl localhost:8080/test)" >> $GITHUB_OUTPUT
58+
59+
- name: Verify X-Ray daemon received traces
60+
run: |
61+
sleep 10
62+
echo "X-Ray daemon logs:"
63+
cat xray-daemon/daemon-logs.log
64+
# Check if the daemon received and processed some data
65+
if grep -q "sending.*batch" xray-daemon/daemon-logs.log; then
66+
echo "✅ X-Ray daemon processed trace data (AWS upload errors are expected)"
67+
exit 0
68+
elif grep -q "processor:.*segment" xray-daemon/daemon-logs.log; then
69+
echo "✅ X-Ray daemon processed segment data (AWS upload errors are expected)"
70+
exit 0
71+
else
72+
echo "❌ No evidence of traces being received by X-Ray daemon"
73+
exit 1
74+
fi
75+
76+
# TODO: Uncomment when we make the first release
77+
# # Publish OTLP UDP Exporter to npm
78+
# - name: Publish to npm
79+
# working-directory: exporters/aws-otel-otlp-udp-exporter
80+
# env:
81+
# NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
82+
# NPM_CONFIG_PROVENANCE: true
83+
# run: npx publish
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "simple-express-server-for-local-testing",
3+
"version": "1.0.0",
4+
"description": "",
5+
"private": true,
6+
"main": "index.js",
7+
"scripts": {
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"keywords": [],
11+
"author": "",
12+
"license": "Apache-2.0",
13+
"dependencies": {
14+
"@aws/aws-otel-otlp-udp-exporter": "file:../../exporters/aws-otel-otlp-udp-exporter/aws-aws-otel-otlp-udp-exporter-0.0.1.tgz",
15+
"@opentelemetry/api": "^1.9.0",
16+
"@opentelemetry/id-generator-aws-xray": "^1.2.2",
17+
"@opentelemetry/propagator-aws-xray": "^1.25.1",
18+
"@opentelemetry/sdk-node": "^0.52.1",
19+
"@opentelemetry/sdk-trace-base": "^1.25.1",
20+
"@opentelemetry/sdk-trace-node": "^1.25.1",
21+
"@types/express": "^4.17.21",
22+
"express": "^4.19.2"
23+
},
24+
"devDependencies": {
25+
"@types/node": "^22.1.0"
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
const { trace, SpanKind, context } = require('@opentelemetry/api');
4+
const { AlwaysOnSampler } = require('@opentelemetry/sdk-trace-node');
5+
const express = require('express');
6+
const process = require('process');
7+
const opentelemetry = require("@opentelemetry/sdk-node");
8+
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');
9+
const { AWSXRayPropagator } = require("@opentelemetry/propagator-aws-xray");
10+
const { AWSXRayIdGenerator } = require("@opentelemetry/id-generator-aws-xray");
11+
const { OTLPUdpSpanExporter } = require("@aws/aws-otel-otlp-udp-exporter")
12+
13+
const _traceExporter = new OTLPUdpSpanExporter();
14+
const _spanProcessor = new SimpleSpanProcessor(_traceExporter);
15+
16+
const PORT = parseInt(process.env.SAMPLE_APP_PORT || '8080', 10);
17+
const app = express();
18+
19+
app.get('/', (req, res) => {
20+
res.send(`healthcheck`)
21+
});
22+
23+
app.get('/test', (req, res) => {
24+
const tracer = trace.getTracer("testTracer");
25+
let ctx = context.active();
26+
let span = tracer.startSpan("testSpan", {kind: SpanKind.SERVER}, ctx);
27+
let traceId = span.spanContext().traceId;
28+
span.end();
29+
let xrayFormatTraceId = "1-" + traceId.substring(0,8) + "-" + traceId.substring(8);
30+
console.log(`X-Ray Trace ID is: ${xrayFormatTraceId}`);
31+
32+
res.send(`${xrayFormatTraceId}`);
33+
});
34+
35+
app.listen(PORT, async () => {
36+
await nodeSDKBuilder();
37+
console.log(`Listening for requests on http://localhost:${PORT}`);
38+
});
39+
40+
async function nodeSDKBuilder() {
41+
const sdk = new opentelemetry.NodeSDK({
42+
textMapPropagator: new AWSXRayPropagator(),
43+
instrumentations: [],
44+
spanProcessor: _spanProcessor,
45+
sampler: new AlwaysOnSampler(),
46+
idGenerator: new AWSXRayIdGenerator(),
47+
});
48+
49+
// this enables the API to record telemetry
50+
await sdk.start();
51+
52+
// gracefully shut down the SDK on process exit
53+
process.on('SIGTERM', () => {
54+
sdk.shutdown()
55+
.then(() => console.log('Tracing terminated'))
56+
.catch((error) => console.log('Error terminating tracing', error))
57+
.finally(() => process.exit(0));
58+
});
59+
}

0 commit comments

Comments
 (0)