From 4f517b1cba83d8f365754152245f5f900f78e74d Mon Sep 17 00:00:00 2001
From: Victor XField <vxfield@outlook.com>
Date: Tue, 17 Nov 2020 00:33:47 -0800
Subject: [PATCH 1/6] Register known folders

---
 src/Tool/Program.cs   | 12 ++++++++++--
 src/Tool/Telemetry.cs | 21 +++++++++++++++++++++
 src/Tool/Tool.csproj  |  5 +++++
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/src/Tool/Program.cs b/src/Tool/Program.cs
index a4b2890022..844926658b 100644
--- a/src/Tool/Program.cs
+++ b/src/Tool/Program.cs
@@ -63,7 +63,8 @@ public static int Main(string[] args)
                         new Dictionary<string, string>()
                         {
                             ["--user-agent"] = "UserAgent",
-                            ["--hosting-env"] = "HostingEnvironment"
+                            ["--hosting-env"] = "HostingEnvironment",
+                            ["--register-folders-for-telemetry"] = "RegisterFoldersForTelemetry"
                         }
                     )
                     .Add(new NormalizedEnvironmentVariableConfigurationSource
@@ -135,7 +136,7 @@ public static int Main(string[] args)
                                 "--hosting-env <ENV>",
                                 "Specifies the hosting environment that this kernel is being run in.",
                                 CommandOptionType.SingleValue
-                            );
+                            );                            
                         }
                     )
                 );
@@ -168,11 +169,18 @@ public static KernelApplication AddWorkspaceOption(KernelApplication app)
             var skipAutoLoadProjectOption = app.Option("--skipAutoLoadProject",
                 "Specifies whether to skip automatically loading the .csproj from the workspace's root folder.", CommandOptionType.SingleValue);
 
+            var registerFoldersForTelemetryOption = app.Option<string>(
+                "--register-folders-for-telemetry <FOLDER>",
+                "Sends the sub-folders names of <FOLDER> as plain-text to Microsoft telemetry systems.",
+                CommandOptionType.SingleValue
+            );
+
             foreach (var command in app.Commands.Where(c => c.Name == "kernel" || c.Name == "server"))
             {
                 command.Options.Add(cacheOption);
                 command.Options.Add(workspaceOption);
                 command.Options.Add(skipAutoLoadProjectOption);
+                command.Options.Add(registerFoldersForTelemetryOption);
             }
 
             return app;
diff --git a/src/Tool/Telemetry.cs b/src/Tool/Telemetry.cs
index 40582b5338..075d8a35e2 100644
--- a/src/Tool/Telemetry.cs
+++ b/src/Tool/Telemetry.cs
@@ -112,6 +112,27 @@ private void InitTelemetryLogger(Applications.Events.ILogger telemetryLogger, IC
             telemetryLogger.SetContext("DeviceId".WithTelemetryNamespace(), GetDeviceId(), PiiKind.GenericData);
             telemetryLogger.SetContext("UserAgent".WithTelemetryNamespace(), config?.GetValue<string>("UserAgent"));
             telemetryLogger.SetContext("HostingEnvironment".WithTelemetryNamespace(), config?.GetValue<string>("HostingEnvironment"));
+            RegisterFoldersForTelemetry(config?.GetValue<string>("RegisterFoldersForTelemetry"));
+            LogManager.UploadNow();
+            System.Threading.Thread.Sleep(10000);
+        }
+
+        private void RegisterFoldersForTelemetry(string folder, string rootFolder = null)
+        {
+            rootFolder ??= Directory.GetParent(folder).FullName;
+            if (!string.IsNullOrEmpty(folder))
+            {
+                var evt = new EventProperties() { Name = "WellKnownFolder".WithTelemetryNamespace() };
+                evt.SetProperty("FolderName".WithTelemetryNamespace(), Path.GetRelativePath(rootFolder, folder), PiiKind.None);
+                evt.SetProperty("FolderNameHash".WithTelemetryNamespace(), Path.GetFileName(folder), PiiKind.GenericData);
+                TelemetryLogger.LogEvent(evt);
+
+                var subFolders = Directory.EnumerateDirectories(folder).Where(s => !Path.GetFileName(s).StartsWith(".")).ToList();
+                foreach (var subFolder in subFolders)
+                {
+                    RegisterFoldersForTelemetry(subFolder, rootFolder);
+                }
+            }
         }
 
         /// <summary>
diff --git a/src/Tool/Tool.csproj b/src/Tool/Tool.csproj
index 272c06015c..132e16870f 100644
--- a/src/Tool/Tool.csproj
+++ b/src/Tool/Tool.csproj
@@ -24,6 +24,10 @@
     <ContentTargetFolders>\</ContentTargetFolders>
     <ApplicationIcon />
   </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <DefineConstants>TRACE;REALTIME_TELEMETRY;TELEMETRY</DefineConstants>
+  </PropertyGroup>
   
   <ItemGroup>
     <Compile Include="..\..\build\DelaySign.cs" Link="Properties\DelaySign.cs" />
@@ -49,6 +53,7 @@
 
   <ItemGroup>
     <FrameworkReference Include="Microsoft.AspNetCore.App" />
+    <PackageReference Include="Microsoft.Applications.Events.Client.Core2" Version="1.1.0.192" />
     <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0" />
     <PackageReference Include="Microsoft.NETCore.Portable.Compatibility" Version="1.0.1" />

From b6a1ecbd4079a2e6c7db20cc6d48e196f73ccc20 Mon Sep 17 00:00:00 2001
From: Victor XField <vxfield@outlook.com>
Date: Mon, 11 Jan 2021 02:20:50 -0800
Subject: [PATCH 2/6] RegisterFoldersForTelemetry if running a build-agent

---
 src/Tool/Telemetry.cs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/Tool/Telemetry.cs b/src/Tool/Telemetry.cs
index 075d8a35e2..b3ddda0b17 100644
--- a/src/Tool/Telemetry.cs
+++ b/src/Tool/Telemetry.cs
@@ -113,8 +113,12 @@ private void InitTelemetryLogger(Applications.Events.ILogger telemetryLogger, IC
             telemetryLogger.SetContext("UserAgent".WithTelemetryNamespace(), config?.GetValue<string>("UserAgent"));
             telemetryLogger.SetContext("HostingEnvironment".WithTelemetryNamespace(), config?.GetValue<string>("HostingEnvironment"));
             RegisterFoldersForTelemetry(config?.GetValue<string>("RegisterFoldersForTelemetry"));
-            LogManager.UploadNow();
-            System.Threading.Thread.Sleep(10000);
+
+            if (config?.GetValue<string>("HostingEnvironment") == "build-agent")
+            {
+                RegisterFoldersForTelemetry(Path.GetFileName(Directory.GetCurrentDirectory()));
+                LogManager.UploadNow();
+            }
         }
 
         private void RegisterFoldersForTelemetry(string folder, string rootFolder = null)

From ed985ecf9efa4d28e4d00b91336945f5d9795f15 Mon Sep 17 00:00:00 2001
From: Victor XField <vxfield@outlook.com>
Date: Mon, 11 Jan 2021 03:54:55 -0800
Subject: [PATCH 3/6] Remove compilation symbols and package reference

---
 src/Tool/Tool.csproj | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/Tool/Tool.csproj b/src/Tool/Tool.csproj
index 132e16870f..77c69eae5a 100644
--- a/src/Tool/Tool.csproj
+++ b/src/Tool/Tool.csproj
@@ -26,7 +26,7 @@
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
-    <DefineConstants>TRACE;REALTIME_TELEMETRY;TELEMETRY</DefineConstants>
+    <DefineConstants>TRACE</DefineConstants>
   </PropertyGroup>
   
   <ItemGroup>
@@ -53,7 +53,6 @@
 
   <ItemGroup>
     <FrameworkReference Include="Microsoft.AspNetCore.App" />
-    <PackageReference Include="Microsoft.Applications.Events.Client.Core2" Version="1.1.0.192" />
     <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0" />
     <PackageReference Include="Microsoft.NETCore.Portable.Compatibility" Version="1.0.1" />

From d2059f0db8f5d7ecc84899459ccb069da2ac6bcd Mon Sep 17 00:00:00 2001
From: XField <58103249+vxfield@users.noreply.github.com>
Date: Thu, 3 Nov 2022 10:32:46 -0700
Subject: [PATCH 4/6] Fixing small issue with null folder name

---
 src/Tool/Telemetry.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Tool/Telemetry.cs b/src/Tool/Telemetry.cs
index 17bea9ed60..042076406b 100644
--- a/src/Tool/Telemetry.cs
+++ b/src/Tool/Telemetry.cs
@@ -119,16 +119,16 @@ private void InitTelemetryLogger(Applications.Events.ILogger telemetryLogger, IC
 
             if (config?.GetValue<string>("HostingEnvironment") == "build-agent")
             {
-                RegisterFoldersForTelemetry(Path.GetFileName(Directory.GetCurrentDirectory()));
+                RegisterFoldersForTelemetry(Directory.GetCurrentDirectory());
                 LogManager.UploadNow();
             }
         }
 
         private void RegisterFoldersForTelemetry(string folder, string rootFolder = null)
         {
-            rootFolder ??= Directory.GetParent(folder).FullName;
             if (!string.IsNullOrEmpty(folder))
             {
+                rootFolder ??= Directory.GetParent(folder).FullName;
                 var evt = new EventProperties() { Name = "WellKnownFolder".WithTelemetryNamespace() };
                 evt.SetProperty("FolderName".WithTelemetryNamespace(), Path.GetRelativePath(rootFolder, folder), PiiKind.None);
                 evt.SetProperty("FolderNameHash".WithTelemetryNamespace(), Path.GetFileName(folder), PiiKind.GenericData);

From 66bdf6ef933c469abcbf0f3fb51c1442728a0c6a Mon Sep 17 00:00:00 2001
From: XField <58103249+vxfield@users.noreply.github.com>
Date: Thu, 3 Nov 2022 10:45:10 -0700
Subject: [PATCH 5/6] register-folders-for-telemetry arg

---
 src/Tool/Program.cs | 68 +++++++++++----------------------------------
 1 file changed, 16 insertions(+), 52 deletions(-)

diff --git a/src/Tool/Program.cs b/src/Tool/Program.cs
index c3c4c44844..1f194ff213 100644
--- a/src/Tool/Program.cs
+++ b/src/Tool/Program.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation.
+// Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT License.
 #nullable enable
 using McMaster.Extensions.CommandLineUtils;
@@ -27,7 +27,6 @@ public class Program
         public class LoggingOptions
         {
             public string? LogPath { get; set; }
-            public LogLevel? FileLogLevel { get; set; }
         }
 
         public static bool TelemetryOptOut
@@ -64,7 +63,8 @@ public static int Main(string[] args)
                         new Dictionary<string, string>()
                         {
                             ["--user-agent"] = "UserAgent",
-                            ["--hosting-env"] = "HostingEnvironment"
+                            ["--hosting-env"] = "HostingEnvironment",
+                            ["--register-folders-for-telemetry"] = "RegisterFoldersForTelemetry"
                         }
                     )
                     .Add(new NormalizedEnvironmentVariableConfigurationSource
@@ -72,23 +72,14 @@ public static int Main(string[] args)
                         Prefix = "IQSHARP_",
                         Aliases = new Dictionary<string, string>
                         {
-                            // Package and project load settings
-                            ["AUTO_LOAD_PACKAGES"] = "AutoLoadPackages",
-                            ["AUTO_OPEN_NAMESPACES"] = "AutoOpenNamespaces",
-                            ["SKIP_AUTO_LOAD_PROJECT"] = "SkipAutoLoadProject",
-                            ["FORCE_TARGETING_HEURISTICS"] = "ForceTargetingHeuristics",
-
-                            // Telemetry and metadata settings
                             ["TELEMETRY_OPT_OUT"] = nameof(TelemetryOptOut),
-                            ["HOSTING_ENV"] = "HostingEnvironment",
                             ["USER_AGENT"] = "UserAgent",
-                            ["USER_AGENT_EXTRA"] = "UserAgentExtra",
-
-                            // Logging settings
+                            ["HOSTING_ENV"] = "HostingEnvironment",
                             ["LOG_PATH"] = "LogPath",
-                            ["FILE_LOG_LEVEL"] = "FileLogLevel",
-                            ["BINLOG_PATH"] = "MSBuildBinlogPath",
-                            ["SESSION_RECORD_PATH"] = "SessionRecordPath",
+                            ["AUTO_LOAD_PACKAGES"] = "AutoLoadPackages",
+                            ["DEFERRED_LOAD_PACKAGES"] = "DeferredLoadPackages",
+                            ["AUTO_OPEN_NAMESPACES"] = "AutoOpenNamespaces",
+                            ["SKIP_AUTO_LOAD_PROJECT"] = "SkipAutoLoadProject",
                         }
                     })
                     .Build();
@@ -107,7 +98,7 @@ public static int Main(string[] args)
                         {
                             loggingBuilder.AddFile(
                                 options.LogPath,
-                                minimumLevel: options.FileLogLevel ?? LogLevel.Debug
+                                minimumLevel: LogLevel.Debug
                             );
                         }
                     }
@@ -126,37 +117,16 @@ public static int Main(string[] args)
                         });
                     }
                 );
-                CommandOption? userAgentOption = null;
 
                 AddWorkspaceOption(
                     app
-                    .AddInstallCommand(installCmd =>
-                    {
-                        userAgentOption = installCmd.Option(
-                            "--user-agent-extra <AGENT>",
-                            "Sets additional user agent information to be sent to the kernel.",
-                            CommandOptionType.SingleValue
-                        );
-                    })
-                    .WithKernelArguments(() =>
-                        // We know that the closure above is called by the time
-                        // we get to this point, such that userAgentOption is
-                        // not null at this point.
-                        userAgentOption!.HasValue()
-                        ? new [] {"--user-agent-extra", userAgentOption!.Value()}
-                        : Array.Empty<string>()
-                    )
+                    .AddInstallCommand()
                     .AddKernelCommand(
                         // These command options will be consumed by the Program.Configuration
                         // object above, rather than by the kernel application object itself.
                         // Thus, we only need placeholders to prevent the kernel application
                         // from raising an exception when unrecognized options are passed.
                         kernelCmd => {
-                            kernelCmd.Option<string>(
-                                "--user-agent-extra <AGENT>",
-                                "Sets additional user agent information to be sent to the kernel.",
-                                CommandOptionType.SingleValue
-                            );
                             kernelCmd.Option<string>(
                                 "--user-agent <AGENT>",
                                 "Specifies which user agent has initiated this kernel instance.",
@@ -166,7 +136,7 @@ public static int Main(string[] args)
                                 "--hosting-env <ENV>",
                                 "Specifies the hosting environment that this kernel is being run in.",
                                 CommandOptionType.SingleValue
-                            );                            
+                            );
                         }
                     )
                 );
