Skip to content

Commit 3189981

Browse files
authored
doc: dotnet tracing example (#3891)
* doc: dotnet tracing example * delete musl.Dockerfile
1 parent b28a42c commit 3189981

File tree

18 files changed

+587
-1
lines changed

18 files changed

+587
-1
lines changed

docs/sources/configure-client/trace-span-profiles/dotnet-span-profiles.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ Refer to the [Tempo data source configuration documentation](https://grafana.com
8080

8181
## Examples
8282

83-
Check out the [examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) directory for a complete demo application of span profiles in multiple languages.
83+
Check out these demo applications for span profiles:
84+
- [.NET example](https://github.com/grafana/pyroscope/tree/main/examples/tracing/dotnet)
85+
- [Other examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) in multiple languages

examples/tracing/dotnet/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.so

examples/tracing/dotnet/Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
ARG SDK_VERSION=8.0
2+
# The build images takes an SDK image of the buildplatform, so the platform the build is running on.
3+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:$SDK_VERSION AS build
4+
5+
ARG TARGETPLATFORM
6+
ARG BUILDPLATFORM
7+
ARG SDK_VERSION
8+
9+
WORKDIR /dotnet
10+
11+
ADD example .
12+
13+
# Set the target framework to SDK_VERSION
14+
RUN sed -i -E 's|<TargetFramework>.*</TargetFramework>|<TargetFramework>net'$SDK_VERSION'</TargetFramework>|' Example.csproj
15+
16+
# We hardcode linux-x64 here, as the profiler doesn't support any other platform
17+
RUN dotnet publish -o . --framework net$SDK_VERSION --runtime linux-x64 --no-self-contained
18+
19+
# This fetches the SDK
20+
FROM --platform=linux/amd64 pyroscope/pyroscope-dotnet:0.9.2-glibc AS sdk
21+
22+
# Runtime only image of the targetplatfrom, so the platform the image will be running on.
23+
FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:$SDK_VERSION
24+
25+
WORKDIR /dotnet
26+
27+
COPY --from=sdk /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so
28+
COPY --from=sdk /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so
29+
COPY --from=build /dotnet/ ./
30+
31+
32+
ENV CORECLR_ENABLE_PROFILING=1
33+
ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A}
34+
ENV CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so
35+
ENV LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so
36+
37+
ENV PYROSCOPE_APPLICATION_NAME=rideshare.dotnet.push.app
38+
ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040
39+
ENV PYROSCOPE_LOG_LEVEL=debug
40+
ENV PYROSCOPE_PROFILING_ENABLED=1
41+
ENV PYROSCOPE_PROFILING_ALLOCATION_ENABLED=true
42+
ENV PYROSCOPE_PROFILING_CONTENTION_ENABLED=true
43+
ENV PYROSCOPE_PROFILING_EXCEPTION_ENABLED=true
44+
ENV PYROSCOPE_PROFILING_HEAP_ENABLED=true
45+
ENV RIDESHARE_LISTEN_PORT=5000
46+
47+
48+
CMD sh -c "ASPNETCORE_URLS=http://*:${RIDESHARE_LISTEN_PORT} exec dotnet /dotnet/example.dll"
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+

examples/tracing/dotnet/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Span Profiles with Grafana Tempo and Pyroscope
2+
3+
The docker compose consists of:
4+
- The .NET Rideshare App
5+
- Tempo
6+
- Pyroscope
7+
- Grafana
8+
9+
The `rideshare` app generate traces and profiling data that should be available in Grafana.
10+
Datasources for Pyroscope and Tempo are provisioned automatically.
11+
12+
### Build and run
13+
14+
The project can be run locally with the following commands:
15+
16+
```shell
17+
# (optionally) pull latest pyroscope and grafana images:
18+
docker pull grafana/pyroscope:latest
19+
docker pull grafana/grafana:latest
20+
21+
# build and run the example
22+
docker compose up --build
23+
```
24+
25+
Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22f36%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.dotnet.push.app%22%5D,%22valueType%22:%22string%22%7D%5D,%22query%22:%22%7Bresource.service.name%3D%5C%22rideshare.dotnet.push.app%5C%22%7D%22%7D%5D,%22range%22:%7B%22from%22:%22now-15m%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile:
26+
27+
![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593)
28+
29+
By default, only the root span gets labeled (the first span created locally): such spans are marked with the _link_ icon
30+
and have the `pyroscope.profile.id` attribute set to the corresponding span ID.
31+
Please note that presence of the attribute does not necessarily
32+
indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is
33+
less than the sample interval (10ms).
34+
35+
### Instrumentation
36+
37+
The `rideshare` demo application is instrumented with Pyroscope: [Pyroscope .NET Agent](https://github.com/grafana/pyroscope-dotnet)
38+
39+
### Grafana Tempo configuration
40+
41+
In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured:
42+
- The profiling data source
43+
- Tags to use when making profiling queries
44+
45+
![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c)
46+
47+
While tags are optional, configuring them is highly recommended for optimizing query performance.
48+
In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label.
49+
This configuration restricts the data set for lookup, ensuring that queries remain
50+
consistently fast. Note that the tags you configure must be present in the span attributes or resources
51+
for a trace to profiles span link to appear.
52+
53+
Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
services:
2+
pyroscope:
3+
image: grafana/pyroscope
4+
ports:
5+
- "4040:4040"
6+
7+
us-east:
8+
ports:
9+
- "5000"
10+
environment: &env
11+
OTLP_URL: tempo:4318
12+
OTEL_TRACES_EXPORTER: otlp
13+
OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317
14+
OTEL_SERVICE_NAME: rideshare.dotnet.push.app
15+
OTEL_METRICS_EXPORTER: none
16+
OTEL_TRACES_SAMPLER: always_on
17+
OTEL_PROPAGATORS: tracecontext
18+
REGION: us-east
19+
PYROSCOPE_LABELS: region=us-east
20+
PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040
21+
build:
22+
context: .
23+
eu-north:
24+
ports:
25+
- "5000"
26+
environment:
27+
<<: *env
28+
REGION: eu-north
29+
build:
30+
context: .
31+
ap-south:
32+
ports:
33+
- "5000"
34+
environment:
35+
<<: *env
36+
REGION: ap-south
37+
build:
38+
context: .
39+
40+
load-generator:
41+
build:
42+
context: .
43+
dockerfile: Dockerfile.load-generator
44+
45+
grafana:
46+
image: grafana/grafana:latest
47+
environment:
48+
- GF_INSTALL_PLUGINS=grafana-pyroscope-app
49+
- GF_AUTH_ANONYMOUS_ENABLED=true
50+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
51+
- GF_AUTH_DISABLE_LOGIN_FORM=true
52+
- GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph
53+
volumes:
54+
- ./grafana-provisioning:/etc/grafana/provisioning
55+
ports:
56+
- "3000:3000"
57+
58+
tempo:
59+
image: grafana/tempo:latest
60+
command: [ "-config.file=/etc/tempo.yml" ]
61+
volumes:
62+
- ./tempo/tempo.yml:/etc/tempo.yml
63+
ports:
64+
- "14268:14268" # jaeger ingest
65+
- "3200:3200" # tempo
66+
- "9095:9095" # tempo grpc
67+
- "4317:4317" # otlp grpc
68+
- "4318:4318" # otlp http
69+
- "9411:9411" # zipkin
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/
2+
obj/
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+
}
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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<AssemblyName>example</AssemblyName>
5+
<OutputType>Exe</OutputType>
6+
<PackageId>example</PackageId>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.8.0" />
11+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.0" />
12+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.0" />
13+
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.8.1" />
14+
<PackageReference Include="Pyroscope.OpenTelemetry" Version="0.2.0" />
15+
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
16+
</ItemGroup>
17+
</Project>

0 commit comments

Comments
 (0)