From c8c7e30501fc2286bb1a22d6eeba9a8ed24e7a94 Mon Sep 17 00:00:00 2001 From: Will Rogers Date: Wed, 21 Jun 2023 23:24:33 -0400 Subject: [PATCH] Add XO.Console.Cli.Instrumentation with support for OpenTelemetry (#6) Provide middleware that wraps command execution in an Activity --- .../CommandAppInstrumentationMiddleware.cs | 74 +++++++ .../CommandAppInstrumentationOptions.cs | 23 ++ .../TracerProviderBuilderExtensions.cs | 35 +++ .../XO.Console.Cli.Instrumentation.csproj | 19 ++ .../packages.lock.json | 199 ++++++++++++++++++ XO.Console.Cli.Instrumentation/version.json | 9 + .../CommandAppInstrumentationTest.cs | 76 +++++++ .../XO.Console.Cli.Tests.csproj | 2 + XO.Console.Cli.Tests/packages.lock.json | 54 ++++- XO.Console.Cli.sln | 6 + 10 files changed, 495 insertions(+), 2 deletions(-) create mode 100644 XO.Console.Cli.Instrumentation/CommandAppInstrumentationMiddleware.cs create mode 100644 XO.Console.Cli.Instrumentation/CommandAppInstrumentationOptions.cs create mode 100644 XO.Console.Cli.Instrumentation/TracerProviderBuilderExtensions.cs create mode 100644 XO.Console.Cli.Instrumentation/XO.Console.Cli.Instrumentation.csproj create mode 100644 XO.Console.Cli.Instrumentation/packages.lock.json create mode 100644 XO.Console.Cli.Instrumentation/version.json create mode 100644 XO.Console.Cli.Tests/CommandAppInstrumentationTest.cs diff --git a/XO.Console.Cli.Instrumentation/CommandAppInstrumentationMiddleware.cs b/XO.Console.Cli.Instrumentation/CommandAppInstrumentationMiddleware.cs new file mode 100644 index 0000000..1ccbf78 --- /dev/null +++ b/XO.Console.Cli.Instrumentation/CommandAppInstrumentationMiddleware.cs @@ -0,0 +1,74 @@ +using System.Diagnostics; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using OpenTelemetry.Trace; + +namespace XO.Console.Cli.Instrumentation; + +/// +/// An middleware that wraps command execution in an . +/// +public sealed class CommandAppInstrumentationMiddleware : ICommandAppMiddleware +{ + /// + /// The name of the for activities started by this middleware. + /// + public const string ActivitySourceName = ThisAssembly.AssemblyName; + + private static readonly ActivitySource Source + = new(ActivitySourceName, version: ThisAssembly.AssemblyInformationalVersion); + + private readonly string _defaultName; + private readonly CommandAppInstrumentationOptions _options; + + /// + /// Initializes a new instance of . + /// + /// The hosting environment. + /// The configuration options. + public CommandAppInstrumentationMiddleware(IHostEnvironment env, IOptions optionsAccessor) + { + _defaultName = env.ApplicationName; + _options = optionsAccessor.Value; + } + + /// + public async Task ExecuteAsync(ExecutorDelegate next, CommandContext context, CancellationToken cancellationToken) + { + int? result = null; + var name = String.Join(' ', from token in context.ParseResult.GetVerbs() select token.Value); + if (String.IsNullOrEmpty(name)) + name = _defaultName; + + var activity = Source.StartActivity(name, _options.ActivityKind); + try + { + if (activity?.IsAllDataRequested == true) + { + activity.AddTag(TraceSemanticConventions.AttributeCodeFunction, nameof(AsyncCommand.ExecuteAsync)); + activity.AddTag(TraceSemanticConventions.AttributeCodeNamespace, context.Command.GetType().FullName); + _options.EnrichWithCommandContext?.Invoke(activity, context); + } + + result = await next(context, cancellationToken) + .ConfigureAwait(false); + + activity?.AddTag("command.exit_code", result); + } + catch (Exception ex) + { + if (activity?.IsAllDataRequested == true) + { + activity.RecordException(ex); + activity.SetStatus(Status.Error.WithDescription(ex.Message)); + } + throw; + } + finally + { + activity?.Dispose(); + } + + return result.Value; + } +} diff --git a/XO.Console.Cli.Instrumentation/CommandAppInstrumentationOptions.cs b/XO.Console.Cli.Instrumentation/CommandAppInstrumentationOptions.cs new file mode 100644 index 0000000..75ac6c0 --- /dev/null +++ b/XO.Console.Cli.Instrumentation/CommandAppInstrumentationOptions.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; + +namespace XO.Console.Cli.Instrumentation; + +/// +/// Configures OpenTelemetry instrumentation for . +/// +public sealed class CommandAppInstrumentationOptions +{ + /// + /// The to assign to command execution activities. + /// + /// + /// Defaults to . Before changing the activity kind, check whether your + /// environment assigns special meaning to certain kinds. + /// + public ActivityKind ActivityKind { get; set; } = ActivityKind.Producer; + + /// + /// A delegate that enriches the with information from the execution context. + /// + public Action? EnrichWithCommandContext { get; set; } +} diff --git a/XO.Console.Cli.Instrumentation/TracerProviderBuilderExtensions.cs b/XO.Console.Cli.Instrumentation/TracerProviderBuilderExtensions.cs new file mode 100644 index 0000000..b92fc4f --- /dev/null +++ b/XO.Console.Cli.Instrumentation/TracerProviderBuilderExtensions.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.DependencyInjection; +using XO.Console.Cli; +using XO.Console.Cli.Instrumentation; + +namespace OpenTelemetry.Trace; + +/// +/// XO.Console.Cli extension methods for . +/// +public static class TracerProviderBuilderExtensions +{ + /// + /// Enables instrumentation. + /// + /// The to configure. + /// A delegate that configures the . + /// The same instance. + public static TracerProviderBuilder AddCommandAppInstrumentation( + this TracerProviderBuilder builder, + Action? configure = default) + { + return builder + .AddSource(CommandAppInstrumentationMiddleware.ActivitySourceName) + .ConfigureServices(services => + { + var optionsBuilder = services.AddOptions(); + + if (configure != null) + optionsBuilder.Configure(configure); + + services.AddCommandAppMiddleware(); + }) + ; + } +} diff --git a/XO.Console.Cli.Instrumentation/XO.Console.Cli.Instrumentation.csproj b/XO.Console.Cli.Instrumentation/XO.Console.Cli.Instrumentation.csproj new file mode 100644 index 0000000..0a0fa36 --- /dev/null +++ b/XO.Console.Cli.Instrumentation/XO.Console.Cli.Instrumentation.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + OpenTelemetry instrumentation for XO.Console.Cli + true + + + + + + + + + + + + + diff --git a/XO.Console.Cli.Instrumentation/packages.lock.json b/XO.Console.Cli.Instrumentation/packages.lock.json new file mode 100644 index 0000000..7b9198d --- /dev/null +++ b/XO.Console.Cli.Instrumentation/packages.lock.json @@ -0,0 +1,199 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Nerdbank.GitVersioning": { + "type": "Direct", + "requested": "[3.6.133, )", + "resolved": "3.6.133", + "contentHash": "VZWMd5YAeDxpjWjAP/X6bAxnRMiEf6tES/ITN0X5CHJgkWLLeHGmEALivmTAfYM6P+P/3Szy6VCITUAkqjcHVw==" + }, + "OpenTelemetry": { + "type": "Direct", + "requested": "[1.5.0, )", + "resolved": "1.5.0", + "contentHash": "Fx44sVmnPkp/JJQSmUC1iHHWjWQ/lBh6wUIUK6SFeTYRdizn2/K/SaQNNy1dlf0ztpWTB6kfFD+xcjBYgdWPgg==", + "dependencies": { + "Microsoft.Extensions.Logging.Configuration": "3.1.0", + "OpenTelemetry.Api.ProviderBuilderExtensions": "1.5.0" + } + }, + "OpenTelemetry.SemanticConventions": { + "type": "Direct", + "requested": "[1.0.0-rc9.9, )", + "resolved": "1.0.0-rc9.9", + "contentHash": "Ag1czlfURv4vthJtbHLWUMO7raVX8/IKlcZRd4RFE8CsBRniXT+wtRvh0RRULYyoTbchOey41U8NkPTIZJl7zg==" + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "Lu41BWNmwhKr6LgyQvcYBOge0pPvmiaK8R5UHXX4//wBhonJyWcT2OK1mqYfEM5G7pTf31fPrpIHOT6sN7EGOA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "3.1.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "o9eELDBfNkR7sUtYysFZ1Q7BQ1mYt27DMkups/3vu7xgPyOpMD+iAfrBZFzUXT2iw0fmFb8s1gfNBZS+IgjKdQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "3.1.0" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "KVkv3aF2MQpmGFRh4xRx2CNbc2sjDFk+lH4ySrjWSOS+XoY1Xc+sJphw3N0iYOpoeCCq8976ceVYDH8sdx2qIQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + }, + "Microsoft.Extensions.FileProviders.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Hosting.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" + } + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "P+8sKQ8L4ooL79sxxqwFPxGGC3aBrUDLB/dZqhs4J0XjTyrkeeyJQ4D4nzJB6OnAhy78HIIgQ/RbD6upOXLynw==", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "3.1.0", + "Microsoft.Extensions.DependencyInjection": "3.1.0", + "Microsoft.Extensions.Logging.Abstractions": "3.1.0", + "Microsoft.Extensions.Options": "3.1.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" + }, + "Microsoft.Extensions.Logging.Configuration": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "yW3nIoNM3T5iZg8bRViiCN4+vIU/02l+mlWSvKqWnr0Fd5Uk1zKdT9jBWKEcJhRIWKVWWSpFWXnM5yWoIAy1Eg==", + "dependencies": { + "Microsoft.Extensions.Logging": "3.1.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "3.1.0" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "tx6gMKE3rDspA1YZT8SlQJmyt1BaBSl6mNjB3g0ZO6m3NnoavCifXkGeBuDk9Ae4XjW8C+dty52p+0u38jPRIQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "3.1.0", + "Microsoft.Extensions.Configuration.Binder": "3.1.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.0", + "Microsoft.Extensions.Options": "3.1.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" + }, + "OpenTelemetry.Api": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "aAugEK9E+ono8I2Crjel78mrpEreJtcK1uzCYVooYELnSEPYytrzJYvw5SBxNizXT/qOBbz+EsfO+rkQfW7Mkg==", + "dependencies": { + "System.Diagnostics.DiagnosticSource": "7.0.0" + } + }, + "OpenTelemetry.Api.ProviderBuilderExtensions": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "Wv28j71V1mizHjBfNx/ILhgqkXpbBZbCcZRoQMvqkF+Pp1bHHJpxOuipDXLqpO7KKHTwrTVl0/TAUHzoXXRK0g==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.0", + "OpenTelemetry.Api": "1.5.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "xo.console.cli": { + "type": "Project" + }, + "xo.console.cli.extensions": { + "type": "Project", + "dependencies": { + "Microsoft.Extensions.Hosting.Abstractions": "[6.0.0, )", + "Microsoft.Extensions.Logging.Abstractions": "[6.0.0, )", + "Microsoft.Extensions.Options": "[6.0.0, )", + "XO.Console.Cli": "[1.0.0, )" + } + } + } + } +} \ No newline at end of file diff --git a/XO.Console.Cli.Instrumentation/version.json b/XO.Console.Cli.Instrumentation/version.json new file mode 100644 index 0000000..d919d0b --- /dev/null +++ b/XO.Console.Cli.Instrumentation/version.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "inherit": true, + "pathFilters": [ + "../Directory.Build.props", + "../global.json", + "." + ] +} diff --git a/XO.Console.Cli.Tests/CommandAppInstrumentationTest.cs b/XO.Console.Cli.Tests/CommandAppInstrumentationTest.cs new file mode 100644 index 0000000..4aeb02d --- /dev/null +++ b/XO.Console.Cli.Tests/CommandAppInstrumentationTest.cs @@ -0,0 +1,76 @@ +using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Trace; +using Xunit; + +namespace XO.Console.Cli.Tests; + +public class CommandAppInstrumentationTest +{ + private static IHostBuilder CreateHostBuilder() + => new HostBuilder() + .ConfigureServices(services => + { + services.AddOpenTelemetry() + .WithTracing(builder => + { + builder.AddCommandAppInstrumentation(options => + { + options.EnrichWithCommandContext = static (activity, context) => + { + activity.SetTag("foo", "bar"); + }; + }); + }); + }) + .UseDefaultServiceProvider(configure => + { + configure.ValidateOnBuild = true; + configure.ValidateScopes = true; + }); + + [Fact] + public async Task CanExecuteWithInstrumentation() + { + Activity? activity = null; + + var result = await CreateHostBuilder() + .RunCommandAppAsync( + Array.Empty(), + (context, _, _) => + { + activity = Activity.Current; + return Task.FromResult(1); + }, + (context, builder) => + { + }); + + Assert.Multiple( + () => Assert.Equal(1, result), + () => Assert.Equal(1, activity?.GetTagItem("command.exit_code")), + () => Assert.Equal("bar", activity?.GetTagItem("foo"))); + } + + [Fact] + public async Task RecordsException() + { + Activity? activity = null; + + var ex = await Assert.ThrowsAsync( + () => CreateHostBuilder() + .RunCommandAppAsync( + Array.Empty(), + (context, _, _) => + { + activity = Activity.Current; + throw new InvalidOperationException("boo"); + }, + (context, builder) => + { + })); + + Assert.Equal(Status.Error.WithDescription(ex.Message), activity.GetStatus()); + } +} diff --git a/XO.Console.Cli.Tests/XO.Console.Cli.Tests.csproj b/XO.Console.Cli.Tests/XO.Console.Cli.Tests.csproj index e2dc123..795db24 100644 --- a/XO.Console.Cli.Tests/XO.Console.Cli.Tests.csproj +++ b/XO.Console.Cli.Tests/XO.Console.Cli.Tests.csproj @@ -12,6 +12,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -30,6 +31,7 @@ + diff --git a/XO.Console.Cli.Tests/packages.lock.json b/XO.Console.Cli.Tests/packages.lock.json index 6d650fd..fe28dcb 100644 --- a/XO.Console.Cli.Tests/packages.lock.json +++ b/XO.Console.Cli.Tests/packages.lock.json @@ -81,6 +81,16 @@ "Microsoft.NETCore.Platforms": "1.1.0" } }, + "OpenTelemetry.Extensions.Hosting": { + "type": "Direct", + "requested": "[1.5.0, )", + "resolved": "1.5.0", + "contentHash": "jFnYfeOcTdag7/OEAZq39JwmVs4073i8FTM344uFILGMzljIsR28hPkCAE//4SLyptib5deC5QPm0hYDlLw35A==", + "dependencies": { + "Microsoft.Extensions.Hosting.Abstractions": "2.1.0", + "OpenTelemetry": "1.5.0" + } + }, "xunit": { "type": "Direct", "requested": "[2.4.2, )", @@ -381,10 +391,41 @@ "resolved": "6.5.0", "contentHash": "QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg==" }, + "OpenTelemetry": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "Fx44sVmnPkp/JJQSmUC1iHHWjWQ/lBh6wUIUK6SFeTYRdizn2/K/SaQNNy1dlf0ztpWTB6kfFD+xcjBYgdWPgg==", + "dependencies": { + "Microsoft.Extensions.Logging.Configuration": "3.1.0", + "OpenTelemetry.Api.ProviderBuilderExtensions": "1.5.0" + } + }, + "OpenTelemetry.Api": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "aAugEK9E+ono8I2Crjel78mrpEreJtcK1uzCYVooYELnSEPYytrzJYvw5SBxNizXT/qOBbz+EsfO+rkQfW7Mkg==", + "dependencies": { + "System.Diagnostics.DiagnosticSource": "7.0.0" + } + }, + "OpenTelemetry.Api.ProviderBuilderExtensions": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "Wv28j71V1mizHjBfNx/ILhgqkXpbBZbCcZRoQMvqkF+Pp1bHHJpxOuipDXLqpO7KKHTwrTVl0/TAUHzoXXRK0g==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.0", + "OpenTelemetry.Api": "1.5.0" + } + }, + "OpenTelemetry.SemanticConventions": { + "type": "Transitive", + "resolved": "1.0.0-rc9.9", + "contentHash": "Ag1czlfURv4vthJtbHLWUMO7raVX8/IKlcZRd4RFE8CsBRniXT+wtRvh0RRULYyoTbchOey41U8NkPTIZJl7zg==" + }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", + "resolved": "7.0.0", + "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0" } @@ -477,6 +518,15 @@ "Microsoft.Extensions.Options": "[6.0.0, )", "XO.Console.Cli": "[1.0.0, )" } + }, + "xo.console.cli.instrumentation": { + "type": "Project", + "dependencies": { + "OpenTelemetry": "[1.5.0, )", + "OpenTelemetry.SemanticConventions": "[1.0.0-rc9.9, )", + "XO.Console.Cli": "[1.0.0, )", + "XO.Console.Cli.Extensions": "[1.0.0, )" + } } } } diff --git a/XO.Console.Cli.sln b/XO.Console.Cli.sln index f47f42f..960e984 100644 --- a/XO.Console.Cli.sln +++ b/XO.Console.Cli.sln @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XO.Console.Cli.Extensions", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XO.Console.Cli.Tests", "XO.Console.Cli.Tests\XO.Console.Cli.Tests.csproj", "{BCAB05F1-84CE-44F2-BEDD-A6987159C61C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XO.Console.Cli.Instrumentation", "XO.Console.Cli.Instrumentation\XO.Console.Cli.Instrumentation.csproj", "{CF67E0CC-3E68-4AF3-ABAA-A6B5E3809C63}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,10 @@ Global {BCAB05F1-84CE-44F2-BEDD-A6987159C61C}.Debug|Any CPU.Build.0 = Debug|Any CPU {BCAB05F1-84CE-44F2-BEDD-A6987159C61C}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCAB05F1-84CE-44F2-BEDD-A6987159C61C}.Release|Any CPU.Build.0 = Release|Any CPU + {CF67E0CC-3E68-4AF3-ABAA-A6B5E3809C63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF67E0CC-3E68-4AF3-ABAA-A6B5E3809C63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF67E0CC-3E68-4AF3-ABAA-A6B5E3809C63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF67E0CC-3E68-4AF3-ABAA-A6B5E3809C63}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE