From f2ef967aaf74c4ce199fb5ff156c818d00f94a53 Mon Sep 17 00:00:00 2001
From: Andrew Wang <waan@microsoft.com>
Date: Tue, 13 Sep 2022 17:43:19 -0700
Subject: [PATCH 1/4] Fix TestThisConditional (#1354)

---
 test/CppTests/Tests/NatvisTests.cs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/test/CppTests/Tests/NatvisTests.cs b/test/CppTests/Tests/NatvisTests.cs
index 37bc46b8f..69b2526c4 100644
--- a/test/CppTests/Tests/NatvisTests.cs
+++ b/test/CppTests/Tests/NatvisTests.cs
@@ -36,6 +36,9 @@ public NatvisTests(ITestOutputHelper outputHelper) : base(outputHelper)
 
         private const string NatvisName = "natvis";
         private const string NatvisSourceName = "main.cpp";
+
+        // These line numbers will need to change if src/natvis/main.cpp changes
+        private const int SimpleClassAssignmentLine = 47;
         private const int ReturnSourceLine = 51;
 
         [Theory]
@@ -369,7 +372,7 @@ public void TestThisConditional(ITestSettings settings)
                 runner.RunCommand(launch);
 
                 this.Comment("Set Breakpoint before assigning 'simpleClass' and end of method.");
-                SourceBreakpoints writerBreakpoints = debuggee.Breakpoints(NatvisSourceName, new int[] { 46, ReturnSourceLine });
+                SourceBreakpoints writerBreakpoints = debuggee.Breakpoints(NatvisSourceName, new int[] { SimpleClassAssignmentLine, ReturnSourceLine });
                 runner.SetBreakpoints(writerBreakpoints);
 
                 runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

From a0849cce53d3afff1054b67c90633cf09708b83a Mon Sep 17 00:00:00 2001
From: Alex Hsu <csigs@users.noreply.github.com>
Date: Fri, 16 Sep 2022 15:45:21 -0700
Subject: [PATCH 2/4] LEGO: Pull request from
 lego/hb_d72c5677-3f00-4225-b18e-0a1e8a8f5f0e_20220916220203345 to main
 (#1356)

Juno: check in to lego/hb_d72c5677-3f00-4225-b18e-0a1e8a8f5f0e_20220916220203345.
---
 loc/lcl/CHS/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/CHT/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/CSY/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/DEU/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/ESN/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/FRA/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/ITA/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/JPN/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/KOR/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/PLK/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/PTB/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/RUS/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 loc/lcl/TRK/OpenFolderSchema.json.lcl | 36 +++++++++++++++++++++++++++
 13 files changed, 468 insertions(+)

diff --git a/loc/lcl/CHS/OpenFolderSchema.json.lcl b/loc/lcl/CHS/OpenFolderSchema.json.lcl
index a17ab9b24..1d907d5d2 100644
--- a/loc/lcl/CHS/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CHS/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[控制在命中时如何处理(通常通过原始 GDB 命令)外部设置的断点。]A;允许的值为 "throw" (好像应用程序抛出了异常)和 "stop" (只会暂停调试会话)。默认值为 "throw"。]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stop]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[字符串]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/CHT/OpenFolderSchema.json.lcl b/loc/lcl/CHT/OpenFolderSchema.json.lcl
index 0ce4d648b..5072a7d00 100644
--- a/loc/lcl/CHT/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CHT/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[控制叫用時如何處理在外部設定的中斷點 (通常是透過原始 GDB 命令)。]A;允許的值為 "throw",其作用就像應用程式擲出例外,以及 "stop",其只會暫停偵錯工作階段。預設值為 "throw"。]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stop]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[字串]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/CSY/OpenFolderSchema.json.lcl b/loc/lcl/CSY/OpenFolderSchema.json.lcl
index d3dd4ad6f..796e5db74 100644
--- a/loc/lcl/CSY/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CSY/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Určuje, jak se mají zarážky nastavené externě (obvykle prostřednictvím nezpracovaných příkazů GDB) zpracovávat při průchodu.]A;Povolené hodnoty jsou throw, která se chová, jako by aplikace vyvolala výjimku, a stop, která pouze pozastaví ladicí relaci. Výchozí hodnota je throw.]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stop]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[řetězec]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/DEU/OpenFolderSchema.json.lcl b/loc/lcl/DEU/OpenFolderSchema.json.lcl
index b8941d421..e89c066ea 100644
--- a/loc/lcl/DEU/OpenFolderSchema.json.lcl
+++ b/loc/lcl/DEU/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Steuert, wie extern gesetzte Haltepunkte (normalerweise über rohe GDB-Befehle) behandelt werden, wenn ihnen begegnet wird.]A;Erlaubte Werte sind "throw", was sich so verhält, als ob eine Ausnahme von der Anwendung ausgelöst würde, und "stop", was die Debugsitzung nur pausiert. Der Standardwert ist "throw".]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[werfen]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[beenden]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Zeichenfolge]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/ESN/OpenFolderSchema.json.lcl b/loc/lcl/ESN/OpenFolderSchema.json.lcl
index 8a9a7376d..3e06b2806 100644
--- a/loc/lcl/ESN/OpenFolderSchema.json.lcl
+++ b/loc/lcl/ESN/OpenFolderSchema.json.lcl
@@ -814,6 +814,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Controla cómo se controlan los puntos de interrupción establecidos externamente (normalmente a través de comandos GDB sin procesar) cuando se alcanzan.]A;Los valores permitidos son "throw", que actúa como si la aplicación iniciara una excepción y "stop", que solo pausa la sesión de depuración. El valor predeterminado es "throw".]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stop]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[cadena]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/FRA/OpenFolderSchema.json.lcl b/loc/lcl/FRA/OpenFolderSchema.json.lcl
index 27f67fc05..613cfd697 100644
--- a/loc/lcl/FRA/OpenFolderSchema.json.lcl
+++ b/loc/lcl/FRA/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Contrôle la façon dont les points d’arrêt définis en externe (généralement via des commandes GDB brutes) sont gérés en cas d’accès.]A;Les valeurs autorisées sont « throw », qui agit comme si une exception était levée par l’application, et « stop », qui suspend uniquement la session de débogage. La valeur par défaut est « throw ».]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stop]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[chaîne]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/ITA/OpenFolderSchema.json.lcl b/loc/lcl/ITA/OpenFolderSchema.json.lcl
index 7443d1a3b..96eae5bef 100644
--- a/loc/lcl/ITA/OpenFolderSchema.json.lcl
+++ b/loc/lcl/ITA/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Controllare la modalità di gestione dei punti di interruzione impostati esternamente (in genere tramite comandi GDB non elaborati) quando vengono selezionati.]A;I valori consentiti sono "throw", che funziona come se fosse stata generata un'eccezione dall'applicazione e "stop", che sospende solo la sessione di debug. Il valore predefinito è "throw".]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[gettare]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[arresto]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[stringa]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/JPN/OpenFolderSchema.json.lcl b/loc/lcl/JPN/OpenFolderSchema.json.lcl
index 68e3dd5f7..07566f91b 100644
--- a/loc/lcl/JPN/OpenFolderSchema.json.lcl
+++ b/loc/lcl/JPN/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[ヒットしたときに外部で設定されたブレークポイント (通常は生の GDB コマンドを使用) を処理する方法を制御します。]A;許容される値は、アプリケーションによって例外がスローされたかのように動作する "throw" と、デバッグ セッションを一時停止するだけの "stop" です。既定値は "throw" です。]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[停止]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[文字列]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/KOR/OpenFolderSchema.json.lcl b/loc/lcl/KOR/OpenFolderSchema.json.lcl
index 2aa095794..ecdc13638 100644
--- a/loc/lcl/KOR/OpenFolderSchema.json.lcl
+++ b/loc/lcl/KOR/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[적중 시 외부에서 설정되는 중단점이(일반적으로 원시 GDB 명령을 통해) 처리되는 방식을 제어합니다.]A;허용 값은 애플리케이션에서 예외가 발생한 것처럼 동작하는 "throw"와 디버그 세션만 일시 중지하는 "stop"입니다. 기본값은 "throw"입니다.]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[중지]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[문자열]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/PLK/OpenFolderSchema.json.lcl b/loc/lcl/PLK/OpenFolderSchema.json.lcl
index e716460bb..e6f347966 100644
--- a/loc/lcl/PLK/OpenFolderSchema.json.lcl
+++ b/loc/lcl/PLK/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Steruje sposobem obsługi punktów przerwania ustawianych zewnętrznie (zwykle za pośrednictwem nieprzetworzonych poleceń GDB) po trafieniu.]A;Dozwolone wartości to „throw”, które działają tak, jakby aplikacja zgłosiła wyjątek, i „stop”, co tylko wstrzymuje sesję debugowania. Wartość domyślna to „throw”.]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[rzucać]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[zatrzymaj]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[ciąg]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/PTB/OpenFolderSchema.json.lcl b/loc/lcl/PTB/OpenFolderSchema.json.lcl
index ad42d83f9..aaecef349 100644
--- a/loc/lcl/PTB/OpenFolderSchema.json.lcl
+++ b/loc/lcl/PTB/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Controla como os pontos de interrupção definidos externamente (geralmente por meio de comandos GDB brutos) são tratados quando atingidos.]A;Os valores permitidos são "throw", que age como se uma exceção fosse lançada pelo aplicativo, e "stop", que apenas pausa a sessão de depuração. O valor padrão é "throw".]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[interromper]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[cadeia de caracteres]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/RUS/OpenFolderSchema.json.lcl b/loc/lcl/RUS/OpenFolderSchema.json.lcl
index 03db31052..3e4c12882 100644
--- a/loc/lcl/RUS/OpenFolderSchema.json.lcl
+++ b/loc/lcl/RUS/OpenFolderSchema.json.lcl
@@ -814,6 +814,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[Управляет тем, как точки останова, установленные извне (обычно через необработанные команды GDB), обрабатываются при попадании.]A;Допустимые значения: "throw", который действует так, как если бы приложение выдало исключение, и "stop", который только приостанавливает сеанс отладки. Значение по умолчанию — "throw".]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[отбросить]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[остановить]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[строка]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>
diff --git a/loc/lcl/TRK/OpenFolderSchema.json.lcl b/loc/lcl/TRK/OpenFolderSchema.json.lcl
index 8ceb87e84..7553f7bec 100644
--- a/loc/lcl/TRK/OpenFolderSchema.json.lcl
+++ b/loc/lcl/TRK/OpenFolderSchema.json.lcl
@@ -865,6 +865,42 @@
         </Str>
         <Disp Icon="Str" />
       </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.description" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[Controls how breakpoints set externally (usually via raw GDB commands) are handled when hit.]A;Allowed values are "throw", which acts as if an exception was thrown by the application, and "stop", which only pauses the debug session. The default value is "throw".]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[İsabet ettiğinde harici olarak (genellikle ham GDB komutları aracılığıyla) ayarlanan kesme noktalarının nasıl işlendiğini kontrol eder.]A;İzin verilen değerler, uygulama tarafından bir istisna oluşturulmuş gibi davranan "throw" ve yalnızca hata ayıklama oturumunu duraklatan "stop" değerleridir. Varsayılan değer "throw"dur.]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[0]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[throw]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[throw]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.enum[1]" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[stop]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[durdurma]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
+      <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.unknownBreakpointHandling.type" ItemType="0" PsrId="306" Leaf="true">
+        <Str Cat="Text">
+          <Val><![CDATA[string]]></Val>
+          <Tgt Cat="Text" Stat="Loc" Orig="New">
+            <Val><![CDATA[dize]]></Val>
+          </Tgt>
+        </Str>
+        <Disp Icon="Str" />
+      </Item>
       <Item ItemId=";debugExtensions.cppdbg.schema.definitions.cpp_schema.properties.useExtendedRemote.description" ItemType="0" PsrId="306" Leaf="true">
         <Str Cat="Text">
           <Val><![CDATA[If true, use gdb extended-remote mode to connect to gdbserver.]]></Val>