@@ -181,16 +151,10 @@ public static int Main(string[] args)
 
         public static IWebHost GetHttpServer(string[]? args)
         {
-           var builder = WebHost.CreateDefaultBuilder(args ?? Array.Empty<string>())
-                .UseUrls("http://localhost:8008")
-                .UseStartup<Startup>();
-
-            if (Configuration is not null)
-            {
-                builder.UseConfiguration(Configuration);
-            }
-                
-            return builder.Build();
+            return WebHost.CreateDefaultBuilder(args)
+                 .UseUrls("http://localhost:8888")
+                 .UseStartup<Startup>()
+                 .Build();
         }
 
         // Adds the Workspace settings to the "server" and "kernel" commands:
@@ -222,4 +186,4 @@ public static KernelApplication AddWorkspaceOption(KernelApplication app)
             return app;
         }
     }
-}
+}
\ No newline at end of file

From c238fc051308aaaeaac4601ae66953d25f2870c7 Mon Sep 17 00:00:00 2001
From: XField <58103249+vxfield@users.noreply.github.com>
Date: Thu, 3 Nov 2022 10:52:38 -0700
Subject: [PATCH 6/6] Merge from main

---
 src/Tool/Program.cs | 78 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/src/Tool/Program.cs b/src/Tool/Program.cs
index 1f194ff213..6f90d21988 100644
--- a/src/Tool/Program.cs
+++ b/src/Tool/Program.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 #nullable enable
 using McMaster.Extensions.CommandLineUtils;
@@ -27,6 +27,7 @@ public class Program
         public class LoggingOptions
         {
             public string? LogPath { get; set; }
+            public LogLevel? FileLogLevel { get; set; }
         }
 
         public static bool TelemetryOptOut
@@ -63,6 +64,7 @@ public static int Main(string[] args)
                         new Dictionary<string, string>()
                         {
                             ["--user-agent"] = "UserAgent",
+                            ["--user-agent-extra"] = "UserAgentExtra",
                             ["--hosting-env"] = "HostingEnvironment",
                             ["--register-folders-for-telemetry"] = "RegisterFoldersForTelemetry"
                         }
@@ -72,14 +74,23 @@ public static int Main(string[] args)
                         Prefix = "IQSHARP_",
                         Aliases = new Dictionary<string, string>
                         {
-                            ["TELEMETRY_OPT_OUT"] = nameof(TelemetryOptOut),
-                            ["USER_AGENT"] = "UserAgent",
-                            ["HOSTING_ENV"] = "HostingEnvironment",
-                            ["LOG_PATH"] = "LogPath",
+                            // Package and project load settings
                             ["AUTO_LOAD_PACKAGES"] = "AutoLoadPackages",
-                            ["DEFERRED_LOAD_PACKAGES"] = "DeferredLoadPackages",
                             ["AUTO_OPEN_NAMESPACES"] = "AutoOpenNamespaces",
                             ["SKIP_AUTO_LOAD_PROJECT"] = "SkipAutoLoadProject",
+                            ["FORCE_TARGETING_HEURISTICS"] = "ForceTargetingHeuristics",
+
+                            // Telemetry and metadata settings
+                            ["TELEMETRY_OPT_OUT"] = nameof(TelemetryOptOut),
+                            ["HOSTING_ENV"] = "HostingEnvironment",
+                            ["USER_AGENT"] = "UserAgent",
+                            ["USER_AGENT_EXTRA"] = "UserAgentExtra",
+
+                            // Logging settings
+                            ["LOG_PATH"] = "LogPath",
+                            ["FILE_LOG_LEVEL"] = "FileLogLevel",
+                            ["BINLOG_PATH"] = "MSBuildBinlogPath",
+                            ["SESSION_RECORD_PATH"] = "SessionRecordPath",
                         }
                     })
                     .Build();
@@ -98,7 +109,7 @@ public static int Main(string[] args)
                         {
                             loggingBuilder.AddFile(
                                 options.LogPath,
-                                minimumLevel: LogLevel.Debug
+                                minimumLevel: options.FileLogLevel ?? LogLevel.Debug
                             );
                         }
                     }
