This is an automated email from the ASF dual-hosted git repository.

FreeAndNil pushed a commit to branch 
Feature/162-quiet-app-settings-in-a-native-host
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git

commit 13d931ef36ecc607786befc4c4cee2226a52ffc8
Author: Jan Friedrich <[email protected]>
AuthorDate: Wed Aug 19 22:12:52 2026 +0200

    Recognise a native host as having no configuration system (#162)
    
    In a process that hosts the runtime natively there is no entry assembly for 
the
    configuration system to derive the config file path from, so reading an
    application setting fails in ClientConfigPaths with a 
PlatformNotSupportedException
    wrapped in a ConfigurationErrorsException. That matched none of the shapes
    IsMissingConfigurationSystem recognised, so log4net blamed the user's 
config file
    and repeated the report for every setting the static constructors read: 
seven
    log4net:ERROR blocks with a stack trace each, at startup, in a well 
configured
    application.
    
    A PlatformNotSupportedException anywhere in the inner exception chain is now
    treated as an absent configuration system, the same as the Native AOT case. 
A
    malformed config file cannot produce one, so unlike the 
FileNotFoundException and
    TypeLoadException cases it needs no check on which assembly it came from. 
The
    failure is logged once at debug level and application settings come from
    environment variables.
    
    Verified on Windows in a C++ host of the CoreCLR built for the purpose, in 
a host
    that loads the runtime through hostfxr, and in powershell.exe loading a
    netstandard2.0 build output: seven error blocks before, none after, and 
exactly one
    debug line with log4net.Internal.Debug on.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 .../162-quiet-app-settings-in-a-native-host.xml    | 14 ++++++++++++++
 src/log4net.Tests/Util/SystemInfoTest.cs           | 13 +++++++++++++
 src/log4net/Util/SystemInfo.cs                     | 22 +++++++++++++++-------
 3 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/src/changelog/3.4.1/162-quiet-app-settings-in-a-native-host.xml 
b/src/changelog/3.4.1/162-quiet-app-settings-in-a-native-host.xml
new file mode 100644
index 00000000..9f995548
--- /dev/null
+++ b/src/changelog/3.4.1/162-quiet-app-settings-in-a-native-host.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns="https://logging.apache.org/xml/ns";
+       xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
+       type="fixed">
+  <issue id="162" link="https://github.com/apache/logging-log4net/issues/162"/>
+  <description format="asciidoc">Stop reporting `log4net:ERROR Exception while 
reading ConfigurationSettings`
+  in a process that hosts the runtime natively, such as `powershell.exe` or a 
C++ host of the CoreCLR.
+  There is no entry assembly there for the configuration system to derive the 
config file path from, so
+  it fails with `PlatformNotSupportedException` before any config file is 
read. That is now recognised
+  as an absent configuration system, the same as under Native AOT: it is 
logged once at debug level and
+  application settings are read from environment variables instead
+  (reported by @viktorgobbi, fixed by @FreeAndNil)</description>
+</entry>
diff --git a/src/log4net.Tests/Util/SystemInfoTest.cs 
b/src/log4net.Tests/Util/SystemInfoTest.cs
index fbf544bd..ebf3a72f 100644
--- a/src/log4net.Tests/Util/SystemInfoTest.cs
+++ b/src/log4net.Tests/Util/SystemInfoTest.cs
@@ -274,6 +274,19 @@ public void 
MissingApplicationAssemblyIsNotTreatedAsAMissingConfigurationSystem(
       new ConfigurationErrorsException("An error occurred creating the 
configuration section handler",
         new FileNotFoundException("Could not load file or assembly", 
"Contoso.SectionHandlers"))), Is.False);
 
+  /// <summary>
+  /// A process that hosts the runtime natively has no entry assembly for the 
configuration system
+  /// to derive the config file path from, so it cannot read a config file 
whatever state that file
+  /// is in. That is recognised and the environment stands in, rather than 
being reported as a
+  /// malformed file on every setting log4net reads.
+  /// </summary>
+  [Test]
+  public void NativeHostExceptionIsRecognised()
+    => Assert.That(IsMissingConfigurationSystem(
+        new ConfigurationErrorsException("Configuration system failed to 
initialize",
+          new PlatformNotSupportedException("Operation is not supported on 
this platform."))),
+      Is.True);
+
   private static bool IsMissingConfigurationSystem(Exception exception)
   {
     MethodInfo method = 
typeof(SystemInfo).GetMethod("IsMissingConfigurationSystem", 
BindingFlags.Static | BindingFlags.NonPublic)
diff --git a/src/log4net/Util/SystemInfo.cs b/src/log4net/Util/SystemInfo.cs
index eb3c656b..f71876d7 100644
--- a/src/log4net/Util/SystemInfo.cs
+++ b/src/log4net/Util/SystemInfo.cs
@@ -721,12 +721,13 @@ public static bool TryParse(string s, out short val)
     {
       if (IsMissingConfigurationSystem(e))
       {
-        // There is no configuration system to read - Native AOT trims 
System.Configuration away.
-        // That is a property of the runtime rather than a fault, so it is not 
reported as an
-        // error, and the environment stands in for the config file as it does 
on Android.
+        // There is no configuration system to read - Native AOT trims 
System.Configuration away,
+        // and a native process hosting the runtime has no entry assembly for 
it to derive the
+        // config file path from. That is a property of the host rather than a 
fault, so it is not
+        // reported as an error, and the environment stands in for the config 
file as on Android.
         _configurationSystemUnavailable = true;
         LogLog.Debug(_declaringType,
-          "No configuration system on this runtime. Using environment 
variables for application settings.", e);
+          "No configuration system on this host. Using environment variables 
for application settings.", e);
         return Environment.GetEnvironmentVariable(key);
       }
 
@@ -746,10 +747,12 @@ public static bool TryParse(string s, out short val)
   /// <returns><see langword="true"/> if the configuration system itself is 
unavailable</returns>
   /// <remarks>
   /// <para>
-  /// The inner exceptions have to be walked, because Native AOT surfaces this 
as a
+  /// The inner exceptions have to be walked, because the runtime surfaces 
both cases as a
   /// <see cref="ConfigurationErrorsException"/> - the very type a malformed 
file produces. What
-  /// distinguishes it is further down the chain: a <see 
cref="MissingMethodException"/> for
-  /// <c>ClientConfigurationHost</c>, whose constructor the trimmer removed.
+  /// distinguishes them is further down the chain: under Native AOT a
+  /// <see cref="MissingMethodException"/> for <c>ClientConfigurationHost</c>, 
whose constructor the
+  /// trimmer removed, and in a native process hosting the runtime a
+  /// <see cref="PlatformNotSupportedException"/> from 
<c>ClientConfigPaths</c>.
   /// </para>
   /// <para>
   /// An unrecognized failure is treated as a configuration file problem, 
which is the safer way
@@ -773,6 +776,11 @@ private static bool 
IsMissingConfigurationSystem(Exception? exception)
     {
       switch (exception)
       {
+        // The configuration system cannot work out where the config file is, 
because there is no
+        // entry assembly to derive its path from. That is what a native 
process hosting the runtime
+        // looks like, and no config file can be read there however well 
formed it is. A malformed
+        // file never produces this, so it needs no check on which assembly it 
came from.
+        case PlatformNotSupportedException:
         case FileNotFoundException { FileName: string fileName }
           when IsConfigurationSystem(fileName):
         case TypeLoadException { TypeName: string typeName }

Reply via email to