diff --git a/.github/workflows/release-udp-exporter.yml b/.github/workflows/release-udp-exporter.yml new file mode 100644 index 00000000..95c20816 --- /dev/null +++ b/.github/workflows/release-udp-exporter.yml @@ -0,0 +1,83 @@ +name: Release ADOT OTLP UDP Exporter +on: + workflow_dispatch: + inputs: + version: + description: The version to tag the release with, e.g., 1.2.0 + required: true + +jobs: + build: + environment: Release + runs-on: ubuntu-latest + steps: + - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Node and run Unit Tests + uses: ./.github/actions/set_up + with: + node_version: "20" + package_name: "@aws/aws-otel-otlp-udp-exporter" + os: ubuntu-latest + run_unit_tests: true + + # Project dependencies and compilation are already done in the previous step + - name: Install Dependencies, Compile, and Build Tarball + id: staging_tarball_build + shell: bash + run: | + cd exporters/aws-otel-otlp-udp-exporter + npm pack + + - name: Download and run X-Ray Daemon + run: | + mkdir xray-daemon + cd xray-daemon + wget https://s3.us-west-2.amazonaws.com/aws-xray-assets.us-west-2/xray-daemon/aws-xray-daemon-linux-3.x.zip + unzip aws-xray-daemon-linux-3.x.zip + ./xray -o -n us-west-2 -f ./daemon-logs.log --log-level debug & + + - name: Setup Sample App + run: | + cd sample-applications/integ-test-http-server + npm install + npm install ../../exporters/aws-otel-otlp-udp-exporter/aws-aws-otel-otlp-udp-exporter-*.tgz + + - name: Run Sample App in Background + run: | + cd sample-applications/integ-test-http-server + node udp-exporter-test-server.js & + # Wait for test server to initialize + sleep 5 + + - name: Call Sample App Endpoint + id: call-endpoint + run: | + echo "traceId=$(curl localhost:8080/test)" >> $GITHUB_OUTPUT + + - name: Verify X-Ray daemon received traces + run: | + sleep 10 + echo "X-Ray daemon logs:" + cat xray-daemon/daemon-logs.log + # Check if the daemon received and processed some data + if grep -q "sending.*batch" xray-daemon/daemon-logs.log; then + echo "✅ X-Ray daemon processed trace data (AWS upload errors are expected)" + exit 0 + elif grep -q "processor:.*segment" xray-daemon/daemon-logs.log; then + echo "✅ X-Ray daemon processed segment data (AWS upload errors are expected)" + exit 0 + else + echo "❌ No evidence of traces being received by X-Ray daemon" + exit 1 + fi + + # TODO: Uncomment when we make the first release + # # Publish OTLP UDP Exporter to npm + # - name: Publish to npm + # working-directory: exporters/aws-otel-otlp-udp-exporter + # env: + # NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + # NPM_CONFIG_PROVENANCE: true + # run: npx publish diff --git a/sample-applications/integ-test-http-server/package.json b/sample-applications/integ-test-http-server/package.json new file mode 100644 index 00000000..8500f5dd --- /dev/null +++ b/sample-applications/integ-test-http-server/package.json @@ -0,0 +1,27 @@ +{ + "name": "simple-express-server-for-local-testing", + "version": "1.0.0", + "description": "", + "private": true, + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@aws/aws-otel-otlp-udp-exporter": "file:../../exporters/aws-otel-otlp-udp-exporter/aws-aws-otel-otlp-udp-exporter-0.0.1.tgz", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/id-generator-aws-xray": "^1.2.2", + "@opentelemetry/propagator-aws-xray": "^1.25.1", + "@opentelemetry/sdk-node": "^0.52.1", + "@opentelemetry/sdk-trace-base": "^1.25.1", + "@opentelemetry/sdk-trace-node": "^1.25.1", + "@types/express": "^4.17.21", + "express": "^4.19.2" + }, + "devDependencies": { + "@types/node": "^22.1.0" + } +} diff --git a/sample-applications/integ-test-http-server/udp-exporter-test-server.js b/sample-applications/integ-test-http-server/udp-exporter-test-server.js new file mode 100644 index 00000000..9f51e718 --- /dev/null +++ b/sample-applications/integ-test-http-server/udp-exporter-test-server.js @@ -0,0 +1,59 @@ +'use strict'; + +const { trace, SpanKind, context } = require('@opentelemetry/api'); +const { AlwaysOnSampler } = require('@opentelemetry/sdk-trace-node'); +const express = require('express'); +const process = require('process'); +const opentelemetry = require("@opentelemetry/sdk-node"); +const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { AWSXRayPropagator } = require("@opentelemetry/propagator-aws-xray"); +const { AWSXRayIdGenerator } = require("@opentelemetry/id-generator-aws-xray"); +const { OTLPUdpSpanExporter } = require("@aws/aws-otel-otlp-udp-exporter") + +const _traceExporter = new OTLPUdpSpanExporter(); +const _spanProcessor = new SimpleSpanProcessor(_traceExporter); + +const PORT = parseInt(process.env.SAMPLE_APP_PORT || '8080', 10); +const app = express(); + +app.get('/', (req, res) => { + res.send(`healthcheck`) +}); + +app.get('/test', (req, res) => { + const tracer = trace.getTracer("testTracer"); + let ctx = context.active(); + let span = tracer.startSpan("testSpan", {kind: SpanKind.SERVER}, ctx); + let traceId = span.spanContext().traceId; + span.end(); + let xrayFormatTraceId = "1-" + traceId.substring(0,8) + "-" + traceId.substring(8); + console.log(`X-Ray Trace ID is: ${xrayFormatTraceId}`); + + res.send(`${xrayFormatTraceId}`); +}); + +app.listen(PORT, async () => { + await nodeSDKBuilder(); + console.log(`Listening for requests on http://localhost:${PORT}`); +}); + +async function nodeSDKBuilder() { + const sdk = new opentelemetry.NodeSDK({ + textMapPropagator: new AWSXRayPropagator(), + instrumentations: [], + spanProcessor: _spanProcessor, + sampler: new AlwaysOnSampler(), + idGenerator: new AWSXRayIdGenerator(), + }); + + // this enables the API to record telemetry + await sdk.start(); + + // gracefully shut down the SDK on process exit + process.on('SIGTERM', () => { + sdk.shutdown() + .then(() => console.log('Tracing terminated')) + .catch((error) => console.log('Error terminating tracing', error)) + .finally(() => process.exit(0)); + }); +}