Voorbeeld: OpenTelemetry gebruiken met Prometheus, Grafana en Jaeger
In dit voorbeeld wordt Prometheus gebruikt voor het verzamelen van metrische gegevens, Grafana voor het maken van een dashboard en Jaeger om gedistribueerde tracering weer te geven.
1. Het project maken
Maak een eenvoudig web-API-project met behulp van de ASP.NET Core Empty-sjabloon in Visual Studio of de volgende .NET CLI-opdracht:
dotnet new web
2. Metrische gegevens en activiteitsdefinities toevoegen
De volgende code definieert een nieuwe metrische waarde (greetings.count
) voor het aantal keren dat de API is aangeroepen en een nieuwe activiteitsbron (OtPrGrYa.Example
).
// Custom metrics for the application
var greeterMeter = new Meter("OtPrGrYa.Example", "1.0.0");
var countGreetings = greeterMeter.CreateCounter<int>("greetings.count", description: "Counts the number of greetings");
// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OtPrGrJa.Example");
3. Een API-eindpunt maken
app.MapGet("/", SendGreeting);
async Task<String> SendGreeting(ILogger<Program> logger)
{
// Create a new Activity scoped to the method
using var activity = greeterActivitySource.StartActivity("GreeterActivity");
// Log a message
logger.LogInformation("Sending greeting");
// Increment the custom counter
countGreetings.Add(1);
// Add a tag to the Activity
activity?.SetTag("greeting", "Hello World!");
return "Hello World!";
}
Notitie
De API-definitie gebruikt niets specifieks voor OpenTelemetry. De .NET-API's worden gebruikt voor waarneembaarheid.
4. Verwijzen naar de OpenTelemetry-pakketten
Gebruik de NuGet-Pakketbeheer of opdrachtregel om de volgende NuGet-pakketten toe te voegen:
<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
</ItemGroup>
Notitie
Gebruik de nieuwste versies, omdat de OTel-API's voortdurend in ontwikkeling zijn.
5. OpenTelemetry configureren met de juiste providers
var tracingOtlpEndpoint = builder.Configuration["OTLP_ENDPOINT_URL"];
var otel = builder.Services.AddOpenTelemetry();
// Configure OpenTelemetry Resources with the application name
otel.ConfigureResource(resource => resource
.AddService(serviceName: builder.Environment.ApplicationName));
// Add Metrics for ASP.NET Core and our custom metrics and export to Prometheus
otel.WithMetrics(metrics => metrics
// Metrics provider from OpenTelemetry
.AddAspNetCoreInstrumentation()
.AddMeter(greeterMeter.Name)
// Metrics provides by ASP.NET Core in .NET 8
.AddMeter("Microsoft.AspNetCore.Hosting")
.AddMeter("Microsoft.AspNetCore.Server.Kestrel")
.AddPrometheusExporter());
// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
otel.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation();
tracing.AddHttpClientInstrumentation();
tracing.AddSource(greeterActivitySource.Name);
if (tracingOtlpEndpoint != null)
{
tracing.AddOtlpExporter(otlpOptions =>
{
otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
});
}
else
{
tracing.AddConsoleExporter();
}
});
Deze code maakt gebruik van ASP.NET Core-instrumentatie om metrische gegevens en activiteiten van ASP.NET Core op te halen. Ook worden de Metrics
en ActivitySource
providers geregistreerd voor respectievelijk metrische gegevens en tracering.
De code maakt gebruik van de Prometheus-exporteur voor metrische gegevens, die gebruikmaakt van ASP.NET Core om het eindpunt te hosten, dus u moet ook het volgende toevoegen:
// Configure the Prometheus scraping endpoint
app.MapPrometheusScrapingEndpoint();
6. Het project uitvoeren
Voer het project uit en open vervolgens de API met de browser of curl.
curl -k http://localhost:7275
Telkens wanneer u de pagina aanvraagt, wordt de telling verhoogd voor het aantal begroetingen dat is gedaan. U hebt toegang tot het eindpunt voor metrische gegevens met behulp van dezelfde basis-URL, met het pad /metrics
.
6.1 Logboekuitvoer
De logboekregistratie-instructies van de code worden uitgevoerd met behulp van ILogger
. De consoleprovider is standaard ingeschakeld, zodat de uitvoer wordt omgeleid naar de console.
Er zijn een aantal opties voor het uitgaan van logboeken vanuit .NET:
stdout
enstderr
uitvoer wordt omgeleid naar logboekbestanden door containersystemen zoals Kubernetes.- Met behulp van logboekbibliotheken die worden geïntegreerd met ILogger, zijn deze onder andere Serilog of NLog.
- Het gebruik van logboekproviders voor OTel, zoals OTLP of de Azure Monitor-exporteur, wordt hieronder verder weergegeven.
6.2 Toegang tot de metrische gegevens
U hebt toegang tot de metrische gegevens met behulp van het /metrics
eindpunt.
curl -k https://localhost:7275/
Hello World!
curl -k https://localhost:7275/metrics
# TYPE greetings_count counter
# HELP greetings_count Counts the number of greetings
greetings_count 1 1686894204856
# TYPE current_connections gauge
# HELP current_connections Number of connections that are currently active on the server.
current_connections{endpoint="127.0.0.1:7275"} 1 1686894204856
current_connections{endpoint="[::1]:7275"} 0 1686894204856
current_connections{endpoint="[::1]:5212"} 1 1686894204856
...
De uitvoer van metrische gegevens is een momentopname van de metrische gegevens op het moment dat het eindpunt wordt aangevraagd. De resultaten worden aangeboden in prometheus tentoonstellingsindeling, die door de mens leesbaar maar beter begrepen wordt door Prometheus. Dit onderwerp wordt behandeld in de volgende fase.
6.3 Toegang tot de tracering
Als u naar de console voor de server kijkt, ziet u de uitvoer van de consoletraceringexporteur, die de informatie uitvoert in een door mensen leesbare indeling. Er moeten twee activiteiten worden weergegeven, één van uw aangepaste ActivitySource
activiteiten en de andere van ASP.NET Core:
Activity.TraceId: 2e00dd5e258d33fe691b965607b91d18
Activity.SpanId: 3b7a891f55b97f1a
Activity.TraceFlags: Recorded
Activity.ParentSpanId: 645071fd0011faac
Activity.ActivitySourceName: OtPrGrYa.Example
Activity.DisplayName: GreeterActivity
Activity.Kind: Internal
Activity.StartTime: 2023-06-16T04:50:26.7675469Z
Activity.Duration: 00:00:00.0023974
Activity.Tags:
greeting: Hello World!
Resource associated with Activity:
service.name: OTel-Prometheus-Grafana-Jaeger
service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.5.0
Activity.TraceId: 2e00dd5e258d33fe691b965607b91d18
Activity.SpanId: 645071fd0011faac
Activity.TraceFlags: Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName: /
Activity.Kind: Server
Activity.StartTime: 2023-06-16T04:50:26.7672615Z
Activity.Duration: 00:00:00.0121259
Activity.Tags:
net.host.name: localhost
net.host.port: 7275
http.method: GET
http.scheme: https
http.target: /
http.url: https://localhost:7275/
http.flavor: 1.1
http.user_agent: curl/8.0.1
http.status_code: 200
Resource associated with Activity:
service.name: OTel-Prometheus-Grafana-Jaeger
service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
telemetry.sdk.name: opentelemetry
telemetry.sdk.language: dotnet
telemetry.sdk.version: 1.5.0
De eerste is de interne aangepaste activiteit die u hebt gemaakt. De tweede wordt gemaakt door ASP.NET voor de aanvraag en bevat tags voor de eigenschappen van de HTTP-aanvraag. U ziet dat beide hetzelfde TraceId
hebben, waarmee één transactie wordt geïdentificeerd en dat in een gedistribueerd systeem kan worden gebruikt om de traceringen van elke service die betrokken is bij een transactie te correleren. De id's worden verzonden als HTTP-headers. ASP.NET Core een TraceId
als er geen aanwezig is wanneer er een aanvraag wordt ontvangen. HttpClient
bevat standaard de headers voor uitgaande aanvragen. Elke activiteit heeft een SpanId
, wat de combinatie is van TraceId
en SpanId
die elke activiteit uniek identificeert. De Greeter
activiteit wordt gekoppeld aan de HTTP-activiteit via ParentSpanId
de activiteit, die wordt toegewezen aan de SpanId
HTTP-activiteit.
In een latere fase voert u deze gegevens in Jaeger in om de gedistribueerde traceringen te visualiseren.
7. Metrische gegevens verzamelen met Prometheus
Prometheus is een verzameling, aggregatie en tijdreeksdatabasesysteem voor metrische gegevens. U configureert deze met de metrische eindpunten voor elke service en de waarden worden periodiek verwijderd en opgeslagen in de tijdreeksdatabase. Vervolgens kunt u ze analyseren en verwerken als dat nodig is.
De metrische gegevens die worden weergegeven in de Prometheus-indeling, zijn een momentopname van een bepaald tijdstip van de metrische gegevens van het proces. Telkens wanneer een aanvraag wordt ingediend bij het eindpunt voor metrische gegevens, worden de huidige waarden weergegeven. Hoewel huidige waarden interessant zijn, worden ze waardevoller in vergelijking met historische waarden om trends te bekijken en te detecteren of waarden afwijkend zijn. Vaak hebben services pieken in het gebruik op basis van het tijdstip van de dag of wereld evenementen, zoals een vakantie winkelen spree. Door de waarden te vergelijken met historische trends, kunt u detecteren of ze abnormaal zijn of als een metrische waarde na verloop van tijd langzaam slechter wordt.
Tijdens het proces worden geen geschiedenis van deze metrische momentopnamen opgeslagen. Het toevoegen van deze mogelijkheid aan het proces kan resource-intensief zijn. In een gedistribueerd systeem hebt u vaak meerdere exemplaren van elk knooppunt, dus u wilt de metrische gegevens uit alle knooppunten kunnen verzamelen en vervolgens aggregeren en vergelijken met hun historische waarden.
7.1 Prometheus installeren en configureren
Download Prometheus voor uw platform van https://prometheus.io/download/ en pak de inhoud van de download uit.
Kijk boven aan de uitvoer van de actieve server om het poortnummer voor het HTTP-eindpunt op te halen. Voorbeeld:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7275
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5212
Wijzig het YAML-configuratiebestand van Prometheus om de poort voor uw HTTP-scraping-eindpunt op te geven en stel een lager scraping-interval in. Voorbeeld:
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
scrape_interval: 1s # poll very quickly for a more responsive demo
static_configs:
- targets: ["localhost:5212"]
Start Prometheus en kijk in de uitvoer voor de poort waarop deze wordt uitgevoerd, meestal 9090:
>prometheus.exe
...
ts=2023-06-16T05:29:02.789Z caller=web.go:562 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090
Open deze URL in uw browser. In de gebruikersinterface van Prometheus kunt u nu query's uitvoeren op uw metrische gegevens. Gebruik de gemarkeerde knop in de volgende afbeelding om de Metrics Explorer te openen, waarin alle beschikbare metrische gegevens worden weergegeven.
Selecteer de greetings_count
metrische waarde om een grafiek met waarden weer te geven.
8. Grafana gebruiken om een dashboard met metrische gegevens te maken
Grafana is een dashboardproduct dat dashboards en waarschuwingen kan maken op basis van Prometheus of andere gegevensbronnen.
Download en installeer de OSS-versie van Grafana door https://grafana.com/oss/grafana/ de instructies voor uw platform te volgen. Na de installatie wordt Grafana doorgaans uitgevoerd op poort 3000, dus open http://localhost:3000
deze in uw browser. U moet zich aanmelden; de standaardgebruikersnaam en het standaardwachtwoord zijn beide admin
.
Kies verbindingen in het hamburgermenu en voer vervolgens de tekst prometheus
in om uw eindpunttype te selecteren. Selecteer Een Prometheus-gegevensbron maken om een nieuwe gegevensbron toe te voegen.
U moet de volgende eigenschappen instellen:
- URL van Prometheus-server:
http://localhost:9090/
de poort wijzigen indien van toepassing
Selecteer Opslaan en testen om de configuratie te controleren.
Zodra u een bericht krijgt dat het is gelukt, kunt u een dashboard configureren. Klik op de koppeling voor het bouwen van een dashboard die wordt weergegeven in de pop-up voor het succesbericht.
Selecteer Een visualisatie toevoegen en kies vervolgens de Prometheus-gegevensbron die u zojuist hebt toegevoegd als de gegevensbron.
De ontwerpfunctie voor dashboardvensters moet worden weergegeven. In de onderste helft van het scherm kunt u de query definiëren.
Selecteer de greetings_count
metrische waarde en selecteer vervolgens Query's uitvoeren om de resultaten te bekijken.
Met Grafana kunt u geavanceerde dashboards ontwerpen waarmee een willekeurig aantal metrische gegevens wordt bijgehouden.
Elke metrische waarde in .NET kan extra dimensies hebben. Dit zijn sleutel-waardeparen die kunnen worden gebruikt om de gegevens te partitioneren. De ASP.NET metrische gegevens bevatten allemaal een aantal dimensies die van toepassing zijn op de teller. De teller heeft Microsoft.AspNetCore.Hosting
bijvoorbeeld current-requests
de volgende dimensies:
Kenmerk | Type | Description | Voorbeelden | Aanwezigheid |
---|---|---|---|---|
method |
string |
HTTP-aanvraagmethode. | GET ; POST ; HEAD |
Altijd |
scheme |
string |
Het URI-schema waarmee het gebruikte protocol wordt geïdentificeerd. | http ; https |
Altijd |
host |
string |
Naam van de lokale HTTP-server die de aanvraag heeft ontvangen. | localhost |
Altijd |
port |
int |
Poort van de lokale HTTP-server die de aanvraag heeft ontvangen. | 8080 |
Toegevoegd indien niet standaard (80 voor http of 443 voor https) |
De grafieken in Grafana worden meestal gepartitioneerd op basis van elke unieke combinatie van dimensies. De dimensies kunnen worden gebruikt in de Grafana-query's om de gegevens te filteren of aggregeren. Als u bijvoorbeeld graaft current_requests
, ziet u waarden die zijn gepartitioneerd op basis van elke combinatie van dimensies. Als u alleen wilt filteren op basis van de host, voegt u een bewerking van Sum
en gebruikt host
u deze als labelwaarde.
9. Gedistribueerde tracering met Jaeger
In stap 6 hebt u gezien dat gedistribueerde traceringsinformatie beschikbaar werd gesteld aan de console. Met deze informatie worden werkeenheden bijgehouden met activiteiten. Sommige activiteiten worden automatisch gemaakt door het platform, zoals de activiteiten van ASP.NET om de verwerking van een aanvraag aan te geven, en bibliotheken en app-code kunnen ook activiteiten maken. Het voorbeeld van begroetingen heeft een Greeter
activiteit. De activiteiten worden gecorreleerd met behulp van de TraceId
, SpanId
en ParentId
tags.
Elk proces in een gedistribueerd systeem produceert een eigen stroom activiteitsgegevens, en zoals metrische gegevens, hebt u een systeem nodig om de activiteiten te verzamelen, op te slaan en te correleren om het werk dat voor elke transactie is uitgevoerd te kunnen visualiseren. Jaeger is een opensource-project om deze verzameling en visualisatie in te schakelen.
Download het meest recente binaire distributiearchief van Jaeger voor uw platform van https://www.jaegertracing.io/download/.
Pak vervolgens de download uit naar een lokale locatie die gemakkelijk toegankelijk is. Voer het uitvoerbare bestand jaeger-all-in-one (.exe) uit:
./jaeger-all-in-one --collector.otlp.enabled
Bekijk de console-uitvoer om de poort te vinden waar wordt geluisterd naar OTLP-verkeer via gRPC. Voorbeeld:
{"level":"info","ts":1686963686.3854616,"caller":"otlpreceiver@v0.78.2/otlp.go:83","msg":"Starting GRPC server","endpoint":"0.0.0.0:4317"}
Deze uitvoer vertelt u dat deze luistert 0.0.0.0:4317
, zodat u die poort kunt configureren als de bestemming voor uw OTLP-exporteur.
Open het AppSettings.json
bestand voor ons project en voeg de volgende regel toe en wijzig indien van toepassing de poort.
"OTLP_ENDPOINT_URL" : "http://localhost:4317/"
Start het begroetingsproces opnieuw, zodat deze de wijziging van de eigenschap kan ophalen en traceringsgegevens naar Jaeger kan leiden.
Nu moet u de Gebruikersinterface http://localhost:16686/
van Jaeger in een webbrowser kunnen zien.
Als u een lijst met traceringen wilt zien, selecteert u OTel-Prometheus-grafana-Jaeger
in de vervolgkeuzelijst Service . Als u een trace selecteert, moet een Gantt-diagram van de activiteiten worden weergegeven als onderdeel van die trace. Als u op elk van de bewerkingen klikt, ziet u meer informatie over de activiteit.
In een gedistribueerd systeem wilt u traceringen van alle processen verzenden naar dezelfde Jaeger-installatie, zodat deze de transacties in het systeem kan correleren.
U kunt uw app iets interessanter maken door deze HTTP-aanroepen naar zichzelf te laten uitvoeren.
Een
HttpClient
factory toevoegen aan de toepassingbuilder.Services.AddHttpClient();
Een nieuw eindpunt toevoegen voor het maken van geneste begroetingsgesprekken
app.MapGet("/NestedGreeting", SendNestedGreeting);
Implementeer het eindpunt zodat er HTTP-aanroepen worden uitgevoerd die ook kunnen worden getraceerd. In dit geval roept het terug naar zichzelf in een kunstmatige lus (echt alleen van toepassing op demoscenario's).
async Task SendNestedGreeting(int nestlevel, ILogger<Program> logger, HttpContext context, IHttpClientFactory clientFactory) { // Create a new Activity scoped to the method using var activity = greeterActivitySource.StartActivity("GreeterActivity"); if (nestlevel <= 5) { // Log a message logger.LogInformation("Sending greeting, level {nestlevel}", nestlevel); // Increment the custom counter countGreetings.Add(1); // Add a tag to the Activity activity?.SetTag("nest-level", nestlevel); await context.Response.WriteAsync($"Nested Greeting, level: {nestlevel}\r\n"); if (nestlevel > 0) { var request = context.Request; var url = new Uri($"{request.Scheme}://{request.Host}{request.Path}?nestlevel={nestlevel - 1}"); // Makes an http call passing the activity information as http headers var nestedResult = await clientFactory.CreateClient().GetStringAsync(url); await context.Response.WriteAsync(nestedResult); } } else { // Log a message logger.LogError("Greeting nest level {nestlevel} too high", nestlevel); await context.Response.WriteAsync("Nest level too high, max is 5"); } }
Dit resulteert in een interessantere grafiek met een piramidevorm voor de aanvragen, omdat elk niveau wacht op het antwoord van de vorige aanroep.