diff --git a/.editorconfig b/.editorconfig
index 9cd7b7c6..e2ad36a5 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,8 +8,6 @@ root = true
# Use 4 spaces as indentation
[*]
insert_final_newline = true
-indent_style = space
-indent_size = 4
trim_trailing_whitespace = true
[*.cs]
@@ -17,5 +15,3 @@ trim_trailing_whitespace = true
dotnet_diagnostic.IDE0073.severity = warning
file_header_template = Copyright (c) TotalSoft.\nThis source code is licensed under the MIT license.
-[{*.csproj, *.fsproj, *.props, *.xml}]
-indent_size = 2
diff --git a/NBB.sln b/NBB.sln
index 435efd58..ab050e36 100644
--- a/NBB.sln
+++ b/NBB.sln
@@ -216,7 +216,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.EventStore.InMemory.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.Application.DataContracts.Schema", "src\Application\NBB.Application.DataContracts.Schema\NBB.Application.DataContracts.Schema.csproj", "{B7F02268-98F8-4C73-9B3A-41250835F3FD}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.Messaging.OpenTracing", "src\Messaging\NBB.Messaging.OpenTracing\NBB.Messaging.OpenTracing.csproj", "{B5C4D462-E7AF-4146-9618-75FF242E148C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.Messaging.OpenTelemetry", "src\Messaging\NBB.Messaging.OpenTelemetry\NBB.Messaging.OpenTelemetry.csproj", "{B5C4D462-E7AF-4146-9618-75FF242E148C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F57779EB-9107-427D-A65C-5AA262C348E1}"
ProjectSection(SolutionItems) = preProject
@@ -311,7 +311,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessManagerSample", "sam
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{EF374BA2-61FC-41FB-8229-5187DCBAA63A}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.Tools.Serilog.OpenTracingSink", "src\Tools\Serilog\NBB.Tools.Serilog.OpenTracingSink\NBB.Tools.Serilog.OpenTracingSink.csproj", "{A5826A9E-7E96-4A52-8A06-2B6DC9855954}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.Tools.Serilog.OpenTelemetryTracingSink", "src\Tools\Serilog\NBB.Tools.Serilog.OpenTelemetryTracingSink\NBB.Tools.Serilog.OpenTelemetryTracingSink.csproj", "{A5826A9E-7E96-4A52-8A06-2B6DC9855954}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NBB.EventStore.AdoNet.MultiTenancy", "src\EventStore\NBB.EventStore.AdoNet.Multitenancy\NBB.EventStore.AdoNet.MultiTenancy.csproj", "{2FEDB78D-E355-4449-A9D3-1C3079E38FD9}"
EndProject
diff --git a/dependencies.props b/dependencies.props
index 74a03152..69ebe2f4 100644
--- a/dependencies.props
+++ b/dependencies.props
@@ -16,17 +16,24 @@
7.0.0
7.0.0
4.7.0
+ 1.4.0-rc.1
+ 1.4.0-rc.1
+ 1.4.0-rc.1
+ 1.0.0-rc9.10
+ 1.0.0-beta.3
+ 1.0.0-rc9.10
+ 1.1.0-beta.2
+ 1.4.0-rc.1
+ 1.4.0-rc.1
7.2.2
2.10.0
3.1.0
4.0.1
5.6.1
4.1.0
- 12.0.0
- 0.12.1
+ 12.0.0
10.6.6
4.17.0
- 0.8.0
1.0.3
6.15.0
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Controllers/ContractsController.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Controllers/ContractsController.cs
index efe4552a..ea84134d 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Controllers/ContractsController.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Controllers/ContractsController.cs
@@ -1,74 +1,78 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.EntityFrameworkCore;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
using NBB.Contracts.PublishedLanguage;
-using NBB.Contracts.ReadModel;
-using NBB.Messaging.Abstractions;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NBB.Contracts.Api.Controllers
-{
- [Route("api/[controller]")]
- public class ContractsController : Controller
- {
- private readonly IQueryable _contractReadModelQuery;
- private readonly IMessageBusPublisher _messageBusPublisher;
-
- public ContractsController(IMessageBusPublisher messageBusPublisher, IQueryable contractReadModelQuery)
- {
- _messageBusPublisher = messageBusPublisher;
- _contractReadModelQuery = contractReadModelQuery;
- }
-
-
- // GET api/contracts
- [HttpGet]
- public async Task Get()
- {
- var query = await _contractReadModelQuery.ToListAsync();
- return Ok(query.ToList());
- }
-
- // GET api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489
- [HttpGet("{id}")]
- public async Task Get(Guid id)
- {
- //var contract = await _contractReadModelRepository.GetFirstOrDefaultAsync(x=> x.ContractId == id, "ContractLines");
- var contract = await _contractReadModelQuery
- .Include(x=> x.ContractLines)
- .SingleOrDefaultAsync(x => x.ContractId == id, CancellationToken.None);
-
- if (contract != null)
- return Ok(contract);
-
- return NotFound();
- }
-
- // POST api/contracts
- [HttpPost]
- public Task Post([FromBody]CreateContract command, CancellationToken cancellationToken)
- {
- return _messageBusPublisher.PublishAsync(command, cancellationToken);
- }
-
- // POST api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489/lines
- [HttpPost("{id}/lines")]
- public Task Post([FromBody]AddContractLine command, CancellationToken cancellationToken)
- {
- return _messageBusPublisher.PublishAsync(command, cancellationToken);
- }
-
- // POST api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489/validate
- [HttpPost("{id}/validate")]
- public Task Post([FromBody]ValidateContract command, CancellationToken cancellationToken)
- {
- return _messageBusPublisher.PublishAsync(command, cancellationToken);
- }
-
- }
-}
+using NBB.Contracts.ReadModel;
+using NBB.Messaging.Abstractions;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NBB.Contracts.Api.Controllers
+{
+ [Route("api/[controller]")]
+ public class ContractsController : Controller
+ {
+ private readonly IQueryable _contractReadModelQuery;
+ private readonly ILogger _logger;
+ private readonly IMessageBusPublisher _messageBusPublisher;
+
+ public ContractsController(IMessageBusPublisher messageBusPublisher, IQueryable contractReadModelQuery, ILogger logger)
+ {
+ _messageBusPublisher = messageBusPublisher;
+ _contractReadModelQuery = contractReadModelQuery;
+ _logger = logger;
+ }
+
+
+ // GET api/contracts
+ [HttpGet]
+ public async Task Get()
+ {
+ var query = await _contractReadModelQuery.ToListAsync();
+ return Ok(query.ToList());
+ }
+
+ // GET api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489
+ [HttpGet("{id}")]
+ public async Task Get(Guid id)
+ {
+ //var contract = await _contractReadModelRepository.GetFirstOrDefaultAsync(x=> x.ContractId == id, "ContractLines");
+ var contract = await _contractReadModelQuery
+ .Include(x=> x.ContractLines)
+ .SingleOrDefaultAsync(x => x.ContractId == id, CancellationToken.None);
+
+ if (contract != null)
+ return Ok(contract);
+
+ return NotFound();
+ }
+
+ // POST api/contracts
+ [HttpPost]
+ public Task Post([FromBody]CreateContract command, CancellationToken cancellationToken)
+ {
+ return _messageBusPublisher.PublishAsync(command, cancellationToken);
+ }
+
+ // POST api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489/lines
+ [HttpPost("{id}/lines")]
+ public Task Post([FromBody]AddContractLine command, CancellationToken cancellationToken)
+ {
+ return _messageBusPublisher.PublishAsync(command, cancellationToken);
+ }
+
+ // POST api/contracts/7327223E-22EA-48DC-BC44-FFF6AB3B9489/validate
+ [HttpPost("{id}/validate")]
+ public Task Post([FromBody]ValidateContract command, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Validating contract");
+ return _messageBusPublisher.PublishAsync(command, cancellationToken);
+ }
+
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Dockerfile b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Dockerfile
index 18cdf68e..17d1fa3b 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Dockerfile
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Dockerfile
@@ -24,7 +24,7 @@ COPY ["src/Messaging/NBB.Messaging.Nats/NBB.Messaging.Nats.csproj", "src/Messagi
COPY ["src/Correlation/NBB.Correlation.AspNet/NBB.Correlation.AspNet.csproj", "src/Correlation/NBB.Correlation.AspNet/"]
COPY ["samples/MicroServices/NBB.Contracts/NBB.Contracts.PublishedLanguage/NBB.Contracts.PublishedLanguage.csproj", "samples/MicroServices/NBB.Contracts/NBB.Contracts.PublishedLanguage/"]
COPY ["src/Messaging/NBB.Messaging.BackwardCompatibility/NBB.Messaging.BackwardCompatibility.csproj", "src/Messaging/NBB.Messaging.BackwardCompatibility/"]
-COPY ["src/Messaging/NBB.Messaging.OpenTracing/NBB.Messaging.OpenTracing.csproj", "src/Messaging/NBB.Messaging.OpenTracing/"]
+COPY ["src/Messaging/NBB.Messaging.OpenTelemetry/NBB.Messaging.OpenTelemetry.csproj", "src/Messaging/NBB.Messaging.OpenTelemetry/"]
COPY ["samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel.Data/NBB.Contracts.ReadModel.Data.csproj", "samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel.Data/"]
COPY ["samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel/NBB.Contracts.ReadModel.csproj", "samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel/"]
COPY ["src/Data/NBB.Data.EntityFramework/NBB.Data.EntityFramework.csproj", "src/Data/NBB.Data.EntityFramework/"]
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/NBB.Contracts.Api.csproj b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/NBB.Contracts.Api.csproj
index 09d54712..8b70415f 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/NBB.Contracts.Api.csproj
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/NBB.Contracts.Api.csproj
@@ -20,18 +20,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
+
+
+
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Program.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Program.cs
index 735b8e8d..a6a2e4c5 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Program.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Program.cs
@@ -3,6 +3,9 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
+using NBB.Correlation.Serilog;
+using NBB.Tools.Serilog.OpenTelemetryTracingSink;
+using Serilog;
namespace NBB.Contracts.Api
{
@@ -15,6 +18,15 @@ public static void Main(string[] args)
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
+ .UseSerilog((context, services, logConfig) =>
+ {
+ logConfig
+ .ReadFrom.Configuration(context.Configuration)
+ .Enrich.FromLogContext()
+ .Enrich.With()
+ .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}")
+ .WriteTo.OpenTelemetryTracing();
+ })
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup();
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Startup.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Startup.cs
index 4ad3fef4..85f2239d 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Startup.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/Startup.cs
@@ -1,10 +1,6 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using Jaeger;
-using Jaeger.Reporters;
-using Jaeger.Samplers;
-using Jaeger.Senders.Thrift;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@@ -12,15 +8,16 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using NBB.Contracts.ReadModel.Data;
using NBB.Correlation.AspNet;
-using NBB.Messaging.Abstractions;
-using NBB.Messaging.OpenTracing.Publisher;
-using OpenTracing;
-using OpenTracing.Noop;
-using OpenTracing.Util;
+using NBB.Messaging.OpenTelemetry;
+using OpenTelemetry;
+using OpenTelemetry.Exporter;
+using OpenTelemetry.Extensions.Propagators;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
using System;
using System.Reflection;
@@ -39,10 +36,7 @@ public Startup(IConfiguration configuration)
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
- services.AddSwaggerGen(c =>
- {
- c.SwaggerDoc("v1", new OpenApiInfo { Title = "Contracts API", Version = "v1" });
- });
+ services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Contracts API", Version = "v1" }); });
services.AddSingleton(Configuration);
services.TryAddSingleton();
@@ -70,39 +64,37 @@ public void ConfigureServices(IServiceCollection services)
services.AddContractsReadModelDataAccess();
- services.Decorate();
+ var assembly = Assembly.GetExecutingAssembly().GetName();
+ void configureResource(ResourceBuilder r) =>
+ r.AddService(assembly.Name, serviceVersion: assembly.Version?.ToString(), serviceInstanceId: Environment.MachineName);
- // OpenTracing
- //services.AddOpenTracingCoreServices(builder => builder
- // .AddAspNetCore()
- // .AddHttpHandler()
- // .AddGenericDiagnostics(x => x.IgnoredListenerNames.Add("Grpc.Net.Client"))
- // .AddLoggerProvider()
- // .AddMicrosoftSqlClient());
+ if (Configuration.GetValue("OpenTelemetry:TracingEnabled"))
+ {
+ Sdk.SetDefaultTextMapPropagator(new JaegerPropagator());
+
+ services.AddOpenTelemetryTracing(builder => builder
+ .ConfigureResource(configureResource)
+ .SetSampler(new AlwaysOnSampler())
+ .AddMessageBusInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddAspNetCoreInstrumentation()
+ .AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true)
+ .AddJaegerExporter()
+ );
+ services.Configure(Configuration.GetSection("OpenTelemetry:Jaeger"));
+ }
- services.AddSingleton(serviceProvider =>
+ if (Configuration.GetValue("OpenTelemetry:MetricsEnabled"))
{
- if (!Configuration.GetValue("OpenTracing:Jaeger:IsEnabled"))
+ services.AddOpenTelemetryMetrics(options =>
{
- return NoopTracerFactory.Create();
- }
-
- string serviceName = Assembly.GetEntryAssembly().GetName().Name;
-
- ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
-
- ITracer tracer = new Tracer.Builder(serviceName)
- .WithLoggerFactory(loggerFactory)
- .WithSampler(new ConstSampler(true))
- .WithReporter(new RemoteReporter.Builder()
- .WithSender(new HttpSender(Configuration.GetValue("OpenTracing:Jaeger:CollectorUrl")))
- .Build())
- .Build();
-
- GlobalTracer.Register(tracer);
-
- return tracer;
- });
+ options.ConfigureResource(configureResource)
+ .AddRuntimeInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddAspNetCoreInstrumentation()
+ .AddPrometheusExporter();
+ });
+ }
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -118,11 +110,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
}
app.UseRouting();
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
+ if (Configuration.GetValue("OpenTelemetry:MetricsEnabled"))
+ app.UseOpenTelemetryPrometheusScrapingEndpoint();
+
+ app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/appsettings.json b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/appsettings.json
index 9074c8ff..ea961e5f 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/appsettings.json
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Api/appsettings.json
@@ -1,35 +1,41 @@
-{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Information"
- }
- },
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
- },
- "Messaging": {
- "Env": "DEV",
- "Source1": "Contracts.Api",
- "TopicResolutionCompatibility": "NBB_5", // NBB_4
- "Transport": "NATS", // NATS Rusi
- "Kafka": {
- "bootstrap_servers": "YOUR_KAFKA_URL"
- },
- "Nats": {
- "natsUrl": "YOUR_NATS_URL",
- "cluster": "faas-cluster",
- "clientId": "NBB_Samples"
- },
- "Rusi": {
- "RusiPort": 50003,
- "PubsubName": "natsstreaming-pubsub"
- }
- },
- "OpenTracing": {
- "Jaeger": {
- "IsEnabled": "true",
- "Collectorurl": "YOUR_COLLECTOR_URL"
- }
- }
-}
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting": "Information"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ },
+ "Messaging": {
+ "Env": "DEV",
+ "Source": "Contracts.Api",
+ "TopicResolutionCompatibility": "NBB_5", // NBB_4
+ "Transport": "NATS", // NATS Rusi
+ "Kafka": {
+ "bootstrap_servers": "YOUR_KAFKA_URL"
+ },
+ "Nats": {
+ "natsUrl": "YOUR_NATS_URL",
+ "cluster": "faas-cluster",
+ "clientId": "NBB_Samples"
+ },
+ "Rusi": {
+ "RusiPort": 50003,
+ "PubsubName": "natsstreaming-pubsub"
+ }
+ },
+ "OpenTelemetry": {
+ "MetricsEnabled": true,
+ "TracingEnabled": true,
+ "Jaeger": {
+ //"AgentHost": "localhost",
+ //"AgentPort": 6831,
+ //"Protocol": "UdpCompactThrift",
+ "Endpoint": "YOUR_COLLECTOR_URL",
+ "Protocol": "HttpBinaryThrift"
+ }
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs
index 52b662b9..18b2af11 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/CommandHandlers/ContractCommandHandlers.cs
@@ -1,51 +1,60 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using MediatR;
-using NBB.Contracts.Domain.ContractAggregate;
+using MediatR;
+using Microsoft.Extensions.Logging;
+using NBB.Contracts.Domain.ContractAggregate;
using NBB.Contracts.PublishedLanguage;
-using NBB.Data.Abstractions;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NBB.Contracts.Application.CommandHandlers
-{
- public class ContractCommandHandlers :
- IRequestHandler,
- IRequestHandler,
- IRequestHandler
- {
- private readonly IEventSourcedRepository _repository;
-
- public ContractCommandHandlers(IEventSourcedRepository repository)
- {
- this._repository = repository;
- }
-
- public async Task Handle(CreateContract command, CancellationToken cancellationToken)
- {
- var contract = new Contract(command.ClientId);
- await _repository.SaveAsync(contract, cancellationToken);
-
- return Unit.Value;
- }
-
- public async Task Handle(AddContractLine command, CancellationToken cancellationToken)
- {
- var contract = await _repository.GetByIdAsync(command.ContractId, cancellationToken);
- contract.AddContractLine(command.Product, command.Price, command.Quantity);
- await _repository.SaveAsync(contract, cancellationToken);
-
- return Unit.Value;
- }
-
- public async Task Handle(ValidateContract command, CancellationToken cancellationToken)
- {
- var contract = await _repository.GetByIdAsync(command.ContractId, cancellationToken);
- contract.Validate();
- await _repository.SaveAsync(contract, cancellationToken);
-
- return Unit.Value;
- }
- }
-}
+using NBB.Data.Abstractions;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NBB.Contracts.Application.CommandHandlers
+{
+ public class ContractCommandHandlers :
+ IRequestHandler,
+ IRequestHandler,
+ IRequestHandler
+ {
+ private readonly IEventSourcedRepository _repository;
+ private readonly ContractDomainMetrics _domainMetrics;
+ private readonly ILogger _logger;
+
+ public ContractCommandHandlers(IEventSourcedRepository repository, ContractDomainMetrics domainMetrics, ILogger logger)
+ {
+ this._repository = repository;
+ _domainMetrics = domainMetrics;
+ _logger = logger;
+ }
+
+ public async Task Handle(CreateContract command, CancellationToken cancellationToken)
+ {
+ var contract = new Contract(command.ClientId);
+ await _repository.SaveAsync(contract, cancellationToken);
+ _domainMetrics.ContractCreated();
+
+ return Unit.Value;
+ }
+
+ public async Task Handle(AddContractLine command, CancellationToken cancellationToken)
+ {
+ var contract = await _repository.GetByIdAsync(command.ContractId, cancellationToken);
+ contract.AddContractLine(command.Product, command.Price, command.Quantity);
+ await _repository.SaveAsync(contract, cancellationToken);
+
+ return Unit.Value;
+ }
+
+ public async Task Handle(ValidateContract command, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Validating contract");
+
+ var contract = await _repository.GetByIdAsync(command.ContractId, cancellationToken);
+ contract.Validate();
+ await _repository.SaveAsync(contract, cancellationToken);
+ _domainMetrics.ContractValidated();
+
+ return Unit.Value;
+ }
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/ContractDomainMetrics.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/ContractDomainMetrics.cs
new file mode 100644
index 00000000..cb1a10fa
--- /dev/null
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/ContractDomainMetrics.cs
@@ -0,0 +1,44 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using System;
+using System.Diagnostics.Metrics;
+using System.Reflection;
+
+namespace NBB.Contracts.Application
+{
+ public class ContractDomainMetrics : IDisposable
+ {
+ private static readonly AssemblyName AssemblyName = Assembly.GetCallingAssembly().GetName();
+ public static readonly string InstrumentationName = AssemblyName.Name;
+ private readonly Counter _contracts;
+ private readonly Counter _validatedContracts;
+ private readonly Meter _meter;
+
+ public ContractDomainMetrics()
+ {
+ _meter = new Meter(AssemblyName.Name);
+ _contracts = _meter.CreateCounter("nbb.contracts.created.count");
+ _validatedContracts = _meter.CreateCounter("nbb.contracts.validated.count");
+
+ _contracts.Add(1);
+ _contracts.Add(1);
+
+ }
+
+ public void ContractCreated()
+ {
+ _contracts.Add(1);
+ }
+ public void ContractValidated()
+ {
+ _validatedContracts.Add(1);
+ }
+
+ ///
+ public void Dispose()
+ {
+ _meter?.Dispose();
+ }
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/DomainEventHandlers/ContractDomainEventHandlers.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/DomainEventHandlers/ContractDomainEventHandlers.cs
index 3cd3fc12..cb92ca6a 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/DomainEventHandlers/ContractDomainEventHandlers.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Application/DomainEventHandlers/ContractDomainEventHandlers.cs
@@ -1,28 +1,28 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using System.Threading;
-using System.Threading.Tasks;
-using MediatR;
-using NBB.Contracts.Domain.ContractAggregate;
-using NBB.Messaging.Abstractions;
-
-namespace NBB.Contracts.Application.DomainEventHandlers
-{
- public class ContractDomainEventHandlers :
- INotificationHandler
- {
- private readonly IMessageBusPublisher _messageBusPublisher;
-
- public ContractDomainEventHandlers(IMessageBusPublisher messageBusPublisher)
- {
- _messageBusPublisher = messageBusPublisher;
- }
-
- public Task Handle(ContractValidated domainEvent, CancellationToken cancellationToken)
- {
- return _messageBusPublisher.PublishAsync(
- new PublishedLanguage.ContractValidated(domainEvent.ContractId, domainEvent.ClientId, domainEvent.Amount), cancellationToken);
- }
- }
-}
+using System.Threading;
+using System.Threading.Tasks;
+using MediatR;
+using NBB.Contracts.Domain.ContractAggregate;
+using NBB.Messaging.Abstractions;
+
+namespace NBB.Contracts.Application.DomainEventHandlers
+{
+ public class ContractDomainEventHandlers :
+ INotificationHandler
+ {
+ private readonly IMessageBusPublisher _messageBusPublisher;
+
+ public ContractDomainEventHandlers(IMessageBusPublisher messageBusPublisher)
+ {
+ _messageBusPublisher = messageBusPublisher;
+ }
+
+ public Task Handle(ContractValidated domainEvent, CancellationToken cancellationToken)
+ {
+ return _messageBusPublisher.PublishAsync(
+ new PublishedLanguage.ContractValidated(domainEvent.ContractId, domainEvent.ClientId, domainEvent.Amount), cancellationToken);
+ }
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Domain/ContractAggregate/Contract.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Domain/ContractAggregate/Contract.cs
index e3d1e15d..1da70258 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Domain/ContractAggregate/Contract.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Domain/ContractAggregate/Contract.cs
@@ -1,111 +1,111 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using NBB.Contracts.Domain.ContractAggregate.Snapshots;
-using NBB.Domain;
-
-namespace NBB.Contracts.Domain.ContractAggregate
-{
- public class Contract : EventSourcedAggregateRoot
- {
- public Guid ContractId { get; private set; }
- public decimal Amount { get; private set; }
-
- public Guid ClientId { get; private set; }
-
- public List ContractLines { get; private set; } = new List();
-
- public bool IsValidated { get; private set; }
-
-
- //needed 4 repository should be private
- public Contract()
- {
- }
-
- public Contract(Guid clientId)
- {
- Emit(new ContractCreated(Guid.NewGuid(), clientId));
- }
-
- public override Guid GetIdentityValue() => ContractId;
-
-
- public void AddContractLine(string product, decimal price, int quantity)
- {
- if (IsValidated)
- throw new Exception("Contract is validated");
-
- Emit(new ContractLineAdded(Guid.NewGuid(), this.ContractId, product, price, quantity));
- Emit(new ContractAmountUpdated(this.ContractId, this.Amount + price * quantity));
- }
-
- public void Validate()
- {
- if (IsValidated)
- throw new Exception("Contract already validated");
- Emit(new ContractValidated(this.ContractId, this.ClientId, this.Amount));
- }
-
- protected override void SetMemento(ContractSnapshot memento)
- {
- Amount = memento.Amount;
- ClientId = memento.ClientId;
- ContractId = memento.ContractId;
- IsValidated = memento.IsValidated;
- ContractLines = memento.ContractLines.Select(x =>
- new ContractLine(
- new Product(x.Product.Name, x.Product.Price),
- x.Quantity, x.ContractId))
- .ToList();
- }
-
- protected override ContractSnapshot CreateMemento()
- {
- return new ContractSnapshot()
- {
- Amount = Amount,
- ClientId = ClientId,
- ContractId = ContractId,
- IsValidated = IsValidated,
- ContractLines = ContractLines.Select(x =>
- new ContractSnapshot.ContractLine
- {
- ContractId = x.ContractId,
- ContractLineId = x.ContractLineId,
- Quantity = x.Quantity,
- Product = new ContractSnapshot.Product
- {
- Name = x.Product.Name,
- Price = x.Product.Price
- }
- }).ToList()
- };
- }
-
- private void Apply(ContractCreated e)
- {
- this.ContractId = e.ContractId;
- this.ClientId = e.ClientId;
- }
-
- private void Apply(ContractAmountUpdated e)
- {
- this.Amount = e.NewAmount;
- }
-
- private void Apply(ContractLineAdded e)
- {
- var contractLine = new ContractLine(new Product(e.Product, e.Price), e.Quantity, this.ContractId);
- this.ContractLines.Add(contractLine);
- }
-
- private void Apply(ContractValidated e)
- {
- this.IsValidated = true;
- }
- }
-}
\ No newline at end of file
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NBB.Contracts.Domain.ContractAggregate.Snapshots;
+using NBB.Domain;
+
+namespace NBB.Contracts.Domain.ContractAggregate
+{
+ public class Contract : EventSourcedAggregateRoot
+ {
+ public Guid ContractId { get; private set; }
+ public decimal Amount { get; private set; }
+
+ public Guid ClientId { get; private set; }
+
+ public List ContractLines { get; private set; } = new List();
+
+ public bool IsValidated { get; private set; }
+
+
+ //needed 4 repository should be private
+ public Contract()
+ {
+ }
+
+ public Contract(Guid clientId)
+ {
+ Emit(new ContractCreated(Guid.NewGuid(), clientId));
+ }
+
+ public override Guid GetIdentityValue() => ContractId;
+
+
+ public void AddContractLine(string product, decimal price, int quantity)
+ {
+ if (IsValidated)
+ throw new Exception("Contract is validated");
+
+ Emit(new ContractLineAdded(Guid.NewGuid(), this.ContractId, product, price, quantity));
+ Emit(new ContractAmountUpdated(this.ContractId, this.Amount + price * quantity));
+ }
+
+ public void Validate()
+ {
+ if (IsValidated)
+ throw new Exception("Contract already validated");
+ Emit(new ContractValidated(this.ContractId, this.ClientId, this.Amount));
+ }
+
+ protected override void SetMemento(ContractSnapshot memento)
+ {
+ Amount = memento.Amount;
+ ClientId = memento.ClientId;
+ ContractId = memento.ContractId;
+ IsValidated = memento.IsValidated;
+ ContractLines = memento.ContractLines.Select(x =>
+ new ContractLine(
+ new Product(x.Product.Name, x.Product.Price),
+ x.Quantity, x.ContractId))
+ .ToList();
+ }
+
+ protected override ContractSnapshot CreateMemento()
+ {
+ return new ContractSnapshot()
+ {
+ Amount = Amount,
+ ClientId = ClientId,
+ ContractId = ContractId,
+ IsValidated = IsValidated,
+ ContractLines = ContractLines.Select(x =>
+ new ContractSnapshot.ContractLine
+ {
+ ContractId = x.ContractId,
+ ContractLineId = x.ContractLineId,
+ Quantity = x.Quantity,
+ Product = new ContractSnapshot.Product
+ {
+ Name = x.Product.Name,
+ Price = x.Product.Price
+ }
+ }).ToList()
+ };
+ }
+
+ private void Apply(ContractCreated e)
+ {
+ this.ContractId = e.ContractId;
+ this.ClientId = e.ClientId;
+ }
+
+ private void Apply(ContractAmountUpdated e)
+ {
+ this.Amount = e.NewAmount;
+ }
+
+ private void Apply(ContractLineAdded e)
+ {
+ var contractLine = new ContractLine(new Product(e.Product, e.Price), e.Quantity, this.ContractId);
+ this.ContractLines.Add(contractLine);
+ }
+
+ private void Apply(ContractValidated e)
+ {
+ this.IsValidated = true;
+ }
+ }
+}
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Dockerfile b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Dockerfile
index dc0da797..b1758e7f 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Dockerfile
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Dockerfile
@@ -38,7 +38,7 @@ COPY ["src/Messaging/NBB.Messaging.Nats/NBB.Messaging.Nats.csproj", "src/Messagi
COPY ["src/EventStore/NBB.EventStore.AdoNet/NBB.EventStore.AdoNet.csproj", "src/EventStore/NBB.EventStore.AdoNet/"]
COPY ["src/Correlation/NBB.Correlation.Serilog/NBB.Correlation.Serilog.csproj", "src/Correlation/NBB.Correlation.Serilog/"]
COPY ["src/Messaging/NBB.Messaging.BackwardCompatibility/NBB.Messaging.BackwardCompatibility.csproj", "src/Messaging/NBB.Messaging.BackwardCompatibility/"]
-COPY ["src/Messaging/NBB.Messaging.OpenTracing/NBB.Messaging.OpenTracing.csproj", "src/Messaging/NBB.Messaging.OpenTracing/"]
+COPY ["src/Messaging/NBB.Messaging.OpenTelemetry/NBB.Messaging.OpenTelemetry.csproj", "src/Messaging/NBB.Messaging.OpenTelemetry/"]
COPY ["samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel.Data/NBB.Contracts.ReadModel.Data.csproj", "samples/MicroServices/NBB.Contracts/NBB.Contracts.ReadModel.Data/"]
COPY ["src/Data/NBB.Data.EntityFramework/NBB.Data.EntityFramework.csproj", "src/Data/NBB.Data.EntityFramework/"]
RUN dotnet restore "samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj"
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj
index 5920e781..12dd8bfe 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/NBB.Contracts.Worker.csproj
@@ -1,62 +1,70 @@
-
- SAK
- SAK
- SAK
- SAK
-
-
-
- Exe
- net7.0
- NBB_Contracts_6a73f87d-2175-4be0-9a42-31cb73bc8e10
- Linux
- ..\..\..\..
-
-
-
- 1701;1702;1705;NU1701
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Always
-
-
- Always
-
-
-
+
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+
+ Exe
+ net7.0
+ NBB_Contracts_6a73f87d-2175-4be0-9a42-31cb73bc8e10
+ Linux
+ ..\..\..\..
+
+
+
+ 1701;1702;1705;NU1701
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs
index 5deb1550..4800da05 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/Program.cs
@@ -1,32 +1,30 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using Jaeger;
-using Jaeger.Reporters;
-using Jaeger.Samplers;
-using Jaeger.Senders.Thrift;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
+using NBB.Contracts.Application;
using NBB.Contracts.Application.CommandHandlers;
using NBB.Contracts.ReadModel.Data;
using NBB.Contracts.WriteModel.Data;
using NBB.Correlation.Serilog;
using NBB.Domain;
-using NBB.Messaging.Abstractions;
using NBB.Messaging.Host;
-using NBB.Messaging.OpenTracing.Publisher;
-using OpenTracing;
-using OpenTracing.Noop;
-using OpenTracing.Util;
+using NBB.Messaging.OpenTelemetry;
+using OpenTelemetry;
+using OpenTelemetry.Exporter;
+using OpenTelemetry.Extensions.Propagators;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
using Serilog;
-using Serilog.Events;
-using Serilog.Sinks.MSSqlServer;
using System;
-using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System.Reflection;
+using NBB.Tools.Serilog.OpenTelemetryTracingSink;
namespace NBB.Contracts.Worker
{
@@ -36,23 +34,14 @@ public static async Task Main(string[] args)
{
var builder = Host
.CreateDefaultBuilder(args)
- .ConfigureLogging((hostingContext, loggingBuilder) =>
+ .UseSerilog((context, services, logConfig) =>
{
- var env = hostingContext.HostingEnvironment.IsDevelopment();
- var connectionString = hostingContext.Configuration.GetConnectionString("Logs");
-
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Debug()
- .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
+ logConfig
+ .ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.Enrich.With()
- .WriteTo.MSSqlServer(connectionString,
- new MSSqlServerSinkOptions { TableName = "Logs", AutoCreateSqlTable = true })
- .CreateLogger();
-
- loggingBuilder.AddSerilog(dispose: true);
- loggingBuilder.AddFilter("Microsoft", logLevel => logLevel >= LogLevel.Warning);
- loggingBuilder.AddConsole();
+ .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}")
+ .WriteTo.OpenTelemetryTracing();
})
.ConfigureServices((hostingContext, services) =>
{
@@ -89,43 +78,52 @@ public static async Task Main(string[] args)
b.UseAdoNetEventRepository(o => o.FromConfiguration());
});
- services.Decorate();
services.AddMessagingHost(hostingContext.Configuration, hostBuilder => hostBuilder.UseStartup());
- // OpenTracing
- //services.AddOpenTracingCoreServices(builder => builder.AddGenericDiagnostics().AddMicrosoftSqlClient());
+ var assembly = Assembly.GetExecutingAssembly().GetName();
+ void configureResource(ResourceBuilder r) =>
+ r.AddService(assembly.Name, serviceVersion: assembly.Version?.ToString(), serviceInstanceId: Environment.MachineName);
+ if (hostingContext.Configuration.GetValue("OpenTelemetry:TracingEnabled"))
+ {
+ Sdk.SetDefaultTextMapPropagator(new JaegerPropagator());
+
+ services.AddOpenTelemetryTracing(builder => builder
+ .ConfigureResource(configureResource)
+ .SetSampler(new AlwaysOnSampler())
+ .AddMessageBusInstrumentation()
+ .AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true)
+ .AddJaegerExporter()
+ );
+ services.Configure(hostingContext.Configuration.GetSection("OpenTelemetry:Jaeger"));
+ }
- services.AddSingleton(serviceProvider =>
+ if (hostingContext.Configuration.GetValue("OpenTelemetry:MetricsEnabled"))
{
- if (!hostingContext.Configuration.GetValue("OpenTracing:Jaeger:IsEnabled"))
+ services.AddOpenTelemetryMetrics(options =>
{
- return NoopTracerFactory.Create();
- }
-
- string serviceName = Assembly.GetEntryAssembly().GetName().Name;
-
- ILoggerFactory loggerFactory = serviceProvider.GetRequiredService();
-
- ITracer tracer = new Tracer.Builder(serviceName)
- .WithLoggerFactory(loggerFactory)
- .WithSampler(new ConstSampler(true))
- .WithReporter(new RemoteReporter.Builder()
- .WithSender(new HttpSender(hostingContext.Configuration.GetValue("OpenTracing:Jaeger:CollectorUrl")))
- .Build())
- .Build();
-
- GlobalTracer.Register(tracer);
-
- return tracer;
- });
-
+ options.ConfigureResource(configureResource)
+ .AddRuntimeInstrumentation()
+ .AddPrometheusHttpListener();
+ AddContractMetrics(options);
+ });
+ }
+ else
+ {
+ services.TryAddSingleton();
+ }
});
var host = builder.Build();
await host.RunAsync();
}
+
+ public static MeterProviderBuilder AddContractMetrics(MeterProviderBuilder builder)
+ {
+ builder.AddMeter(ContractDomainMetrics.InstrumentationName);
+ return builder.AddInstrumentation();
+ }
}
class MessagingHostStartup : IMessagingHostStartup
@@ -141,7 +139,6 @@ public Task Configure(IMessagingHostConfigurationBuilder hostConfigurationBuilde
.UsePipeline(pipelineBuilder => pipelineBuilder
.UseCorrelationMiddleware()
.UseExceptionHandlingMiddleware()
- .UseOpenTracingMiddleware()
.UseDefaultResiliencyMiddleware()
.UseMediatRMiddleware()
);
diff --git a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/appsettings.json b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/appsettings.json
index 86600956..3d4ad970 100644
--- a/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/appsettings.json
+++ b/samples/MicroServices/NBB.Contracts/NBB.Contracts.Worker/appsettings.json
@@ -1,47 +1,49 @@
{
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
- "Logs": "Server=YOUR_SERVER_URL;Database=NBB_Logs;User Id=YOUR_USER_NAME;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
+ "Logs": "Server=YOUR_SERVER_URL;Database=NBB_Logs;User Id=YOUR_USER_NAME;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ },
+ "Messaging": {
+ "Env": "DEV",
+ "Source": "Contracts.Worker",
+ "Transport": "NATS", // NATS Rusi
+ "TopicResolutionCompatibility": "NBB_5", // NBB_4
+ "Host": {
+ "TransportErrorStrategy": "Retry",
+ "StartRetryCount": 10
},
- "Messaging": {
- "Env": "DEV",
- "Source": "Contracts.Worker",
- "Transport": "NATS", // NATS Rusi
- "TopicResolutionCompatibility": "NBB_5", // NBB_4
- "Host": {
- "TransportErrorStrategy": "Retry",
- "StartRetryCount": 10
- },
- "Kafka": {
- "bootstrap_servers": "YOUR_KAFKA_URL",
- "group_id": "NBB.Contracts.Worker"
- },
- "Nats": {
- "natsUrl": "YOUR_NATS_URL",
- "cluster": "faas-cluster",
- "clientId": "NBB_Samples",
- "qGroup": "NBB.Contracts.Worker",
- "durableName": "durable"
- },
- "Rusi": {
- "RusiPort": 50003,
- "PubsubName": "natsstreaming-pubsub"
- }
+ "Kafka": {
+ "bootstrap_servers": "YOUR_KAFKA_URL",
+ "group_id": "NBB.Contracts.Worker"
},
- "EventStore": {
- "NBB": {
- "ConnectionString": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
- },
- "GetEventStore": {
- },
- "SqlStreamStore": {
- "ConnectionString": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
- }
+ "Nats": {
+ "natsUrl": "YOUR_NATS_URL",
+ "cluster": "faas-cluster",
+ "clientId": "NBB_Samples",
+ "qGroup": "NBB.Contracts.Worker",
+ "durableName": "durable"
},
- "OpenTracing": {
- "Jaeger": {
- "IsEnabled": "True",
- "Collectorurl": "YOUR_COLLECTOR_URL"
- }
+ "Rusi": {
+ "RusiPort": 50003,
+ "PubsubName": "natsstreaming-pubsub"
}
+ },
+ "EventStore": {
+ "NBB": {
+ "ConnectionString": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ },
+ "GetEventStore": {
+ },
+ "SqlStreamStore": {
+ "ConnectionString": "Server=YOUR_SERVER;Database=NBB_Contracts;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ }
+ },
+ "OpenTelemetry": {
+ "MetricsEnabled": true,
+ "TracingEnabled": true,
+ "Jaeger": {
+ "Endpoint": "YOUR_COLLECTOR_URL",
+ "Protocol": "HttpBinaryThrift"
+ }
+ }
}
diff --git a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/appsettings.json b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/appsettings.json
index 3c46a950..0fae0770 100644
--- a/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/appsettings.json
+++ b/samples/MicroServices/NBB.Payments/NBB.Payments.Worker/appsettings.json
@@ -7,7 +7,7 @@
"Env": "DEV",
"Source": "Payments.Worker",
"Kafka": {
- "bootstrap_servers": "kube-worker1",
+ "bootstrap_servers": "YOUR_KAFKA_URL",
"group_id": "NBB.Payments.Worker"
},
"Nats": {
diff --git a/samples/MultiTenancy/NBB.Todo.Api/NBB.Todo.Api.csproj b/samples/MultiTenancy/NBB.Todo.Api/NBB.Todo.Api.csproj
index 9e029aae..4d4374fe 100644
--- a/samples/MultiTenancy/NBB.Todo.Api/NBB.Todo.Api.csproj
+++ b/samples/MultiTenancy/NBB.Todo.Api/NBB.Todo.Api.csproj
@@ -12,7 +12,15 @@
-
+
+
+
+
+
+
+
+
+
@@ -21,9 +29,11 @@
+
+
diff --git a/samples/MultiTenancy/NBB.Todo.Api/Program.cs b/samples/MultiTenancy/NBB.Todo.Api/Program.cs
index 79f1a862..462a1ba2 100644
--- a/samples/MultiTenancy/NBB.Todo.Api/Program.cs
+++ b/samples/MultiTenancy/NBB.Todo.Api/Program.cs
@@ -7,6 +7,7 @@
using NBB.Correlation.Serilog;
using Microsoft.Extensions.DependencyInjection;
using NBB.Tools.Serilog.Enrichers.TenantId;
+using NBB.Tools.Serilog.OpenTelemetryTracingSink;
namespace NBB.Todo.Api
{
@@ -28,8 +29,9 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.Enrich.With()
- .Enrich.With(services.GetRequiredService());
- logConfig.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}");
+ .Enrich.With(services.GetRequiredService())
+ .WriteTo.OpenTelemetryTracing()
+ .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}");
})
.ConfigureWebHostDefaults(webBuilder =>
{
diff --git a/samples/MultiTenancy/NBB.Todo.Api/Startup.cs b/samples/MultiTenancy/NBB.Todo.Api/Startup.cs
index 64295b60..135c90a7 100644
--- a/samples/MultiTenancy/NBB.Todo.Api/Startup.cs
+++ b/samples/MultiTenancy/NBB.Todo.Api/Startup.cs
@@ -11,11 +11,19 @@
using Microsoft.Extensions.Hosting;
using NBB.Correlation;
using NBB.Correlation.AspNet;
+using NBB.Messaging.OpenTelemetry;
using NBB.MultiTenancy.Abstractions.Repositories;
using NBB.MultiTenancy.AspNet;
using NBB.Todos.Data;
using NBB.Tools.Serilog.Enrichers.TenantId;
+using OpenTelemetry;
+using OpenTelemetry.Exporter;
+using OpenTelemetry.Extensions.Propagators;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
using System;
+using System.Reflection;
using ProblemDetailsOptions = Hellang.Middleware.ProblemDetails.ProblemDetailsOptions;
namespace NBB.Todo.Api
@@ -53,6 +61,38 @@ public void ConfigureServices(IServiceCollection services)
services.AddProblemDetails(config => ConfigureProblemDetails(config));
+ var assembly = Assembly.GetExecutingAssembly().GetName();
+ void configureResource(ResourceBuilder r) =>
+ r.AddService(assembly.Name, serviceVersion: assembly.Version?.ToString(), serviceInstanceId: Environment.MachineName);
+
+ if (Configuration.GetValue("OpenTelemetry:TracingEnabled"))
+ {
+ Sdk.SetDefaultTextMapPropagator(new JaegerPropagator());
+
+ services.AddOpenTelemetryTracing(builder => builder
+ .ConfigureResource(configureResource)
+ .SetSampler(new AlwaysOnSampler())
+ .AddHttpClientInstrumentation()
+ .AddAspNetCoreInstrumentation()
+ .AddMessageBusInstrumentation()
+ .AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true)
+ .AddJaegerExporter()
+ );
+ services.Configure(Configuration.GetSection("OpenTelemetry:Jaeger"));
+ }
+
+ if (Configuration.GetValue("OpenTelemetry:MetricsEnabled"))
+ {
+ services.AddOpenTelemetryMetrics(options =>
+ {
+ options.ConfigureResource(configureResource)
+ .AddRuntimeInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddAspNetCoreInstrumentation()
+ .AddPrometheusExporter();
+ });
+ }
+
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/samples/MultiTenancy/NBB.Todo.Api/appsettings.json b/samples/MultiTenancy/NBB.Todo.Api/appsettings.json
index 065c6b40..5ba8d6dc 100644
--- a/samples/MultiTenancy/NBB.Todo.Api/appsettings.json
+++ b/samples/MultiTenancy/NBB.Todo.Api/appsettings.json
@@ -1,79 +1,87 @@
{
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
- "Log_Database": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
+ "Log_Database": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ },
+ "Serilog": {
+ "Properties": {
+ "ServiceName": "NBB.Todo.Api"
},
- "Serilog": {
- "Properties": {
- "ServiceName": "NBB.Todo.Api"
- },
- "MinimumLevel": {
- "Default": "Debug",
- "Override": {
- "Microsoft": "Information",
- "OpenTracing": "Warning",
- "System.Net": "Warning"
- }
- },
- "WriteTo": [
- {
- "Name": "MSSqlServer",
- "Args": {
- "connectionString": "Log_Database",
- "sinkOptionsSection": {
- "tableName": "__Logs",
- "schemaName": "dbo",
- "autoCreateSqlTable": true,
- "batchPostingLimit": 5000
- },
- //"restrictedToMinimumLevel": "Information",
- "columnOptionsSection": {
- "addStandardColumns": [ "LogEvent" ],
- "removeStandardColumns": [ "MessageTemplate", "Properties" ],
- "additionalColumns": [
- {
- "ColumnName": "ServiceName",
- "DataType": "varchar",
- "DataLength": 200
- },
- {
- "ColumnName": "TenantId",
- "DataType": "UniqueIdentifier"
- },
- {
- "ColumnName": "CorrelationId",
- "DataType": "UniqueIdentifier"
- }
- ]
- }
- }
- }
- ]
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft": "Information",
+ "OpenTelemetry": "Warning",
+ "System.Net": "Warning"
+ }
},
-
- "Messaging": {
- "Env": "DEV",
- "Source": "Todo.Api",
- "Nats": {
- "natsUrl": "YOUR_NATS_URL",
- "cluster": "faas-cluster",
- "clientId": "NBB_Samples"
+ "WriteTo": [
+ {
+ "Name": "MSSqlServer",
+ "Args": {
+ "connectionString": "Log_Database",
+ "sinkOptionsSection": {
+ "tableName": "__Logs",
+ "schemaName": "dbo",
+ "autoCreateSqlTable": true,
+ "batchPostingLimit": 5000
+ },
+ //"restrictedToMinimumLevel": "Information",
+ "columnOptionsSection": {
+ "addStandardColumns": [ "LogEvent" ],
+ "removeStandardColumns": [ "MessageTemplate", "Properties" ],
+ "additionalColumns": [
+ {
+ "ColumnName": "ServiceName",
+ "DataType": "varchar",
+ "DataLength": 200
+ },
+ {
+ "ColumnName": "TenantId",
+ "DataType": "UniqueIdentifier"
+ },
+ {
+ "ColumnName": "CorrelationId",
+ "DataType": "UniqueIdentifier"
+ }
+ ]
+ }
}
+ }
+ ]
+ },
+
+ "Messaging": {
+ "Env": "DEV",
+ "Source": "Todo.Api",
+ "Nats": {
+ "natsUrl": "YOUR_NATS_URL",
+ "cluster": "faas-cluster",
+ "clientId": "NBB_Samples"
+ }
+ },
+ "MultiTenancy": {
+ "TenancyType": "MultiTenant", // "MultiTenant" "MonoTenant"
+ "Defaults": {
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ }
},
- "MultiTenancy": {
- "TenancyType": "MultiTenant", // "MultiTenant" "MonoTenant"
- "Defaults": {
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
- }
- },
- "Tenants": {
- "tenant1": {
- "TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7"
- },
- "tenant2": {
- "TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7"
- }
- }
+ "Tenants": {
+ "tenant1": {
+ "TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7"
+ },
+ "tenant2": {
+ "TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7"
+ }
+ }
+ },
+ "OpenTelemetry": {
+ "MetricsEnabled": true,
+ "TracingEnabled": true,
+ "Jaeger": {
+ "Endpoint": "YOUR_COLLECTOR_URL",
+ "Protocol": "HttpBinaryThrift"
}
+ }
}
diff --git a/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj b/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj
index 294ef933..52600b6f 100644
--- a/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj
+++ b/samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj
@@ -25,6 +25,13 @@
+
+
+
+
+
+
+
@@ -34,11 +41,11 @@
-
+
-
+
diff --git a/samples/MultiTenancy/NBB.Todo.Worker/Program.cs b/samples/MultiTenancy/NBB.Todo.Worker/Program.cs
index bc4f1995..8bbee54b 100644
--- a/samples/MultiTenancy/NBB.Todo.Worker/Program.cs
+++ b/samples/MultiTenancy/NBB.Todo.Worker/Program.cs
@@ -12,11 +12,19 @@
using NBB.Todo.Worker.Application;
using NBB.Messaging.Host;
using NBB.Messaging.MultiTenancy;
+using NBB.Messaging.OpenTelemetry;
using NBB.MultiTenancy.Abstractions.Repositories;
-using Serilog.Events;
-using Microsoft.Extensions.Logging;
using NBB.Correlation.Serilog;
using NBB.Tools.Serilog.Enrichers.TenantId;
+using Microsoft.Extensions.Configuration;
+using OpenTelemetry;
+using OpenTelemetry.Extensions.Propagators;
+using OpenTelemetry.Exporter;
+using OpenTelemetry.Resources;
+using System.Reflection;
+using OpenTelemetry.Trace;
+using OpenTelemetry.Metrics;
+using NBB.Tools.Serilog.OpenTelemetryTracingSink;
namespace NBB.Todo.Worker
{
@@ -55,6 +63,7 @@ public static IHost BuildConsoleHost(string[] args) =>
.Enrich.FromLogContext()
.Enrich.With()
.Enrich.With(services.GetRequiredService())
+ .WriteTo.OpenTelemetryTracing()
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}");
})
.UseConsoleLifetime()
@@ -96,6 +105,37 @@ private static void ConfigureServices(HostBuilderContext hostingContext, IServic
.AddTenantRepository();
services.AddSingleton();
+
+
+ var assembly = Assembly.GetExecutingAssembly().GetName();
+ void configureResource(ResourceBuilder r) =>
+ r.AddService(assembly.Name, serviceVersion: assembly.Version?.ToString(), serviceInstanceId: Environment.MachineName);
+
+
+ if (hostingContext.Configuration.GetValue("OpenTelemetry:TracingEnabled"))
+ {
+ Sdk.SetDefaultTextMapPropagator(new JaegerPropagator());
+
+ services.AddOpenTelemetryTracing(builder => builder
+ .ConfigureResource(configureResource)
+ .SetSampler(new AlwaysOnSampler())
+ .AddMessageBusInstrumentation()
+ .AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true)
+ .AddJaegerExporter()
+ );
+ services.Configure(hostingContext.Configuration.GetSection("OpenTelemetry:Jaeger"));
+ }
+
+
+ if (hostingContext.Configuration.GetValue("OpenTelemetry:MetricsEnabled"))
+ {
+ services.AddOpenTelemetryMetrics(options =>
+ {
+ options.ConfigureResource(configureResource)
+ .AddRuntimeInstrumentation()
+ .AddPrometheusHttpListener();
+ });
+ }
}
}
}
diff --git a/samples/MultiTenancy/NBB.Todo.Worker/appsettings.json b/samples/MultiTenancy/NBB.Todo.Worker/appsettings.json
index fa662978..f48d4608 100644
--- a/samples/MultiTenancy/NBB.Todo.Worker/appsettings.json
+++ b/samples/MultiTenancy/NBB.Todo.Worker/appsettings.json
@@ -1,80 +1,88 @@
{
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
- "Log_Database": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
+ "Log_Database": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ },
+ "Serilog": {
+ "Properties": {
+ "ServiceName": "NBB.Todo.Worker"
},
- "Serilog": {
- "Properties": {
- "ServiceName": "NBB.Todo.Worker"
- },
- "MinimumLevel": {
- "Default": "Debug",
- "Override": {
- "Microsoft": "Information",
- "OpenTracing": "Warning",
- "System.Net": "Warning"
- }
- },
- "WriteTo": [
- {
- "Name": "MSSqlServer",
- "Args": {
- "connectionString": "Log_Database",
- "sinkOptionsSection": {
- "tableName": "__Logs",
- "schemaName": "dbo",
- "autoCreateSqlTable": true,
- "batchPostingLimit": 5000
- },
- //"restrictedToMinimumLevel": "Information",
- "columnOptionsSection": {
- "addStandardColumns": [ "LogEvent" ],
- "removeStandardColumns": [ "MessageTemplate", "Properties" ],
- "additionalColumns": [
- {
- "ColumnName": "ServiceName",
- "DataType": "varchar",
- "DataLength": 200
- },
- {
- "ColumnName": "TenantId",
- "DataType": "UniqueIdentifier"
- },
- {
- "ColumnName": "CorrelationId",
- "DataType": "UniqueIdentifier"
- }
- ]
- }
- }
- }
- ]
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft": "Information",
+ "OpenTelemetry": "Warning",
+ "System.Net": "Warning"
+ }
},
- "Messaging": {
- "Env": "DEV",
- "Source": "NBB.Todo.Worker",
- "Nats": {
- "natsUrl": "YOUR_NATS_URL",
- "cluster": "faas-cluster",
- "clientId": "NBB.Todo.Worker",
- "qGroup": "NBB.Todo.Worker",
- "durableName": "durable"
+ "WriteTo": [
+ {
+ "Name": "MSSqlServer",
+ "Args": {
+ "connectionString": "Log_Database",
+ "sinkOptionsSection": {
+ "tableName": "__Logs",
+ "schemaName": "dbo",
+ "autoCreateSqlTable": true,
+ "batchPostingLimit": 5000
+ },
+ //"restrictedToMinimumLevel": "Information",
+ "columnOptionsSection": {
+ "addStandardColumns": [ "LogEvent" ],
+ "removeStandardColumns": [ "MessageTemplate", "Properties" ],
+ "additionalColumns": [
+ {
+ "ColumnName": "ServiceName",
+ "DataType": "varchar",
+ "DataLength": 200
+ },
+ {
+ "ColumnName": "TenantId",
+ "DataType": "UniqueIdentifier"
+ },
+ {
+ "ColumnName": "CorrelationId",
+ "DataType": "UniqueIdentifier"
+ }
+ ]
+ }
}
+ }
+ ]
+ },
+ "Messaging": {
+ "Env": "DEV",
+ "Source": "NBB.Todo.Worker",
+ "Nats": {
+ "natsUrl": "YOUR_NATS_URL",
+ "cluster": "faas-cluster",
+ "clientId": "NBB.Todo.Worker",
+ "qGroup": "NBB.Todo.Worker",
+ "durableName": "durable"
+ }
+ },
+ "MultiTenancy": {
+ "TenancyType": "MultiTenant", // "MultiTenant" "MonoTenant",
+ "Defaults": {
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
+ }
},
- "MultiTenancy": {
- "TenancyType": "MultiTenant", // "MultiTenant" "MonoTenant",
- "Defaults": {
- "ConnectionStrings": {
- "DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
- }
- },
- "Tenants": {
- "tenant1": {
- "TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7"
- },
- "tenant2": {
- "TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7"
- }
- }
+ "Tenants": {
+ "tenant1": {
+ "TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7"
+ },
+ "tenant2": {
+ "TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7"
+ }
+ }
+ },
+ "OpenTelemetry": {
+ "MetricsEnabled": true,
+ "TracingEnabled": true,
+ "Jaeger": {
+ "Endpoint": "YOUR_COLLECTOR_URL",
+ "Protocol": "HttpBinaryThrift"
}
+ }
}
diff --git a/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj b/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj
index a3c09a86..1565d354 100644
--- a/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj
+++ b/samples/Orchestration/ProcessManagerSample/ProcessManagerSample.csproj
@@ -31,7 +31,6 @@
-
diff --git a/samples/Orchestration/ProcessManagerSample/Startup.cs b/samples/Orchestration/ProcessManagerSample/Startup.cs
index c4838b71..bc412a4a 100644
--- a/samples/Orchestration/ProcessManagerSample/Startup.cs
+++ b/samples/Orchestration/ProcessManagerSample/Startup.cs
@@ -43,7 +43,6 @@ public static void ConfigureServicesDelegate(HostBuilderContext context, IServic
.UsePipeline(builder => builder
.UseCorrelationMiddleware()
.UseExceptionHandlingMiddleware()
- //.UseOpenTracingMiddleware()
.UseDefaultResiliencyMiddleware()
.UseMiddleware()
.UseMediatRMiddleware())
diff --git a/src/Core/NBB.Core.Abstractions/ActivityExtensions.cs b/src/Core/NBB.Core.Abstractions/ActivityExtensions.cs
new file mode 100644
index 00000000..8402808b
--- /dev/null
+++ b/src/Core/NBB.Core.Abstractions/ActivityExtensions.cs
@@ -0,0 +1,182 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace NBB.Core.Abstractions
+{
+ public static class ActivityExtensions
+ {
+ ///
+ /// Sets the status of activity execution.
+ /// Activity class in .NET does not support 'Status'.
+ /// This extension provides a workaround to store Status as special tags with key name of otel.status_code and otel.status_description.
+ /// Read more about SetStatus here https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status.
+ ///
+ /// Activity instance.
+ /// Activity execution status.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void SetStatus(this Activity activity, Status status)
+ {
+ Debug.Assert(activity != null, "Activity should not be null");
+
+ activity.SetTag(SpanAttributeConstants.StatusCodeKey, StatusHelper.GetTagValueForStatusCode(status.StatusCode));
+ activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, status.Description);
+ }
+
+ ///
+ /// Adds an activity event containing information from the specified exception.
+ ///
+ /// Activity instance.
+ /// Exception to be recorded.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void SetException(this Activity activity, Exception ex)
+ {
+ activity?.SetException(ex, default);
+ }
+
+ ///
+ /// Adds an activity event containing information from the specified exception and additional tags.
+ ///
+ /// Activity instance.
+ /// Exception to be recorded.
+ /// Additional tags to record on the event.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void SetException(this Activity activity, Exception ex, in TagList tags)
+ {
+ if (ex == null || activity == null)
+ {
+ return;
+ }
+
+ var tagsCollection = new ActivityTagsCollection
+ {
+ { SemanticConventions.AttributeExceptionType, ex.GetType().FullName },
+ { SemanticConventions.AttributeExceptionStacktrace, ex.ToInvariantString() },
+ };
+
+ if (!string.IsNullOrWhiteSpace(ex.Message))
+ {
+ tagsCollection.Add(SemanticConventions.AttributeExceptionMessage, ex.Message);
+ }
+
+ foreach (var tag in tags)
+ {
+ tagsCollection[tag.Key] = tag.Value;
+ }
+
+ activity.AddEvent(new ActivityEvent(SemanticConventions.AttributeExceptionEventName, default, tagsCollection));
+ }
+ }
+
+
+ ///
+ /// Canonical result code of span execution.
+ ///
+ public enum StatusCode
+ {
+ ///
+ /// The default status.
+ ///
+ Unset = 0,
+
+ ///
+ /// The operation completed successfully.
+ ///
+ Ok = 1,
+
+ ///
+ /// The operation contains an error.
+ ///
+ Error = 2,
+ }
+
+ ///
+ /// Defines well-known span attribute keys.
+ ///
+ internal static class SpanAttributeConstants
+ {
+ public const string StatusCodeKey = "otel.status_code";
+ public const string StatusDescriptionKey = "otel.status_description";
+ public const string DatabaseStatementTypeKey = "db.statement_type";
+ }
+
+ ///
+ /// Span execution status.
+ ///
+ public readonly record struct Status(StatusCode StatusCode, string Description = null)
+ {
+ ///
+ /// The operation completed successfully.
+ ///
+ public static readonly Status Ok = new(StatusCode.Ok);
+
+ ///
+ /// The default status.
+ ///
+ public static readonly Status Unset = new(StatusCode.Unset);
+
+ ///
+ /// The operation contains an error.
+ ///
+ public static readonly Status Error = new(StatusCode.Error);
+ }
+ internal static class StatusHelper
+ {
+ public const string UnsetStatusCodeTagValue = "UNSET";
+ public const string OkStatusCodeTagValue = "OK";
+ public const string ErrorStatusCodeTagValue = "ERROR";
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string GetTagValueForStatusCode(StatusCode statusCode)
+ {
+ return statusCode switch
+ {
+ /*
+ * Note: Order here does matter for perf. Unset is
+ * first because assumption is most spans will be
+ * Unset, then Error. Ok is not set by the SDK.
+ */
+ StatusCode.Unset => UnsetStatusCodeTagValue,
+ StatusCode.Error => ErrorStatusCodeTagValue,
+ StatusCode.Ok => OkStatusCodeTagValue,
+ _ => null,
+ };
+ }
+ }
+
+ internal static class SemanticConventions {
+ public const string AttributeExceptionEventName = "exception";
+ public const string AttributeExceptionType = "exception.type";
+ public const string AttributeExceptionMessage = "exception.message";
+ public const string AttributeExceptionStacktrace = "exception.stacktrace";
+ }
+
+ internal static class ExceptionExtensions
+ {
+ ///
+ /// Returns a culture-independent string representation of the given object,
+ /// appropriate for diagnostics tracing.
+ ///
+ /// Exception to convert to string.
+ /// Exception as string with no culture.
+ public static string ToInvariantString(this Exception exception)
+ {
+ var originalUICulture = Thread.CurrentThread.CurrentUICulture;
+
+ try
+ {
+ Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
+ return exception.ToString();
+ }
+ finally
+ {
+ Thread.CurrentThread.CurrentUICulture = originalUICulture;
+ }
+ }
+ }
+}
diff --git a/src/Correlation/README.md b/src/Correlation/README.md
index 750f7d18..3fa95d28 100644
--- a/src/Correlation/README.md
+++ b/src/Correlation/README.md
@@ -23,7 +23,7 @@ There is a dedicated messaging header **nbb-correlationID** interpreted by:
* [`message bus publisher`](../Messaging/NBB.Messaging.Abstractions#publish) - the publisher automatically adds the current correlation ID to the envelope headers
* [`messaging host`](../Messaging/NBB.Messaging.Host#readme) - there is a built-in [`correlation middleware `](../Messaging/NBB.Messaging.Host#built-in-correlation-middleware) that reads the messaging header and sets the current correlation ID
-### Open Tracing integration
+### Open Telemetry integration
A tag named **nbb.correlation_id** is added to the messaging publisher and subscriber spans.
-For details see [`NBB.Messaging.OpenTracing`](./../Messaging/NBB.Messaging.OpenTracing#readme)
\ No newline at end of file
+For details see [`NBB.Messaging.OpenTelemetry`](./../Messaging/NBB.Messaging.OpenTelemetry#readme)
diff --git a/src/Messaging/NBB.Messaging.Abstractions/MessageBus.cs b/src/Messaging/NBB.Messaging.Abstractions/MessageBus.cs
index bb5f09c5..7babeb37 100644
--- a/src/Messaging/NBB.Messaging.Abstractions/MessageBus.cs
+++ b/src/Messaging/NBB.Messaging.Abstractions/MessageBus.cs
@@ -50,4 +50,4 @@ Task HandleMessage(MessagingEnvelope msg)
return await tcs.Task;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/MessagingTags.cs b/src/Messaging/NBB.Messaging.Abstractions/TracingTags.cs
similarity index 54%
rename from src/Messaging/NBB.Messaging.OpenTracing/MessagingTags.cs
rename to src/Messaging/NBB.Messaging.Abstractions/TracingTags.cs
index 5a38fea6..cc9d1f72 100644
--- a/src/Messaging/NBB.Messaging.OpenTracing/MessagingTags.cs
+++ b/src/Messaging/NBB.Messaging.Abstractions/TracingTags.cs
@@ -1,12 +1,19 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-namespace NBB.Messaging.OpenTracing
-{
- public static class MessagingTags
- {
- public const string ComponentMessaging = "NBB.Messaging";
- public const string CorrelationId = "nbb.correlation_id";
- public const string MessagingEnvelopeHeaderSpanTagPrefix = "messaging_header.";
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NBB.Messaging.Abstractions
+{
+ public static class TracingTags
+ {
+ public const string ComponentMessaging = "NBB.Messaging";
+ public const string CorrelationId = "nbb.correlation_id";
+ public const string TenantId = "nbb.tenant_id";
+ public const string MessagingEnvelopeHeaderSpanTagPrefix = "messaging_header.";
+ }
+}
diff --git a/src/Messaging/NBB.Messaging.Host/MessagingPipeline/CorrelationMiddleware.cs b/src/Messaging/NBB.Messaging.Host/MessagingPipeline/CorrelationMiddleware.cs
index ba21559f..f214c32b 100644
--- a/src/Messaging/NBB.Messaging.Host/MessagingPipeline/CorrelationMiddleware.cs
+++ b/src/Messaging/NBB.Messaging.Host/MessagingPipeline/CorrelationMiddleware.cs
@@ -2,11 +2,12 @@
// This source code is licensed under the MIT license.
using NBB.Core.Pipeline;
-using NBB.Correlation;
using NBB.Messaging.Abstractions;
using System;
+using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
+using CorrelationManager = NBB.Correlation.CorrelationManager;
// ReSharper disable once CheckNamespace
namespace NBB.Messaging.Host
@@ -21,6 +22,8 @@ public async Task Invoke(MessagingContext context, CancellationToken cancellatio
{
using (CorrelationManager.NewCorrelationId(context.MessagingEnvelope.GetCorrelationId()))
{
+ Activity.Current?.SetTag(TracingTags.CorrelationId, CorrelationManager.GetCorrelationId()?.ToString());
+
await next();
}
}
diff --git a/src/Messaging/NBB.Messaging.Host/MessagingPipeline/ExceptionHandlingMiddleware.cs b/src/Messaging/NBB.Messaging.Host/MessagingPipeline/ExceptionHandlingMiddleware.cs
index 2d53c922..543fa95b 100644
--- a/src/Messaging/NBB.Messaging.Host/MessagingPipeline/ExceptionHandlingMiddleware.cs
+++ b/src/Messaging/NBB.Messaging.Host/MessagingPipeline/ExceptionHandlingMiddleware.cs
@@ -48,6 +48,9 @@ public async Task Invoke(MessagingContext context, CancellationToken cancellatio
"An unhandled exception has occurred while processing message of type {MessageType}.",
context.MessagingEnvelope.Payload.GetType().GetPrettyName());
+ Activity.Current?.SetException(ex);
+ Activity.Current?.SetStatus(Status.Error);
+
_deadLetterQueue.Push(context.MessagingEnvelope, context.TopicName, ex);
}
finally
diff --git a/src/Messaging/NBB.Messaging.Host/README.md b/src/Messaging/NBB.Messaging.Host/README.md
index 0305bc0a..7710c778 100644
--- a/src/Messaging/NBB.Messaging.Host/README.md
+++ b/src/Messaging/NBB.Messaging.Host/README.md
@@ -138,7 +138,6 @@ services.AddMessagingHost(
.UsePipeline(builder => builder
.UseCorrelationMiddleware()
.UseExceptionHandlingMiddleware()
- .UseOpenTracing()
.UseDefaultResiliencyMiddleware()
.UseMiddleware());
}));
@@ -353,16 +352,6 @@ Includes the following resiliency policies for incoming messages:
```
Tipically configured last in the pipeline, it acts as a message dispatcher (broker) that delivers messages to MediatR handlers
-#### built-in OpenTracing middleware
-
-```csharp
-.UsePipeline(pipelineBuilder => pipelineBuilder.UseOpenTracing())
-```
-
-Typically configured early in the pipeline, it creates an OpenTracing span for incoming message processing and correlates it with the publisher span.
-
-To use it you must reference the *NBB.Messaging.OpenTracing* package
-
#### built-in Multi Tenant middleware
```csharp
diff --git a/src/Messaging/NBB.Messaging.MultiTenancy/MultiTenancyMessageBusPublisherDecorator.cs b/src/Messaging/NBB.Messaging.MultiTenancy/MultiTenancyMessageBusPublisherDecorator.cs
index 27d0756b..779eb651 100644
--- a/src/Messaging/NBB.Messaging.MultiTenancy/MultiTenancyMessageBusPublisherDecorator.cs
+++ b/src/Messaging/NBB.Messaging.MultiTenancy/MultiTenancyMessageBusPublisherDecorator.cs
@@ -1,6 +1,7 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@@ -42,6 +43,8 @@ public async Task PublishAsync(T message, MessagingPublisherOptions options =
void NewCustomizer(MessagingEnvelope outgoingEnvelope)
{
+ Activity.Current?.SetTag(TracingTags.TenantId, tenantId);
+
outgoingEnvelope.SetHeader(MessagingHeaders.TenantId, tenantId.ToString());
options.EnvelopeCustomizer?.Invoke(outgoingEnvelope);
}
diff --git a/src/Messaging/NBB.Messaging.MultiTenancy/TenantMiddleware.cs b/src/Messaging/NBB.Messaging.MultiTenancy/TenantMiddleware.cs
index 27c0ba03..5f4614ab 100644
--- a/src/Messaging/NBB.Messaging.MultiTenancy/TenantMiddleware.cs
+++ b/src/Messaging/NBB.Messaging.MultiTenancy/TenantMiddleware.cs
@@ -12,6 +12,7 @@
using NBB.MultiTenancy.Abstractions.Repositories;
using NBB.MultiTenancy.Identification.Services;
using NBB.MultiTenancy.Abstractions;
+using System.Diagnostics;
namespace NBB.Messaging.MultiTenancy
{
@@ -55,6 +56,8 @@ public async Task Invoke(MessagingContext context, CancellationToken cancellatio
_tenantContextAccessor.TenantContext = new TenantContext(tenant);
+ Activity.Current?.SetTag(TracingTags.TenantId, tenantId);
+
await next();
}
}
diff --git a/src/Messaging/NBB.Messaging.OpenTelemetry/MessagingActivitySource.cs b/src/Messaging/NBB.Messaging.OpenTelemetry/MessagingActivitySource.cs
new file mode 100644
index 00000000..34f87eb1
--- /dev/null
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/MessagingActivitySource.cs
@@ -0,0 +1,22 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using NBB.Messaging.OpenTelemetry.Publisher;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NBB.Messaging.OpenTelemetry
+{
+ public static class MessagingActivitySource
+ {
+ private static readonly AssemblyName assemblyName = typeof(OpenTelemetryPublisherDecorator).Assembly.GetName();
+ private static readonly ActivitySource activitySource = new(assemblyName.Name, assemblyName.Version.ToString());
+
+ public static ActivitySource Current => activitySource;
+ }
+}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/NBB.Messaging.OpenTracing.csproj b/src/Messaging/NBB.Messaging.OpenTelemetry/NBB.Messaging.OpenTelemetry.csproj
similarity index 55%
rename from src/Messaging/NBB.Messaging.OpenTracing/NBB.Messaging.OpenTracing.csproj
rename to src/Messaging/NBB.Messaging.OpenTelemetry/NBB.Messaging.OpenTelemetry.csproj
index df67de05..4a08e84e 100644
--- a/src/Messaging/NBB.Messaging.OpenTracing/NBB.Messaging.OpenTracing.csproj
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/NBB.Messaging.OpenTelemetry.csproj
@@ -1,17 +1,20 @@
-
-
-
- net7.0
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Messaging/NBB.Messaging.OpenTelemetry/Publisher/OpenTelemetryPublisherDecorator.cs b/src/Messaging/NBB.Messaging.OpenTelemetry/Publisher/OpenTelemetryPublisherDecorator.cs
new file mode 100644
index 00000000..d7093c7c
--- /dev/null
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/Publisher/OpenTelemetryPublisherDecorator.cs
@@ -0,0 +1,71 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using NBB.Messaging.Abstractions;
+using OpenTelemetry;
+using OpenTelemetry.Trace;
+using OpenTelemetry.Context.Propagation;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Reflection;
+using NBB.Core.Abstractions;
+
+namespace NBB.Messaging.OpenTelemetry.Publisher
+{
+ public class OpenTelemetryPublisherDecorator : IMessageBusPublisher
+ {
+ private readonly IMessageBusPublisher _inner;
+ private readonly ITopicRegistry _topicRegistry;
+
+ private static readonly ActivitySource activitySource = MessagingActivitySource.Current;
+ private static readonly TextMapPropagator propagator = Propagators.DefaultTextMapPropagator;
+
+ public OpenTelemetryPublisherDecorator(IMessageBusPublisher inner, ITopicRegistry topicRegistry)
+ {
+ _inner = inner;
+ _topicRegistry = topicRegistry;
+ }
+
+ public async Task PublishAsync(T message, MessagingPublisherOptions options = null,
+ CancellationToken cancellationToken = default)
+ {
+ options ??= MessagingPublisherOptions.Default;
+
+ void NewCustomizer(MessagingEnvelope outgoingEnvelope)
+ {
+
+ if (Activity.Current != null)
+ {
+ var contextToInject = Activity.Current.Context;
+ propagator.Inject(new PropagationContext(contextToInject, Baggage.Current), outgoingEnvelope.Headers, (headers, key, value) => headers[key] = value);
+ }
+
+ options.EnvelopeCustomizer?.Invoke(outgoingEnvelope);
+ }
+
+ var formattedTopicName = _topicRegistry.GetTopicForName(options.TopicName) ??
+ _topicRegistry.GetTopicForMessageType(message.GetType());
+ var operationName = $"{message.GetType().GetPrettyName()} send";
+
+ using var activity = activitySource.StartActivity(operationName, ActivityKind.Producer);
+
+ activity?.SetTag(TraceSemanticConventions.AttributeMessagingDestination, formattedTopicName);
+ activity?.SetTag(TracingTags.CorrelationId, Correlation.CorrelationManager.GetCorrelationId()?.ToString());
+
+ try
+ {
+ await _inner.PublishAsync(message, options with { EnvelopeCustomizer = NewCustomizer },
+ cancellationToken);
+
+ }
+ catch (Exception exception)
+ {
+ activity?.SetStatus(ActivityStatusCode.Error, exception.Message);
+ activity?.RecordException(exception);
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/README.md b/src/Messaging/NBB.Messaging.OpenTelemetry/README.md
similarity index 76%
rename from src/Messaging/NBB.Messaging.OpenTracing/README.md
rename to src/Messaging/NBB.Messaging.OpenTelemetry/README.md
index 2c2b1639..e098f61f 100644
--- a/src/Messaging/NBB.Messaging.OpenTracing/README.md
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/README.md
@@ -1,18 +1,18 @@
-# NBB.Messaging.OpenTracing
+# NBB.Messaging.OpenTelemetry
-This package provides open tracing support in the messaging publishers and subscribers.
+This package provides open telemetry support in the messaging publishers and subscribers.
## NuGet install
```
-dotnet add package NBB.Messaging.OpenTracing
+dotnet add package NBB.Messaging.OpenTelemetry
```
## Publisher
To enable creating a publisher span, register the following publisher decorator in DI.
```csharp
-services.Decorate();
+services.Decorate();
```
The span is tagged with **span.kind** = "producer", **component** = "NBB.Messaging", **message_bus.destination** = the topic for the published message, **nbb.correlation_id** = the current correlation ID
@@ -25,7 +25,7 @@ To enable creating a subscriber span, add the following middleware in the messag
{
pipelineBuilder
...
- .UseOpenTracing()
+ .UseOpenTelemetry()
...
});
```
diff --git a/src/Messaging/NBB.Messaging.OpenTelemetry/Subscriber/OpenTelemetrySubscriberDecorator.cs b/src/Messaging/NBB.Messaging.OpenTelemetry/Subscriber/OpenTelemetrySubscriberDecorator.cs
new file mode 100644
index 00000000..f3fafaa0
--- /dev/null
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/Subscriber/OpenTelemetrySubscriberDecorator.cs
@@ -0,0 +1,68 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using NBB.Messaging.Abstractions;
+using OpenTelemetry.Trace;
+using OpenTelemetry;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using OpenTelemetry.Context.Propagation;
+using NBB.Core.Abstractions;
+using NBB.Messaging.OpenTelemetry.Publisher;
+using System.Reflection.PortableExecutable;
+
+namespace NBB.Messaging.OpenTelemetry.Subscriber
+{
+ public class OpenTelemetrySubscriberDecorator : IMessageBusSubscriber
+ {
+ private readonly IMessageBusSubscriber _inner;
+
+ private static readonly ActivitySource activitySource = MessagingActivitySource.Current;
+ private static readonly TextMapPropagator propagator = Propagators.DefaultTextMapPropagator;
+
+ public OpenTelemetrySubscriberDecorator(IMessageBusSubscriber inner)
+ {
+ _inner = inner;
+ }
+
+ public Task SubscribeAsync(Func, Task> handler, MessagingSubscriberOptions options = null, CancellationToken cancellationToken = default)
+ {
+ async Task NewHandler(MessagingEnvelope incommingEnvelope)
+ {
+ var parentContext = propagator.Extract(default, incommingEnvelope.Headers,
+ (headers, key) => headers.TryGetValue(key, out var value) ? new[] { value } : Enumerable.Empty());
+ Baggage.Current = parentContext.Baggage;
+
+ string activityName = $"{incommingEnvelope.Payload.GetType().GetPrettyName()} receive";
+
+ using var activity = activitySource.StartActivity(activityName, ActivityKind.Consumer, parentContext.ActivityContext);
+ activity?.SetTag(TraceSemanticConventions.AttributeMessagingDestination, options.TopicName);
+ activity?.SetTag(TraceSemanticConventions.AttributePeerService, incommingEnvelope.Headers.TryGetValue(MessagingHeaders.Source, out var value)
+ ? value
+ : default);
+
+ foreach (var header in incommingEnvelope.Headers)
+ activity?.SetTag(TracingTags.MessagingEnvelopeHeaderSpanTagPrefix + header.Key.ToLower(), header.Value);
+
+ try
+ {
+ await handler?.Invoke(incommingEnvelope);
+ }
+ catch (Exception exception)
+ {
+ activity?.SetStatus(ActivityStatusCode.Error, exception.Message);
+ activity?.RecordException(exception);
+ throw;
+ }
+ }
+
+ return _inner.SubscribeAsync((Func, Task>)NewHandler, options, cancellationToken);
+ }
+ }
+}
diff --git a/src/Messaging/NBB.Messaging.OpenTelemetry/TracerProviderBuilderExtensions.cs b/src/Messaging/NBB.Messaging.OpenTelemetry/TracerProviderBuilderExtensions.cs
new file mode 100644
index 00000000..cee6af48
--- /dev/null
+++ b/src/Messaging/NBB.Messaging.OpenTelemetry/TracerProviderBuilderExtensions.cs
@@ -0,0 +1,33 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using NBB.Messaging.OpenTelemetry.Subscriber;
+using OpenTelemetry.Trace;
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using NBB.Messaging.Abstractions;
+using NBB.Messaging.OpenTelemetry.Publisher;
+
+namespace NBB.Messaging.OpenTelemetry
+{
+ public static class TracerProviderBuilderExtensions
+ {
+ public static TracerProviderBuilder AddMessageBusInstrumentation(this TracerProviderBuilder builder)
+ {
+ if (builder is null)
+ {
+ throw new ArgumentNullException(nameof(builder), "Must not be null");
+ }
+
+ builder
+ .AddSource(MessagingActivitySource.Current.Name)
+ .ConfigureServices(services =>
+ {
+ services.Decorate();
+ services.Decorate();
+ });
+
+ return builder;
+ }
+ }
+}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/Publisher/OpenTracingPublisherDecorator.cs b/src/Messaging/NBB.Messaging.OpenTracing/Publisher/OpenTracingPublisherDecorator.cs
deleted file mode 100644
index dfee8554..00000000
--- a/src/Messaging/NBB.Messaging.OpenTracing/Publisher/OpenTracingPublisherDecorator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using NBB.Core.Abstractions;
-using NBB.Correlation;
-using NBB.Messaging.Abstractions;
-using OpenTracing;
-using OpenTracing.Propagation;
-using OpenTracing.Tag;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NBB.Messaging.OpenTracing.Publisher
-{
- public class OpenTracingPublisherDecorator : IMessageBusPublisher
- {
- private readonly IMessageBusPublisher _inner;
- private readonly ITracer _tracer;
- private readonly ITopicRegistry _topicRegistry;
-
- public OpenTracingPublisherDecorator(IMessageBusPublisher inner, ITracer tracer, ITopicRegistry topicRegistry)
- {
- _inner = inner;
- _tracer = tracer;
- _topicRegistry = topicRegistry;
- }
-
- public Task PublishAsync(T message, MessagingPublisherOptions options = null,
- CancellationToken cancellationToken = default)
- {
- options ??= MessagingPublisherOptions.Default;
-
- void NewCustomizer(MessagingEnvelope outgoingEnvelope)
- {
- if (_tracer.ActiveSpan != null)
- {
- _tracer.Inject(_tracer.ActiveSpan.Context, BuiltinFormats.TextMap,
- new TextMapInjectAdapter(outgoingEnvelope.Headers));
- }
-
- options.EnvelopeCustomizer?.Invoke(outgoingEnvelope);
-
- if (_tracer.ActiveSpan != null)
- {
- foreach (var header in outgoingEnvelope.Headers)
- _tracer.ActiveSpan.SetTag(MessagingTags.MessagingEnvelopeHeaderSpanTagPrefix + header.Key.ToLower(), header.Value);
- }
- }
-
- var formattedTopicName = _topicRegistry.GetTopicForName(options.TopicName) ??
- _topicRegistry.GetTopicForMessageType(message.GetType());
- var operationName = $"Publisher {message.GetType().GetPrettyName()}";
-
- using var scope = _tracer.BuildSpan(operationName)
- .WithTag(Tags.Component, MessagingTags.ComponentMessaging)
- .WithTag(Tags.SpanKind, Tags.SpanKindProducer)
- .WithTag(Tags.MessageBusDestination, formattedTopicName)
- .WithTag(MessagingTags.CorrelationId, CorrelationManager.GetCorrelationId()?.ToString())
- .WithTag(Tags.SamplingPriority, 1)
- .StartActive(true);
- try
- {
- return _inner.PublishAsync(message, options with { EnvelopeCustomizer = NewCustomizer },
- cancellationToken);
- }
- catch (Exception exception)
- {
- scope.Span.SetException(exception);
- throw;
- }
- }
- }
-}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/SpanExtensions.cs b/src/Messaging/NBB.Messaging.OpenTracing/SpanExtensions.cs
deleted file mode 100644
index adca3ed5..00000000
--- a/src/Messaging/NBB.Messaging.OpenTracing/SpanExtensions.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using OpenTracing;
-using OpenTracing.Tag;
-
-namespace NBB.Messaging.OpenTracing
-{
- public static class SpanExtensions
- {
- public static void SetException(this ISpan span, Exception exception)
- {
- span.Log(new Dictionary(3)
- {
- {LogFields.Event, Tags.Error.Key},
- {LogFields.ErrorKind, exception.GetType().Name},
- {LogFields.ErrorObject, exception}
- });
-
- span.SetTag(Tags.Error, true);
- }
- }
-}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/MessagingPipelineExtensions.cs b/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/MessagingPipelineExtensions.cs
deleted file mode 100644
index 5298a263..00000000
--- a/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/MessagingPipelineExtensions.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using NBB.Core.Pipeline;
-using NBB.Messaging.Abstractions;
-using NBB.Messaging.OpenTracing.Subscriber;
-
-// ReSharper disable once CheckNamespace
-namespace NBB.Messaging.Host;
-
-public static class MessagingPipelineExtensions
-{
- ///
- /// Adds to the pipeline a middleware that creates an OpenTracing span.
- ///
- /// The pipeline builder.
- /// The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.
- public static IPipelineBuilder UseOpenTracingMiddleware(
- this IPipelineBuilder pipelineBuilder)
- => UseMiddleware(pipelineBuilder);
-
-
- private static IPipelineBuilder UseMiddleware(
- this IPipelineBuilder pipelineBuilder)
- where TMiddleware : IPipelineMiddleware
- => pipelineBuilder.UseMiddleware();
-}
diff --git a/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/OpenTracingMiddleware.cs b/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/OpenTracingMiddleware.cs
deleted file mode 100644
index a5971a71..00000000
--- a/src/Messaging/NBB.Messaging.OpenTracing/Subscriber/OpenTracingMiddleware.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using NBB.Core.Abstractions;
-using NBB.Core.Pipeline;
-using NBB.Correlation;
-using NBB.Messaging.Abstractions;
-using OpenTracing;
-using OpenTracing.Propagation;
-using OpenTracing.Tag;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NBB.Messaging.OpenTracing.Subscriber
-{
- public class OpenTracingMiddleware : IPipelineMiddleware
- {
- private readonly ITracer _tracer;
-
- public OpenTracingMiddleware(ITracer tracer)
- {
- _tracer = tracer;
- }
-
- public async Task Invoke(MessagingContext context, CancellationToken cancellationToken, Func next)
- {
- var extractedSpanContext = _tracer.Extract(BuiltinFormats.TextMap, new TextMapExtractAdapter(context.MessagingEnvelope.Headers));
- string operationName = $"Subscriber {context.MessagingEnvelope.Payload.GetType().GetPrettyName()}";
-
- using var scope = _tracer.BuildSpan(operationName)
- .AddReference(References.FollowsFrom, extractedSpanContext)
- .WithTag(Tags.Component, "NBB.Messaging")
- .WithTag(Tags.SpanKind, Tags.SpanKindConsumer)
- .WithTag(Tags.PeerService,
- context.MessagingEnvelope.Headers.TryGetValue(MessagingHeaders.Source, out var value)
- ? value
- : default)
- .WithTag(MessagingTags.CorrelationId, CorrelationManager.GetCorrelationId()?.ToString())
- .WithTag(Tags.SamplingPriority, 1)
- .StartActive(true);
-
- foreach (var header in context.MessagingEnvelope.Headers)
- scope.Span.SetTag(MessagingTags.MessagingEnvelopeHeaderSpanTagPrefix + header.Key.ToLower(), header.Value);
-
- try
- {
- await next();
- }
- catch (Exception exception)
- {
- scope.Span.SetException(exception);
- throw;
- }
- }
- }
-}
diff --git a/src/Messaging/README.md b/src/Messaging/README.md
index 2c3142e5..d66efcd3 100644
--- a/src/Messaging/README.md
+++ b/src/Messaging/README.md
@@ -46,4 +46,4 @@ Other packages
* *NBB.Messaging.DataContracts* - helps us formalize and instrument messaging data contracts
* *NBB.Messaging.Effects* - messaging side effects and handlers for the NBB effects infrastructure
* *NBB.Messaging.MultiTenancy* - support for messaging in multi-tenant environments
-* *NBB.Messaging.OpenTracing* - support for *OpenTracing* in messaging publishers and subscribers
+* *NBB.Messaging.OpenTelemetry* - support for *OpenTelemetry* in messaging publishers and subscribers
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingContribFilter.cs b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingContribFilter.cs
similarity index 87%
rename from src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingContribFilter.cs
rename to src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingContribFilter.cs
index 0642d340..c7962a8b 100644
--- a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingContribFilter.cs
+++ b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingContribFilter.cs
@@ -5,9 +5,9 @@
using System.Linq;
using Serilog.Events;
-namespace NBB.Tools.Serilog.OpenTracingSink.Internal
+namespace NBB.Tools.Serilog.OpenTelemetryTracingSink.Internal
{
- internal static class OpenTracingContribFilter
+ internal static class OpenTelemetryTracingContribFilter
{
private static List ExcludedLogSources = new()
{
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingSink.cs b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingSink.cs
new file mode 100644
index 00000000..c66dda5a
--- /dev/null
+++ b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/Internal/OpenTelemetryTracingSink.cs
@@ -0,0 +1,64 @@
+// Copyright (c) TotalSoft.
+// This source code is licensed under the MIT license.
+
+using OpenTelemetry.Trace;
+using Serilog.Core;
+using Serilog.Events;
+using System;
+using System.Diagnostics;
+
+namespace NBB.Tools.Serilog.OpenTelemetryTracingSink.Internal
+{
+ internal class OpenTelemetryTracingSink : ILogEventSink
+ {
+ private readonly Func _filter;
+
+ public OpenTelemetryTracingSink(Func filter = null)
+ {
+
+ _filter = filter ?? (logEvent => false);
+ }
+
+ public void Emit(LogEvent logEvent)
+ {
+ var activity = Activity.Current;
+
+ if (!(activity?.IsAllDataRequested ?? false))
+ {
+ // Creating a new activity for a log message seems brutal so we ignore messages if we can't attach it to the current span.
+ return;
+ }
+
+ if (_filter(logEvent))
+ {
+ return;
+ }
+
+ try
+ {
+ var tags = new ActivityTagsCollection
+ {
+ { "Message", logEvent.RenderMessage() },
+ { "LogLevel", logEvent.Level },
+ };
+
+ foreach (var property in logEvent.Properties)
+ {
+ tags[property.Key] = property.Value.ToString();
+ }
+
+ var activityEvent = new ActivityEvent("log", logEvent.Timestamp, tags);
+ activity.AddEvent(activityEvent);
+
+ if (logEvent.Exception != null)
+ {
+ activity.RecordException(logEvent.Exception);
+ }
+ }
+ catch (Exception logException)
+ {
+ activity.RecordException(logException);
+ }
+ }
+ }
+}
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/NBB.Tools.Serilog.OpenTracingSink.csproj b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/NBB.Tools.Serilog.OpenTelemetryTracingSink.csproj
similarity index 71%
rename from src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/NBB.Tools.Serilog.OpenTracingSink.csproj
rename to src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/NBB.Tools.Serilog.OpenTelemetryTracingSink.csproj
index 0e5376e3..d4e2fd6b 100644
--- a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/NBB.Tools.Serilog.OpenTracingSink.csproj
+++ b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/NBB.Tools.Serilog.OpenTelemetryTracingSink.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/OpenTracingConfigurationExtensions.cs b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/OpenTelemetryTracingConfigurationExtensions.cs
similarity index 53%
rename from src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/OpenTracingConfigurationExtensions.cs
rename to src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/OpenTelemetryTracingConfigurationExtensions.cs
index 4f4d4468..16f26b3d 100644
--- a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/OpenTracingConfigurationExtensions.cs
+++ b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTelemetryTracingSink/OpenTelemetryTracingConfigurationExtensions.cs
@@ -1,29 +1,29 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
-using NBB.Tools.Serilog.OpenTracingSink.Internal;
+using NBB.Tools.Serilog.OpenTelemetryTracingSink.Internal;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using System;
-namespace NBB.Tools.Serilog.OpenTracingSink
+namespace NBB.Tools.Serilog.OpenTelemetryTracingSink
{
- public static class OpenTracingConfigurationExtensions
+ public static class OpenTelemetryTracingConfigurationExtensions
{
- public static LoggerConfiguration OpenTracing(
+ public static LoggerConfiguration OpenTelemetryTracing(
this LoggerSinkConfiguration sinkConfiguration,
LogEventLevel restrictedToMinimumLevel = LogEventLevel.Warning,
LoggingLevelSwitch levelSwitch = null,
- bool exludeOpenTracingContribEvents = true
+ bool exludeOpenTelemetryContribEvents = true
)
{
if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration));
- var sink = exludeOpenTracingContribEvents ?
- new Internal.OpenTracingSink(OpenTracingContribFilter.ShouldExclude) :
- new Internal.OpenTracingSink();
+ var sink = exludeOpenTelemetryContribEvents ?
+ new Internal.OpenTelemetryTracingSink(OpenTelemetryTracingContribFilter.ShouldExclude) :
+ new Internal.OpenTelemetryTracingSink();
return sinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch);
}
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingSink.cs b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingSink.cs
deleted file mode 100644
index f5fb2708..00000000
--- a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/OpenTracingSink.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using OpenTracing;
-using OpenTracing.Util;
-using Serilog.Core;
-using Serilog.Events;
-using System;
-using System.Collections.Generic;
-
-namespace NBB.Tools.Serilog.OpenTracingSink.Internal
-{
- internal class OpenTracingSink : ILogEventSink
- {
- private readonly ITracer _tracer;
- private readonly Func _filter;
-
- public OpenTracingSink(Func filter = null)
- {
- _tracer = GlobalTracer.Instance;
- _filter = filter ?? (logEvent => false);
- }
-
- public void Emit(LogEvent logEvent)
- {
- ISpan span = _tracer.ActiveSpan;
-
- if (span == null)
- {
- // Creating a new span for a log message seems brutal so we ignore messages if we can't attach it to an active span.
- return;
- }
-
- if (_tracer.IsNoopTracer())
- {
- return;
- }
-
- if (_filter(logEvent))
- {
- return;
- }
-
- var fields = new Dictionary();
-
- try
- {
- fields[LogFields.Event] = "log";
- fields[LogFields.Message] = logEvent.RenderMessage();
- fields["level"] = logEvent.Level;
-
- if (logEvent.Exception != null)
- {
- fields[LogFields.ErrorKind] = logEvent.Exception.GetType().FullName;
- fields[LogFields.ErrorObject] = logEvent.Exception;
- }
-
- foreach (var property in logEvent.Properties)
- {
- fields[property.Key] = property.Value.ToString();
- }
- }
- catch (Exception logException)
- {
- fields["opentracing.contrib.netcore.error"] = logException.ToString();
- }
-
- span.Log(fields);
- }
- }
-}
diff --git a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/TracerExtensions.cs b/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/TracerExtensions.cs
deleted file mode 100644
index b58490e8..00000000
--- a/src/Tools/Serilog/NBB.Tools.Serilog.OpenTracingSink/Internal/TracerExtensions.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) TotalSoft.
-// This source code is licensed under the MIT license.
-
-using OpenTracing;
-using OpenTracing.Noop;
-using OpenTracing.Util;
-
-namespace NBB.Tools.Serilog.OpenTracingSink.Internal
-{
- internal static class TracerExtensions
- {
- public static bool IsNoopTracer(this ITracer tracer)
- {
- if (tracer is NoopTracer)
- return true;
-
- if (tracer is GlobalTracer && !GlobalTracer.IsRegistered())
- return true;
-
- return false;
- }
- }
-}
diff --git a/src/Tools/Serilog/README.md b/src/Tools/Serilog/README.md
index 52f1474a..e08a8d09 100644
--- a/src/Tools/Serilog/README.md
+++ b/src/Tools/Serilog/README.md
@@ -6,4 +6,4 @@ The package [`NBB.Tools.Serilog.Enrichers.ServiceIdentifier`](NBB.Tools.Serilog.
The package [`NBB.Tools.Serilog.Enrichers.TenantId`](NBB.Tools.Serilog.Enrichers.TenantId) provides an enricher for tenant id from nbb tenant context.
-The package [`NBB.Tools.Serilog.OpenTracingSink`](NBB.Tools.Serilog.OpenTracingSink) provides a sink for serilog and opentracing.
+The package [`NBB.Tools.Serilog.OpenTelemetryTracingSink`](NBB.Tools.Serilog.OpenTelemetrySink) provides a sink for serilog and OpenTelemetry.