Skip to content

Commit 1f4f454

Browse files
authored
feat: Set up UDP Exporter Release Workflow (#184)
1 parent 3c11b63 commit 1f4f454

File tree

15 files changed

+772
-0
lines changed

15 files changed

+772
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Release ADOT OTLP UDP Exporter
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Version number for deployment e.g. 0.1.0'
8+
required: true
9+
type: string
10+
11+
jobs:
12+
build-test-publish:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
17+
- name: Set up .NET CLI
18+
uses: actions/setup-dotnet@v2
19+
with:
20+
dotnet-version: '8.0.x'
21+
22+
- name: Download and run X-Ray Daemon
23+
run: |
24+
mkdir xray-daemon
25+
cd xray-daemon
26+
wget https://s3.us-west-2.amazonaws.com/aws-xray-assets.us-west-2/xray-daemon/aws-xray-daemon-linux-3.x.zip
27+
unzip aws-xray-daemon-linux-3.x.zip
28+
./xray -o -n us-west-2 -f ./daemon-logs.log --log-level debug &
29+
30+
- name: Create NuGet.Config with multiple sources
31+
working-directory: sample-applications/udp-exporter-test-app
32+
run: |
33+
cat > NuGet.Config << EOF
34+
<?xml version="1.0" encoding="utf-8"?>
35+
<configuration>
36+
<packageSources>
37+
<clear />
38+
<add key="local-udp-exporter" value="$GITHUB_WORKSPACE/exporters/AWS.OpenTelemetry.Exporter.Otlp.Udp/bin/Release" />
39+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
40+
</packageSources>
41+
</configuration>
42+
EOF
43+
44+
# Show the created config
45+
cat NuGet.Config
46+
47+
48+
- name: Build & Package the UDP exporter locally
49+
working-directory: exporters/AWS.OpenTelemetry.Exporter.Otlp.Udp
50+
run: |
51+
dotnet pack -c Release
52+
53+
- name: Run Sample App in Background
54+
working-directory: sample-applications/udp-exporter-test-app
55+
run: |
56+
# Install the locally built version of the UDP exporter
57+
dotnet add package AWS.OpenTelemetry.Exporter.Otlp.Udp
58+
# Start validation app
59+
dotnet run &
60+
# Wait for validation app to initialize
61+
sleep 5
62+
63+
- name: Call Sample App Endpoint
64+
run: |
65+
curl localhost:8080/test
66+
67+
- name: Verify X-Ray daemon received traces
68+
run: |
69+
sleep 10
70+
echo "X-Ray daemon logs:"
71+
cat xray-daemon/daemon-logs.log
72+
73+
# Check if the daemon received and processed some data
74+
if grep -q "sending.*batch" xray-daemon/daemon-logs.log; then
75+
echo "✅ X-Ray daemon processed trace data (AWS upload errors are expected)"
76+
exit 0
77+
elif grep -q "processor:.*segment" xray-daemon/daemon-logs.log; then
78+
echo "✅ X-Ray daemon processed segment data (AWS upload errors are expected)"
79+
exit 0
80+
else
81+
echo "❌ No evidence of traces being received by X-Ray daemon"
82+
exit 1
83+
fi
84+
85+
# TODO: Steps to publish to NuGet
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using Amazon.S3;
3+
using Microsoft.AspNetCore.Mvc;
4+
using System.Diagnostics;
5+
using System.Net.Http;
6+
using Microsoft.AspNetCore.Http.Extensions;
7+
using OpenTelemetry;
8+
using OpenTelemetry.Metrics;
9+
using OpenTelemetry.Instrumentation;
10+
using System.Diagnostics.Metrics;
11+
using OpenTelemetry.Resources;
12+
using OpenTelemetry.Trace;
13+
14+
namespace dotnet_sample_app.Controllers
15+
{
16+
[ApiController]
17+
[Route("[controller]")]
18+
public class AppController : ControllerBase
19+
{
20+
private readonly AmazonS3Client s3Client = new AmazonS3Client();
21+
private readonly HttpClient httpClient = new HttpClient();
22+
private static Random rand = new Random(DateTime.Now.Millisecond);
23+
24+
public static readonly ActivitySource tracer = new(
25+
"dotnet-sample-app");
26+
27+
public AppController() {}
28+
29+
[HttpGet]
30+
[Route("/outgoing-http-call")]
31+
public string OutgoingHttp()
32+
{
33+
using var activity = tracer.StartActivity("outgoing-http-call");
34+
activity?.SetTag("language", "dotnet");
35+
activity?.SetTag("signal", "trace");
36+
37+
var res = httpClient.GetAsync("https://aws.amazon.com/").Result;
38+
string statusCode = res.StatusCode.ToString();
39+
40+
// Request Based Metrics
41+
Startup.metricEmitter.emitReturnTimeMetric(MimicLatency());
42+
int loadSize = MimicPayLoadSize();
43+
Startup.metricEmitter.apiRequestSentMetric();
44+
Startup.metricEmitter.updateTotalBytesSentMetric(loadSize);
45+
46+
return GetTraceId();
47+
}
48+
49+
[HttpGet]
50+
[Route("/test")]
51+
public string AWSSDKCall()
52+
{
53+
using var activity = tracer.StartActivity("test_parent_span");
54+
activity?.SetTag("language", "dotnet");
55+
activity?.SetTag("signal", "trace");
56+
activity?.SetTag("test.attribute", "test_value");
57+
58+
string traceId = activity?.TraceId.ToString() ?? "no-trace-available";
59+
60+
return traceId;
61+
}
62+
63+
[HttpGet]
64+
[Route("/")]
65+
public string Default()
66+
{
67+
return "Application started!";
68+
}
69+
70+
[HttpGet]
71+
[Route("/outgoing-sampleapp")]
72+
public string OutgoingSampleApp()
73+
{
74+
using var activity = tracer.StartActivity("outgoing-sampleapp");
75+
activity?.SetTag("language", "dotnet");
76+
activity?.SetTag("signal", "trace");
77+
string statusCode = "";
78+
79+
if (Program.cfg.SampleAppPorts.Length == 0) {
80+
var res = httpClient.GetAsync("https://aws.amazon.com/").Result;
81+
statusCode = res.StatusCode.ToString();
82+
}
83+
else {
84+
foreach (string port in Program.cfg.SampleAppPorts) {
85+
if (!String.IsNullOrEmpty(port)) {
86+
string uri = string.Format("http://127.0.0.1:{0}/outgoing-sampleapp", port);
87+
var res = httpClient.GetAsync(uri).Result;
88+
statusCode = res.StatusCode.ToString();
89+
}
90+
}
91+
}
92+
93+
// Request Based Metrics
94+
Startup.metricEmitter.emitReturnTimeMetric(MimicLatency());
95+
int loadSize = MimicPayLoadSize();
96+
Startup.metricEmitter.apiRequestSentMetric();
97+
Startup.metricEmitter.updateTotalBytesSentMetric(loadSize);
98+
99+
return GetTraceId();
100+
}
101+
102+
private string GetTraceId()
103+
{
104+
var traceId = Activity.Current.TraceId.ToHexString();
105+
var version = "1";
106+
var epoch = traceId.Substring(0, 8);
107+
var random = traceId.Substring(8);
108+
return "{" + "\"traceId\"" + ": " + "\"" + version + "-" + epoch + "-" + random + "\"" + "}";
109+
}
110+
111+
private static int MimicPayLoadSize()
112+
{
113+
return rand.Next(101);
114+
}
115+
116+
private static int MimicLatency()
117+
{
118+
return rand.Next(100,500);
119+
}
120+
}
121+
122+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.IO;
2+
using YamlDotNet.Serialization;
3+
using YamlDotNet.Serialization.NamingConventions;
4+
5+
namespace dotnet_sample_app.Controllers
6+
{
7+
public class Config
8+
{
9+
public string Host;
10+
public string Port;
11+
public int TimeInterval;
12+
public int RandomTimeAliveIncrementer;
13+
public int RandomTotalHeapSizeUpperBound;
14+
public int RandomThreadsActiveUpperBound;
15+
public int RandomCpuUsageUpperBound;
16+
public string[] SampleAppPorts;
17+
18+
public Config() {
19+
this.Host = "0.0.0.0";
20+
this.Port = "8080";
21+
this.TimeInterval = 1;
22+
this.RandomTimeAliveIncrementer = 1;
23+
this.RandomTotalHeapSizeUpperBound = 100;
24+
this.RandomThreadsActiveUpperBound = 10;
25+
this.RandomCpuUsageUpperBound = 100;
26+
this.SampleAppPorts = new string[0];
27+
}
28+
29+
public static Config ReadInFile(string file) {
30+
var deserializer = new DeserializerBuilder()
31+
.WithNamingConvention(PascalCaseNamingConvention.Instance)
32+
.Build();
33+
34+
Config returnConfig = null;
35+
try {
36+
returnConfig = deserializer.Deserialize<Config>(File.ReadAllText(file));
37+
}
38+
catch {
39+
returnConfig = new Config();
40+
}
41+
return returnConfig;
42+
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)