@@ -117,16 +128,37 @@ public static int Main(string[] args)
                         });
                     }
                 );
+                CommandOption? userAgentOption = null;
 
                 AddWorkspaceOption(
                     app
-                    .AddInstallCommand()
+                    .AddInstallCommand(installCmd =>
+                    {
+                        userAgentOption = installCmd.Option(
+                            "--user-agent-extra <AGENT>",
+                            "Sets additional user agent information to be sent to the kernel.",
+                            CommandOptionType.SingleValue
+                        );
+                    })
+                    .WithKernelArguments(() =>
+                        // We know that the closure above is called by the time
+                        // we get to this point, such that userAgentOption is
+                        // not null at this point.
+                        userAgentOption!.HasValue()
+                        ? new[] { "--user-agent-extra", userAgentOption!.Value() }
+                        : Array.Empty<string>()
+                    )
                     .AddKernelCommand(
                         // These command options will be consumed by the Program.Configuration
                         // object above, rather than by the kernel application object itself.
                         // Thus, we only need placeholders to prevent the kernel application
                         // from raising an exception when unrecognized options are passed.
                         kernelCmd => {
+                            kernelCmd.Option<string>(
+                                "--user-agent-extra <AGENT>",
+                                "Sets additional user agent information to be sent to the kernel.",
+                                CommandOptionType.SingleValue
+                            );
                             kernelCmd.Option<string>(
                                 "--user-agent <AGENT>",
                                 "Specifies which user agent has initiated this kernel instance.",
@@ -137,6 +169,11 @@ public static int Main(string[] args)
                                 "Specifies the hosting environment that this kernel is being run in.",
                                 CommandOptionType.SingleValue
                             );
+                            kernelCmd.Option<string>(
+                                "--register-folders-for-telemetry <FOLDER>",
+                                "Sends the sub-folders names of <FOLDER> as plain-text to Microsoft telemetry systems.",
+                                CommandOptionType.SingleValue
+                            );
                         }
                     )
                 );
@@ -151,10 +188,16 @@ public static int Main(string[] args)
 
         public static IWebHost GetHttpServer(string[]? args)
         {
-            return WebHost.CreateDefaultBuilder(args)
-                 .UseUrls("http://localhost:8888")
-                 .UseStartup<Startup>()
-                 .Build();
+            var builder = WebHost.CreateDefaultBuilder(args ?? Array.Empty<string>())
+                 .UseUrls("http://localhost:8008")
+                 .UseStartup<Startup>();
+
+            if (Configuration is not null)
+            {
+                builder.UseConfiguration(Configuration);
+            }
+
+            return builder.Build();
         }
 
         // Adds the Workspace settings to the "server" and "kernel" commands:
@@ -168,12 +211,11 @@ public static KernelApplication AddWorkspaceOption(KernelApplication app)
                 "operations available for simulation.", CommandOptionType.SingleValue);
             var skipAutoLoadProjectOption = app.Option("--skipAutoLoadProject",
                 "Specifies whether to skip automatically loading the .csproj from the workspace's root folder.", CommandOptionType.SingleValue);
-
             var registerFoldersForTelemetryOption = app.Option<string>(
-                "--register-folders-for-telemetry <FOLDER>",
-                "Sends the sub-folders names of <FOLDER> as plain-text to Microsoft telemetry systems.",
-                CommandOptionType.SingleValue
-            );
+                    "--register-folders-for-telemetry <FOLDER>",
+                    "Sends the sub-folders names of <FOLDER> as plain-text to Microsoft telemetry systems.",
+                    CommandOptionType.SingleValue
+                );
 
             foreach (var command in app.Commands.Where(c => c.Name == "kernel" || c.Name == "server"))
             {
@@ -186,4 +228,4 @@ public static KernelApplication AddWorkspaceOption(KernelApplication app)
             return app;
         }
     }
-}
\ No newline at end of file
+}