From fd190c03bab7f332e522aa2bfb2f8b755206c787 Mon Sep 17 00:00:00 2001
From: Andrew Wang <waan@microsoft.com>
Date: Mon, 3 Oct 2022 17:26:25 -0700
Subject: [PATCH 3/4] Refactor Engine Logging and Add Natvis Diagnostic Logging
 (#1322)

Refactor Engine Logging to be implemented through channels and add a new channel called NatvisDiagnostics
---
 src/AndroidDebugLauncher/InstallPaths.cs      |   2 +-
 src/AndroidDebugLauncher/Launcher.cs          |  14 +-
 src/DebugEngineHost.Common/HostLogChannel.cs  | 141 ++++++++++++++++++
 .../DebugEngineHost.ref.cs                    | 117 ++++++++++-----
 .../DebugEngineHost.VSCode.csproj             |   2 +
 .../HostConfigurationStore.cs                 |  14 --
 src/DebugEngineHost.VSCode/HostLogger.cs      |  78 +++-------
 src/DebugEngineHost.VSCode/Logger.cs          |  33 ----
 src/DebugEngineHost/DebugEngineHost.csproj    |   2 +
 src/DebugEngineHost/HostConfigurationStore.cs |  32 ----
 src/DebugEngineHost/HostLogger.cs             |  87 ++---------
 src/MICore/CommandFactories/gdb.cs            |   3 +-
 src/MICore/Debugger.cs                        |  10 +-
 src/MICore/ExceptionHelper.cs                 |   4 +-
 src/MICore/LaunchOptions.cs                   |   4 +-
 src/MICore/Logger.cs                          | 102 ++++++-------
 src/MICore/MICore.csproj                      |   1 -
 src/MICore/MIResults.cs                       |   3 +-
 src/MICore/SetMIDebugLogging.cmd              | 130 ----------------
 src/MICore/Transports/PipeTransport.cs        |   3 +-
 .../Transports/RunInTerminalTransport.cs      |  10 +-
 src/MICore/Transports/StreamTransport.cs      |   4 +-
 .../Transports/UnixShellPortTransport.cs      |   6 +-
 src/MICore/UnixUtilities.cs                   |   5 +-
 src/MIDebugEngine/AD7.Impl/AD7Engine.cs       |   6 +-
 .../Engine.Impl/DebugUnixChildProcess.cs      |   2 +-
 .../Engine.Impl/DebuggedThread.cs             |   5 +-
 .../Engine.Impl/EngineCallback.cs             |   2 +-
 src/MIDebugEngine/Natvis.Impl/Natvis.cs       |  20 +--
 src/MIDebugEngine/Natvis.Impl/NatvisNames.cs  |   5 +-
 src/MIDebugEngineUnitTests/NatvisNamesTest.cs |  15 +-
 src/OpenDebugAD7/AD7DebugSession.cs           |  58 ++++++-
 src/OpenDebugAD7/AD7Resources.Designer.cs     |  18 +++
 src/OpenDebugAD7/AD7Resources.resx            |   8 +
 src/OpenDebugAD7/DebugEventLogger.cs          |   2 +
 src/OpenDebugAD7/OpenDebug/Program.cs         |  59 ++++++--
 src/OpenDebugAD7/OpenDebug/Utilities.cs       |   2 +-
 37 files changed, 511 insertions(+), 498 deletions(-)
 create mode 100644 src/DebugEngineHost.Common/HostLogChannel.cs
 delete mode 100644 src/DebugEngineHost.VSCode/Logger.cs
 delete mode 100644 src/MICore/SetMIDebugLogging.cmd

diff --git a/src/AndroidDebugLauncher/InstallPaths.cs b/src/AndroidDebugLauncher/InstallPaths.cs
index 72a1b9f12..70c456b10 100644
--- a/src/AndroidDebugLauncher/InstallPaths.cs
+++ b/src/AndroidDebugLauncher/InstallPaths.cs
@@ -69,7 +69,7 @@ public static InstallPaths Resolve(CancellationToken token, AndroidLaunchOptions
                     ThrowExternalFileNotFoundException(ndkReleaseVersionFile, LauncherResources.ProductName_NDK);
                 }
 
-                logger.WriteLine("Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);
+                logger.WriteLine(Microsoft.DebugEngineHost.LogLevel.Verbose, "Using NDK '{0}' from path '{1}'", ndkReleaseId, ndkRoot);
 
                 // 32 vs 64-bit doesn't matter when comparing
                 var r11 = new NdkReleaseId(11, 'a');
diff --git a/src/AndroidDebugLauncher/Launcher.cs b/src/AndroidDebugLauncher/Launcher.cs
index 1ca37f537..0730aef67 100644
--- a/src/AndroidDebugLauncher/Launcher.cs
+++ b/src/AndroidDebugLauncher/Launcher.cs
@@ -52,7 +52,7 @@ void IPlatformAppLauncher.Initialize(HostConfigurationStore configStore, IDevice
 
             _eventCallback = eventCallback;
             RegistryRoot.Set(configStore.RegistryRoot);
-            Logger = MICore.Logger.EnsureInitialized(configStore);
+            Logger = MICore.Logger.EnsureInitialized();
         }
 
         void IPlatformAppLauncher.SetLaunchOptions(string exePath, string args, string dir, object launcherXmlOptions, TargetEngine targetEngine)
@@ -747,7 +747,7 @@ private Task StartGdbServer(string gdbServerRemotePath, string workingDirectory,
                     debugMessage.Replace("\r", "\\r");
                     debugMessage.Replace("\n", "\\n");
                     debugMessage.Replace("\t", "\\t");
-                    Logger.WriteLine(debugMessage.ToString());
+                    Logger.WriteLine(LogLevel.Verbose, debugMessage.ToString());
                 }
 
                 // Here is the expected output from GDB Server --
@@ -769,7 +769,7 @@ private Task StartGdbServer(string gdbServerRemotePath, string workingDirectory,
 
             _gdbServerExecCancellationSource.Token.ThrowIfCancellationRequested();
 
-            Logger.WriteLine("ADB<-{0}", gdbServerCommand);
+            Logger.WriteLine(LogLevel.Verbose, "ADB<-{0}", gdbServerCommand);
             Task serverExitedOrCanceled = _shell.ExecAsync(gdbServerCommand, _gdbServerExecCancellationSource.Token, outputHandler);
             int completedTask = Task.WaitAny(serverReady.Task, serverExitedOrCanceled);
 
@@ -781,7 +781,7 @@ private Task StartGdbServer(string gdbServerRemotePath, string workingDirectory,
                 // they fail, try again with TCP.
                 if (useUnixSocket && HasGdbServerInvalidSocketError(errorOutput))
                 {
-                    Logger.WriteLine("Retrying GDB Server launch using TCP socket.");
+                    Logger.WriteLine(LogLevel.Verbose, "Retrying GDB Server launch using TCP socket.");
                     return StartGdbServer(gdbServerRemotePath, workingDirectory, /*useUnixSocket:*/ false, out gdbServerSocketDescription);
                 }
 
@@ -842,11 +842,11 @@ private string ExecCommand(string command)
         {
             Debug.Assert(_shell != null, "ExecCommand called before m_shell is set");
 
-            Logger.WriteLine("ADB<-{0}", command);
+            Logger.WriteLine(LogLevel.Verbose, "ADB<-{0}", command);
 
             string response = ExecCommandNoLog(command);
 
-            Logger.WriteTextBlock("ADB->", response);
+            Logger.WriteTextBlock(LogLevel.Verbose, "ADB->", response);
 
             return response;
         }
@@ -892,7 +892,7 @@ void IPlatformAppLauncher.OnResume()
                     }
                     catch (JDbg.JdwpException e)
                     {
-                        Logger.WriteLine("JdwpException: {0}", e.Message);
+                        Logger.WriteLine(LogLevel.Warning, "JdwpException: {0}", e.Message);
 
                         string message = LauncherResources.Warning_JDbgResumeFailure;
 
diff --git a/src/DebugEngineHost.Common/HostLogChannel.cs b/src/DebugEngineHost.Common/HostLogChannel.cs
new file mode 100644
index 000000000..1c3a2bab7
--- /dev/null
+++ b/src/DebugEngineHost.Common/HostLogChannel.cs
@@ -0,0 +1,141 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*
+ * NOTE: This file is shared between DebugEngineHost and DebugEngineHost.VSCode
+ */
+
+using System;
+using System.Globalization;
+using System.IO;
+
+namespace Microsoft.DebugEngineHost
+{
+    public enum LogLevel
+    {
+        /// <summary>
+        /// Logs that are used for interactive investigation during development.
+        /// These logs should primarily contain information useful for debugging and have no long-term value.
+        /// </summary>
+        Verbose,
+        /// <summary>
+        /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop.
+        /// </summary>
+        Warning,
+        /// <summary>
+        /// Logs that highlight when the current flow of execution is stopped due to a failure.
+        /// These should indicate a failure in the current activity, not an application-wide failure.
+        /// </summary>
+        Error,
+        /// <summary>
+        /// Not used for writing log messages.
+        /// Specifies that a logging category should not write any messages.
+        /// </summary>
+        None
+    }
+
+    // This must match the interface in DebugEngineHost.ref.cs
+    public interface ILogChannel
+    {
+        void WriteLine(LogLevel level, string message);
+
+        void WriteLine(LogLevel level, string format, params object[] values);
+
+        void Flush();
+
+        void Close();
+    }
+
+    public class HostLogChannel : ILogChannel
+    {
+        private readonly Action<string> _log;
+        private StreamWriter _logFile;
+        private LogLevel _minLevelToBeLogged;
+
+        private readonly object _lock = new object();
+
+        private HostLogChannel() { }
+
+        public HostLogChannel(Action<string> logAction, string file, LogLevel logLevel)
+        {
+            _log = logAction;
+
+            if (!string.IsNullOrEmpty(file))
+            {
+                _logFile = File.CreateText(file);
+            }
+
+            _minLevelToBeLogged = logLevel;
+        }
+
+        /// <summary>
+        /// Sets the log level to the provided level.
+        /// </summary>
+        /// <param name="level">The level to set the logger.</param>
+        public void SetLogLevel(LogLevel level)
+        {
+            _minLevelToBeLogged = level;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="verbosity"></param>
+        /// <param name="message"></param>
+        public void WriteLine(LogLevel level, string message)
+        {
+            if (level >= _minLevelToBeLogged)
+            {
+                lock (_lock)
+                {
+                    string prefix = string.Empty;
+                    // Only indicate level if not verbose.
+                    if (level != LogLevel.Verbose)
+                    {
+                        prefix = string.Format(CultureInfo.InvariantCulture, "[{0}] ", level.ToString());
+                    }
+                    string levelMsg = string.Format(CultureInfo.InvariantCulture, "{0}{1}", prefix, message);
+                    _log?.Invoke(levelMsg);
+                    _logFile?.WriteLine(levelMsg);
+                    _logFile?.Flush();
+                }
+
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="verbosity"></param>
+        /// <param name="format"></param>
+        /// <param name="values"></param>
+        public void WriteLine(LogLevel level, string format, params object[] values)
+        {
+            if (level >= _minLevelToBeLogged)
+            {
+                lock (_lock)
+                {
+                    string message = string.Format(CultureInfo.CurrentCulture, format, values);
+                    this.WriteLine(level, message);
+                }
+            }
+        }
+
+        public void Flush()
+        {
+            lock (_lock)
+            {
+                _logFile?.Flush();
+            }
+        }
+
+        public void Close()
+        {
+            lock (_lock)
+            {
+                _logFile?.Close();
+                _logFile = null;
+            }
+        }
+    }
+}
diff --git a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
index 9d528c1bd..b4ebb6124 100644
--- a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
+++ b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
@@ -162,21 +162,6 @@ public void GetExceptionCategorySettings(Guid categoryId, out HostConfigurationS
             throw new NotImplementedException();
         }
 
-        /// <summary>
-        /// Checks if logging is enabled, and if so returns a logger object.
-        ///
-        /// In VS, this is wired up to read from the registry and return a logger which writes a log file to %TMP%\log-file-name.
-        /// In VS Code, this will check if the '--engineLogging' switch is enabled, and if so return a logger that will write to the Console.
-        /// </summary>
-        /// <param name="enableLoggingSettingName">[Optional] In VS, the name of the settings key to check if logging is enabled.
-        /// If not specified, this will check 'EnableLogging' in the AD7 Metrics.</param>
-        /// <param name="logFileName">[Required] name of the log file to open if logging is enabled.</param>
-        /// <returns>[Optional] If logging is enabled, the logging object.</returns>
-        public HostLogger GetLogger(string enableLoggingSettingName, string logFileName)
-        {
-            throw new NotImplementedException();
-        }
-
         /// <summary>
         /// Read the debugger setting
         ///
@@ -197,56 +182,116 @@ public object GetCustomLauncher(string launcherTypeName)
         {
             throw new NotImplementedException();
         }
-}
+    }
 
-/// <summary>
-/// The host logger returned from HostConfigurationStore.GetLogger.
-/// </summary>
-public sealed class HostLogger
+    /// <summary>
+    /// Level of logging used for HostLogChannel
+    /// </summary>
+    public enum LogLevel
     {
         /// <summary>
-        /// Callback for programmatic display of log messages
+        /// Logs that are used for interactive investigation during development.
+        /// These logs should primarily contain information useful for debugging and have no long-term value.
         /// </summary>
-        /// <param name="outputMessage"></param>
-        public delegate void OutputCallback(string outputMessage);
+        Verbose,
+        /// <summary>
+        /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop.
+        /// </summary>
+        Warning,
+        /// <summary>
+        /// Logs that highlight when the current flow of execution is stopped due to a failure.
+        /// These should indicate a failure in the current activity, not an application-wide failure.
+        /// </summary>
+        Error,
+        /// <summary>
+        /// Not used for writing log messages.
+        /// Specifies that a logging category should not write any messages.
+        /// </summary>
+        None
+    }
 
-        private HostLogger()
+    /// <summary>
+    /// The channel used for logging messages.
+    /// Channels are used if there are multiple types of logs,
+    /// e.g. Engine logs and Natvis logs
+    /// </summary>
+    public interface ILogChannel
+    {
+        /// <summary>
+        /// Writes the given message with a newline to the log channel.
+        /// </summary>
+        /// <param name="level">The level of the log</param>
+        /// <param name="message">The message string to send.</param>
+        void WriteLine(LogLevel level, string message);
+
+        /// <summary>
+        /// Writes the given formatted message with the additional values with a newline to the log channel.
+        /// </summary>
+        /// <param name="level">The level of the log</param>
+        /// <param name="format">Format to use.</param>
+        /// <param name="values">Values to use within the provided format.</param>
+        void WriteLine(LogLevel level, string format, params object[] values);
+
+        /// <summary>
+        /// If the log is implemented as a file, this flushes the file.
+        /// </summary>
+        void Flush();
+
+        /// <summary>
+        /// If the log is implemented as a file, this closes the file.
+        /// </summary>
+        void Close();
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    public static class HostLogger
+    {
+        // EnableNatvisLogger is only used in OpenDebugAD7
+
+        /// <summary>
+        /// Enables engine logging if not already enabled.
+        /// </summary>
+        /// <param name="callback">The callback to use to send the engine log.</param>
+        /// <param name="level">The level of the log to filter the channel on.</param>
+        public static void EnableHostLogging(Action<string> callback, LogLevel level = LogLevel.Verbose)
         {
             throw new NotImplementedException();
         }
 
         /// <summary>
-        /// Writes a line to the log
+        /// Sets the log file to write to.
         /// </summary>
-        /// <param name="line">Line to write.</param>
-        public void WriteLine(string line)
+        /// <param name="logFile">The file to write engine logs to.</param>
+        public static void SetEngineLogFile(string logFile)
         {
             throw new NotImplementedException();
         }
 
+
         /// <summary>
-        /// If the log is implemented as a file, this flushes the file.
+        /// Gets the engine log channel created by 'EnableHostLogging'
         /// </summary>
-        public void Flush()
+        /// <returns>A logger object if logging is enabled, or null if it is not</returns>
+        public static ILogChannel GetEngineLogChannel()
         {
             throw new NotImplementedException();
         }
 
         /// <summary>
-        /// If the log is implemented as a file, this closes the file.
+        /// Gets the Natvis log channel if its been created.
         /// </summary>
-        public void Close()
+        /// <returns>A logger object if logging is enabled, or null if it is not</returns>
+        public static ILogChannel GetNatvisLogChannel()
         {
             throw new NotImplementedException();
         }
 
         /// <summary>
-        /// Get a logger after the user has explicitly configured a log file/callback
+        /// Clears the logging objects if enabled.
         /// </summary>
-        /// <param name="logFileName"></param>
-        /// <param name="callback"></param>
-        /// <returns>The host logger object</returns>
-        public static HostLogger GetLoggerFromCmd(string logFileName, HostLogger.OutputCallback callback)
+        public static void Reset()
         {
             throw new NotImplementedException();
         }
diff --git a/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj b/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj
index eef5e304b..428c8b4ca 100644
--- a/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj
+++ b/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj
@@ -23,6 +23,8 @@
   <ItemGroup Label="Compile Shared Interfaces">
     <Compile Include="$(MIEngineRoot)\src\DebugEngineHost.Stub\Shared\Microsoft.VisualStudio.Debugger.Interop.DAP.cs" />
     <Compile Include="..\DebugEngineHost.Stub\Shared\Microsoft.VisualStudio.Debugger.Interop.MI.cs" Link="Microsoft.VisualStudio.Debugger.Interop.MI.cs" />
+
+    <Compile Include="$(MIEngineRoot)\src\DebugEngineHost.Common\HostLogChannel.cs" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/DebugEngineHost.VSCode/HostConfigurationStore.cs b/src/DebugEngineHost.VSCode/HostConfigurationStore.cs
index 8eaf45de3..9736c3735 100644
--- a/src/DebugEngineHost.VSCode/HostConfigurationStore.cs
+++ b/src/DebugEngineHost.VSCode/HostConfigurationStore.cs
@@ -64,20 +64,6 @@ public void GetExceptionCategorySettings(Guid categoryId, out HostConfigurationS
             categoryConfigSection = new HostConfigurationSection(category.DefaultTriggers);
         }
 
-        /// <summary>
-        /// Checks if logging is enabled, and if so returns a logger object. 
-        /// 
-        /// In VS, this is wired up to read from the registry and return a logger which writes a log file to %TMP%\log-file-name.
-        /// In VS Code, this will check if the '--engineLogging' switch is enabled, and if so return a logger that wil write to the logger output.
-        /// </summary>
-        /// <param name="enableLoggingSettingName">[Optional] In VS, the name of the settings key to check if logging is enabled. If not specified, this will check 'EnableLogging' in the AD7 Metrics.</param>
-        /// <param name="logFileName">[Required] name of the log file to open if logging is enabled. This is ignored for VSCode.</param>
-        /// <returns>[Optional] If logging is enabled, the logging object.</returns>
-        public HostLogger GetLogger(string enableLoggingSettingName, string logFileName)
-        {
-            return HostLogger.Instance;
-        }
-
         /// <summary>
         /// Read the debugger setting
         /// </summary>
diff --git a/src/DebugEngineHost.VSCode/HostLogger.cs b/src/DebugEngineHost.VSCode/HostLogger.cs
index 71658194d..5eda359e8 100644
--- a/src/DebugEngineHost.VSCode/HostLogger.cs
+++ b/src/DebugEngineHost.VSCode/HostLogger.cs
@@ -5,85 +5,51 @@
 
 namespace Microsoft.DebugEngineHost
 {
-    public sealed class HostLogger
+    public static class HostLogger
     {
-        public delegate void OutputCallback(string outputMessage);
+        private static ILogChannel s_natvisLogChannel;
+        private static ILogChannel s_engineLogChannel;
 
-        private static HostLogger s_instance;
-        private static readonly object s_lock = new object();
+        private static string s_engineLogFile;
 
-        /// <summary>[Optional] VSCode-only host logger instance.</summary>
-        public static HostLogger Instance { get { return s_instance; } }
-
-        /// <summary>[Optional] VSCode-only method for obtaining the current host logger instance.</summary>
-        public static void EnableHostLogging()
+        public static void EnableNatvisLogger(Action<string> callback, LogLevel level = LogLevel.Verbose)
         {
-            if (s_instance == null)
+            if (s_natvisLogChannel == null)
             {
-                lock (s_lock)
-                {
-                    if (s_instance == null)
-                    {
-                        s_instance = new HostLogger();
-                    }
-                }
+                // TODO: Support writing natvis logs to a file.
+                s_natvisLogChannel = new HostLogChannel(callback, null, level);
             }
         }
 
-        private string _logFilePath = null;
-        private System.IO.StreamWriter _logFile = null;
-
-        /// <summary>Callback for logging text to the desired output stream.</summary>
-        public Action<string> LogCallback { get; set; } = null;
-
-        /// <summary>The path to the log file.</summary>
-        public string LogFilePath
+        public static void EnableHostLogging(Action<string> callback, LogLevel level = LogLevel.Verbose)
         {
-            get
+            if (s_engineLogChannel == null)
             {
-                return _logFilePath;
-            }
-            set
-            {
-                _logFile?.Dispose();
-                _logFilePath = value;
-
-                if (!String.IsNullOrEmpty(_logFilePath))
-                {
-                    _logFile = System.IO.File.CreateText(_logFilePath);
-                }
+                s_engineLogChannel = new HostLogChannel(callback, s_engineLogFile, level);
             }
         }
 
-        private HostLogger() { }
-
-        public void WriteLine(string line)
+        public static void SetEngineLogFile(string logFile)
         {
-            lock (s_lock)
-            {
-                _logFile?.WriteLine(line);
-                _logFile?.Flush();
-                LogCallback?.Invoke(line);
-            }
+            s_engineLogFile = logFile;
         }
 
-        public void Flush()
+        public static ILogChannel GetEngineLogChannel()
         {
+            return s_engineLogChannel;
         }
 
-        public void Close()
+        public static ILogChannel GetNatvisLogChannel()
         {
+            return s_natvisLogChannel;
         }
 
-        /// <summary>
-        /// Get a logger after the user has explicitly configured a log file/callback
-        /// </summary>
-        /// <param name="logFileName"></param>
-        /// <param name="callback"></param>
-        /// <returns>The host logger object</returns>
-        public static HostLogger GetLoggerFromCmd(string logFileName, HostLogger.OutputCallback callback)
+        public static void Reset()
         {
-            throw new NotImplementedException();
+            s_natvisLogChannel?.Close();
+            s_natvisLogChannel = null;
+            s_engineLogChannel?.Close();
+            s_engineLogChannel = null;
         }
     }
 }
diff --git a/src/DebugEngineHost.VSCode/Logger.cs b/src/DebugEngineHost.VSCode/Logger.cs
deleted file mode 100644
index 19dcaa868..000000000
--- a/src/DebugEngineHost.VSCode/Logger.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.DebugEngineHost
-{
-    /// <summary>
-    /// VS Code only class to write to the log. This is enabled through the '--engineLogging[=file]' command line argument.
-    /// </summary>
-    public static class Logger
-    {
-        public static void WriteFrame([CallerMemberName]string caller = null)
-        {
-            CoreWrite(caller);
-        }
-
-        public static void WriteLine(string s)
-        {
-            CoreWrite(s);
-        }
-
-        private static void CoreWrite(string line)
-        {
-            HostLogger.Instance?.WriteLine(line);
-        }
-    }
-}
diff --git a/src/DebugEngineHost/DebugEngineHost.csproj b/src/DebugEngineHost/DebugEngineHost.csproj
index ba45d7f48..5a09a365d 100755
--- a/src/DebugEngineHost/DebugEngineHost.csproj
+++ b/src/DebugEngineHost/DebugEngineHost.csproj
@@ -29,6 +29,8 @@
   <ItemGroup Label="Compile Shared Interfaces">
     <Compile Include="$(MIEngineRoot)\src\DebugEngineHost.Stub\Shared\Microsoft.VisualStudio.Debugger.Interop.DAP.cs" />
     <Compile Include="$(MIEngineRoot)\src\DebugEngineHost.Stub\Shared\Microsoft.VisualStudio.Debugger.Interop.MI.cs" />
+
+    <Compile Include="$(MIEngineRoot)\src\DebugEngineHost.Common\HostLogChannel.cs" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/DebugEngineHost/HostConfigurationStore.cs b/src/DebugEngineHost/HostConfigurationStore.cs
index 258dc59ec..37a700617 100644
--- a/src/DebugEngineHost/HostConfigurationStore.cs
+++ b/src/DebugEngineHost/HostConfigurationStore.cs
@@ -81,38 +81,6 @@ public void GetExceptionCategorySettings(Guid categoryId, out HostConfigurationS
             categoryName = categoryKey.GetSubKeyNames().Single();
         }
 
-        /// <summary>
-        /// Checks if logging is enabled, and if so returns a logger object.
-        /// </summary>
-        /// <param name="enableLoggingSettingName">[Optional] In VS, the name of the settings key to check if logging is enabled. If not specified, this will check 'Logging' in the AD7 Metrics.</param>
-        /// <param name="logFileName">[Required] name of the log file to open if logging is enabled.</param>
-        /// <returns>If no error then logging object. If file cannot be openened then throw an exception. Otherwise return an empty logger - the user can explictly reconfigure it later</returns>
-        public HostLogger GetLogger(string enableLoggingSettingName, string logFileName)
-        {
-            if (string.IsNullOrEmpty(logFileName))
-            {
-                throw new ArgumentNullException(nameof(logFileName));
-            }
-            object enableLoggingValue;
-            if (!string.IsNullOrEmpty(enableLoggingSettingName))
-            {
-                enableLoggingValue = GetOptionalValue(DebuggerSectionName, enableLoggingSettingName);
-            }
-            else
-            {
-                enableLoggingValue = GetEngineMetric("EnableLogging");
-            }
-
-            if (enableLoggingValue == null ||
-                !(enableLoggingValue is int) ||
-                ((int)enableLoggingValue) == 0)
-            {
-                return null;
-            }
-
-            return new HostLogger(HostLogger.GetStreamForName(logFileName, throwInUseError:false));
-        }
-
         public T GetDebuggerConfigurationSetting<T>(string settingName, T defaultValue)
         {
             return GetDebuggerConfigurationSetting(DebuggerSectionName, settingName, defaultValue);
diff --git a/src/DebugEngineHost/HostLogger.cs b/src/DebugEngineHost/HostLogger.cs
index 808a24394..413c0157f 100644
--- a/src/DebugEngineHost/HostLogger.cs
+++ b/src/DebugEngineHost/HostLogger.cs
@@ -3,101 +3,46 @@
 
 using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
 namespace Microsoft.DebugEngineHost
 {
-    public sealed class HostLogger
+    public static class HostLogger
     {
-        /// <summary>
-        /// Callback for programmatic display of log messages
-        /// </summary>
-        /// <param name="outputString"></param>
-        public delegate void OutputCallback(string outputString);
+        private static ILogChannel s_natvisLogChannel;
+        private static ILogChannel s_engineLogChannel;
 
-        private StreamWriter _streamWriter;
-        private OutputCallback _callback;
-        private readonly object _locker = new object();
+        private static string s_engineLogFile;
 
-        internal HostLogger(StreamWriter streamWriter = null, OutputCallback callback = null)
+        public static void EnableHostLogging(Action<string> callback, LogLevel level = LogLevel.Verbose)
         {
-            _streamWriter = streamWriter;
-            _callback = callback;
-        }
-
-        public void WriteLine(string line)
-        {
-            lock (_locker)
+            if (s_engineLogChannel == null)
             {
-                if (_streamWriter != null)
-                    _streamWriter.WriteLine(line);
-                _callback?.Invoke(line);
+                s_engineLogChannel = new HostLogChannel(callback, s_engineLogFile, level);
             }
         }
 
-        public void Flush()
+        public static void SetEngineLogFile(string logFile)
         {
-            lock (_locker)
-            {
-                if (_streamWriter != null)
-                    _streamWriter.Flush();
-            }
+            s_engineLogFile = logFile;
         }
 
-        public void Close()
+        public static ILogChannel GetEngineLogChannel()
         {
-            lock (_locker)
-            {
-                if (_streamWriter != null)
-                    _streamWriter.Close();
-                _streamWriter = null;
-            }
+            return s_engineLogChannel;
         }
 
-        internal static StreamWriter GetStreamForName(string logFileName, bool throwInUseError)
+        public static ILogChannel GetNatvisLogChannel()
         {
-            if (string.IsNullOrEmpty(logFileName))
-            {
-                return null;
-            }
-            string tempDirectory = Path.GetTempPath();
-            StreamWriter writer = null;
-            if (Path.IsPathRooted(logFileName) || (!string.IsNullOrEmpty(tempDirectory) && Directory.Exists(tempDirectory)))
-            {
-                string filePath = Path.Combine(tempDirectory, logFileName);
-
-                try
-                {
-                    FileStream stream = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.Read);
-                    writer = new StreamWriter(stream);
-                }
-                catch (IOException)
-                {
-                    if (throwInUseError)
-                        throw;
-                    // ignore failures from the log being in use by another process
-                }
-            }
-            else
-            {
-                throw new ArgumentOutOfRangeException(nameof(logFileName));
-            }
-            return writer;
+            return s_natvisLogChannel;
         }
 
-        /// <summary>
-        /// Get a logger after the user has explicitly configured a log file/callback
-        /// </summary>
-        /// <param name="logFileName"></param>
-        /// <param name="callback"></param>
-        /// <returns>The host logger object</returns>
-        public static HostLogger GetLoggerFromCmd(string logFileName, HostLogger.OutputCallback callback)
+        public static void Reset()
         {
-            StreamWriter writer = HostLogger.GetStreamForName(logFileName, throwInUseError: true);
-            return new HostLogger(writer, callback);
+            s_natvisLogChannel = null;
+            s_engineLogChannel = null;
         }
     }
 }
diff --git a/src/MICore/CommandFactories/gdb.cs b/src/MICore/CommandFactories/gdb.cs
index 92c28938b..35d256e45 100644
--- a/src/MICore/CommandFactories/gdb.cs
+++ b/src/MICore/CommandFactories/gdb.cs
@@ -10,6 +10,7 @@
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Globalization;
+using Microsoft.DebugEngineHost;
 
 namespace MICore
 {
@@ -298,7 +299,7 @@ public override async Task<string[]> AutoComplete(string command, int threadId,
             var matchlist = res.Find<ValueListValue>("matches");
 
             if (int.Parse(res.FindString("max_completions_reached"), CultureInfo.InvariantCulture) != 0)
-                _debugger.Logger.WriteLine("We reached max-completions!");
+                _debugger.Logger.WriteLine(LogLevel.Verbose, "We reached max-completions!");
 
             return matchlist?.AsStrings;
         }
diff --git a/src/MICore/Debugger.cs b/src/MICore/Debugger.cs
index de2796da2..cd26301f6 100755
--- a/src/MICore/Debugger.cs
+++ b/src/MICore/Debugger.cs
@@ -172,7 +172,7 @@ public Debugger(LaunchOptions launchOptions, Logger logger)
         protected void SetDebuggerPid(int debuggerPid)
         {
             // Used for testing
-            Logger.WriteLine(string.Concat("DebuggerPid=", debuggerPid));
+            Logger.WriteLine(LogLevel.Verbose, string.Concat("DebuggerPid=", debuggerPid));
             _localDebuggerPid = debuggerPid;
         }
 
@@ -201,7 +201,7 @@ private void RetryBreak(object o)
             {
                 if (_waitingToStop && _retryCount < BREAK_RETRY_MAX)
                 {
-                    Logger.WriteLine("Debugger failed to break. Trying again.");
+                    Logger.WriteLine(LogLevel.Verbose, "Debugger failed to break. Trying again.");
                     CmdBreak(BreakRequest.Internal);
                     _retryCount++;
                 }
@@ -935,7 +935,7 @@ void ITransportCallback.OnStdOutLine(string line)
 
         void ITransportCallback.OnStdErrorLine(string line)
         {
-            Logger.WriteLine("STDERR: " + line);
+            Logger.WriteLine(LogLevel.Warning, "STDERR: " + line);
 
             if (_initialErrors != null)
             {
@@ -1047,7 +1047,7 @@ void SendUnsupportedWindowsGdbEvent(string version)
 
         void ITransportCallback.AppendToInitializationLog(string line)
         {
-            Logger.WriteLine(line);
+            Logger.WriteLine(LogLevel.Verbose, line);
 
             if (_initializationLog != null)
             {
@@ -1240,7 +1240,7 @@ public void ProcessStdOutLine(string line)
                         if (waitingOperation != null)
                         {
                             Results results = _miResults.ParseCommandOutput(noprefix);
-                            Logger.WriteLine(id.ToString(CultureInfo.InvariantCulture) + ": elapsed time " + ((int)(DateTime.Now - waitingOperation.StartTime).TotalMilliseconds).ToString(CultureInfo.InvariantCulture));
+                            Logger.WriteLine(LogLevel.Verbose, id.ToString(CultureInfo.InvariantCulture) + ": elapsed time " + ((int)(DateTime.Now - waitingOperation.StartTime).TotalMilliseconds).ToString(CultureInfo.InvariantCulture));
                             waitingOperation.OnComplete(results, this.MICommandFactory);
                             return;
                         }
diff --git a/src/MICore/ExceptionHelper.cs b/src/MICore/ExceptionHelper.cs
index 5563ff4cb..7295142b8 100644
--- a/src/MICore/ExceptionHelper.cs
+++ b/src/MICore/ExceptionHelper.cs
@@ -32,8 +32,8 @@ public static bool BeforeCatch(Exception currentException, Logger logger, bool r
             {
                 HostTelemetry.ReportCurrentException(currentException, "Microsoft.MIDebugEngine");
 
-                logger?.WriteLine("EXCEPTION: " + currentException.GetType());
-                logger?.WriteTextBlock("EXCEPTION: ", currentException.StackTrace);
+                logger?.WriteLine(LogLevel.Error, "EXCEPTION: ", currentException.GetType());
+                logger?.WriteTextBlock(LogLevel.Error, "EXCEPTION: ", currentException.StackTrace);
             }
             catch
             {
diff --git a/src/MICore/LaunchOptions.cs b/src/MICore/LaunchOptions.cs
index 835005b83..6ba4b10c1 100644
--- a/src/MICore/LaunchOptions.cs
+++ b/src/MICore/LaunchOptions.cs
@@ -1260,7 +1260,7 @@ public static LaunchOptions GetInstance(HostConfigurationStore configStore, stri
             if (string.IsNullOrEmpty(options))
                 throw new InvalidLaunchOptionsException(MICoreResources.Error_StringIsNullOrEmpty);
 
-            logger?.WriteTextBlock("LaunchOptions", options);
+            logger?.WriteTextBlock(LogLevel.Verbose, "LaunchOptions", options);
 
             LaunchOptions launchOptions = null;
             Guid clsidLauncher = Guid.Empty;
@@ -1500,7 +1500,7 @@ internal static SupplementalLaunchOptions GetOptionsFromFile(Logger logger)
                     {
                         try
                         {
-                            logger?.WriteTextBlock("SupplementalOptions", suppOptions);
+                            logger?.WriteTextBlock(LogLevel.Verbose, "SupplementalOptions", suppOptions);
                             XmlReader xmlRrd = OpenXml(suppOptions);
                             XmlSerializer serializer = GetXmlSerializer(typeof(Xml.LaunchOptions.SupplementalLaunchOptions));
                             return (Xml.LaunchOptions.SupplementalLaunchOptions)Deserialize(serializer, xmlRrd);
diff --git a/src/MICore/Logger.cs b/src/MICore/Logger.cs
index 05e8e9ca9..5efb488e4 100644
--- a/src/MICore/Logger.cs
+++ b/src/MICore/Logger.cs
@@ -15,41 +15,45 @@
 
 namespace MICore
 {
-    public interface ILogger
-    {
-        void WriteLine(string line);
-
-        void WriteLine(string format, params object[] args);
-    }
-
     /// <summary>
-    /// Class which implements logging. The logging is control by a registry key. If enabled, logging goes to %TMP%\Microsoft.MIDebug.log
+    /// Class which implements logging.
     /// </summary>
-    public class Logger : ILogger
+    public class Logger
     {
         private static bool s_isInitialized;
         private static bool s_isEnabled;
         private static DateTime s_initTime;
-        // NOTE: We never clean this up
-        private static HostLogger s_logger;
+        /// <summary>
+        /// Optional logger to get engine diagnostics logs
+        /// </summary>
+        private ILogChannel EngineLogger => HostLogger.GetEngineLogChannel();
+        /// <summary>
+        /// Optional logger to get natvis diagnostics logs
+        /// </summary>
+        public ILogChannel NatvisLogger => HostLogger.GetNatvisLogChannel();
         private static int s_count;
-        private int _id;
+        private readonly int _id;
+
+        #region Command Window
+
         public class LogInfo
         {
             public string logFile;
-            public HostLogger.OutputCallback logToOutput;
+            public Action<string> logToOutput;
             public bool enabled;
         };
-        private static LogInfo s_cmdLogInfo = new LogInfo();
+
+        private readonly static LogInfo s_cmdLogInfo = new LogInfo();
         public static LogInfo CmdLogInfo { get { return s_cmdLogInfo; } }
 
+        #endregion
 
         private Logger()
         {
             _id = Interlocked.Increment(ref s_count);
         }
 
-        public static Logger EnsureInitialized(HostConfigurationStore configStore)
+        public static Logger EnsureInitialized()
         {
             Logger res = new Logger();
             if (!s_isInitialized)
@@ -57,8 +61,8 @@ public static Logger EnsureInitialized(HostConfigurationStore configStore)
                 s_isInitialized = true;
                 s_initTime = DateTime.Now;
 
-                LoadMIDebugLogger(configStore);
-                res.WriteLine("Initialized log at: " + s_initTime.ToString(CultureInfo.InvariantCulture));
+                LoadMIDebugLogger();
+                res.WriteLine(LogLevel.Verbose, "Initialized log at: " + s_initTime.ToString(CultureInfo.InvariantCulture));
             }
 
 #if DEBUG
@@ -70,75 +74,65 @@ public static Logger EnsureInitialized(HostConfigurationStore configStore)
             return res;
         }
 
-        public static void LoadMIDebugLogger(HostConfigurationStore configStore)
+        public static void LoadMIDebugLogger()
         {
-            if (s_logger == null)
-            { 
-                if (CmdLogInfo.enabled)
-                {   // command configured log file
-                    s_logger = HostLogger.GetLoggerFromCmd(CmdLogInfo.logFile, CmdLogInfo.logToOutput);
-                }
-                else
-                {   // use default logging
-                    s_logger = configStore.GetLogger("EnableMIDebugLogger", "Microsoft.MIDebug.log");
-                }
-                if (s_logger != null)
-                {
-                    s_isEnabled = true;
-                }
+            if (CmdLogInfo.enabled)
+            {   // command configured log file
+                HostLogger.Reset();
+                HostLogger.SetEngineLogFile(CmdLogInfo.logFile);
+                HostLogger.EnableHostLogging(CmdLogInfo.logToOutput);
             }
+
+            s_isEnabled = true;
         }
 
         public static void Reset()
         {
-            HostLogger logger;
             if (CmdLogInfo.enabled)
             {
-                logger = HostLogger.GetLoggerFromCmd(CmdLogInfo.logFile, CmdLogInfo.logToOutput);
-                logger = Interlocked.Exchange(ref s_logger, logger);
-                logger?.Close();
-                if (s_logger != null)
-                {
-                    s_isEnabled = true;
-                }
+                HostLogger.Reset();
+                s_isEnabled = false;
             }
         }
 
         /// <summary>
         /// If logging is enabled, writes a line of text to the log
         /// </summary>
+        /// <param name="level">[Required] The level of the log.</param>
         /// <param name="line">[Required] line to write</param>
-        public void WriteLine(string line)
+        public void WriteLine(LogLevel level, string line)
         {
             if (s_isEnabled)
             {
-                WriteLineImpl(line);
+                WriteLineImpl(level, line);
             }
         }
 
         /// <summary>
         /// If logging is enabled, writes a line of text to the log
         /// </summary>
+        /// <param name="level">[Required] The level of the log.</param>
         /// <param name="format">[Required] format string</param>
         /// <param name="args">arguments to use in the format string</param>
-        public void WriteLine(string format, params object[] args)
+        public void WriteLine(LogLevel level, string format, params object[] args)
         {
             if (s_isEnabled)
             {
-                WriteLineImpl(format, args);
+                WriteLineImpl(level, format, args);
             }
         }
 
         /// <summary>
         /// If logging is enabled, writes a block of text which may contain newlines to the log
         /// </summary>
+        /// <param name="level">[Required] The level of the log.</param>
         /// <param name="prefix">[Optional] Prefix to put on the front of each line</param>
         /// <param name="textBlock">Block of text to write</param>
-        public void WriteTextBlock(string prefix, string textBlock)
+        public void WriteTextBlock(LogLevel level, string prefix, string textBlock)
         {
             if (s_isEnabled)
             {
-                WriteTextBlockImpl(prefix, textBlock);
+                WriteTextBlockImpl(level, prefix, textBlock);
             }
         }
 
@@ -159,10 +153,10 @@ public static bool IsEnabled
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)] // Disable inlining since logging is off by default, and we want to allow the public method to be inlined
-        private void WriteLineImpl(string line)
+        private void WriteLineImpl(LogLevel level, string line)
         {
             string fullLine = String.Format(CultureInfo.CurrentCulture, "{2}: ({0}) {1}", (int)(DateTime.Now - s_initTime).TotalMilliseconds, line, _id);
-            s_logger?.WriteLine(fullLine);
+            HostLogger.GetEngineLogChannel()?.WriteLine(level, fullLine);
 #if DEBUG
             Debug.WriteLine("MS_MIDebug: " + fullLine);
 #endif
@@ -171,17 +165,17 @@ private void WriteLineImpl(string line)
         [MethodImpl(MethodImplOptions.NoInlining)] // Disable inlining since logging is off by default, and we want to allow the public method to be inlined
         private static void FlushImpl()
         {
-            s_logger?.Flush();
+            HostLogger.GetEngineLogChannel()?.Flush();
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)] // Disable inlining since logging is off by default, and we want to allow the public method to be inlined
-        private void WriteLineImpl(string format, object[] args)
+        private void WriteLineImpl(LogLevel level, string format, object[] args)
         {
-            WriteLineImpl(string.Format(CultureInfo.CurrentCulture, format, args));
+            WriteLineImpl(level, string.Format(CultureInfo.CurrentCulture, format, args));
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)] // Disable inlining since logging is off by default, and we want to allow the public method to be inlined
-        private void WriteTextBlockImpl(string prefix, string textBlock)
+        private void WriteTextBlockImpl(LogLevel level, string prefix, string textBlock)
         {
             using (var reader = new StringReader(textBlock))
             {
@@ -192,9 +186,9 @@ private void WriteTextBlockImpl(string prefix, string textBlock)
                         break;
 
                     if (!string.IsNullOrEmpty(prefix))
-                        WriteLineImpl(prefix + line);
+                        WriteLineImpl(level, prefix + line);
                     else
-                        WriteLineImpl(line);
+                        WriteLineImpl(level, line);
                 }
             }
         }
diff --git a/src/MICore/MICore.csproj b/src/MICore/MICore.csproj
index 149488eba..abdc47283 100755
--- a/src/MICore/MICore.csproj
+++ b/src/MICore/MICore.csproj
@@ -65,7 +65,6 @@
   
   <ItemGroup>
     <None Include="LaunchOptions.xsd" />
-    <None Include="SetMIDebugLogging.cmd" />
     <ContentWithTargetPath Include="osxlaunchhelper.scpt">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <TargetPath>vscode\osxlaunchhelper.scpt</TargetPath>
diff --git a/src/MICore/MIResults.cs b/src/MICore/MIResults.cs
index 0e3a45704..0b8e4b9a2 100644
--- a/src/MICore/MIResults.cs
+++ b/src/MICore/MIResults.cs
@@ -9,6 +9,7 @@
 using System.Diagnostics;
 using System.Collections;
 using System.Globalization;
+using Microsoft.DebugEngineHost;
 
 namespace MICore
 {
@@ -1199,7 +1200,7 @@ private void ParseError(string message, Span input)
             string result = CreateErrorMessageFromSpan(input);
             Debug.Fail(message + ": " + result);
 
-            Logger?.WriteLine(String.Format(CultureInfo.CurrentCulture, "MI parsing error: {0}: \"{1}\"", message, result));
+            Logger?.WriteLine(LogLevel.Error, String.Format(CultureInfo.CurrentCulture, "MI parsing error: {0}: \"{1}\"", message, result));
 
         }
 
diff --git a/src/MICore/SetMIDebugLogging.cmd b/src/MICore/SetMIDebugLogging.cmd
deleted file mode 100644
index 23396aa7c..000000000
--- a/src/MICore/SetMIDebugLogging.cmd
+++ /dev/null
@@ -1,130 +0,0 @@
-@echo off
-setlocal
-
-if /i "%~1"=="" goto Help
-if /i "%~1"=="-?" goto Help
-if /i "%~1"=="/?" goto Help
-
-set LoggingValue=
-set Exp=0
-set ServerLogging=
-set VSRootDir=
-set MIEngineRelativeDir=Common7\IDE\CommonExtensions\Microsoft\MDD\Debugger
-set MIEngineRelativePath=%MIEngineRelativeDir%\Microsoft.MIDebugEngine.dll
-
-:ArgLoop
-if /i "%~1"=="on" set LoggingValue=1& goto ArgLoopCondition
-if /i "%~1"=="off" set LoggingValue=0& goto ArgLoopCondition
-if /i "%~1"=="/VSRootDir" goto SetVSRoot
-if /i "%~1"=="-VSRootDir" goto SetVSRoot
-if /i "%~1"=="-serverlogging" goto SetServerLogging
-if /i "%~1"=="/serverlogging" goto SetServerLogging
-echo ERROR: Unknown argument '%~1'& exit /b -1
-
-:SetVSRoot
-shift
-if "%~1"=="" echo ERROR: Expected version number.
-set VSRootDir=%~1
-if not exist "%VSRootDir%" echo ERROR: '/VSRootDir' value '%VSRootDir%' does not exist & exit /b -1
-if not exist "%VSRootDir%\%MIEngineRelativePath%" echo ERROR: '/VSRootDir' value '%VSRootDir%' does not contain MIEngine (%VSRootDir%\%MIEngineRelativePath%) & exit /b -1
-goto ArgLoopCondition
-
-:SetServerLogging
-REM Documentation on GDBServer command line arguments: http://www.sourceware.org/gdb/onlinedocs/gdb/Server.html
-set ServerLogging=--debug
-if /i "%~2"=="full" shift & set ServerLogging=--debug --remote-debug
-goto ArgLoopCondition
-
-:ArgLoopCondition
-shift
-if NOT "%~1"=="" goto :ArgLoop
-
-if "%LoggingValue%"=="" echo ERROR: 'on' or 'off' must be specified.& exit /b -1
-if /i NOT "%LoggingValue%"=="1" if NOT "%ServerLogging%"=="" echo ERROR: '/serverlogging' can only be used with 'on'& exit /b -1
-
-set SetLoggingError=
-if NOT "%VSRootDir%"=="" call :SetLogging "%VSRootDir%" & goto Done
-
-REM If '/VSRootDir' is NOT specified, try ALL the default locations
-set ProgRoot=%ProgramFiles(x86)%
-if "%ProgRoot%"=="" set ProgRoot=%ProgramFiles%
-set VSVersionFound=
-set MIEngineFound=
-call :TryVSPath "%ProgRoot%\Microsoft Visual Studio 14.0"
-call :TryVSPaths "%ProgRoot%\Microsoft Visual Studio\2017\*"
-if "%VSVersionFound%"=="" echo ERROR: Visual Studio 2015+ is not installed, or not installed to the default location. Use '/VSRootDir' to specify the directory. & exit /b -1
-if "%MIEngineFound%"=="" echo ERROR: The found version(s) of Visual Studio do not have the MIEngine installed. & exit /b -1
-goto Done
-
-:Done
-    echo.
-    if NOT "%SetLoggingError%"=="" exit /b -1
-    echo SetMIDebugLogging.cmd succeeded. Restart Visual Studio to take effect.
-    if "%LoggingValue%"=="1" echo Logging will be saved to %TMP%\Microsoft.MIDebug.log.
-    exit /b 0
-
-:TryVSPaths
-    for /d %%d in (%1) do call :TryVSPath "%%d"
-    goto :EOF
-
-:TryVSPath
-    REM Arg1: path to VS Root
-
-    if NOT "%SetLoggingError%"=="" goto :EOF
-    if not exist "%~1" goto :EOF
-    set VSVersionFound=1
-    if not exist "%~1\%MIEngineRelativePath%" goto :EOF
-    set MIEngineFound=1
-    goto SetLogging
-
-:SetLogging
-    REM Arg1: path to VS Root
-    set PkgDefFile=%~1\%MIEngineRelativeDir%\logging.pkgdef
-
-    if NOT exist "%PkgDefFile%" goto SetLogging_NoPkgDef
-        del "%PkgDefFile%"
-        if NOT exist "%PkgDefFile%" goto SetLogging_NoPkgDef
-        echo ERROR: Failed to remove "%PkgDefFile%". Ensure this script is run as an administrator.
-        set SetLoggingError=1
-        goto :EOF
-    :SetLogging_NoPkgDef
-
-    if "%LoggingValue%"=="0" goto UpdateConfiguration
-
-    :EnableLogging
-        echo [$RootKey$\Debugger]> "%PkgDefFile%"
-            if exist "%PkgDefFile%" goto EnableLogging_PkgDefCreated
-            echo ERROR: Failed to create "%PkgDefFile%". Ensure this script is run as an administrator.
-            set SetLoggingError=1
-            goto :EOF
-        :EnableLogging_PkgDefCreated
-
-        echo "EnableMIDebugLogger"=dword:00000001>> "%PkgDefFile%"
-        if NOT "%ServerLogging%"=="" echo "GDBServerLoggingArguments"="%ServerLogging%">> "%PkgDefFile%"
-
-    :UpdateConfiguration
-    echo Setting logging for %1
-    call "%~1\Common7\IDE\devenv.com" /updateconfiguration
-    if "%ERRORLEVEL%"=="0" goto :EOF
-    echo ERROR: '"%~1\Common7\IDE\devenv.com" /updateconfiguration' failed with error %ERRORLEVEL%. 
-    set SetLoggingError=1
-    goto :EOF
-
-:Help
-echo SetMIDebugLogging.cmd ^<on^|off^> [/serverlogging [full]] [/VSRootDir ^<value^>]
-echo.
-echo SetMIDebugLogging.cmd is used to enable/disable logging for the Microsoft
-echo MI debug engine.
-echo.
-echo Logging will be saved to %TMP%\Microsoft.MIDebug.log.
-echo.
-echo /serverlogging [full] Enables logging from gdbserver. This option is only 
-echo            supported when enabling logging ('on'). 'full' logging will
-echo            turn on packet logging in addition to normal logging.
-echo.
-echo /VSRootDir ^<value^> sets the path to the root of Visual Studio 
-echo            (ex: C:\Program Files (x86)\Microsoft Visual Studio 14.0). If not
-echo            specified, the default install directories for all versions of VS
-echo            2015+ will be used.
-echo.
-:eof
diff --git a/src/MICore/Transports/PipeTransport.cs b/src/MICore/Transports/PipeTransport.cs
index b71e53b26..e19b6b137 100644
--- a/src/MICore/Transports/PipeTransport.cs
+++ b/src/MICore/Transports/PipeTransport.cs
@@ -11,6 +11,7 @@
 using System.Threading.Tasks;
 using System.Globalization;
 using System.Runtime.InteropServices;
+using Microsoft.DebugEngineHost;
 
 namespace MICore
 {
@@ -369,7 +370,7 @@ public override int ExecuteSyncCommand(string commandDescription, string command
             Process proc = new Process();
             proc.StartInfo.FileName = _pipePath;
             proc.StartInfo.Arguments = PipeLaunchOptions.ReplaceDebuggerCommandToken(_cmdArgs, commandText, true);
-            Logger.WriteLine("Running process {0} {1}", proc.StartInfo.FileName, proc.StartInfo.Arguments);
+            Logger.WriteLine(LogLevel.Verbose, "Running process {0} {1}", proc.StartInfo.FileName, proc.StartInfo.Arguments);
             proc.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(_pipePath);
             proc.EnableRaisingEvents = false;
             proc.StartInfo.RedirectStandardInput = false;
diff --git a/src/MICore/Transports/RunInTerminalTransport.cs b/src/MICore/Transports/RunInTerminalTransport.cs
index f4fce7818..4418f105d 100644
--- a/src/MICore/Transports/RunInTerminalTransport.cs
+++ b/src/MICore/Transports/RunInTerminalTransport.cs
@@ -132,7 +132,7 @@ public override async void Init(ITransportCallback transportCallback, LaunchOpti
                     debuggerCmd,
                     localOptions.GetMiDebuggerArgs());
 
-                logger?.WriteTextBlock("DbgCmd:", launchDebuggerCommand);
+                logger?.WriteTextBlock(LogLevel.Verbose, "DbgCmd:", launchDebuggerCommand);
 
                 using (FileStream dbgCmdStream = new FileStream(dbgCmdScript, FileMode.CreateNew))
                 using (StreamWriter dbgCmdWriter = new StreamWriter(dbgCmdStream, encNoBom) { AutoFlush = true })
@@ -175,7 +175,7 @@ public override async void Init(ITransportCallback transportCallback, LaunchOpti
                          throw new InvalidOperationException(error);
                      },
                      logger);
-            logger?.WriteLine("Wait for connection completion.");
+            logger?.WriteLine(LogLevel.Verbose, "Wait for connection completion.");
 
             if (_waitForConnection != null)
             {
@@ -216,7 +216,7 @@ private void LogDebuggerErrors()
                     string line = this.GetLineFromStream(_errorStream, _streamReadPidCancellationTokenSource.Token);
                     if (line == null)
                         break;
-                    Logger?.WriteTextBlock("dbgerr:", line);
+                    Logger?.WriteTextBlock(LogLevel.Error, "dbgerr:", line);
                 }
             }
         }
@@ -244,7 +244,7 @@ private void LaunchSuccess(int? pid)
                 {
                     shellPid = int.Parse(readShellPidTask.Result, CultureInfo.InvariantCulture);
                     // Used for testing
-                    Logger?.WriteLine(string.Concat("ShellPid=", shellPid));
+                    Logger?.WriteLine(LogLevel.Verbose, string.Concat("ShellPid=", shellPid));
                 }
                 else
                 {
@@ -300,7 +300,7 @@ private void ShellExited(object sender, EventArgs e)
                 ((Process)sender).Exited -= ShellExited;
             }
 
-            Logger?.WriteLine("Shell exited, stop debugging");
+            Logger?.WriteLine(LogLevel.Verbose, "Shell exited, stop debugging");
             this.Callback.OnDebuggerProcessExit(null);
 
             Close();
diff --git a/src/MICore/Transports/StreamTransport.cs b/src/MICore/Transports/StreamTransport.cs
index 53618e5ab..9de2f3c32 100644
--- a/src/MICore/Transports/StreamTransport.cs
+++ b/src/MICore/Transports/StreamTransport.cs
@@ -71,7 +71,7 @@ private void TransportLoop()
                         break;
 
                     line = line.TrimEnd();
-                    Logger?.WriteLine("->" + line);
+                    Logger?.WriteLine(LogLevel.Verbose, "->" + line);
                     Logger?.Flush();
 
                     try
@@ -144,7 +144,7 @@ protected void Echo(string cmd)
         {
             if (!String.IsNullOrWhiteSpace(cmd))
             {
-                Logger?.WriteLine("<-" + cmd);
+                Logger?.WriteLine(LogLevel.Verbose, "<-" + cmd);
                 Logger?.Flush();
             }
 
diff --git a/src/MICore/Transports/UnixShellPortTransport.cs b/src/MICore/Transports/UnixShellPortTransport.cs
index c1801a13c..95cd72933 100644
--- a/src/MICore/Transports/UnixShellPortTransport.cs
+++ b/src/MICore/Transports/UnixShellPortTransport.cs
@@ -37,7 +37,7 @@ public KillCommandCallback(Logger logger)
 
             public void OnOutputLine(string line)
             {
-                _logger?.WriteLine("[kill] ->" + line);
+                _logger?.WriteLine(LogLevel.Verbose, "[kill] ->" + line);
             }
 
             public void OnExit(string exitCode)
@@ -74,7 +74,7 @@ public void Close()
 
         public void Send(string cmd)
         {
-            _logger?.WriteLine("<-" + cmd);
+            _logger?.WriteLine(LogLevel.Verbose, "<-" + cmd);
             _logger?.Flush();
             _asyncCommand.WriteLine(cmd);
         }
@@ -104,7 +104,7 @@ void IDebugUnixShellCommandCallback.OnOutputLine(string line)
                 _callback.OnStdOutLine(line);
             }
 
-            _logger?.WriteLine("->" + line);
+            _logger?.WriteLine(LogLevel.Verbose, "->" + line);
             _logger?.Flush();
         }
 
diff --git a/src/MICore/UnixUtilities.cs b/src/MICore/UnixUtilities.cs
index 6de8664f9..0496723aa 100644
--- a/src/MICore/UnixUtilities.cs
+++ b/src/MICore/UnixUtilities.cs
@@ -1,6 +1,7 @@
 // Copyright (c) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
+using Microsoft.DebugEngineHost;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -116,7 +117,7 @@ internal static string MakeFifo(string identifier = null, Logger logger = null)
             if (result != 0)
             {
                 // Failed to create the fifo. Bail.
-                logger?.WriteLine("Failed to create fifo");
+                logger?.WriteLine(LogLevel.Error, "Failed to create fifo");
                 throw new ArgumentException("MakeFifo failed to create fifo at path {0}", path);
             }
 
@@ -203,7 +204,7 @@ internal static void OutputNonEmptyString(string str, string prefix, Logger logg
         {
             if (!String.IsNullOrWhiteSpace(str) && logger != null)
             {
-                logger.WriteLine(prefix + str);
+                logger.WriteLine(LogLevel.Verbose, prefix + str);
             }
         }
 
diff --git a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs
index 0535572a6..ad050bd4f 100755
--- a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs
+++ b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs
@@ -189,7 +189,7 @@ public int Attach(IDebugProgram2[] portProgramArray, IDebugProgramNode2[] progra
         {
             Debug.Assert(_ad7ProgramId == Guid.Empty);
 
-            Logger.LoadMIDebugLogger(_configStore);
+            Logger.LoadMIDebugLogger();
 
             if (celtPrograms != 1)
             {
@@ -498,7 +498,7 @@ public int SetMetric(string pszMetric, object varValue)
         public int SetRegistryRoot(string registryRoot)
         {
             _configStore = new HostConfigurationStore(registryRoot);
-            Logger = Logger.EnsureInitialized(_configStore);
+            Logger = Logger.EnsureInitialized();
             return Constants.S_OK;
         }
 
@@ -539,7 +539,7 @@ int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, stri
             Debug.Assert(_ad7ProgramId == Guid.Empty);
 
             // Check if the logger was enabled late.
-            Logger.LoadMIDebugLogger(_configStore);
+            Logger.LoadMIDebugLogger();
 
             process = null;
 
diff --git a/src/MIDebugEngine/Engine.Impl/DebugUnixChildProcess.cs b/src/MIDebugEngine/Engine.Impl/DebugUnixChildProcess.cs
index b883c5d98..6c50d58f6 100644
--- a/src/MIDebugEngine/Engine.Impl/DebugUnixChildProcess.cs
+++ b/src/MIDebugEngine/Engine.Impl/DebugUnixChildProcess.cs
@@ -232,7 +232,7 @@ public async Task<bool> Stopped(Results results, int tid)
                     else
                     {
                         // sometimes gdb misses the breakpoint at exec and execution will proceed to a breakpoint in the child
-                        _process.Logger.WriteLine("Missed catching the exec after vfork. Spawning the child's debugger.");
+                        _process.Logger.WriteLine(LogLevel.Verbose, "Missed catching the exec after vfork. Spawning the child's debugger.");
                         s.State = State.AtExec;
                         goto missedExec;
                     }
diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedThread.cs b/src/MIDebugEngine/Engine.Impl/DebuggedThread.cs
index 4d9362de8..ff739b61e 100644
--- a/src/MIDebugEngine/Engine.Impl/DebuggedThread.cs
+++ b/src/MIDebugEngine/Engine.Impl/DebuggedThread.cs
@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
 using MICore;
+using Microsoft.DebugEngineHost;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -136,7 +137,7 @@ internal async Task<List<ThreadContext>> StackFrames(DebuggedThread thread)
             }
             catch (UnexpectedMIResultException)
             {
-                _debugger.Logger.WriteLine("Stack walk failed on thread: " + thread.TargetId);
+                _debugger.Logger.WriteLine(LogLevel.Error, "Stack walk failed on thread: " + thread.TargetId);
                 _stateChange = true;   // thread may have been deleted. Force a resync
             }
             lock (_threadList)
@@ -291,7 +292,7 @@ private async Task<List<ThreadContext>> WalkStack(DebuggedThread thread)
             TupleValue[] frameinfo = await _debugger.MICommandFactory.StackListFrames(thread.Id, 0, 1000);
             if (frameinfo == null)
             {
-                _debugger.Logger.WriteLine("Failed to get frame info");
+                _debugger.Logger.WriteLine(LogLevel.Error, "Failed to get frame info");
             }
             else
             {
diff --git a/src/MIDebugEngine/Engine.Impl/EngineCallback.cs b/src/MIDebugEngine/Engine.Impl/EngineCallback.cs
index d87a541e8..e009a3fa6 100644
--- a/src/MIDebugEngine/Engine.Impl/EngineCallback.cs
+++ b/src/MIDebugEngine/Engine.Impl/EngineCallback.cs
@@ -31,7 +31,7 @@ public void Send(IDebugEvent2 eventObject, string iidEvent, IDebugProgram2 progr
             Guid riidEvent = new Guid(iidEvent);
             if (!(eventObject is AD7OutputDebugStringEvent))
             {
-                _engine.Logger.WriteLine("Send Event {0}", eventObject.GetType().Name);
+                _engine.Logger.WriteLine(LogLevel.Verbose, "Send Event {0}", eventObject.GetType().Name);
             }
             EngineUtils.RequireOk(eventObject.GetAttributes(out attributes));
             EngineUtils.RequireOk(_eventCallback.Event(_engine, null, program, thread, eventObject, ref riidEvent, attributes));
diff --git a/src/MIDebugEngine/Natvis.Impl/Natvis.cs b/src/MIDebugEngine/Natvis.Impl/Natvis.cs
index 9927883c9..31f74fb6f 100755
--- a/src/MIDebugEngine/Natvis.Impl/Natvis.cs
+++ b/src/MIDebugEngine/Natvis.Impl/Natvis.cs
@@ -325,7 +325,7 @@ private bool LoadFile(string path)
                 XmlSerializer serializer = new XmlSerializer(typeof(AutoVisualizer));
                 if (!File.Exists(path))
                 {
-                    _process.WriteOutput(String.Format(CultureInfo.CurrentCulture, ResourceStrings.FileNotFound, path));
+                    _process.Logger.NatvisLogger?.WriteLine(LogLevel.Error, ResourceStrings.FileNotFound, path);
                     return false;
                 }
                 XmlReaderSettings settings = new XmlReaderSettings();
@@ -355,7 +355,7 @@ private bool LoadFile(string path)
                             if (o is VisualizerType)
                             {
                                 VisualizerType v = (VisualizerType)o;
-                                TypeName t = TypeName.Parse(v.Name, _process.Logger);
+                                TypeName t = TypeName.Parse(v.Name, _process.Logger.NatvisLogger);
                                 if (t != null)
                                 {
                                     lock (_typeVisualizers)
@@ -368,7 +368,7 @@ private bool LoadFile(string path)
                                 {
                                     foreach (var a in v.AlternativeType)
                                     {
-                                        t = TypeName.Parse(a.Name, _process.Logger);
+                                        t = TypeName.Parse(a.Name, _process.Logger.NatvisLogger);
                                         if (t != null)
                                         {
                                             lock (_typeVisualizers)
@@ -382,7 +382,7 @@ private bool LoadFile(string path)
                             else if (o is AliasType)
                             {
                                 AliasType a = (AliasType)o;
-                                TypeName t = TypeName.Parse(a.Name, _process.Logger);
+                                TypeName t = TypeName.Parse(a.Name, _process.Logger.NatvisLogger);
                                 if (t != null)
                                 {
                                     lock (_typeVisualizers)
@@ -406,7 +406,7 @@ private bool LoadFile(string path)
             catch (Exception exception)
             {
                 // don't allow natvis failures to stop debugging
-                _process.WriteOutput(String.Format(CultureInfo.CurrentCulture, ResourceStrings.ErrorReadingFile, exception.Message, path));
+                _process.Logger.NatvisLogger?.WriteLine(LogLevel.Error, ResourceStrings.ErrorReadingFile, exception.Message, path);
                 return false;
             }
         }
@@ -451,7 +451,7 @@ private bool LoadFile(string path)
             {
                 // don't allow natvis to mess up debugging
                 // eat any exceptions and return the variable's value
-                _process.Logger.WriteLine("natvis FormatDisplayString: " + e.Message);
+                _process.Logger.NatvisLogger?.WriteLine(LogLevel.Error, "FormatDisplayString: " + e.Message);
             }
             finally
             {
@@ -502,7 +502,7 @@ internal IVariableInformation[] Expand(IVariableInformation variable)
             }
             catch (Exception e)
             {
-                _process.Logger.WriteLine("natvis Expand: " + e.Message);    // TODO: add telemetry
+                _process.Logger.WriteLine(LogLevel.Error, "natvis Expand: " + e.Message);    // TODO: add telemetry
                 return variable.Children;
             }
         }
@@ -1135,7 +1135,7 @@ private VisualizerInfo Scan(TypeName name, IVariableInformation variable)
                     }
 
                     string newName = ReplaceNamesInExpression(alias.Alias.Value, null, scopedNames);
-                    name = TypeName.Parse(newName, _process.Logger);
+                    name = TypeName.Parse(newName, _process.Logger.NatvisLogger);
                     aliasChain++;
                     if (aliasChain > MAX_ALIAS_CHAIN)
                     {
@@ -1157,7 +1157,7 @@ private VisualizerInfo FindType(IVariableInformation variable)
             {
                 return _vizCache[variable.TypeName];
             }
-            TypeName parsedName = TypeName.Parse(variable.TypeName, _process.Logger);
+            TypeName parsedName = TypeName.Parse(variable.TypeName, _process.Logger.NatvisLogger);
             IVariableInformation var = variable;
             while (parsedName != null)
             {
@@ -1176,7 +1176,7 @@ private VisualizerInfo FindType(IVariableInformation variable)
                 {
                     break;
                 }
-                parsedName = TypeName.Parse(var.TypeName, _process.Logger);
+                parsedName = TypeName.Parse(var.TypeName, _process.Logger.NatvisLogger);
             }
             return null;
         }
diff --git a/src/MIDebugEngine/Natvis.Impl/NatvisNames.cs b/src/MIDebugEngine/Natvis.Impl/NatvisNames.cs
index 7c145a6d8..85972bdd8 100644
--- a/src/MIDebugEngine/Natvis.Impl/NatvisNames.cs
+++ b/src/MIDebugEngine/Natvis.Impl/NatvisNames.cs
@@ -9,6 +9,7 @@
 using System.Text.RegularExpressions;
 using MICore;
 using System.Globalization;
+using Microsoft.DebugEngineHost;
 
 namespace Microsoft.MIDebugEngine.Natvis
 {
@@ -138,7 +139,7 @@ public bool Match(TypeName t)
         /// </summary>
         /// <param name="fullyQualifiedName"></param>
         /// <returns></returns>
-        public static TypeName Parse(string fullyQualifiedName, ILogger logger)
+        public static TypeName Parse(string fullyQualifiedName, ILogChannel logger)
         {
             if (String.IsNullOrEmpty(fullyQualifiedName))
                 return null;
@@ -146,7 +147,7 @@ public static TypeName Parse(string fullyQualifiedName, ILogger logger)
             TypeName t = MatchTypeName(fullyQualifiedName.Trim(), out rest);
             if (!String.IsNullOrWhiteSpace(rest))
             {
-                logger.WriteLine("Natvis failed to parse typename: {0}", fullyQualifiedName);
+                logger.WriteLine(LogLevel.Error, "Natvis failed to parse typename: {0}", fullyQualifiedName);
                 return null;
             }
             return t;
diff --git a/src/MIDebugEngineUnitTests/NatvisNamesTest.cs b/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
index a59dfc1bd..027dfdfad 100644
--- a/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
+++ b/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
@@ -4,10 +4,11 @@
 using MICore;
 using Xunit.Abstractions;
 using System.Globalization;
+using Microsoft.DebugEngineHost;
 
 namespace MIDebugEngineUnitTests
 {
-    class TestLogger : ILogger
+    class TestLogger : ILogChannel
     {
         private static TestLogger s_instance;
 
@@ -26,22 +27,26 @@ public static TestLogger Instance
 
         private ITestOutputHelper _output;
 
-        private TestLogger() {}
-
         internal void RegisterTestOutputHelper(ITestOutputHelper output)
         {
             _output = output;
         }
 
-        public void WriteLine(string line)
+        public void WriteLine(LogLevel level, string line)
         {
             _output?.WriteLine(line);
         }
 
-        public void WriteLine(string format, params object[] args)
+        public void WriteLine(LogLevel level, string format, params object[] args)
         {
             _output?.WriteLine(string.Format(CultureInfo.InvariantCulture, format, args));
         }
+
+        // Unused as ITestOutputHelper does not have a Flush implementation
+        public void Flush() { }
+
+        // Unused as ITestOutputHelper does not have a Close implementation
+        public void Close() { }
     }
 
     public class NatvisNamesTest
diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs
index 425061684..a9126074f 100644
--- a/src/OpenDebugAD7/AD7DebugSession.cs
+++ b/src/OpenDebugAD7/AD7DebugSession.cs
@@ -215,17 +215,38 @@ private void SetCommonDebugSettings(Dictionary<string, JToken> args)
 
             if (logging != null)
             {
+                HostLogger.Reset();
+
                 m_logger.SetLoggingConfiguration(LoggingCategory.Exception, logging.GetValueAsBool("exceptions").GetValueOrDefault(true));
                 m_logger.SetLoggingConfiguration(LoggingCategory.Module, logging.GetValueAsBool("moduleLoad").GetValueOrDefault(true));
                 m_logger.SetLoggingConfiguration(LoggingCategory.StdOut, logging.GetValueAsBool("programOutput").GetValueOrDefault(true));
                 m_logger.SetLoggingConfiguration(LoggingCategory.StdErr, logging.GetValueAsBool("programOutput").GetValueOrDefault(true));
 
-                bool? engineLogging = logging.GetValueAsBool("engineLogging");
-                if (engineLogging.HasValue)
+                JToken engineLogging = logging.GetValue("engineLogging", StringComparison.OrdinalIgnoreCase);
+                if (engineLogging != null)
                 {
-                    m_logger.SetLoggingConfiguration(LoggingCategory.EngineLogging, engineLogging.Value);
-                    HostLogger.EnableHostLogging();
-                    HostLogger.Instance.LogCallback = s => m_logger.WriteLine(LoggingCategory.EngineLogging, s);
+                    if (engineLogging.Type == JTokenType.Boolean)
+                    {
+                        bool engineLoggingBool = engineLogging.Value<bool>();
+                        if (engineLoggingBool)
+                        {
+                            m_logger.SetLoggingConfiguration(LoggingCategory.EngineLogging, true);
+                            HostLogger.EnableHostLogging((message) => m_logger.WriteLine(LoggingCategory.EngineLogging, message), LogLevel.Verbose);
+                        }
+                    }
+                    else if (engineLogging.Type == JTokenType.String)
+                    {
+                        string engineLoggingString = engineLogging.Value<string>();
+                        if (Enum.TryParse(engineLoggingString, ignoreCase: true, out LogLevel level))
+                        {
+                            m_logger.SetLoggingConfiguration(LoggingCategory.EngineLogging, true);
+                            HostLogger.EnableHostLogging((message) => m_logger.WriteLine(LoggingCategory.EngineLogging, message), level);
+                        }
+                    }
+                    else
+                    {
+                        m_logger.WriteLine(LoggingCategory.EngineLogging, string.Format(CultureInfo.CurrentCulture, AD7Resources.Warning_EngineLoggingParse, engineLogging.ToString()));
+                    }
                 }
 
                 bool? trace = logging.GetValueAsBool("trace");
@@ -239,6 +260,33 @@ private void SetCommonDebugSettings(Dictionary<string, JToken> args)
                 {
                     m_logger.SetLoggingConfiguration(LoggingCategory.AdapterResponse, traceResponse.Value);
                 }
+
+                JToken natvisDiagnostics = logging.GetValue("natvisDiagnostics", StringComparison.OrdinalIgnoreCase);
+                if (natvisDiagnostics != null)
+                {
+                    if (natvisDiagnostics.Type == JTokenType.Boolean)
+                    {
+                        bool natvisDiagnosticsBool = natvisDiagnostics.Value<bool>();
+                        if (natvisDiagnosticsBool)
+                        {
+                            m_logger.SetLoggingConfiguration(LoggingCategory.NatvisDiagnostics, true);
+                            HostLogger.EnableNatvisLogger((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, message), LogLevel.Verbose);
+                        }
+                    }
+                    else if (natvisDiagnostics.Type == JTokenType.String)
+                    {
+                        string natvisDiagnosticsString = natvisDiagnostics.Value<string>();
+                        if (Enum.TryParse(natvisDiagnosticsString, ignoreCase: true, out LogLevel level))
+                        {
+                            m_logger.SetLoggingConfiguration(LoggingCategory.NatvisDiagnostics, true);
+                            HostLogger.EnableNatvisLogger((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, string.Concat("[Natvis] ", message)), level);
+                        }
+                    }
+                    else
+                    {
+                        m_logger.WriteLine(LoggingCategory.EngineLogging, string.Format(CultureInfo.CurrentCulture, AD7Resources.Warning_NatvisLoggingParse, natvisDiagnostics.ToString()));
+                    }
+                }
             }
         }
 
diff --git a/src/OpenDebugAD7/AD7Resources.Designer.cs b/src/OpenDebugAD7/AD7Resources.Designer.cs
index eea617771..abb7d62bf 100644
--- a/src/OpenDebugAD7/AD7Resources.Designer.cs
+++ b/src/OpenDebugAD7/AD7Resources.Designer.cs
@@ -632,6 +632,15 @@ internal static string Registers_Scope_Name {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Failed to parse engine logging setting: &apos;{0}&apos;.
+        /// </summary>
+        internal static string Warning_EngineLoggingParse {
+            get {
+                return ResourceManager.GetString("Warning_EngineLoggingParse", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Could not detect launch url..
         /// </summary>
@@ -650,6 +659,15 @@ internal static string Warning_LaunchBrowserFailed {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Failed to parse Nativs logging setting: &apos;{0}&apos;.
+        /// </summary>
+        internal static string Warning_NatvisLoggingParse {
+            get {
+                return ResourceManager.GetString("Warning_NatvisLoggingParse", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to WARNING: Unable to terminate &apos;{0}&apos; process. {1}
         ///.
diff --git a/src/OpenDebugAD7/AD7Resources.resx b/src/OpenDebugAD7/AD7Resources.resx
index 60be8f97f..e50d73343 100644
--- a/src/OpenDebugAD7/AD7Resources.resx
+++ b/src/OpenDebugAD7/AD7Resources.resx
@@ -338,4 +338,12 @@
   <data name="Error_InvalidStackFrameOnEvaluateExpression" xml:space="preserve">
     <value>Cannot evaluate expression on the specified stack frame.</value>
   </data>
+  <data name="Warning_EngineLoggingParse" xml:space="preserve">
+    <value>Failed to parse engine logging setting: '{0}'</value>
+    <comment>{0} is the string passed in by the user</comment>
+  </data>
+  <data name="Warning_NatvisLoggingParse" xml:space="preserve">
+    <value>Failed to parse Nativs logging setting: '{0}'</value>
+    <comment>{0} is the string passed in by the user</comment>
+  </data>
 </root>
\ No newline at end of file
diff --git a/src/OpenDebugAD7/DebugEventLogger.cs b/src/OpenDebugAD7/DebugEventLogger.cs
index 45ef9c66d..612039b97 100644
--- a/src/OpenDebugAD7/DebugEventLogger.cs
+++ b/src/OpenDebugAD7/DebugEventLogger.cs
@@ -35,6 +35,8 @@ internal enum LoggingCategory
         Module,
         /// <summary>Process exit message.</summary>
         ProcessExit,
+        /// <summary>Natvis Diagnostic Messages</summary>
+        NatvisDiagnostics
     }
 
     /// <summary>Logging class to handle when and how various classes of output should be logged.</summary>
diff --git a/src/OpenDebugAD7/OpenDebug/Program.cs b/src/OpenDebugAD7/OpenDebug/Program.cs
index 875a91fd4..7106c36f4 100644
--- a/src/OpenDebugAD7/OpenDebug/Program.cs
+++ b/src/OpenDebugAD7/OpenDebug/Program.cs
@@ -27,6 +27,9 @@ private static int Main(string[] argv)
         {
             int port = -1;
             List<LoggingCategory> loggingCategories = new List<LoggingCategory>();
+            bool enableEngineLogger = false;
+            LogLevel level = LogLevel.Verbose;
+            string logFilePath = string.Empty;
 
             // parse command line arguments
             foreach (var a in argv)
@@ -49,6 +52,10 @@ private static int Main(string[] argv)
                         Console.WriteLine("--trace=response: print requests and response from VS Code to the console.");
                         Console.WriteLine("--engineLogging[=filePath]: Enable logging from the debug engine. If not");
                         Console.WriteLine("    specified, the log will go to the console.");
+                        Console.WriteLine("--engineLogLevel=<LogLevel>: Set's the log level for engine logging.");
+                        Console.WriteLine("    If not specified, default log level is LogLevel.Trace");
+                        Console.WriteLine("--natvisDiagnostics[=logLevel]: Enable logging for natvis. If not");
+                        Console.WriteLine("    specified, the log will go to the console. Default logging level is LogLevel.Trace.");
                         Console.WriteLine("--server[=port_num] : Start the debug adapter listening for requests on the");
                         Console.WriteLine("    specified TCP/IP port instead of stdin/out. If port is not specified");
                         Console.WriteLine("    TCP {0} will be used.", DEFAULT_PORT);
@@ -64,8 +71,14 @@ private static int Main(string[] argv)
                         loggingCategories.Add(LoggingCategory.AdapterResponse);
                         break;
                     case "--engineLogging":
-                        loggingCategories.Add(LoggingCategory.EngineLogging);
-                        HostLogger.EnableHostLogging();
+                        enableEngineLogger = true;
+                        break;
+                    case "--natvisDiagnostics":
+                        loggingCategories.Add(LoggingCategory.NatvisDiagnostics);
+                        HostLogger.EnableNatvisLogger((msg) =>
+                        {
+                            Console.Error.WriteLine(msg);
+                        }, LogLevel.Verbose);
                         break;
                     case "--server":
                         port = DEFAULT_PORT;
@@ -87,17 +100,28 @@ private static int Main(string[] argv)
                                 return -1;
                             }
                         }
-                        else if (a.StartsWith("--engineLogging=", StringComparison.Ordinal))
+                        else if (a.StartsWith("--natvisDiagnostics=", StringComparison.Ordinal))
                         {
-                            HostLogger.EnableHostLogging();
-                            try
+                            if (!Enum.TryParse(a.Substring("--natvisDiagnostics=".Length), out LogLevel natvisLogLevel))
                             {
-                                HostLogger.Instance.LogFilePath = a.Substring("--engineLogging=".Length);
+                                loggingCategories.Add(LoggingCategory.NatvisDiagnostics);
+                                HostLogger.EnableNatvisLogger((msg) =>
+                                {
+                                    Console.Error.WriteLine(msg);
+                                }, natvisLogLevel);
                             }
-                            catch (Exception e)
+                        }
+                        else if (a.StartsWith("--engineLogging=", StringComparison.Ordinal))
+                        {
+                            enableEngineLogger = true;
+                            logFilePath = a.Substring("--engineLogging=".Length);
+                            HostLogger.SetEngineLogFile(logFilePath);
+                        }
+                        else if (a.StartsWith("--engineLogLevel=", StringComparison.Ordinal))
+                        {
+                            if (!Enum.TryParse(a.Substring("--engineLogLevel=".Length), out level))
                             {
-                                Console.Error.WriteLine("OpenDebugAD7: ERROR: Unable to open log file. " + e.Message);
-                                return -1;
+                                level = LogLevel.Verbose;
                             }
                         }
                         else if (a.StartsWith("--adapterDirectory=", StringComparison.Ordinal))
@@ -119,6 +143,23 @@ private static int Main(string[] argv)
                 }
             }
 
+            if (enableEngineLogger)
+            {
+                loggingCategories.Add(LoggingCategory.EngineLogging);
+                try
+                {
+                    HostLogger.EnableHostLogging((msg) =>
+                    {
+                        Console.Error.WriteLine(msg);
+                    }, level);
+                }
+                catch (Exception e)
+                {
+                    Console.Error.WriteLine("OpenDebugAD7: ERROR: Unable to open log file. " + e.Message);
+                    return -1;
+                }
+            }
+
             if (port > 0)
             {
                 // TCP/IP server
diff --git a/src/OpenDebugAD7/OpenDebug/Utilities.cs b/src/OpenDebugAD7/OpenDebug/Utilities.cs
index 39f44b116..d2d0d39a6 100644
--- a/src/OpenDebugAD7/OpenDebug/Utilities.cs
+++ b/src/OpenDebugAD7/OpenDebug/Utilities.cs
@@ -336,7 +336,7 @@ public static void ReportException(Exception e)
             try
             {
                 HostTelemetry.ReportCurrentException(e, null);
-                Logger.WriteLine("EXCEPTION: " + e.ToString());
+                HostLogger.GetEngineLogChannel()?.WriteLine(LogLevel.Error, "EXCEPTION: " + e.ToString());
             }
             catch
             {

From b20b747a715a6b07aafc3a2429609d5e7449b3f1 Mon Sep 17 00:00:00 2001
From: Andrew Wang <waan@microsoft.com>
Date: Mon, 10 Oct 2022 12:49:36 -0700
Subject: [PATCH 4/4] Enable NatvisDiagnostics for VS Debug Option (#1357)

* Enable NatvisDiagnostics for VS Debug Option

This PR enables Natvis Diagnostics for VS.
If the NatvisDiagnostics in the VS Debug Options is enabled, it will
output to the debug pane.
---
 src/DebugEngineHost.Common/HostLogChannel.cs  |   2 +
 .../DebugEngineHost.ref.cs                    |  27 ++-
 src/DebugEngineHost.VSCode/HostLogger.cs      |   2 +-
 .../HostNatvisProject.cs                      |   6 +
 .../HostConfigurationSection.cs               |   3 +
 src/DebugEngineHost/HostConfigurationStore.cs |  45 +++++
 src/DebugEngineHost/HostLogger.cs             |  13 ++
 src/DebugEngineHost/HostNatvisProject.cs      | 124 ++++++++++++++
 src/DebugEngineHost/HostOutputWindow.cs       | 157 ++++++++++++++----
 src/DebugEngineHost/RegistryMonitor.cs        | 145 ++++++++++++++++
 src/DebugEngineHost/Resource.Designer.cs      |  11 +-
 src/DebugEngineHost/Resource.resx             |   4 +
 src/MICore/Logger.cs                          |   5 +
 .../Engine.Impl/DebuggedProcess.cs            |   4 +-
 src/MIDebugEngine/Natvis.Impl/Natvis.cs       |  16 +-
 src/MIDebugEngineUnitTests/NatvisNamesTest.cs |   3 +
 src/OpenDebugAD7/AD7DebugSession.cs           |   4 +-
 src/OpenDebugAD7/OpenDebug/Program.cs         |   8 +-
 18 files changed, 537 insertions(+), 42 deletions(-)
 create mode 100644 src/DebugEngineHost/RegistryMonitor.cs

diff --git a/src/DebugEngineHost.Common/HostLogChannel.cs b/src/DebugEngineHost.Common/HostLogChannel.cs
index 1c3a2bab7..14bdc1b57 100644
--- a/src/DebugEngineHost.Common/HostLogChannel.cs
+++ b/src/DebugEngineHost.Common/HostLogChannel.cs
@@ -37,6 +37,8 @@ public enum LogLevel
     // This must match the interface in DebugEngineHost.ref.cs
     public interface ILogChannel
     {
+        void SetLogLevel(LogLevel level);
+
         void WriteLine(LogLevel level, string message);
 
         void WriteLine(LogLevel level, string format, params object[] values);
diff --git a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
index b4ebb6124..9b42b62e0 100644
--- a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
+++ b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs
@@ -217,6 +217,12 @@ public enum LogLevel
     /// </summary>
     public interface ILogChannel
     {
+        /// <summary>
+        /// Changes the log level of the channel
+        /// </summary>
+        /// <param name="newLevel">The new log level to use.</param>
+        void SetLogLevel(LogLevel newLevel);
+
         /// <summary>
         /// Writes the given message with a newline to the log channel.
         /// </summary>
@@ -248,8 +254,6 @@ public interface ILogChannel
     /// </summary>
     public static class HostLogger
     {
-        // EnableNatvisLogger is only used in OpenDebugAD7
-
         /// <summary>
         /// Enables engine logging if not already enabled.
         /// </summary>
@@ -260,6 +264,16 @@ public static void EnableHostLogging(Action<string> callback, LogLevel level = L
             throw new NotImplementedException();
         }
 
+        /// <summary>
+        /// Enables natvis logging if not already enabled.
+        /// </summary>
+        /// <param name="callback">The callback to use to send the natvis log.</param>
+        /// <param name="level">The level of the log to filter the channel on.</param>
+        public static void EnableNatvisDiagnostics(Action<string> callback, LogLevel level = LogLevel.Verbose)
+        {
+            throw new NotImplementedException();
+        }
+
         /// <summary>
         /// Sets the log file to write to.
         /// </summary>
@@ -269,7 +283,6 @@ public static void SetEngineLogFile(string logFile)
             throw new NotImplementedException();
         }
 
-
         /// <summary>
         /// Gets the engine log channel created by 'EnableHostLogging'
         /// </summary>
@@ -439,6 +452,14 @@ public static void FindNatvis(NatvisLoader loader)
             throw new NotImplementedException();
         }
 
+        /// <summary>
+        /// Enable's tracking the VS 'Natvis Diagnostic Messages (C++ only)' setting.
+        /// </summary>
+        public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger)
+        {
+            throw new NotImplementedException();
+        }
+
         /// <summary>
         /// Return the solution's root directory, null if no solution
         /// </summary>
diff --git a/src/DebugEngineHost.VSCode/HostLogger.cs b/src/DebugEngineHost.VSCode/HostLogger.cs
index 5eda359e8..6723a4aee 100644
--- a/src/DebugEngineHost.VSCode/HostLogger.cs
+++ b/src/DebugEngineHost.VSCode/HostLogger.cs
@@ -12,7 +12,7 @@ public static class HostLogger
 
         private static string s_engineLogFile;
 
-        public static void EnableNatvisLogger(Action<string> callback, LogLevel level = LogLevel.Verbose)
+        public static void EnableNatvisDiagnostics(Action<string> callback, LogLevel level = LogLevel.Verbose)
         {
             if (s_natvisLogChannel == null)
             {
diff --git a/src/DebugEngineHost.VSCode/HostNatvisProject.cs b/src/DebugEngineHost.VSCode/HostNatvisProject.cs
index 7456f3b1d..e24c4f812 100644
--- a/src/DebugEngineHost.VSCode/HostNatvisProject.cs
+++ b/src/DebugEngineHost.VSCode/HostNatvisProject.cs
@@ -14,6 +14,12 @@ public static void FindNatvis(NatvisLoader loader)
             // In-solution natvis is not supported for VS Code now, so do nothing.
         }
 
+        public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger)
+        {
+            // VS Code does not have a registry setting for Natvis Diagnostics
+            return null;
+        }
+
         public static string FindSolutionRoot()
         {
             // This was added in MIEngine to support breakpoint sourcefile mapping. 
diff --git a/src/DebugEngineHost/HostConfigurationSection.cs b/src/DebugEngineHost/HostConfigurationSection.cs
index c076e8e18..7f3f3f402 100644
--- a/src/DebugEngineHost/HostConfigurationSection.cs
+++ b/src/DebugEngineHost/HostConfigurationSection.cs
@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
 using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -42,5 +43,7 @@ public IEnumerable<string> GetValueNames()
         {
             return _key.GetValueNames();
         }
+
+        public SafeRegistryHandle Handle => _key.Handle;
     }
 }
diff --git a/src/DebugEngineHost/HostConfigurationStore.cs b/src/DebugEngineHost/HostConfigurationStore.cs
index 37a700617..1f491a3d9 100644
--- a/src/DebugEngineHost/HostConfigurationStore.cs
+++ b/src/DebugEngineHost/HostConfigurationStore.cs
@@ -8,8 +8,10 @@
 using System.Globalization;
 using System.IO;
 using System.Linq;
+using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading.Tasks;
+using static Microsoft.VisualStudio.Shell.RegistrationAttribute;
 
 namespace Microsoft.DebugEngineHost
 {
@@ -17,9 +19,12 @@ public sealed class HostConfigurationStore
     {
         private const string DebuggerSectionName = "Debugger";
         private const string LaunchersSectionName = "MILaunchers";
+        private const string NatvisDiagnosticsSectionName = "NatvisDiagnostics";
 
         private string _engineId;
         private string _registryRoot;
+
+        // HKLM RegistryKey
         private RegistryKey _configKey;
 
         public HostConfigurationStore(string registryRoot)
@@ -131,5 +136,45 @@ private object GetOptionalValue(string section, string valueName)
                 return key.GetValue(valueName);
             }
         }
+
+        /// <summary>
+        /// This method grabs the Debugger Subkey in HKCU
+        /// </summary>
+        /// <returns>The subkey of Debugger if it exists. Returns null otherwise.</returns>
+        public HostConfigurationSection GetCurrentUserDebuggerSection()
+        {
+            using (RegistryKey hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot))
+            {
+                RegistryKey debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName);
+                if (debuggerSection != null)
+                {
+                    return new HostConfigurationSection(debuggerSection);
+                }
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Grabs the Debugger/NatvisDiagnostic subkey in HKCU
+        /// </summary>
+        /// <returns>The NatvisDiagnostic subkey if it exists. Returns null otherwise.</returns>
+        public HostConfigurationSection GetNatvisDiagnosticSection()
+        {
+            using (RegistryKey hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot))
+            {
+                using (RegistryKey debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName))
+                {
+                    if (debuggerSection != null)
+                    {
+                        RegistryKey natvisDiagnosticKey = debuggerSection.OpenSubKey(NatvisDiagnosticsSectionName);
+                        if (natvisDiagnosticKey != null)
+                        {
+                            return new HostConfigurationSection(natvisDiagnosticKey);
+                        }
+                    }
+                }
+            }
+            return null;
+        }
     }
 }
diff --git a/src/DebugEngineHost/HostLogger.cs b/src/DebugEngineHost/HostLogger.cs
index 413c0157f..9ce19cf22 100644
--- a/src/DebugEngineHost/HostLogger.cs
+++ b/src/DebugEngineHost/HostLogger.cs
@@ -24,6 +24,19 @@ public static void EnableHostLogging(Action<string> callback, LogLevel level = L
             }
         }
 
+        public static void EnableNatvisDiagnostics(Action<string> callback, LogLevel level = LogLevel.Verbose)
+        {
+            if (s_natvisLogChannel== null)
+            {
+                s_natvisLogChannel = new HostLogChannel(callback, null, level);
+            }
+        }
+
+        public static void DisableNatvisDiagnostics()
+        {
+            s_natvisLogChannel = null;
+        }
+
         public static void SetEngineLogFile(string logFile)
         {
             s_engineLogFile = logFile;
diff --git a/src/DebugEngineHost/HostNatvisProject.cs b/src/DebugEngineHost/HostNatvisProject.cs
index 5ccf3974d..4c969b652 100644
--- a/src/DebugEngineHost/HostNatvisProject.cs
+++ b/src/DebugEngineHost/HostNatvisProject.cs
@@ -18,9 +18,26 @@
 using Microsoft.VisualStudio.Workspace;
 using Microsoft.VisualStudio.Workspace.Indexing;
 using Microsoft.VisualStudio.Workspace.VSIntegration.Contracts;
+using Microsoft.Win32;
 
 namespace Microsoft.DebugEngineHost
 {
+    internal class RegisterMonitorWrapper : IDisposable
+    {
+        public RegistryMonitor CurrentMonitor { get; set; }
+
+        internal RegisterMonitorWrapper(RegistryMonitor currentMonitor)
+        {
+            CurrentMonitor = currentMonitor;
+        }
+
+        public void Dispose()
+        {
+            CurrentMonitor.Dispose();
+            CurrentMonitor = null;
+        }
+    }
+
     /// <summary>
     /// Provides interactions with the host's source workspace to locate and load any natvis files
     /// in the project.
@@ -49,6 +66,113 @@ public static void FindNatvis(NatvisLoader loader)
             paths.ForEach((s) => loader(s));
         }
 
+        public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger)
+        {
+            RegisterMonitorWrapper rmw = null;
+
+            HostConfigurationSection natvisDiagnosticSection = configStore.GetNatvisDiagnosticSection();
+            if (natvisDiagnosticSection != null)
+            {
+                // DiagnosticSection exists, set current log level and watch for changes.
+                SetNatvisLogLevel(natvisDiagnosticSection);
+
+                rmw = new RegisterMonitorWrapper(CreateAndStartNatvisDiagnosticMonitor(natvisDiagnosticSection, natvisLogger));
+            }
+            else
+            {
+                // NatvisDiagnostic section has not been created, we need to watch for the creation.
+                HostConfigurationSection debuggerSection = configStore.GetCurrentUserDebuggerSection();
+
+                if (debuggerSection != null)
+                {
+                    // We only care about the debugger subkey's keys since we are waiting for the NatvisDiagnostics
+                    // section to be created.
+                    RegistryMonitor rm = new RegistryMonitor(debuggerSection, false, natvisLogger);
+
+                    rmw = new RegisterMonitorWrapper(rm);
+
+                    rm.RegChanged += (sender, e) =>
+                    {
+                        HostConfigurationSection checkForSection = configStore.GetNatvisDiagnosticSection();
+
+                        if (checkForSection != null)
+                        {
+                            // NatvisDiagnostic section found. Update the logger
+                            SetNatvisLogLevel(checkForSection);
+
+                            // Remove debugger section tracking 
+                            IDisposable disposable = rmw.CurrentMonitor;
+
+                            // Watch NatvisDiagnostic section
+                            rmw = new RegisterMonitorWrapper(CreateAndStartNatvisDiagnosticMonitor(natvisDiagnosticSection, natvisLogger));
+
+                            disposable.Dispose();
+                        }
+                    };
+
+                    rm.Start();
+                }
+            }
+
+
+            return rmw;
+        }
+
+        private static RegistryMonitor CreateAndStartNatvisDiagnosticMonitor(HostConfigurationSection natvisDiagnosticSection, ILogChannel natvisLogger)
+        {
+            RegistryMonitor rm = new RegistryMonitor(natvisDiagnosticSection, true, natvisLogger);
+
+            rm.RegChanged += (sender, e) =>
+            {
+                SetNatvisLogLevel(natvisDiagnosticSection);
+            };
+
+            rm.Start();
+
+            return rm;
+        }
+
+        private static void SetNatvisLogLevel(HostConfigurationSection natvisDiagnosticSection)
+        {
+            string level = natvisDiagnosticSection.GetValue("Level") as string;
+            if (level != null)
+            {
+                level = level.ToLower(CultureInfo.InvariantCulture);
+            }
+            LogLevel logLevel;
+            switch (level)
+            {
+                case "off":
+                    logLevel = LogLevel.None;
+                    break;
+                case "error":
+                    logLevel = LogLevel.Error;
+                    break;
+                case "warning":
+                    logLevel = LogLevel.Warning;
+                    break;
+                case "verbose":
+                    logLevel = LogLevel.Verbose;
+                    break;
+                default: // Unknown, default to Warning
+                    logLevel = LogLevel.Warning;
+                    break;
+            }
+
+            if (logLevel == LogLevel.None)
+            {
+                HostLogger.DisableNatvisDiagnostics();
+            }
+            else
+            {
+                HostLogger.EnableNatvisDiagnostics((message) => {
+                    string formattedMessage = string.Format(CultureInfo.InvariantCulture, "Natvis: {0}", message);
+                    HostOutputWindow.WriteLaunchError(formattedMessage);
+                }, logLevel);
+                HostLogger.GetNatvisLogChannel().SetLogLevel(logLevel);
+            }
+        }
+
         public static string FindSolutionRoot()
         {
             string path = null;
diff --git a/src/DebugEngineHost/HostOutputWindow.cs b/src/DebugEngineHost/HostOutputWindow.cs
index e1136f04b..1d2b63632 100644
--- a/src/DebugEngineHost/HostOutputWindow.cs
+++ b/src/DebugEngineHost/HostOutputWindow.cs
@@ -2,13 +2,139 @@
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
 using System;
-
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
 
 namespace Microsoft.DebugEngineHost
 {
+    internal static class VsOutputWindowWrapper
+    {
+        private static Lazy<IVsOutputWindow> outputWindowLazy = new Lazy<IVsOutputWindow>(() =>
+        {
+            IVsOutputWindow outputWindow = null;
+            try
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                outputWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
+            }
+            catch (Exception)
+            {
+                Debug.Fail("Could not get OutputWindow service.");
+            }
+            return outputWindow;
+        }, LazyThreadSafetyMode.PublicationOnly);
+
+        private static Lazy<IVsUIShell> shellLazy = new Lazy<IVsUIShell>(() =>
+        {
+            IVsUIShell shell = null;
+            try
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                shell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell;
+            }
+            catch (Exception)
+            {
+                Debug.Fail("Could not get VSShell service.");
+            }
+            return shell;
+            // Use "PublicationOnly", because the implementation of GetService does its own locking
+        }, LazyThreadSafetyMode.PublicationOnly);
+
+        private class PaneInfo
+        {
+            public PaneInfo(Guid paneId)
+            {
+                this.paneId = paneId;
+                this.Shown = false;
+            }
+
+            internal Guid paneId;
+            internal bool Shown { get; set; }
+        }
+
+        private const string DefaultOutputPane = "Debug";
+
+        private static Dictionary<string, PaneInfo> panes = new Dictionary<string, PaneInfo>()
+        {
+            // The 'Debug' pane exists by default
+            { DefaultOutputPane, new PaneInfo(VSConstants.GUID_OutWindowDebugPane) }
+        };
+
+        /// <summary>
+        /// Writes text directly to the VS Output window.
+        /// </summary>
+        public static void Write(string message, string pane = DefaultOutputPane)
+        {
+            ThreadHelper.JoinableTaskFactory.RunAsync(async delegate
+            {
+                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                try
+                {
+                    // Get the Output window
+                    IVsOutputWindow outputWindow = outputWindowLazy.Value;
+                    if (outputWindow == null)
+                    {
+                        return;
+                    }
+
+                    // Get the pane guid
+                    PaneInfo paneInfo;
+                    if (!panes.TryGetValue(pane, out paneInfo))
+                    {
+                        // Pane didn't exist, create it
+                        paneInfo = new PaneInfo(Guid.NewGuid());
+                        panes.Add(pane, paneInfo);
+                    }
+
+                    // Get the pane
+                    IVsOutputWindowPane outputPane;
+                    if (outputWindow.GetPane(ref paneInfo.paneId, out outputPane) != VSConstants.S_OK)
+                    {
+                        // Failed to get the pane - might need to create it first
+                        outputWindow.CreatePane(ref paneInfo.paneId, pane, fInitVisible: 1, fClearWithSolution: 1);
+                        outputWindow.GetPane(ref paneInfo.paneId, out outputPane);
+                    }
+
+                    // The first time we output text to a pane, ensure it's visible
+                    if (!paneInfo.Shown)
+                    {
+                        paneInfo.Shown = true;
+
+                        // Switch to the pane of the Output window
+                        outputPane.Activate();
+
+                        // Show the output window
+                        IVsUIShell shell = shellLazy.Value;
+                        if (shell != null)
+                        {
+                            object inputVariant = null;
+                            shell.PostExecCommand(VSConstants.GUID_VSStandardCommandSet97, (uint)VSConstants.VSStd97CmdID.OutputWindow, 0, ref inputVariant);
+                        }
+                    }
+
+                    // Output the text
+                    outputPane.OutputString(message);
+                }
+                catch (Exception)
+                {
+                    Debug.Fail("Failed to write to output pane.");
+                }
+            }).FileAndForget("VS/Diagnostics/Debugger/DebugEngineHost/VsOutputWindowWrapper/Write");
+        }
+
+        /// <summary>
+        /// Writes text directly to the VS Output window, appending a newline.
+        /// </summary>
+        public static void WriteLine(string message, string pane = DefaultOutputPane)
+        {
+            Write(string.Concat(message, Environment.NewLine), pane);
+        }
+    }
+
     /// <summary>
     /// Provides direct access to the underlying output window without going through debug events
     /// </summary>
@@ -19,32 +145,7 @@ private static class VsImpl
         {
             internal static void SetText(string outputMessage)
             {
-                int hr;
-
-                var outputWindow = (IVsOutputWindow)Package.GetGlobalService(typeof(SVsOutputWindow));
-                if (outputWindow == null)
-                    return;
-
-                IVsOutputWindowPane pane;
-                Guid guidDebugOutputPane = VSConstants.GUID_OutWindowDebugPane;
-                hr = outputWindow.GetPane(ref guidDebugOutputPane, out pane);
-                if (hr < 0)
-                    return;
-
-                pane.Clear();
-                pane.Activate();
-
-                hr = pane.OutputString(outputMessage);
-                if (hr < 0)
-                    return;
-
-                var shell = (IVsUIShell)Package.GetGlobalService(typeof(SVsUIShell));
-                if (shell == null)
-                    return;
-
-                Guid commandSet = VSConstants.GUID_VSStandardCommandSet97;
-                object inputVariant = null;
-                shell.PostExecCommand(commandSet, (uint)VSConstants.VSStd97CmdID.OutputWindow, 0, ref inputVariant);
+                VsOutputWindowWrapper.WriteLine(outputMessage);
             }
         }
 
@@ -63,4 +164,4 @@ public static void WriteLaunchError(string outputMessage)
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/DebugEngineHost/RegistryMonitor.cs b/src/DebugEngineHost/RegistryMonitor.cs
new file mode 100644
index 000000000..6c6f1dcc0
--- /dev/null
+++ b/src/DebugEngineHost/RegistryMonitor.cs
@@ -0,0 +1,145 @@
+// // Copyright (c) Microsoft. All rights reserved.
+// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.Remoting.Messaging;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static System.Collections.Specialized.BitVector32;
+
+namespace Microsoft.DebugEngineHost
+{
+    internal class RegistryMonitor : IDisposable
+    {
+        #region Native Methods
+
+        /// <summary>
+        /// Filter for notifications reported by <see cref="RegistryMonitor"/>.
+        /// </summary>
+        [Flags]
+        public enum RegChangeNotifyFilter
+        {
+            /// <summary>Notify the caller if a subkey is added or deleted.</summary>
+            REG_NOTIFY_CHANGE_NAME = 1,
+            /// <summary>Notify the caller of changes to the attributes of the key,
+            /// such as the security descriptor information.</summary>
+            REG_NOTIFY_CHANGE_ATTRIBUTES = 2,
+            /// <summary>Notify the caller of changes to a value of the key. This can
+            /// include adding or deleting a value, or changing an existing value.</summary>
+            REG_NOTIFY_CHANGE_LAST_SET = 4,
+            /// <summary>Notify the caller of changes to the security descriptor
+            /// of the key.</summary>
+            REG_NOTIFY_CHANGE_SECURITY = 8,
+        }
+
+        [DllImport("advapi32.dll", SetLastError = true)]
+        private static extern int RegNotifyChangeKeyValue(SafeRegistryHandle hKey, bool bWatchSubtree,
+                                                          RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent,
+                                                          bool fAsynchronous);
+
+        #endregion
+
+        private HostConfigurationSection _section;
+        private readonly bool _watchSubtree;
+
+        // Set when registry value is changed
+        private AutoResetEvent m_changeEvent;
+
+        // Set when monitoring is stopped
+        private AutoResetEvent m_stoppedEvent;
+
+        /// <summary>
+        /// Occurs when the specified registry key has changed.
+        /// </summary>
+        public event EventHandler RegChanged;
+
+        private readonly ILogChannel _nativsLogger;
+
+        public RegistryMonitor(HostConfigurationSection section, bool watchSubtree, ILogChannel nativsLogger)
+        {
+            _section = section;
+            _watchSubtree = watchSubtree;
+            _nativsLogger = nativsLogger;
+        }
+
+        public void Start()
+        {
+            Thread registryMonitor = new Thread(Monitor);
+            registryMonitor.IsBackground = true;
+            registryMonitor.Name = "Microsoft.DebugEngineHost.RegistryMonitor";
+            registryMonitor.Start();
+        }
+
+        public void Stop()
+        {
+            if (m_stoppedEvent != null)
+            {
+                m_stoppedEvent.Set();
+            }
+        }
+
+        // The handle is owned by change event instance which lives while we use the handle.
+        [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle")]
+        private void Monitor()
+        {
+            bool stopped = false;
+            try
+            {
+                m_stoppedEvent = new AutoResetEvent(false);
+                m_changeEvent = new AutoResetEvent(false);
+
+                IntPtr handle = m_changeEvent.SafeWaitHandle.DangerousGetHandle();
+
+                int errorCode = RegNotifyChangeKeyValue(_section.Handle, _watchSubtree, RegChangeNotifyFilter.REG_NOTIFY_CHANGE_NAME | RegChangeNotifyFilter.REG_NOTIFY_CHANGE_LAST_SET, handle, true);
+                if (errorCode != 0) // 0 is ERROR_SUCCESS
+                {
+                    _nativsLogger?.WriteLine(LogLevel.Error, Resource.Error_WatchRegistry, errorCode);
+                }
+                else
+                {
+                    while (!stopped)
+                    {
+                        int waitResult = WaitHandle.WaitAny(new WaitHandle[] { m_stoppedEvent, m_changeEvent });
+
+                        if (waitResult == 0)
+                        {
+                            stopped = true;
+                        }
+                        else
+                        {
+                            errorCode = RegNotifyChangeKeyValue(_section.Handle, _watchSubtree, RegChangeNotifyFilter.REG_NOTIFY_CHANGE_NAME | RegChangeNotifyFilter.REG_NOTIFY_CHANGE_LAST_SET, handle, true);
+                            if (errorCode != 0) // 0 is ERROR_SUCCESS
+                            {
+                                _nativsLogger?.WriteLine(LogLevel.Error, Resource.Error_WatchRegistry, errorCode);
+                                break;
+                            }
+                            RegChanged?.Invoke(this, null);
+                        }
+                    }
+                }
+            }
+            finally
+            {
+                _section.Dispose();
+                m_stoppedEvent?.Dispose();
+                m_changeEvent?.Dispose();
+
+                m_stoppedEvent = null;
+                m_changeEvent = null;
+            }
+        }
+
+        public void Dispose()
+        {
+            m_stoppedEvent?.Dispose();
+        }
+    }
+}
diff --git a/src/DebugEngineHost/Resource.Designer.cs b/src/DebugEngineHost/Resource.Designer.cs
index a6ce3bf9e..4671d7f72 100644
--- a/src/DebugEngineHost/Resource.Designer.cs
+++ b/src/DebugEngineHost/Resource.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.DebugEngineHost {
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     internal class Resource {
@@ -60,6 +60,15 @@ internal Resource() {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Failed to watch RegistryKey with error code &apos;{0}&apos;..
+        /// </summary>
+        internal static string Error_WatchRegistry {
+            get {
+                return ResourceManager.GetString("Error_WatchRegistry", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Workspace index is incomplete; some .natvis files may not have been found..
         /// </summary>
diff --git a/src/DebugEngineHost/Resource.resx b/src/DebugEngineHost/Resource.resx
index a9188fcdb..d4f310d72 100644
--- a/src/DebugEngineHost/Resource.resx
+++ b/src/DebugEngineHost/Resource.resx
@@ -117,6 +117,10 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <data name="Error_WatchRegistry" xml:space="preserve">
+    <value>Failed to watch RegistryKey with error code '{0}'.</value>
+    <comment>{0} is an error code</comment>
+  </data>
   <data name="IndexIncomplete" xml:space="preserve">
     <value>Workspace index is incomplete; some .natvis files may not have been found.</value>
   </data>
diff --git a/src/MICore/Logger.cs b/src/MICore/Logger.cs
index 5efb488e4..86e2db72f 100644
--- a/src/MICore/Logger.cs
+++ b/src/MICore/Logger.cs
@@ -74,6 +74,11 @@ public static Logger EnsureInitialized()
             return res;
         }
 
+        public static void EnableNatvisDiagnostics(LogLevel level)
+        {
+            HostLogger.EnableNatvisDiagnostics(HostOutputWindow.WriteLaunchError, level);
+        }
+
         public static void LoadMIDebugLogger()
         {
             if (CmdLogInfo.enabled)
diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
index 5debd856c..24141685c 100755
--- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
+++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
@@ -65,7 +65,7 @@ public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngin
             _deleteEntryPointBreakpoint = false;
             MICommandFactory = MICommandFactory.GetInstance(launchOptions.DebuggerMIMode, this);
             _waitDialog = (MICommandFactory.SupportsStopOnDynamicLibLoad() && launchOptions.WaitDynamicLibLoad) ? new HostWaitDialog(ResourceStrings.LoadingSymbolMessage, ResourceStrings.LoadingSymbolCaption) : null;
-            Natvis = new Natvis.Natvis(this, launchOptions.ShowDisplayString);
+            Natvis = new Natvis.Natvis(this, launchOptions.ShowDisplayString, configStore);
 
             // we do NOT have real Win32 process IDs, so we use a guid
             AD_PROCESS_ID pid = new AD_PROCESS_ID();
@@ -1033,6 +1033,8 @@ private void Dispose()
                 _waitDialog.Dispose();
             }
 
+            Natvis?.Dispose();
+
             Logger.Flush();
         }
 
diff --git a/src/MIDebugEngine/Natvis.Impl/Natvis.cs b/src/MIDebugEngine/Natvis.Impl/Natvis.cs
index 31f74fb6f..81b52ee84 100755
--- a/src/MIDebugEngine/Natvis.Impl/Natvis.cs
+++ b/src/MIDebugEngine/Natvis.Impl/Natvis.cs
@@ -157,7 +157,7 @@ public VisualizerId(string name,int id)
         }
     };
 
-    public class Natvis
+    public class Natvis : IDisposable
     {
         private class AliasInfo
         {
@@ -227,6 +227,7 @@ public VisualizerInfo(VisualizerType viz, TypeName name)
         private static Regex s_expression = new Regex(@"^\{[^\}]*\}");
         private List<FileInfo> _typeVisualizers;
         private DebuggedProcess _process;
+        private HostConfigurationStore _configStore;
         private Dictionary<string, VisualizerInfo> _vizCache;
         private uint _depth;
         public HostWaitDialog WaitDialog { get; private set; }
@@ -237,6 +238,8 @@ public VisualizerInfo(VisualizerType viz, TypeName name)
         private const int MAX_FORMAT_DEPTH = 10;
         private const int MAX_ALIAS_CHAIN = 10;
 
+        private IDisposable _natvisSettingWatcher;
+
         public enum DisplayStringsState
         {
             On,
@@ -245,7 +248,7 @@ public enum DisplayStringsState
         }
         public DisplayStringsState ShowDisplayStrings { get; set; }
 
-        internal Natvis(DebuggedProcess process, bool showDisplayString)
+        internal Natvis(DebuggedProcess process, bool showDisplayString, HostConfigurationStore configStore)
         {
             _typeVisualizers = new List<FileInfo>();
             _process = process;
@@ -254,12 +257,14 @@ internal Natvis(DebuggedProcess process, bool showDisplayString)
             ShowDisplayStrings = showDisplayString ? DisplayStringsState.On : DisplayStringsState.ForVisualizedItems;  // don't compute display strings unless explicitly requested
             _depth = 0;
             Cache = new VisualizationCache();
+            _configStore = configStore;
         }
 
         public void Initialize(string fileName)
         {
             try
             {
+                _natvisSettingWatcher = HostNatvisProject.WatchNatvisOptionSetting(_configStore, _process.Logger.NatvisLogger);
                 HostNatvisProject.FindNatvis((s) => LoadFile(s));
             }
             catch (FileNotFoundException)
@@ -1365,5 +1370,12 @@ private string GetDisplayNameFromArrayIndex(uint arrayIndex, int rank, uint[] di
             return displayName.ToString();
         }
 
+        public void Dispose()
+        {
+            GC.SuppressFinalize(this);
+
+            _natvisSettingWatcher?.Dispose();
+            _natvisSettingWatcher = null;
+        }
     }
 }
diff --git a/src/MIDebugEngineUnitTests/NatvisNamesTest.cs b/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
index 027dfdfad..3de8665d6 100644
--- a/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
+++ b/src/MIDebugEngineUnitTests/NatvisNamesTest.cs
@@ -47,6 +47,9 @@ public void Flush() { }
 
         // Unused as ITestOutputHelper does not have a Close implementation
         public void Close() { }
+
+        // Unused as ITestOutputHelper does not have LogLevels
+        public void SetLogLevel(LogLevel level) { }
     }
 
     public class NatvisNamesTest
diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs
index a9126074f..dcea56bc0 100644
--- a/src/OpenDebugAD7/AD7DebugSession.cs
+++ b/src/OpenDebugAD7/AD7DebugSession.cs
@@ -270,7 +270,7 @@ private void SetCommonDebugSettings(Dictionary<string, JToken> args)
                         if (natvisDiagnosticsBool)
                         {
                             m_logger.SetLoggingConfiguration(LoggingCategory.NatvisDiagnostics, true);
-                            HostLogger.EnableNatvisLogger((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, message), LogLevel.Verbose);
+                            HostLogger.EnableNatvisDiagnostics((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, message), LogLevel.Verbose);
                         }
                     }
                     else if (natvisDiagnostics.Type == JTokenType.String)
@@ -279,7 +279,7 @@ private void SetCommonDebugSettings(Dictionary<string, JToken> args)
                         if (Enum.TryParse(natvisDiagnosticsString, ignoreCase: true, out LogLevel level))
                         {
                             m_logger.SetLoggingConfiguration(LoggingCategory.NatvisDiagnostics, true);
-                            HostLogger.EnableNatvisLogger((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, string.Concat("[Natvis] ", message)), level);
+                            HostLogger.EnableNatvisDiagnostics((message) => m_logger.WriteLine(LoggingCategory.NatvisDiagnostics, string.Concat("[Natvis] ", message)), level);
                         }
                     }
                     else
diff --git a/src/OpenDebugAD7/OpenDebug/Program.cs b/src/OpenDebugAD7/OpenDebug/Program.cs
index 7106c36f4..21eb7c36a 100644
--- a/src/OpenDebugAD7/OpenDebug/Program.cs
+++ b/src/OpenDebugAD7/OpenDebug/Program.cs
@@ -53,9 +53,9 @@ private static int Main(string[] argv)
                         Console.WriteLine("--engineLogging[=filePath]: Enable logging from the debug engine. If not");
                         Console.WriteLine("    specified, the log will go to the console.");
                         Console.WriteLine("--engineLogLevel=<LogLevel>: Set's the log level for engine logging.");
-                        Console.WriteLine("    If not specified, default log level is LogLevel.Trace");
+                        Console.WriteLine("    If not specified, default log level is LogLevel.Verbose");
                         Console.WriteLine("--natvisDiagnostics[=logLevel]: Enable logging for natvis. If not");
-                        Console.WriteLine("    specified, the log will go to the console. Default logging level is LogLevel.Trace.");
+                        Console.WriteLine("    specified, the log will go to the console. Default logging level is LogLevel.Verbose.");
                         Console.WriteLine("--server[=port_num] : Start the debug adapter listening for requests on the");
                         Console.WriteLine("    specified TCP/IP port instead of stdin/out. If port is not specified");
                         Console.WriteLine("    TCP {0} will be used.", DEFAULT_PORT);
@@ -75,7 +75,7 @@ private static int Main(string[] argv)
                         break;
                     case "--natvisDiagnostics":
                         loggingCategories.Add(LoggingCategory.NatvisDiagnostics);
-                        HostLogger.EnableNatvisLogger((msg) =>
+                        HostLogger.EnableNatvisDiagnostics((msg) =>
                         {
                             Console.Error.WriteLine(msg);
                         }, LogLevel.Verbose);
@@ -105,7 +105,7 @@ private static int Main(string[] argv)
                             if (!Enum.TryParse(a.Substring("--natvisDiagnostics=".Length), out LogLevel natvisLogLevel))
                             {
                                 loggingCategories.Add(LoggingCategory.NatvisDiagnostics);
-                                HostLogger.EnableNatvisLogger((msg) =>
+                                HostLogger.EnableNatvisDiagnostics((msg) =>
                                 {
                                     Console.Error.WriteLine(msg);
                                 }, natvisLogLevel);