From 4cb89eb373fbca1f157693646f95b0d2dd7972f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BIAUDET?= Date: Tue, 8 Nov 2022 12:40:06 +0100 Subject: [PATCH 1/2] Add Bot.Builder.Community.OpenTelemetry --- Bot.Builder.Community.sln | 24 +- ...Bot.Builder.Community.OpenTelemetry.csproj | 23 ++ .../BotOpenTelemetryClient.cs | 239 ++++++++++++++++++ .../BotOpenTelemetryHelper.cs | 19 ++ .../MeterProviderBuilderExtensions.cs | 31 +++ .../README.md | 54 ++++ .../TracerProviderBuilderExtensions.cs | 31 +++ ...ilder.Community.OpenTelemetry.Tests.csproj | 23 ++ .../BotOpenTelemetryClientTests.cs | 136 ++++++++++ .../Usings.cs | 1 + 10 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/Bot.Builder.Community.OpenTelemetry.csproj create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryClient.cs create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryHelper.cs create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/MeterProviderBuilderExtensions.cs create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/README.md create mode 100644 libraries/Bot.Builder.Community.OpenTelemetry/TracerProviderBuilderExtensions.cs create mode 100644 tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj create mode 100644 tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs create mode 100644 tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs diff --git a/Bot.Builder.Community.sln b/Bot.Builder.Community.sln index 0e3583bc..3d4ce185 100644 --- a/Bot.Builder.Community.sln +++ b/Bot.Builder.Community.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.31911.260 MinimumVisualStudioVersion = 10.0.40219.1 @@ -183,6 +183,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapt EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapters.Facebook.Tests", "tests\Bot.Builder.Community.Adapters.Facebook.Tests\Bot.Builder.Community.Adapters.Facebook.Tests.csproj", "{8201DC48-763A-4534-9E51-466E15DF01D8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot.Builder.Community.OpenTelemetry", "libraries\Bot.Builder.Community.OpenTelemetry\Bot.Builder.Community.OpenTelemetry.csproj", "{502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot.Builder.Community.OpenTelemetry.Tests", "tests\Bot.Builder.Community.OpenTelemetry.Tests\Bot.Builder.Community.OpenTelemetry.Tests.csproj", "{E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU @@ -805,6 +809,22 @@ Global {8201DC48-763A-4534-9E51-466E15DF01D8}.Documentation|Any CPU.Build.0 = Debug|Any CPU {8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.Build.0 = Release|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Documentation|Any CPU.Build.0 = Debug|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE}.Release|Any CPU.Build.0 = Release|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Documentation|Any CPU.Build.0 = Debug|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -893,6 +913,8 @@ Global {428AD1B4-DF58-4D21-9C19-AB4AB6001A90} = {840D4038-9AB8-4750-9FFE-365386CE47E2} {3348B9A5-E3CE-4AF8-B059-8B4D7971C25A} = {840D4038-9AB8-4750-9FFE-365386CE47E2} {8201DC48-763A-4534-9E51-466E15DF01D8} = {840D4038-9AB8-4750-9FFE-365386CE47E2} + {502BFD1C-37E2-46E5-BBA4-5A4BD2C255EE} = {57D9879A-FC9F-468C-B86F-BE45A1472F88} + {E9F0C9BA-DD15-4791-A1C2-93DAA76A6058} = {840D4038-9AB8-4750-9FFE-365386CE47E2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9FE3B75E-BA2B-45BC-BBF0-DDA8BA10C4F0} diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/Bot.Builder.Community.OpenTelemetry.csproj b/libraries/Bot.Builder.Community.OpenTelemetry/Bot.Builder.Community.OpenTelemetry.csproj new file mode 100644 index 00000000..b7fb9785 --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/Bot.Builder.Community.OpenTelemetry.csproj @@ -0,0 +1,23 @@ + + + + + netstandard2.0 + This library integrates the Microsoft Bot Builder SDK with Open Telemetry + This library provides integration between the Microsoft Bot Builder SDK and Open Telemetry. + Bot Builder Community + Bot Builder Community + https://github.com/botbuildercommunity/botbuilder-community-dotnet/blob/master/LICENSE + https://github.com/botbuildercommunity/botbuilder-community-dotnet + https://github.com/botbuildercommunity/botbuilder-community-dotnet + bot framework;bot builder;azure bot service;dialogs;adaptivedialogs;rest + 1.0.0 + 1.0.0 + 1.0.0 + + + + + + + diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryClient.cs b/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryClient.cs new file mode 100644 index 00000000..79232c28 --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryClient.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Metrics; +using Microsoft.Bot.Builder; +using OpenTelemetry.Trace; + +namespace Bot.Builder.Community.OpenTelemetry +{ + public class BotOpenTelemetryClient : IBotTelemetryClient, IBotPageViewTelemetryClient + { + private readonly Dictionary> meters = new Dictionary>(); + + public BotOpenTelemetryClient() + { + } + + /// + /// Send information about availability of an application. + /// + /// Availability test name. + /// The time when the availability was captured. + /// The time taken for the availability test to run. + /// Name of the location the availability test was run from. + /// True if the availability test ran successfully. + /// Error message on availability test run failure. + /// Named string values you can use to classify and search for this availability telemetry. + /// Additional values associated with this availability telemetry. + public void TrackAvailability(string name, DateTimeOffset timeStamp, TimeSpan duration, string runLocation, bool success, string message = null, IDictionary properties = null, IDictionary metrics = null) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("Availability", ActivityKind.Internal, null, null, null, timeStamp)) + { + activity.DisplayName = name; + + activity.SetEndTime(timeStamp.Add(duration).DateTime); + + activity.AddTag("availability.runLocation", runLocation); + activity.AddTag("availability.success", success); + activity.AddTag("availability.message", message); + + if (properties != null) + { + foreach (var property in properties) + { + activity.SetTag(property.Key, property.Value); + } + } + + if (metrics != null) + { + foreach (var metric in metrics) + { + var meter = BotOpenTelemetryHelper.Meter.CreateHistogram(metric.Key); + meter.Record(metric.Value); + } + } + } + } + + /// + /// Send information about an external dependency (outgoing call) in the application. + /// + /// Name of the command initiated with this dependency call. Low cardinality value. + /// Examples are SQL, Azure table, and HTTP. + /// External dependency target. + /// Name of the command initiated with this dependency call. Low cardinality value. + /// Examples are stored procedure name and URL path template. + /// Command initiated by this dependency call. Examples are SQL statement and HTTP + /// URL's with all query parameters. + /// The time when the dependency was called. + /// The time taken by the external dependency to handle the call. + /// Result code of dependency call execution. + /// True if the dependency call was handled successfully. + public void TrackDependency(string dependencyTypeName, string target, string dependencyName, string data, DateTimeOffset startTime, TimeSpan duration, string resultCode, bool success) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("Dependency", ActivityKind.Internal, null, null, null, startTime)) + { + activity.DisplayName = dependencyTypeName; + + activity.SetEndTime(startTime.Add(duration).DateTime); + + activity.AddTag("dependency.target", target); + activity.AddTag("dependency.dependencyName", dependencyName); + activity.AddTag("dependency.resultCode", resultCode); + activity.AddTag("dependency.success", success); + } + } + + /// + /// Logs custom events with extensible named fields. + /// + /// A name for the event. + /// Named string values you can use to search and classify events. + /// Measurements associated with this event. + public void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("Event")) + { + activity.DisplayName = eventName; + + if (properties != null) + { + foreach (var property in properties) + { + activity.SetTag(property.Key, property.Value); + } + } + + if (metrics != null) + { + foreach (var metric in metrics) + { + if (!meters.TryGetValue(metric.Key, out Histogram meter)) + { + meter = BotOpenTelemetryHelper.Meter.CreateHistogram(metric.Key); + meters.Add(metric.Key, meter); + } + + meter.Record(metric.Value); + activity.SetTag($"metrics.{metric.Key}", metric.Value); + } + } + + activity.AddEvent(new ActivityEvent(eventName, DateTimeOffset.Now)); + } + } + + /// + /// Logs a system exception. + /// + /// The exception to log. + /// Named string values you can use to classify and search for this exception. + /// Additional values associated with this exception. + public void TrackException(Exception exception, IDictionary properties = null, IDictionary metrics = null) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("Exception")) + { + activity.DisplayName = exception.Message; + + if (properties != null) + { + foreach (var property in properties) + { + activity.SetTag(property.Key, property.Value); + } + } + + if (metrics != null) + { + foreach (var metric in metrics) + { + if (!meters.TryGetValue(metric.Key, out Histogram meter)) + { + meter = BotOpenTelemetryHelper.Meter.CreateHistogram(metric.Key); + meters.Add(metric.Key, meter); + } + + meter.Record(metric.Value); + activity.SetTag($"metrics.{metric.Key}", metric.Value); + } + } + + activity?.SetStatus(ActivityStatusCode.Error, exception.Message); + activity?.RecordException(exception); + } + } + + /// + /// Logs a dialog entry / as an Application Insights page view. + /// + /// The name of the dialog to log the entry / start for. + /// Named string values you can use to search and classify events. + /// Measurements associated with this event. + public void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("PageView")) + { + activity.DisplayName = dialogName; + + if (properties != null) + { + foreach (var property in properties) + { + activity.SetTag(property.Key, property.Value); + } + } + + if (metrics != null) + { + foreach (var metric in metrics) + { + if (!meters.TryGetValue(metric.Key, out Histogram meter)) + { + meter = BotOpenTelemetryHelper.Meter.CreateHistogram(metric.Key); + meters.Add(metric.Key, meter); + } + + meter.Record(metric.Value); + activity.SetTag($"metrics.{metric.Key}", metric.Value); + } + } + } + } + + /// + /// Send a trace message. + /// + /// Message to display. + /// Trace severity level . + /// Named string values you can use to search and classify events. + public void TrackTrace(string message, Severity severityLevel, IDictionary properties) + { + using (var activity = BotOpenTelemetryHelper.ActivitySource.StartActivity("Trace")) + { + activity.DisplayName = message; + activity.AddTag("trace.message", message); + activity.AddTag("trace.severityLevel", severityLevel.ToString()); + + var eventTags = new ActivityTagsCollection(); + + if (properties != null) + { + foreach (var property in properties) + { + eventTags.Add(property.Key, property.Value); + } + } + } + } + + /// + /// Flushes the in-memory buffer and any metrics being pre-aggregated. + /// + public void Flush() + { + } + } + +} \ No newline at end of file diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryHelper.cs b/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryHelper.cs new file mode 100644 index 00000000..fbe6bc5a --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/BotOpenTelemetryHelper.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Diagnostics.Metrics; + +namespace Bot.Builder.Community.OpenTelemetry +{ + + internal class BotOpenTelemetryHelper + { + public static readonly AssemblyName AssemblyName = typeof(BotOpenTelemetryHelper).Assembly.GetName(); + public static readonly string InstrumentationName = AssemblyName.Name; + public static readonly string ActivityName = InstrumentationName + ".Execute"; + private static readonly Version Version = typeof(BotOpenTelemetryHelper).Assembly.GetName().Version; + internal static readonly ActivitySource ActivitySource = new ActivitySource(InstrumentationName, Version.ToString()); + internal static readonly Meter Meter = new Meter(InstrumentationName, Version.ToString()); + } +} \ No newline at end of file diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/MeterProviderBuilderExtensions.cs b/libraries/Bot.Builder.Community.OpenTelemetry/MeterProviderBuilderExtensions.cs new file mode 100644 index 00000000..a7e72192 --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/MeterProviderBuilderExtensions.cs @@ -0,0 +1,31 @@ +using System; +using Bot.Builder.Community.OpenTelemetry; +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Metrics; + +namespace OpenTelemetry.Trace +{ + /// + /// Extension methods to simplify registering of dependency instrumentation. + /// + public static class MeterProviderBuilderExtensions + { + /// + /// Enables Bot Builder instrumentation. + /// + /// being configured. + /// Bot Builder configuration options. + /// The instance of to chain the calls. + public static MeterProviderBuilder AddBotBuilderInstrumentation( + this MeterProviderBuilder builder) + { + + builder.ConfigureServices(services => services.AddSingleton()); + + builder.AddMeter(BotOpenTelemetryHelper.InstrumentationName); + + return builder; + } + } +} \ No newline at end of file diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/README.md b/libraries/Bot.Builder.Community.OpenTelemetry/README.md new file mode 100644 index 00000000..4d88cfa3 --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/README.md @@ -0,0 +1,54 @@ +# Bot Builder Instrumentation for OpenTelemetry + +## Description + +This is part of the [Bot Builder Community](https://github.com/botbuildercommunity) project which contains Bot Framework Components and other projects / packages for use with Bot Framework Composer and the Bot Builder .NET SDK v4. + +This is an [Instrumentation Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), which instruments Bot Builder and collects telemetry. +OpenTelemetry is a collection of tools, APIs, and SDKs. Use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) to help you analyze your software’s performance and behavior. You can get more info at https://opentelemetry.io + +## Usage + +- [Installation](#Installation) +- [Enable Bot Builder Instrumentation at application startup](#Enable-Bot-Builder-Instrumentation-at-application-startup) + +## Installation + +You need to install the `Bot.Builder.Community.OpenTelemetry` to be able to use the OpenTelemetry Bot Instrumentation. + +Available via NuGet package [Bot.Builder.Community.OpenTelemetry](https://www.nuget.org/packages/Bot.Builder.Community.OpenTelemetry/) + +```shell +dotnet add Bot.Builder.Community.OpenTelemetry +``` + +## Enable Bot Builder Instrumentation at application startup + +Bot Builder instrumentation must be enabled at application startup. + +The following example demonstrates adding Bot Builder instrumentation to a +console application. This example also sets up the OpenTelemetry Console +exporter, which requires adding the package +[`OpenTelemetry.Exporter.Console`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Console/README.md) +to the application. + +```csharp +using OpenTelemetry.Trace; +public class Program +{ + public static void Main(string[] args) + { + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddBotBuilderInstrumentation() + .AddConsoleExporter() + .Build(); + } +} +``` + +For an ASP.NET Core application, adding instrumentation is typically done in +the `ConfigureServices` of your `Startup` class. Refer to [example](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/examples/AspNetCore/Program.cs). + +For an ASP.NET application, adding instrumentation is typically done in the +`Global.asax.cs`. Refer to [example](../../examples/AspNet/Global.asax.cs). +In order to sucessfully configure Zoom to send requests to your bot, you are required to provide it with you bot's Zoom endpoint. To do this deploy your bot to Azure and make a note of the URL to your deployed bot. Your Zoom messaging endpoint is the URL for your bot, which will be the URL of your deployed application (or ngrok endpoint), plus '/api/zoom' (for example, `https://yourbotapp.azurewebsites.net/api/zoom`). diff --git a/libraries/Bot.Builder.Community.OpenTelemetry/TracerProviderBuilderExtensions.cs b/libraries/Bot.Builder.Community.OpenTelemetry/TracerProviderBuilderExtensions.cs new file mode 100644 index 00000000..2e18e5f2 --- /dev/null +++ b/libraries/Bot.Builder.Community.OpenTelemetry/TracerProviderBuilderExtensions.cs @@ -0,0 +1,31 @@ +using System; +using Bot.Builder.Community.OpenTelemetry; +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Trace +{ + /// + /// Extension methods to simplify registering of dependency instrumentation. + /// + public static class TracerProviderBuilderExtensions + { + /// + /// Enables Bot Builder instrumentation. + /// + /// being configured. + /// Bot Builder configuration options. + /// The instance of to chain the calls. + public static TracerProviderBuilder AddBotBuilderInstrumentation( + this TracerProviderBuilder builder) + { + // Guard.ThrowIfNull(builder); + + builder.ConfigureServices(services => services.AddSingleton()); + + builder.AddSource(BotOpenTelemetryHelper.InstrumentationName); + + return builder; + } + } +} \ No newline at end of file diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj new file mode 100644 index 00000000..94b2c578 --- /dev/null +++ b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs b/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs new file mode 100644 index 00000000..6469bcac --- /dev/null +++ b/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs @@ -0,0 +1,136 @@ +using System.Diagnostics; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Dialogs; +using Microsoft.Bot.Builder.Adapters; +using Microsoft.Bot.Schema; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using System; +using System.Diagnostics.Metrics; + +namespace Bot.Builder.Community.OpenTelemetry.Tests +{ + [TestClass] + public class BotOpenTelemetryClientTests + { + [TestMethod] + public void ShouldTrackEvent() + { + var activities = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddInMemoryExporter(activities) + .AddBotBuilderInstrumentation() + .Build(); + + var telemetryClient = new BotOpenTelemetryClient(); + + telemetryClient.TrackEvent("Event1"); + + tracerProvider?.ForceFlush(); + + Assert.AreEqual(1, activities.Count); + } + + [TestMethod] + public void ShouldTrackEventWithMetrics() + { + var activities = new List(); + var metrics = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddInMemoryExporter(activities) + .AddBotBuilderInstrumentation() + .Build(); + + var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddInMemoryExporter(metrics) + .AddBotBuilderInstrumentation() + .Build(); + + var telemetryClient = new BotOpenTelemetryClient(); + + var eventMetrics = new Dictionary() { + {"event.duration", 100} + }; + + telemetryClient.TrackEvent("Event1", metrics: eventMetrics); + + tracerProvider?.ForceFlush(); + meterProvider.ForceFlush(); + + Assert.AreEqual(1, activities.Count); + Assert.AreEqual(1, metrics.Count); + } + + [TestMethod] + public async Task ShouldTrackDialogEventAsync() + { + var activities = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddInMemoryExporter(activities) + .AddBotBuilderInstrumentation() + .Build(); + + var conversationState = new ConversationState(new MemoryStorage()); + var dialogState = conversationState.CreateProperty("dialogState"); + + var adapter = new TestAdapter() + .Use(new AutoSaveStateMiddleware(conversationState)); + + // Create new DialogSet. + var dialogs = new DialogSet(dialogState); + + dialogs.Add(new WaterfallDialog("test", NewWaterfall())); + dialogs.TelemetryClient = new BotOpenTelemetryClient(); + + await new TestFlow(adapter, async (turnContext, cancellationToken) => + { + var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken); + await dc.ContinueDialogAsync(cancellationToken); + if (!turnContext.Responded) + { + await dc.BeginDialogAsync("test", null, cancellationToken); + } + }) + .Send("hello") + .AssertReply("step1") + .Send("hello") + .AssertReply("step2") + .Send("hello") + .AssertReply("step3") + .StartTestAsync(); + + tracerProvider?.ForceFlush(); + + Assert.AreEqual(5, activities.Count); + } + + private static WaterfallStep[] NewWaterfall() + { + return new WaterfallStep[] + { + async (step, cancellationToken) => + { + await step.Context.SendActivityAsync("step1"); + return Dialog.EndOfTurn; + }, + async (step, cancellationToken) => + { + await step.Context.SendActivityAsync("step2"); + return Dialog.EndOfTurn; + }, + async (step, cancellationToken) => + { + await step.Context.SendActivityAsync("step3"); + return Dialog.EndOfTurn; + }, + }; + } + } + + +} \ No newline at end of file diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs new file mode 100644 index 00000000..ab67c7ea --- /dev/null +++ b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file From 6583d97525961e7fd62e330472a3be8c15b40336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BIAUDET?= Date: Tue, 8 Nov 2022 12:50:41 +0100 Subject: [PATCH 2/2] Back test to netcoreapp3.1 --- .../Bot.Builder.Community.OpenTelemetry.Tests.csproj | 5 ++--- .../BotOpenTelemetryClientTests.cs | 3 +++ tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs | 1 - 3 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj index 94b2c578..eb1619f6 100644 --- a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj +++ b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Bot.Builder.Community.OpenTelemetry.Tests.csproj @@ -1,9 +1,8 @@ + - net6.0 - enable - enable + netcoreapp3.1 false diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs b/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs index 6469bcac..8aa175ed 100644 --- a/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs +++ b/tests/Bot.Builder.Community.OpenTelemetry.Tests/BotOpenTelemetryClientTests.cs @@ -9,6 +9,9 @@ using OpenTelemetry.Trace; using System; using System.Diagnostics.Metrics; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.Threading.Tasks; namespace Bot.Builder.Community.OpenTelemetry.Tests { diff --git a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs b/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs deleted file mode 100644 index ab67c7ea..00000000 --- a/tests/Bot.Builder.Community.OpenTelemetry.Tests/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file