diff --git a/libraries/Microsoft.Bot.Builder.ApplicationInsights/BotTelemetryClient.cs b/libraries/Microsoft.Bot.Builder.ApplicationInsights/BotTelemetryClient.cs index db46399b19..25c4cd624e 100644 --- a/libraries/Microsoft.Bot.Builder.ApplicationInsights/BotTelemetryClient.cs +++ b/libraries/Microsoft.Bot.Builder.ApplicationInsights/BotTelemetryClient.cs @@ -11,7 +11,7 @@ namespace Microsoft.Bot.Builder.ApplicationInsights /// /// A logging client for bot telemetry. /// - public class BotTelemetryClient : IBotTelemetryClient + public class BotTelemetryClient : IBotTelemetryClient, IBotPageViewTelemetryClient { private readonly TelemetryClient _telemetryClient; @@ -168,6 +168,35 @@ public virtual void TrackTrace(string message, Severity severityLevel, IDictiona _telemetryClient.TrackTrace(telemetry); } + /// + /// 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 virtual void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + var telemetry = new PageViewTelemetry(dialogName); + + if (properties != null) + { + foreach (var pair in properties) + { + telemetry.Properties.Add(pair.Key, pair.Value); + } + } + + if (metrics != null) + { + foreach (var pair in metrics) + { + telemetry.Metrics.Add(pair.Key, pair.Value); + } + } + + _telemetryClient.TrackPageView(telemetry); + } + /// /// Flushes the in-memory buffer and any metrics being pre-aggregated. /// diff --git a/libraries/Microsoft.Bot.Builder.Dialogs/ComponentDialog.cs b/libraries/Microsoft.Bot.Builder.Dialogs/ComponentDialog.cs index 161c8cc952..1bcd601e2b 100644 --- a/libraries/Microsoft.Bot.Builder.Dialogs/ComponentDialog.cs +++ b/libraries/Microsoft.Bot.Builder.Dialogs/ComponentDialog.cs @@ -88,6 +88,8 @@ public override IBotTelemetryClient TelemetryClient return await EndComponentAsync(outerDc, turnResult.Result, cancellationToken).ConfigureAwait(false); } + TelemetryClient.TrackDialogView(Id); + // Just signal waiting return Dialog.EndOfTurn; } diff --git a/libraries/Microsoft.Bot.Builder.Dialogs/WaterfallDialog.cs b/libraries/Microsoft.Bot.Builder.Dialogs/WaterfallDialog.cs index 1882fa412c..157777b2a1 100644 --- a/libraries/Microsoft.Bot.Builder.Dialogs/WaterfallDialog.cs +++ b/libraries/Microsoft.Bot.Builder.Dialogs/WaterfallDialog.cs @@ -77,6 +77,7 @@ public WaterfallDialog AddStep(WaterfallStep step) { "InstanceId", instanceId }, }; TelemetryClient.TrackEvent("WaterfallStart", properties); + TelemetryClient.TrackDialogView(Id); // Run first step return await RunStepAsync(dc, 0, DialogReason.BeginCalled, null, cancellationToken).ConfigureAwait(false); diff --git a/libraries/Microsoft.Bot.Builder/IBotPageViewTelemetryClient.cs b/libraries/Microsoft.Bot.Builder/IBotPageViewTelemetryClient.cs new file mode 100644 index 0000000000..11060e6830 --- /dev/null +++ b/libraries/Microsoft.Bot.Builder/IBotPageViewTelemetryClient.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Microsoft.Bot.Builder +{ + /// + /// Describes a logging client for bot telemetry. + /// + public interface IBotPageViewTelemetryClient + { + /// + /// Logs 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. + void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null); + } +} diff --git a/libraries/Microsoft.Bot.Builder/IBotTelemetryClientExtensions.cs b/libraries/Microsoft.Bot.Builder/IBotTelemetryClientExtensions.cs new file mode 100644 index 0000000000..068c1ae8b1 --- /dev/null +++ b/libraries/Microsoft.Bot.Builder/IBotTelemetryClientExtensions.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Microsoft.Bot.Builder +{ + public static class IBotTelemetryClientExtensions + { + /// + /// Log a DialogView using the TrackPageView method on the IBotTelemetryClient if IBotPageViewTelemetryClient has been implemented. + /// Alternatively log the information out via TrackTrace. + /// + /// The TelemetryClient that implements IBotTelemetryClient. + /// 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 static void TrackDialogView(this IBotTelemetryClient telemetryClient, string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + if (telemetryClient is IBotPageViewTelemetryClient pageViewClient) + { + pageViewClient.TrackPageView(dialogName, properties, metrics); + } + else + { + telemetryClient.TrackTrace($"Dialog View: {dialogName}", Severity.Information, properties); + } + } + } +} diff --git a/libraries/Microsoft.Bot.Builder/NullBotTelemetryClient.cs b/libraries/Microsoft.Bot.Builder/NullBotTelemetryClient.cs index 796c824fe6..41050c13fc 100644 --- a/libraries/Microsoft.Bot.Builder/NullBotTelemetryClient.cs +++ b/libraries/Microsoft.Bot.Builder/NullBotTelemetryClient.cs @@ -6,7 +6,7 @@ namespace Microsoft.Bot.Builder { - public class NullBotTelemetryClient : IBotTelemetryClient + public class NullBotTelemetryClient : IBotTelemetryClient, IBotPageViewTelemetryClient { public static IBotTelemetryClient Instance { get; } = new NullBotTelemetryClient(); @@ -33,5 +33,9 @@ public void TrackException(Exception exception, IDictionary prop public void TrackTrace(string message, Severity severityLevel, IDictionary properties) { } + + public void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + } } } diff --git a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/TelemetryBotIdInitializer.cs b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/TelemetryBotIdInitializer.cs index 9e84b86dc6..9da60e2663 100644 --- a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/TelemetryBotIdInitializer.cs +++ b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/TelemetryBotIdInitializer.cs @@ -38,7 +38,7 @@ public void Initialize(ITelemetry telemetry) if (items != null) { if ((telemetry is RequestTelemetry || telemetry is EventTelemetry - || telemetry is TraceTelemetry || telemetry is DependencyTelemetry) + || telemetry is TraceTelemetry || telemetry is DependencyTelemetry || telemetry is PageViewTelemetry) && items.ContainsKey(BotActivityKey)) { if (items[BotActivityKey] is JObject body) diff --git a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/BotTelemetryClientTests.cs b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/BotTelemetryClientTests.cs index 7c2c53eb36..4c760a7c41 100644 --- a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/BotTelemetryClientTests.cs +++ b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/BotTelemetryClientTests.cs @@ -128,6 +128,16 @@ public void TrackTraceTest() _mockTelemetryChannel.Verify(tc => tc.Send(It.Is(t => t.SeverityLevel == SeverityLevel.Critical))); _mockTelemetryChannel.Verify(tc => tc.Send(It.Is(t => t.Properties["foo"] == "bar"))); } + + [TestMethod] + public void TrackPageViewTest() + { + _botTelemetryClient.TrackDialogView("test", new Dictionary() { { "hello", "value" } }, new Dictionary() { { "metric", 0.6 } }); + + _mockTelemetryChannel.Verify(tc => tc.Send(It.Is(t => t.Name == "test"))); + _mockTelemetryChannel.Verify(tc => tc.Send(It.Is(t => t.Properties["hello"] == "value"))); + _mockTelemetryChannel.Verify(tc => tc.Send(It.Is(t => t.Metrics["metric"] == 0.6))); + } } } } diff --git a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/MyBotTelemetryClient.cs b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/MyBotTelemetryClient.cs index 195cb555a9..8d53d7ae64 100644 --- a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/MyBotTelemetryClient.cs +++ b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/MyBotTelemetryClient.cs @@ -40,6 +40,11 @@ public override void TrackTrace(string message, Severity severityLevel, IDiction base.TrackTrace(message, severityLevel, properties); } + public override void TrackPageView(string name, IDictionary properties = null, IDictionary metrics = null) + { + base.TrackPageView(name, properties, metrics); + } + public override void Flush() { base.Flush(); diff --git a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/TelemetryWaterfallTests.cs b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/TelemetryWaterfallTests.cs index c3a12c72da..87e18ba699 100644 --- a/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/TelemetryWaterfallTests.cs +++ b/tests/Microsoft.Bot.Builder.ApplicationInsights.Tests/TelemetryWaterfallTests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder.Adapters; +using Microsoft.Bot.Builder.ApplicationInsights; using Microsoft.Bot.Builder.Dialogs; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; diff --git a/tests/Microsoft.Bot.Builder.Dialogs.Tests/ComponentDialogTests.cs b/tests/Microsoft.Bot.Builder.Dialogs.Tests/ComponentDialogTests.cs index 82a8732250..3fd84588d7 100644 --- a/tests/Microsoft.Bot.Builder.Dialogs.Tests/ComponentDialogTests.cs +++ b/tests/Microsoft.Bot.Builder.Dialogs.Tests/ComponentDialogTests.cs @@ -475,7 +475,7 @@ public CancelledComponentDialog(Dialog waterfallDialog) } } - private class MyBotTelemetryClient : IBotTelemetryClient + private class MyBotTelemetryClient : IBotTelemetryClient, IBotPageViewTelemetryClient { public MyBotTelemetryClient() { @@ -496,6 +496,11 @@ public void TrackDependency(string dependencyTypeName, string target, string dep throw new NotImplementedException(); } + public void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + throw new NotImplementedException(); + } + public void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) { throw new NotImplementedException(); diff --git a/tests/Microsoft.Bot.Builder.Dialogs.Tests/DialogSetTests.cs b/tests/Microsoft.Bot.Builder.Dialogs.Tests/DialogSetTests.cs index 2b6fe61d86..74efc1ce4d 100644 --- a/tests/Microsoft.Bot.Builder.Dialogs.Tests/DialogSetTests.cs +++ b/tests/Microsoft.Bot.Builder.Dialogs.Tests/DialogSetTests.cs @@ -130,7 +130,7 @@ public async Task DialogSet_HeterogeneousLoggers() await Task.CompletedTask; } - private class MyBotTelemetryClient : IBotTelemetryClient + private class MyBotTelemetryClient : IBotTelemetryClient, IBotPageViewTelemetryClient { public MyBotTelemetryClient() { @@ -151,6 +151,11 @@ public void TrackDependency(string dependencyTypeName, string target, string dep throw new NotImplementedException(); } + public void TrackPageView(string dialogName, IDictionary properties = null, IDictionary metrics = null) + { + throw new NotImplementedException(); + } + public void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) { throw new NotImplementedException();