-
Notifications
You must be signed in to change notification settings - Fork 69
Update Telemetry for Public Preview in MSAZ #251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
d7a00ce
78efff5
32cf41d
e68ca3d
1182fbc
15c81b0
d8cd11b
85d9bf7
9263c03
49a9885
adfe00d
97849df
5da719a
98d73d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| using System.Text.Json; | ||
|
|
||
| using Microsoft.ApplicationInsights; | ||
| using Microsoft.ApplicationInsights.WorkerService; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Microsoft.Azure.Agent; | ||
|
|
||
| public class AzTrace | ||
| { | ||
| private static readonly string s_installationId; | ||
| static AzTrace() | ||
| { | ||
| string azureConfigDir = Environment.GetEnvironmentVariable("AZURE_CONFIG_DIR"); | ||
| string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | ||
| string userProfilePath = string.IsNullOrEmpty(azureConfigDir) ? Path.Combine(userProfile, ".Azure", "azureProfile.json") : azureConfigDir; | ||
|
||
|
|
||
| JsonElement array; | ||
| s_installationId = null; | ||
|
|
||
| if (File.Exists(userProfilePath)) | ||
| { | ||
| using var jsonStream = new FileStream(userProfilePath, FileMode.Open, FileAccess.Read); | ||
| array = JsonSerializer.Deserialize<JsonElement>(jsonStream); | ||
| s_installationId = array.GetProperty("installationId").GetString(); | ||
| } | ||
| else | ||
| { | ||
| try | ||
| { | ||
| userProfilePath = string.IsNullOrEmpty(azureConfigDir) ? Path.Combine(userProfile, ".Azure", "AzureRmContextSettings.json") : azureConfigDir; | ||
|
||
| using var jsonStream = new FileStream(userProfilePath, FileMode.Open, FileAccess.Read); | ||
| array = JsonSerializer.Deserialize<JsonElement>(jsonStream); | ||
| s_installationId = array.GetProperty("Settings").GetProperty("InstallationId").GetString(); | ||
| } | ||
| catch | ||
| { | ||
| // If finally no installation id found, just return null. | ||
| s_installationId = null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| internal AzTrace() | ||
| { | ||
| InstallationId = s_installationId; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Installation id from the Azure CLI installation. | ||
| /// </summary> | ||
| internal string InstallationId { get; } | ||
|
|
||
| /// <summary> | ||
| /// Topic name of the response from Azure Copilot. | ||
| /// </summary> | ||
| internal string TopicName { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Each chat has a unique conversation id. When the customer runs '/refresh', | ||
| /// a new chat will be initiated (i.e. a new conversation id will be created). | ||
| /// </summary> | ||
| internal string ConversationId { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The activity id of the user's query. | ||
| /// </summary> | ||
| internal string QueryId { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The event type of this telemetry. | ||
| /// </summary> | ||
| internal string EventType { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The shell command that triggered this telemetry. | ||
| /// </summary> | ||
| internal string ShellCommand { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Detailed information. | ||
| /// </summary> | ||
| internal object Details { get; set; } | ||
|
|
||
| internal static AzTrace UserAction( | ||
| string shellCommand, | ||
| CopilotResponse response, | ||
| object details, | ||
| bool isFeedback = false) | ||
| { | ||
| if (Telemetry.Enabled) | ||
| { | ||
| return new() | ||
| { | ||
| QueryId = response.ReplyToId, | ||
| TopicName = response.TopicName, | ||
| ConversationId = response.ConversationId, | ||
| ShellCommand = shellCommand, | ||
| EventType = isFeedback ? "Feedback" : "UserAction", | ||
| Details = details | ||
| }; | ||
| } | ||
|
|
||
| // Don't create an object when telemetry is disabled. | ||
| return null; | ||
| } | ||
|
|
||
| internal static AzTrace Chat(CopilotResponse response) | ||
| { | ||
| if (Telemetry.Enabled) | ||
| { | ||
| return new() | ||
| { | ||
| EventType = "Chat", | ||
| QueryId = response.ReplyToId, | ||
| TopicName = response.TopicName, | ||
| ConversationId = response.ConversationId | ||
| }; | ||
| } | ||
|
|
||
| // Don't create an object when telemetry is disabled. | ||
| return null; | ||
| } | ||
|
|
||
| internal static AzTrace Exception(CopilotResponse response, object details) | ||
| { | ||
| if (Telemetry.Enabled) | ||
| { | ||
| return new() | ||
| { | ||
| EventType = "Exception", | ||
| QueryId = response?.ReplyToId, | ||
| TopicName = response?.TopicName, | ||
| ConversationId = response?.ConversationId, | ||
| Details = details | ||
| }; | ||
| } | ||
|
|
||
| // Don't create an object when telemetry is disabled. | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| internal class Telemetry | ||
| { | ||
| private static Telemetry s_singleton; | ||
| private readonly TelemetryClient _telemetryClient; | ||
|
|
||
| private Telemetry() | ||
| { | ||
| // Being a regular console app, there is no appsettings.json or configuration providers enabled by default. | ||
| // Hence connection string must be specified here. | ||
| IServiceCollection services = new ServiceCollection() | ||
| .AddApplicationInsightsTelemetryWorkerService((ApplicationInsightsServiceOptions options) => | ||
| { | ||
| // Application insights in the test environment. | ||
| options.ConnectionString = "InstrumentationKey=eea660a1-d969-44f8-abe4-96666e7fb159"; | ||
| options.EnableHeartbeat = false; | ||
| options.EnableDiagnosticsTelemetryModule = false; | ||
| }); | ||
|
|
||
| // Obtain TelemetryClient instance from DI, for additional manual tracking or to flush. | ||
| _telemetryClient = services | ||
| .BuildServiceProvider() | ||
| .GetRequiredService<TelemetryClient>(); | ||
|
|
||
| // Suppress the PII recorded by default to reduce risk. | ||
| _telemetryClient.Context.Cloud.RoleInstance = "Not Available"; | ||
| } | ||
|
|
||
| private void LogTelemetry(AzTrace trace, Exception e = null) | ||
| { | ||
| Dictionary<string, string> telemetryEvent = new() | ||
| { | ||
| ["QueryId"] = trace.QueryId, | ||
| ["ConversationId"] = trace.ConversationId, | ||
| ["InstallationId"] = trace.InstallationId, | ||
| ["TopicName"] = trace.TopicName, | ||
| ["EventType"] = trace.EventType, | ||
| ["ShellCommand"] = trace.ShellCommand, | ||
| ["Details"] = GetDetailedMessage(trace.Details), | ||
| }; | ||
|
|
||
| _telemetryClient.TrackTrace("AIShell", telemetryEvent); | ||
| if (e != null) { _telemetryClient.TrackException(e); } | ||
|
||
| _telemetryClient.Flush(); | ||
| } | ||
|
|
||
| private static string GetDetailedMessage(object details) | ||
| { | ||
| if (details is null) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| if (details is string str) | ||
| { | ||
| return str; | ||
| } | ||
|
|
||
| return JsonSerializer.Serialize(details, Utils.RelaxedJsonEscapingOptions); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets whether or not telemetry is enabled. | ||
| /// </summary> | ||
| internal static bool Enabled => s_singleton is not null; | ||
|
|
||
| /// <summary> | ||
| /// Initialize telemetry client. | ||
| /// </summary> | ||
| internal static void Initialize() => s_singleton ??= new Telemetry(); | ||
|
|
||
| /// <summary> | ||
| /// Trace a telemetry metric. | ||
| /// The method does nothing when it's disabled. | ||
| /// </summary> | ||
| internal static void Trace(AzTrace trace) => s_singleton?.LogTelemetry(trace); | ||
|
|
||
| /// <summary> | ||
| /// Trace a telemetry metric and an Exception with it. | ||
| /// The method does nothing when it's disabled. | ||
| /// </summary> | ||
| internal static void Trace(AzTrace trace, Exception e) => s_singleton?.LogTelemetry(trace, e); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.