From 34d5bbbd6f6a18c3a01e93143cafd906eae25072 Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:35:33 +0300 Subject: [PATCH 1/7] added serilog --- Observability.Homework/Homework.http | 8 ++++++++ Observability.Homework/Observability.Homework.csproj | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 Observability.Homework/Homework.http diff --git a/Observability.Homework/Homework.http b/Observability.Homework/Homework.http new file mode 100644 index 0000000..f4c0462 --- /dev/null +++ b/Observability.Homework/Homework.http @@ -0,0 +1,8 @@ +@HomeWorkToDoList_HostAddress = http://localhost:5216 + +POST {{HomeWorkToDoList_HostAddress}}/order/ +Accept: application/json +Content-Type: application/json + +{"product":{"type":0},"client":{"id":"rgerg"}} +### \ No newline at end of file diff --git a/Observability.Homework/Observability.Homework.csproj b/Observability.Homework/Observability.Homework.csproj index c150414..3137923 100644 --- a/Observability.Homework/Observability.Homework.csproj +++ b/Observability.Homework/Observability.Homework.csproj @@ -6,4 +6,11 @@ enable + + + + + + + From 6ab2afa222dbe63f7785ff5a9c8f4e1c4cffcdf0 Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:39:40 +0300 Subject: [PATCH 2/7] add logging --- Observability.Homework/Program.cs | 9 ++++++--- .../Services/PizzaBakeryService.cs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index 6c4ba0e..5beaf93 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -38,9 +38,12 @@ app.MapPost("/order", async ([FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => { - if (order.Product.Type is ProductType.Pizza) - await pizzaBakeryService.DoPizza(order.Product, cancellationToken); - + using (app.Logger.BeginScope(new Dictionary { { "ClientId", order.Client.Id } })) + { + app.Logger.LogInformation("request"); + if (order.Product.Type is ProductType.Pizza) + await pizzaBakeryService.DoPizza(order.Product, cancellationToken); + } return Results.Ok(order.Product); }); diff --git a/Observability.Homework/Services/PizzaBakeryService.cs b/Observability.Homework/Services/PizzaBakeryService.cs index 15529f1..86a16d4 100644 --- a/Observability.Homework/Services/PizzaBakeryService.cs +++ b/Observability.Homework/Services/PizzaBakeryService.cs @@ -11,10 +11,17 @@ public interface IPizzaBakeryService public class PizzaBakeryService : IPizzaBakeryService { + private readonly ILogger _logger; private readonly ConcurrentDictionary _bake = new(); + public PizzaBakeryService(ILogger logger) + { + _logger = logger; + } + public async Task DoPizza(Product product, CancellationToken cancellationToken = default) { + _logger.LogInformation("DoPizza id:{productId} type:{productType}",product.Id, product.Type); try { await MakePizza(product, cancellationToken); @@ -24,17 +31,20 @@ public async Task DoPizza(Product product, CancellationToken cancellati } catch (OperationCanceledException) { + _logger.LogError("PizzaBakeryService cancel do pizza"); DropPizza(product); throw; } catch (BurntPizzaException) { + _logger.LogError("PizzaBakeryService burnt pizza"); return await DoPizza(product, cancellationToken); } } private async Task BakePizza(Product product, CancellationToken cancellationToken = default) { + _logger.LogInformation("BakePizza id:{productId} type:{productType}",product.Id, product.Type); PushToBake(product); var bakeForSeconds = new Random().Next(3, 9); await Task.Delay(TimeSpan.FromSeconds(bakeForSeconds), cancellationToken); @@ -48,29 +58,34 @@ private async Task BakePizza(Product product, CancellationToken cancell private async Task MakePizza(Product product, CancellationToken cancellationToken = default) { + _logger.LogInformation("MakePizza id:{productId} type:{productType}",product.Id, product.Type); await Task.Delay(new Random().Next(1, 3) * 1000, cancellationToken); return product; } private async Task PackPizza(Product product, CancellationToken cancellationToken = default) { + _logger.LogInformation("PackPizza id:{productId} type:{productType}",product.Id, product.Type); await Task.Delay(new Random().Next(1, 2) * 1000, cancellationToken); return product; } private void PushToBake(Product product) { + _logger.LogInformation("PushToBake id:{productId} type:{productType}",product.Id, product.Type); _bake[product.Id] = product; } private Product PopFromBake(Product product) { + _logger.LogInformation("PopFromBake id:{productId} type:{productType}",product.Id, product.Type); _bake.Remove(product.Id, out var pizza); return pizza!; //пусть у нас всегда есть пицца } private void DropPizza(Product product) { + _logger.LogInformation("DropPizza id:{productId} type:{productType}",product.Id, product.Type); _bake.Remove(product.Id, out _); } } \ No newline at end of file From c23695118c4b56ff80e534708be9d77464200118 Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:37:09 +0300 Subject: [PATCH 3/7] added logging config --- .../Extensions/LoggingConfig.cs | 41 +++++++++++++++++++ .../Observability.Homework.csproj | 4 ++ Observability.Homework/Program.cs | 3 +- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Observability.Homework/Extensions/LoggingConfig.cs diff --git a/Observability.Homework/Extensions/LoggingConfig.cs b/Observability.Homework/Extensions/LoggingConfig.cs new file mode 100644 index 0000000..e011409 --- /dev/null +++ b/Observability.Homework/Extensions/LoggingConfig.cs @@ -0,0 +1,41 @@ +using System.Globalization; +using Serilog; +using Serilog.Events; +using Serilog.Formatting.Elasticsearch; + +namespace Observability.Homework.Extensions; + +public static class LoggingConfig +{ + public static void AppLogging(this WebApplicationBuilder builder) + { + ArgumentNullException.ThrowIfNull(builder); + + builder.Host.UseSerilog( + (context, configuration) => + { + configuration + .ReadFrom.Configuration(context.Configuration); + + + if (builder.Environment.EnvironmentName == "Development") + configuration + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) + .WriteTo.Console(formatProvider: CultureInfo.DefaultThreadCurrentCulture, + outputTemplate: + "[{Level:u3} {Timestamp:HH:mm:ss} {ScopePath}] {ClientId} {Message:lj}{NewLine}{Exception}"); + + else + configuration + .MinimumLevel.Warning() + .WriteTo.Async( + to => to.Console( + new ExceptionAsObjectJsonFormatter( + renderMessage: true, + inlineFields: true), + standardErrorFromLevel: LogEventLevel.Warning)); + } + ); + } +} \ No newline at end of file diff --git a/Observability.Homework/Observability.Homework.csproj b/Observability.Homework/Observability.Homework.csproj index 3137923..e43bf48 100644 --- a/Observability.Homework/Observability.Homework.csproj +++ b/Observability.Homework/Observability.Homework.csproj @@ -8,8 +8,12 @@ + + + + diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index 5beaf93..6b38bc5 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -27,13 +27,14 @@ */ using Microsoft.AspNetCore.Mvc; +using Observability.Homework.Extensions; using Observability.Homework.Models; using Observability.Homework.Services; var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton(); - +builder.AppLogging(); var app = builder.Build(); app.MapPost("/order", async ([FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => From 14e36bb8150bc6a9378039ad9ca368f8c8b6bced Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:56:35 +0300 Subject: [PATCH 4/7] add new project --- .../Models/Client.cs | 6 +++ .../Models/Order.cs | 23 +++++++++ .../Models/Product.cs | 15 ++++++ ...servability.Homework.Tracing.Client.csproj | 16 ++++++ .../Program.cs | 27 ++++++++++ Observability.Homework.sln | 6 +++ .../Observability.Homework.csproj | 6 +++ Observability.Homework/Program.cs | 25 ++++++++-- .../Services/PizzaBakeryService.cs | 50 ++++++++++++------- 9 files changed, 153 insertions(+), 21 deletions(-) create mode 100644 Observability.Homework.Tracing.Client/Models/Client.cs create mode 100644 Observability.Homework.Tracing.Client/Models/Order.cs create mode 100644 Observability.Homework.Tracing.Client/Models/Product.cs create mode 100644 Observability.Homework.Tracing.Client/Observability.Homework.Tracing.Client.csproj create mode 100644 Observability.Homework.Tracing.Client/Program.cs diff --git a/Observability.Homework.Tracing.Client/Models/Client.cs b/Observability.Homework.Tracing.Client/Models/Client.cs new file mode 100644 index 0000000..4200a70 --- /dev/null +++ b/Observability.Homework.Tracing.Client/Models/Client.cs @@ -0,0 +1,6 @@ +namespace Observability.Homework.Models; + +public class Client +{ + public required string Id { get; set; } +} \ No newline at end of file diff --git a/Observability.Homework.Tracing.Client/Models/Order.cs b/Observability.Homework.Tracing.Client/Models/Order.cs new file mode 100644 index 0000000..00049d0 --- /dev/null +++ b/Observability.Homework.Tracing.Client/Models/Order.cs @@ -0,0 +1,23 @@ +namespace Observability.Homework.Models; + +public class Order +{ + public required Client Client { get; set; } + + public required Product Product { get; set; } + + public static Order Create(ProductType type) + { + return new Order + { + Client = new() + { + Id = Guid.NewGuid().ToString() + }, + Product = new Product + { + Type = type + } + }; + } +} \ No newline at end of file diff --git a/Observability.Homework.Tracing.Client/Models/Product.cs b/Observability.Homework.Tracing.Client/Models/Product.cs new file mode 100644 index 0000000..661ea4c --- /dev/null +++ b/Observability.Homework.Tracing.Client/Models/Product.cs @@ -0,0 +1,15 @@ +namespace Observability.Homework.Models; + +public class Product +{ + public Guid Id { get; } = Guid.NewGuid(); + + public required ProductType Type { get; set; } +} + +public enum ProductType +{ + Pizza = 0, + Desert = 1, + Beverage = 2 +} \ No newline at end of file diff --git a/Observability.Homework.Tracing.Client/Observability.Homework.Tracing.Client.csproj b/Observability.Homework.Tracing.Client/Observability.Homework.Tracing.Client.csproj new file mode 100644 index 0000000..b5b9bcf --- /dev/null +++ b/Observability.Homework.Tracing.Client/Observability.Homework.Tracing.Client.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + diff --git a/Observability.Homework.Tracing.Client/Program.cs b/Observability.Homework.Tracing.Client/Program.cs new file mode 100644 index 0000000..e0591d7 --- /dev/null +++ b/Observability.Homework.Tracing.Client/Program.cs @@ -0,0 +1,27 @@ +// See https://aka.ms/new-console-template for more information + +using System.Net.Http.Json; +using Observability.Homework.Models; +using OpenTelemetry; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +var serviceName = "Observability.Homework.Tracing.Client"; + +using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource(serviceName) + .AddHttpClientInstrumentation() + .SetResourceBuilder( + ResourceBuilder.CreateDefault() + .AddService(serviceName: serviceName)) + .AddJaegerExporter() + .Build(); +Random random = new Random(); +while (true) +{ + using var httpClient = new HttpClient(); + var response = await httpClient.PostAsync("http://localhost:5216/order/", JsonContent.Create(Order.Create((ProductType)random.Next(0,2)))); + response.EnsureSuccessStatusCode(); + Console.WriteLine("Response received successfully."); +} + diff --git a/Observability.Homework.sln b/Observability.Homework.sln index cd11401..2388734 100644 --- a/Observability.Homework.sln +++ b/Observability.Homework.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Observability.Homework", "Observability.Homework\Observability.Homework.csproj", "{FA51BFEE-F62F-4D80-A43A-3C384C62D1AB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Observability.Homework.Tracing.Client", "Observability.Homework.Tracing.Client\Observability.Homework.Tracing.Client.csproj", "{ED0F7FFB-2DD2-429F-B389-76680F8825C8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {FA51BFEE-F62F-4D80-A43A-3C384C62D1AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA51BFEE-F62F-4D80-A43A-3C384C62D1AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA51BFEE-F62F-4D80-A43A-3C384C62D1AB}.Release|Any CPU.Build.0 = Release|Any CPU + {ED0F7FFB-2DD2-429F-B389-76680F8825C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED0F7FFB-2DD2-429F-B389-76680F8825C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED0F7FFB-2DD2-429F-B389-76680F8825C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED0F7FFB-2DD2-429F-B389-76680F8825C8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Observability.Homework/Observability.Homework.csproj b/Observability.Homework/Observability.Homework.csproj index e43bf48..18a651e 100644 --- a/Observability.Homework/Observability.Homework.csproj +++ b/Observability.Homework/Observability.Homework.csproj @@ -7,6 +7,12 @@ + + + + + + diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index 6b38bc5..d1545e6 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -30,15 +30,34 @@ using Observability.Homework.Extensions; using Observability.Homework.Models; using Observability.Homework.Services; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +var serviceName = "Observability.Homework"; var builder = WebApplication.CreateBuilder(args); - +//builder.AppLogging(); +//Trace don,t work with logging=( +builder.Logging.ClearProviders(); +builder.Services.AddOpenTelemetry().WithTracing(tcb => +{ + tcb + .AddSource(serviceName) + .SetResourceBuilder( + ResourceBuilder.CreateDefault() + .AddService(serviceName: serviceName)) + .AddAspNetCoreInstrumentation() + .AddJaegerExporter(); +}); +builder.Services.AddSingleton(TracerProvider.Default.GetTracer(serviceName)); builder.Services.AddSingleton(); -builder.AppLogging(); + var app = builder.Build(); -app.MapPost("/order", async ([FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => +app.MapPost("/order", async ([FromServices] Tracer tracer, [FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => { + using var span = tracer.StartActiveSpan("Request DoPizza"); + span.SetAttribute("userId", order.Client.Id); + span.SetAttribute("productId", order.Product.Id.ToString()); using (app.Logger.BeginScope(new Dictionary { { "ClientId", order.Client.Id } })) { app.Logger.LogInformation("request"); diff --git a/Observability.Homework/Services/PizzaBakeryService.cs b/Observability.Homework/Services/PizzaBakeryService.cs index 86a16d4..62fe3e9 100644 --- a/Observability.Homework/Services/PizzaBakeryService.cs +++ b/Observability.Homework/Services/PizzaBakeryService.cs @@ -1,6 +1,8 @@ using System.Collections.Concurrent; using Observability.Homework.Exceptions; using Observability.Homework.Models; +using OpenTelemetry.Trace; + namespace Observability.Homework.Services; @@ -9,19 +11,15 @@ public interface IPizzaBakeryService Task DoPizza(Product product, CancellationToken cancellationToken = default); } -public class PizzaBakeryService : IPizzaBakeryService +public class PizzaBakeryService(Tracer tracer, ILogger logger) : IPizzaBakeryService { - private readonly ILogger _logger; + private readonly Tracer _tracer = tracer; private readonly ConcurrentDictionary _bake = new(); - public PizzaBakeryService(ILogger logger) - { - _logger = logger; - } - public async Task DoPizza(Product product, CancellationToken cancellationToken = default) { - _logger.LogInformation("DoPizza id:{productId} type:{productType}",product.Id, product.Type); + logger.LogInformation("DoPizza id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("DoPizza"); try { await MakePizza(product, cancellationToken); @@ -29,22 +27,28 @@ public async Task DoPizza(Product product, CancellationToken cancellati await PackPizza(product, cancellationToken); return product; } - catch (OperationCanceledException) + catch (OperationCanceledException ex) { - _logger.LogError("PizzaBakeryService cancel do pizza"); + logger.LogError("PizzaBakeryService cancel do pizza"); + span.SetStatus(Status.Error.WithDescription("PizzaBakeryService cancel do pizza")); + span.RecordException(ex); DropPizza(product); throw; } - catch (BurntPizzaException) + catch (BurntPizzaException ex) { - _logger.LogError("PizzaBakeryService burnt pizza"); + logger.LogError("PizzaBakeryService burnt pizza"); + span.SetStatus(Status.Error.WithDescription("PizzaBakeryService burnt pizza")); + span.RecordException(ex); return await DoPizza(product, cancellationToken); } } private async Task BakePizza(Product product, CancellationToken cancellationToken = default) { - _logger.LogInformation("BakePizza id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("BakePizza"); + logger.LogInformation("BakePizza id:{productId} type:{productType}",product.Id, product.Type); + PushToBake(product); var bakeForSeconds = new Random().Next(3, 9); await Task.Delay(TimeSpan.FromSeconds(bakeForSeconds), cancellationToken); @@ -58,34 +62,44 @@ private async Task BakePizza(Product product, CancellationToken cancell private async Task MakePizza(Product product, CancellationToken cancellationToken = default) { - _logger.LogInformation("MakePizza id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("MakePizza"); + logger.LogInformation("MakePizza id:{productId} type:{productType}",product.Id, product.Type); + await Task.Delay(new Random().Next(1, 3) * 1000, cancellationToken); return product; } private async Task PackPizza(Product product, CancellationToken cancellationToken = default) { - _logger.LogInformation("PackPizza id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("PackPizza"); + logger.LogInformation("PackPizza id:{productId} type:{productType}",product.Id, product.Type); + await Task.Delay(new Random().Next(1, 2) * 1000, cancellationToken); return product; } private void PushToBake(Product product) { - _logger.LogInformation("PushToBake id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("PushToBake"); + logger.LogInformation("PushToBake id:{productId} type:{productType}",product.Id, product.Type); + _bake[product.Id] = product; } private Product PopFromBake(Product product) { - _logger.LogInformation("PopFromBake id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("PopFromBake"); + logger.LogInformation("PopFromBake id:{productId} type:{productType}",product.Id, product.Type); + _bake.Remove(product.Id, out var pizza); return pizza!; //пусть у нас всегда есть пицца } private void DropPizza(Product product) { - _logger.LogInformation("DropPizza id:{productId} type:{productType}",product.Id, product.Type); + using var span = tracer.StartActiveSpan("DropPizza"); + logger.LogInformation("DropPizza id:{productId} type:{productType}",product.Id, product.Type); + _bake.Remove(product.Id, out _); } } \ No newline at end of file From 1fe4e87ca60637a36763f985bd243ab4d25da43e Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:44:03 +0300 Subject: [PATCH 5/7] added metrics --- .../Program.cs | 5 +- .../Observability.Homework.csproj | 2 + Observability.Homework/Program.cs | 36 ++++++++----- .../Properties/launchSettings.json | 2 +- .../Services/PizzaBakeryService.cs | 5 +- .../Services/PizzeriaMetricsService.cs | 50 +++++++++++++++++++ 6 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 Observability.Homework/Services/PizzeriaMetricsService.cs diff --git a/Observability.Homework.Tracing.Client/Program.cs b/Observability.Homework.Tracing.Client/Program.cs index e0591d7..c049cf0 100644 --- a/Observability.Homework.Tracing.Client/Program.cs +++ b/Observability.Homework.Tracing.Client/Program.cs @@ -20,8 +20,9 @@ while (true) { using var httpClient = new HttpClient(); - var response = await httpClient.PostAsync("http://localhost:5216/order/", JsonContent.Create(Order.Create((ProductType)random.Next(0,2)))); + var order = Order.Create((ProductType)random.Next(0, 3)); + var response = await httpClient.PostAsync("http://localhost:5216/order/", JsonContent.Create(order)); response.EnsureSuccessStatusCode(); - Console.WriteLine("Response received successfully."); + Console.WriteLine("Response received successfully.{0}",order.Product.Type); } diff --git a/Observability.Homework/Observability.Homework.csproj b/Observability.Homework/Observability.Homework.csproj index 18a651e..b00ff6d 100644 --- a/Observability.Homework/Observability.Homework.csproj +++ b/Observability.Homework/Observability.Homework.csproj @@ -11,6 +11,8 @@ + + diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index d1545e6..54a2081 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -30,6 +30,7 @@ using Observability.Homework.Extensions; using Observability.Homework.Models; using Observability.Homework.Services; +using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; @@ -38,26 +39,37 @@ //builder.AppLogging(); //Trace don,t work with logging=( builder.Logging.ClearProviders(); -builder.Services.AddOpenTelemetry().WithTracing(tcb => -{ - tcb - .AddSource(serviceName) - .SetResourceBuilder( - ResourceBuilder.CreateDefault() - .AddService(serviceName: serviceName)) - .AddAspNetCoreInstrumentation() - .AddJaegerExporter(); -}); +builder.Services + .AddOpenTelemetry() + // .WithTracing(tcb => + // { + // tcb + // .AddSource(serviceName) + // .SetResourceBuilder( + // ResourceBuilder.CreateDefault() + // .AddService(serviceName: serviceName)) + // .AddAspNetCoreInstrumentation() + // .AddJaegerExporter(); + // }) + .WithMetrics(mpb => mpb + .AddAspNetCoreInstrumentation() + //.AddRuntimeInstrumentation() + //.AddProcessInstrumentation() + .AddPrometheusExporter() + .AddMeter(PizzeriaMetricsService.MeterName) + ); builder.Services.AddSingleton(TracerProvider.Default.GetTracer(serviceName)); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); var app = builder.Build(); - -app.MapPost("/order", async ([FromServices] Tracer tracer, [FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => +app.MapPrometheusScrapingEndpoint(); +app.MapPost("/order", async ([FromServices] Tracer tracer,PizzeriaMetricsService metric, [FromBody] Order order, IPizzaBakeryService pizzaBakeryService, CancellationToken cancellationToken) => { using var span = tracer.StartActiveSpan("Request DoPizza"); span.SetAttribute("userId", order.Client.Id); span.SetAttribute("productId", order.Product.Id.ToString()); + metric.ProductType(order.Product); using (app.Logger.BeginScope(new Dictionary { { "ClientId", order.Client.Id } })) { app.Logger.LogInformation("request"); diff --git a/Observability.Homework/Properties/launchSettings.json b/Observability.Homework/Properties/launchSettings.json index 5ccdcce..9a7f4fa 100644 --- a/Observability.Homework/Properties/launchSettings.json +++ b/Observability.Homework/Properties/launchSettings.json @@ -22,7 +22,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:7205;http://localhost:5216", + "applicationUrl": "https://localhost:7242;http://localhost:5216", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/Observability.Homework/Services/PizzaBakeryService.cs b/Observability.Homework/Services/PizzaBakeryService.cs index 62fe3e9..5e0c513 100644 --- a/Observability.Homework/Services/PizzaBakeryService.cs +++ b/Observability.Homework/Services/PizzaBakeryService.cs @@ -11,8 +11,9 @@ public interface IPizzaBakeryService Task DoPizza(Product product, CancellationToken cancellationToken = default); } -public class PizzaBakeryService(Tracer tracer, ILogger logger) : IPizzaBakeryService +public class PizzaBakeryService(Tracer tracer, ILogger logger, PizzeriaMetricsService pizzeriaMetricsService) : IPizzaBakeryService { + private readonly PizzeriaMetricsService _metrics = pizzeriaMetricsService; private readonly Tracer _tracer = tracer; private readonly ConcurrentDictionary _bake = new(); @@ -29,6 +30,7 @@ public async Task DoPizza(Product product, CancellationToken cancellati } catch (OperationCanceledException ex) { + _metrics.ProductCancel(); logger.LogError("PizzaBakeryService cancel do pizza"); span.SetStatus(Status.Error.WithDescription("PizzaBakeryService cancel do pizza")); span.RecordException(ex); @@ -37,6 +39,7 @@ public async Task DoPizza(Product product, CancellationToken cancellati } catch (BurntPizzaException ex) { + _metrics.ProductBurnt(); logger.LogError("PizzaBakeryService burnt pizza"); span.SetStatus(Status.Error.WithDescription("PizzaBakeryService burnt pizza")); span.RecordException(ex); diff --git a/Observability.Homework/Services/PizzeriaMetricsService.cs b/Observability.Homework/Services/PizzeriaMetricsService.cs new file mode 100644 index 0000000..1093723 --- /dev/null +++ b/Observability.Homework/Services/PizzeriaMetricsService.cs @@ -0,0 +1,50 @@ +using System.Diagnostics.Metrics; +using Observability.Homework.Models; + +namespace Observability.Homework.Services; + +public class PizzeriaMetricsService +{ + public static readonly string MeterName = "Observability.Metrics.Pizzeria"; + + private const string ProductTypeMetricName = "pizzeria.product.type"; + private const string ProductBurntMetricName = "pizzeria.product.burnt"; + private const string ProductCancelMetricName = "pizzeria.product.cancel"; + private const string ProductCookingTimeMetricName = "pizzeria.product.cooking.time"; + private const string ProductCookingCountMetricName = "pizzeria.product.cooking.count"; + + private readonly Counter _productTypeCounter; + private readonly Counter _productBurntCounter; + private readonly Counter _productCancelCounter; + + public PizzeriaMetricsService(IMeterFactory meterFactory) + { + var meter = meterFactory.Create(MeterName); + _productTypeCounter = meter.CreateCounter(ProductTypeMetricName); + _productBurntCounter = meter.CreateCounter(ProductBurntMetricName); + _productCancelCounter = meter.CreateCounter(ProductCancelMetricName); + } + + public void ProductType(Product product) + { + _productTypeCounter.Add(1, new KeyValuePair[] + { + new("product.type", product.Type.ToString()), + }); + } + + public void ProductBurnt() + { + _productBurntCounter.Add(1); + } + + public void ProductCancel() + { + _productCancelCounter.Add(1); + } + + public void RecordProductCooking(Product product, double cookingTime) + { + + } +} \ No newline at end of file From 5f07623241338042ccb66053eedd9be096f7a914 Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:42:10 +0300 Subject: [PATCH 6/7] added baking counter and cooking time --- Observability.Homework.Tracing.Client/Program.cs | 14 +++++++++----- Observability.Homework/Program.cs | 2 ++ .../Services/PizzaBakeryService.cs | 1 + .../Services/PizzeriaMetricsService.cs | 13 +++++++++++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Observability.Homework.Tracing.Client/Program.cs b/Observability.Homework.Tracing.Client/Program.cs index c049cf0..f9f25f8 100644 --- a/Observability.Homework.Tracing.Client/Program.cs +++ b/Observability.Homework.Tracing.Client/Program.cs @@ -19,10 +19,14 @@ Random random = new Random(); while (true) { - using var httpClient = new HttpClient(); - var order = Order.Create((ProductType)random.Next(0, 3)); - var response = await httpClient.PostAsync("http://localhost:5216/order/", JsonContent.Create(order)); - response.EnsureSuccessStatusCode(); - Console.WriteLine("Response received successfully.{0}",order.Product.Type); + Parallel.For(0, 30, _ => + { + using var httpClient = new HttpClient(); + var order = Order.Create((ProductType)random.Next(0, 3)); + var response = httpClient.PostAsync("http://localhost:5216/order/", JsonContent.Create(order)).Result; + response.EnsureSuccessStatusCode(); + Console.WriteLine("Response received successfully.{0}", order.Product.Type); + }); + } diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index 54a2081..59a8fbf 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -70,12 +70,14 @@ span.SetAttribute("userId", order.Client.Id); span.SetAttribute("productId", order.Product.Id.ToString()); metric.ProductType(order.Product); + DateTime start = DateTime.Now; using (app.Logger.BeginScope(new Dictionary { { "ClientId", order.Client.Id } })) { app.Logger.LogInformation("request"); if (order.Product.Type is ProductType.Pizza) await pizzaBakeryService.DoPizza(order.Product, cancellationToken); } + metric.RecordProductCooking((DateTime.Now-start).Microseconds); return Results.Ok(order.Product); }); diff --git a/Observability.Homework/Services/PizzaBakeryService.cs b/Observability.Homework/Services/PizzaBakeryService.cs index 5e0c513..4ad7069 100644 --- a/Observability.Homework/Services/PizzaBakeryService.cs +++ b/Observability.Homework/Services/PizzaBakeryService.cs @@ -20,6 +20,7 @@ public class PizzaBakeryService(Tracer tracer, ILogger logge public async Task DoPizza(Product product, CancellationToken cancellationToken = default) { logger.LogInformation("DoPizza id:{productId} type:{productType}",product.Id, product.Type); + _metrics.ProductBakingCount(_bake.Count); using var span = tracer.StartActiveSpan("DoPizza"); try { diff --git a/Observability.Homework/Services/PizzeriaMetricsService.cs b/Observability.Homework/Services/PizzeriaMetricsService.cs index 1093723..e8f26f5 100644 --- a/Observability.Homework/Services/PizzeriaMetricsService.cs +++ b/Observability.Homework/Services/PizzeriaMetricsService.cs @@ -16,6 +16,8 @@ public class PizzeriaMetricsService private readonly Counter _productTypeCounter; private readonly Counter _productBurntCounter; private readonly Counter _productCancelCounter; + private readonly Histogram _productCookingTime; + private readonly Histogram _productBakingCounter; public PizzeriaMetricsService(IMeterFactory meterFactory) { @@ -23,6 +25,8 @@ public PizzeriaMetricsService(IMeterFactory meterFactory) _productTypeCounter = meter.CreateCounter(ProductTypeMetricName); _productBurntCounter = meter.CreateCounter(ProductBurntMetricName); _productCancelCounter = meter.CreateCounter(ProductCancelMetricName); + _productCookingTime = meter.CreateHistogram(ProductCookingTimeMetricName); + _productBakingCounter = meter.CreateHistogram(ProductCookingCountMetricName); } public void ProductType(Product product) @@ -43,8 +47,13 @@ public void ProductCancel() _productCancelCounter.Add(1); } - public void RecordProductCooking(Product product, double cookingTime) + public void RecordProductCooking(double cookingTime) { - + _productCookingTime.Record(cookingTime); + } + + public void ProductBakingCount(int bakingCount) + { + _productBakingCounter.Record(bakingCount); } } \ No newline at end of file From 62c674433fc824aaed3bf097cfe56d0baa2dbd40 Mon Sep 17 00:00:00 2001 From: Pavel <98314322+PavelRnD@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:53:35 +0300 Subject: [PATCH 7/7] With tracing --- Observability.Homework/Program.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Observability.Homework/Program.cs b/Observability.Homework/Program.cs index 59a8fbf..d1a2804 100644 --- a/Observability.Homework/Program.cs +++ b/Observability.Homework/Program.cs @@ -41,16 +41,16 @@ builder.Logging.ClearProviders(); builder.Services .AddOpenTelemetry() - // .WithTracing(tcb => - // { - // tcb - // .AddSource(serviceName) - // .SetResourceBuilder( - // ResourceBuilder.CreateDefault() - // .AddService(serviceName: serviceName)) - // .AddAspNetCoreInstrumentation() - // .AddJaegerExporter(); - // }) + .WithTracing(tcb => + { + tcb + .AddSource(serviceName) + .SetResourceBuilder( + ResourceBuilder.CreateDefault() + .AddService(serviceName: serviceName)) + .AddAspNetCoreInstrumentation() + .AddJaegerExporter(); + }) .WithMetrics(mpb => mpb .AddAspNetCoreInstrumentation() //.AddRuntimeInstrumentation()