Skip to content

Commit 16c99b8

Browse files
authored
Fix dynamic tags on alpine/musl (#105)
* Fix dynamic tags on alpine/musl * Unpin tracing libraries from a specific Pyroscope version * Add an integration test app (wip) * Add GitHub workflow for running tests * lower timeout * checkout submodules * Improve verifications script * Fix variable name
1 parent e8fc0e6 commit 16c99b8

23 files changed

+566
-22
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Integration Test
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build-profiler-images:
14+
name: Build Profiler Image
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
flavour:
19+
- glibc
20+
- musl
21+
steps:
22+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23+
with:
24+
submodules: true
25+
- name: Build ${{ matrix.flavour }} profiler image
26+
run: |
27+
if [ "${{ matrix.flavour }}" = "musl" ]; then
28+
docker build --platform linux/amd64 -t pyroscope-dotnet-musl:test -f Pyroscope.musl.Dockerfile --build-arg CMAKE_BUILD_TYPE=Debug .
29+
else
30+
docker build --platform linux/amd64 -t pyroscope-dotnet-glibc:test -f Pyroscope.Dockerfile --build-arg CMAKE_BUILD_TYPE=Debug .
31+
fi
32+
docker save pyroscope-dotnet-${{ matrix.flavour }}:test -o pyroscope-dotnet-${{ matrix.flavour }}.tar
33+
- name: Upload ${{ matrix.flavour }} profiler image artifact
34+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
35+
with:
36+
name: pyroscope-dotnet-${{ matrix.flavour }}
37+
path: pyroscope-dotnet-${{ matrix.flavour }}.tar
38+
retention-days: 1
39+
run-integration-test:
40+
name: Run Integration Test
41+
needs: build-profiler-images
42+
runs-on: ubuntu-latest
43+
strategy:
44+
matrix:
45+
dotnet_version:
46+
- '8.0'
47+
# - '7.0' # this does not work at the moment
48+
- '6.0'
49+
flavour:
50+
- glibc
51+
- musl
52+
steps:
53+
- name: Download ${{ matrix.flavour }} profiler image artifact
54+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
55+
with:
56+
name: pyroscope-dotnet-${{ matrix.flavour }}
57+
path: .
58+
- name: Load ${{matrix.flavour}} Docker image
59+
run: |
60+
docker load --input pyroscope-dotnet-${{ matrix.flavour }}.tar
61+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
62+
- name: Build service image for ${{ matrix.flavour }} and .NET ${{ matrix.dotnet_version }}
63+
run: |
64+
if [ "${{ matrix.flavour }}" = "glibc" ]; then
65+
SDK_IMAGE_SUFFIX="-jammy"
66+
else
67+
SDK_IMAGE_SUFFIX="-alpine"
68+
fi
69+
70+
docker build --platform linux/amd64 \
71+
--build-arg PYROSCOPE_SDK_IMAGE=pyroscope-dotnet-${{ matrix.flavour }}:test \
72+
--build-arg SDK_VERSION=${{ matrix.dotnet_version }} \
73+
--build-arg SDK_IMAGE_SUFFIX=${SDK_IMAGE_SUFFIX} \
74+
-t rideshare-app-${{ matrix.flavour }}:net${{ matrix.dotnet_version }} \
75+
-f itest.Dockerfile .
76+
- name: Run integration test
77+
run: |
78+
# Create a unique project name for this matrix combination
79+
VERSION_HYPHEN=$(echo "${{ matrix.dotnet_version }}" | tr '.' '-')
80+
export COMPOSE_PROJECT_NAME="pyroscope-dotnet-${{ matrix.flavour }}-net$VERSION_HYPHEN"
81+
82+
# Set the service name to start and to use in the load generator
83+
export SERVICE_NAME="rideshare-${{ matrix.flavour }}-net-$VERSION_HYPHEN"
84+
# Set up trap to ensure cleanup happens on exit
85+
trap 'docker compose -f docker-compose-itest.yml down --remove-orphans --volumes' EXIT
86+
87+
# Start the services
88+
docker compose -f docker-compose-itest.yml up --build --force-recreate -d pyroscope load-generator $SERVICE_NAME
89+
90+
# Run the verification script
91+
./IntegrationTest/verify_profiles.sh ${{ matrix.flavour }} ${{ matrix.dotnet_version }}
92+
93+
# Remove the trap since we're exiting normally
94+
trap - EXIT
95+
docker compose -f docker-compose-itest.yml down --remove-orphans --volumes

IntegrationTest/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/
2+
obj/

IntegrationTest/BikeService.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Example;
2+
3+
internal class BikeService
4+
{
5+
private readonly OrderService _orderService;
6+
7+
public BikeService(OrderService orderService)
8+
{
9+
_orderService = orderService;
10+
}
11+
12+
public void Order(int searchRadius)
13+
{
14+
_orderService.FindNearestVehicle(searchRadius, "bike");
15+
}
16+
}

IntegrationTest/CarService.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Example;
2+
3+
internal class CarService
4+
{
5+
private readonly OrderService _orderService;
6+
7+
public CarService(OrderService orderService)
8+
{
9+
_orderService = orderService;
10+
}
11+
12+
public void Order(int searchRadius)
13+
{
14+
_orderService.FindNearestVehicle(searchRadius, "car");
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM python:3.9
2+
3+
RUN pip3 install requests
4+
5+
COPY load-generator.py ./load-generator.py
6+
7+
ENV PYTHONUNBUFFERED=1
8+
9+
CMD [ "python", "load-generator.py" ]
10+

IntegrationTest/OrderService.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
3+
namespace Example;
4+
5+
internal class OrderService
6+
{
7+
public void FindNearestVehicle(long searchRadius, string vehicle)
8+
{
9+
lock (_lock)
10+
{
11+
var labels = Pyroscope.LabelSet.Empty.BuildUpon()
12+
.Add("vehicle", vehicle)
13+
.Build();
14+
Pyroscope.LabelsWrapper.Do(labels, () =>
15+
{
16+
for (long i = 0; i < searchRadius * 1000000000; i++)
17+
{
18+
}
19+
20+
if (vehicle.Equals("car"))
21+
{
22+
CheckDriverAvailability(labels, searchRadius);
23+
}
24+
});
25+
}
26+
}
27+
28+
private readonly object _lock = new();
29+
30+
private static void CheckDriverAvailability(Pyroscope.LabelSet ctx, long searchRadius)
31+
{
32+
var region = System.Environment.GetEnvironmentVariable("REGION") ?? "unknown_region";
33+
ctx = ctx.BuildUpon()
34+
.Add("driver_region", region)
35+
.Build();
36+
Pyroscope.LabelsWrapper.Do(ctx, () =>
37+
{
38+
for (long i = 0; i < searchRadius * 1000000000; i++)
39+
{
40+
}
41+
42+
var now = DateTime.Now.Minute % 2 == 0;
43+
var forceMutexLock = DateTime.Now.Minute % 2 == 0;
44+
if ("eu-north".Equals(region) && forceMutexLock)
45+
{
46+
MutexLock(searchRadius);
47+
}
48+
});
49+
}
50+
51+
private static void MutexLock(long searchRadius)
52+
{
53+
for (long i = 0; i < 30 * searchRadius * 1000000000; i++)
54+
{
55+
}
56+
}
57+
}

IntegrationTest/Program.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Threading;
5+
using System.Collections;
6+
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Builder;
9+
using Microsoft.Extensions.DependencyInjection;
10+
11+
namespace Example;
12+
13+
public static class Program
14+
{
15+
private static readonly List<FileStream> Files = new();
16+
public static void Main(string[] args)
17+
{
18+
var orderService = new OrderService();
19+
var bikeService = new BikeService(orderService);
20+
var scooterService = new ScooterService(orderService);
21+
var carService = new CarService(orderService);
22+
23+
var builder = WebApplication.CreateBuilder(args);
24+
var app = builder.Build();
25+
26+
app.MapGet("/bike", () =>
27+
{
28+
bikeService.Order(1);
29+
return "Bike ordered";
30+
});
31+
app.MapGet("/scooter", () =>
32+
{
33+
scooterService.Order(2);
34+
return "Scooter ordered";
35+
});
36+
37+
app.MapGet("/car", () =>
38+
{
39+
carService.Order(3);
40+
return "Car ordered";
41+
});
42+
43+
app.Run();
44+
}
45+
}

IntegrationTest/Rideshare.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<TargetFramework>net6.0</TargetFramework>
4+
<AssemblyName>rideshare</AssemblyName>
5+
<OutputType>Exe</OutputType>
6+
<PackageId>rideshare</PackageId>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="../Pyroscope/Pyroscope/Pyroscope.csproj" />
11+
</ItemGroup>
12+
</Project>

IntegrationTest/ScooterService.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Diagnostics;
2+
3+
namespace Example;
4+
5+
internal class ScooterService
6+
{
7+
private readonly OrderService _orderService;
8+
9+
public ScooterService(OrderService orderService)
10+
{
11+
_orderService = orderService;
12+
}
13+
14+
public void Order(int searchRadius)
15+
{
16+
for (long i = 0; i < 2000000000; i++)
17+
{
18+
}
19+
OrderInternal(searchRadius);
20+
DoSomeOtherWork();
21+
}
22+
23+
private void OrderInternal(int searchRadius)
24+
{
25+
_orderService.FindNearestVehicle(searchRadius, "scooter");
26+
}
27+
28+
private void DoSomeOtherWork()
29+
{
30+
for (long i = 0; i < 1000000000; i++)
31+
{
32+
}
33+
}
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
apiVersion: 1
3+
datasources:
4+
- uid: pyroscope
5+
type: grafana-pyroscope-datasource
6+
name: Pyroscope
7+
url: http://pyroscope:4040
8+
jsonData:
9+
keepCookies: [pyroscope_git_session]

0 commit comments

Comments
 (0)