diff --git a/.gitignore b/.gitignore
index 3eb5a821..2515b681 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,6 @@ $tf*/
#Nuget downloaded files
packages/
deps/
+
+# Visual Studio 2017 Solution files
+.vs/
diff --git a/QtSharp.CLI/ConsoleLogger.cs b/QtSharp.CLI/ConsoleLogger.cs
deleted file mode 100644
index bcf8864e..00000000
--- a/QtSharp.CLI/ConsoleLogger.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.IO;
-
-namespace QtSharp.CLI
-{
- public class ConsoleLogger
- {
-
- /// Original Console Output Stream.
- /// Original Console Output Stream.
- public TextWriter ConsoleStdOutput { get; set; }
-
- /// Original Console Output Stream.
- /// Original Console Output Stream.
- public TextWriter ConsoleErrOutput { get; set; }
-
- /// Path to the Log File.
- /// Path to the Log File.
- public string LogFilePath
- {
- get
- {
- return logFilePath;
- }
- }
- protected string logFilePath;
-
- /// Filestream used for output.
- protected FileStream fstream { get; set; }
-
- /// Filestream Writer used for output.
- protected StreamWriter fstreamwriter { get; set; }
-
- /// Default constructor.
- public ConsoleLogger()
- {
- ConsoleStdOutput = Console.Out;
- ConsoleErrOutput = Console.Error;
- logFilePath = null;
- }
-
- /// Sets the log file output.
- /// Filename of the log file to use.
- public void SetLogFile(string filename)
- {
- logFilePath = Path.Combine("logs", filename);
- }
-
- /// Starts console redirection.
- public void Start()
- {
- Stop();
- fstream = new FileStream(logFilePath, FileMode.Create);
- fstreamwriter = new StreamWriter(fstream);
- Console.SetOut(fstreamwriter);
- Console.SetError(fstreamwriter);
- }
-
- /// Stops console redirection.
- public void Stop()
- {
- Console.SetOut(ConsoleStdOutput);
- Console.SetError(ConsoleErrOutput);
- if (fstreamwriter != null) fstreamwriter.Close();
- if (fstream != null) fstream.Close();
- }
-
- /// Creates log directory.
- public void CreateLogDirectory()
- {
- if (Directory.Exists("logs") == false) Directory.CreateDirectory("logs");
- }
- }
-}
diff --git a/QtSharp.CLI/Helpers/CppSharpLog.cs b/QtSharp.CLI/Helpers/CppSharpLog.cs
new file mode 100644
index 00000000..f7899386
--- /dev/null
+++ b/QtSharp.CLI/Helpers/CppSharpLog.cs
@@ -0,0 +1,69 @@
+using System.Collections.Generic;
+using System.Linq;
+using CppSharp;
+using QtSharp.CLI.Logging;
+
+namespace QtSharp.CLI.Helpers
+{
+ /// Used to override CppSharp's default Logging output.
+ public class CppSharpLog : IDiagnostics
+ {
+ /// Gets the LibLog logger instance.
+ /// LibLog Logger.
+ private static ILog Log => _Log ?? (_Log = LogProvider.GetCurrentClassLogger());
+ private static ILog _Log;
+
+ /// Default constructor.
+ public CppSharpLog()
+ {
+ Indents = new Stack();
+ Level = DiagnosticKind.Message;
+ }
+
+ /// The number of indents to add to the message.
+ public Stack Indents;
+
+ /// Normally a cutoff for the logging level, not used here since SerilOg handles that.
+ public DiagnosticKind Level { get; set; }
+
+ /// Handle the logging message.
+ /// The log information.
+ public void Emit(DiagnosticInfo info) {
+ var currentIndent = Indents.Sum();
+ var message = new string(' ', currentIndent) + info.Message;
+ var level = DiagnosticKind_To_LibLog(info.Kind);
+ Log.Log(level, () => message);
+ }
+
+ /// Increases the indent of the log output.
+ /// amount to increase the indent.
+ public void PushIndent(int level = 4) {
+ Indents.Push(level);
+ }
+
+ /// Decrease the indent of the log output.
+ public void PopIndent() {
+ Indents.Pop();
+ }
+
+ /// Convert DiagnosticKind loglevel to LibLog loglevel
+ /// CppSharp DiagnosticKind loglevel
+ /// LibLog LogLevel.
+ private static LogLevel DiagnosticKind_To_LibLog(DiagnosticKind level)
+ {
+ switch (level)
+ {
+ case DiagnosticKind.Error:
+ return LogLevel.Error;
+ case DiagnosticKind.Warning:
+ return LogLevel.Warn;
+ case DiagnosticKind.Message:
+ return LogLevel.Info;
+ case DiagnosticKind.Debug:
+ return LogLevel.Debug;
+ default:
+ return LogLevel.Info;
+ }
+ }
+ }
+}
diff --git a/QtSharp.CLI/Helpers/LibLog.cs b/QtSharp.CLI/Helpers/LibLog.cs
new file mode 100644
index 00000000..d41a139e
--- /dev/null
+++ b/QtSharp.CLI/Helpers/LibLog.cs
@@ -0,0 +1,2450 @@
+//
+//===============================================================================
+// LibLog
+//
+// https://github.com/damianh/LibLog
+//===============================================================================
+// Copyright © 2011-2017 Damian Hickey. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//===============================================================================
+
+// ReSharper disable PossibleNullReferenceException
+
+// Define LIBLOG_PORTABLE conditional compilation symbol for PCL compatibility
+//
+// Define LIBLOG_PUBLIC to enable ability to GET a logger (LogProvider.For<>() etc) from outside this library. NOTE:
+// this can have unintended consequences of consumers of your library using your library to resolve a logger. If the
+// reason is because you want to open this functionality to other projects within your solution,
+// consider [InternalsVisibleTo] instead.
+//
+// Define LIBLOG_PROVIDERS_ONLY if your library provides its own logging API and you just want to use the
+// LibLog providers internally to provide built in support for popular logging frameworks.
+
+#pragma warning disable 1591
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "QtSharp.CLI.Logging")]
+[assembly: SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Scope = "member", Target = "QtSharp.CLI.Logging.Logger.#Invoke(QtSharp.CLI.Logging.LogLevel,System.Func`1,System.Exception,System.Object[])")]
+
+// If you copied this file manually, you need to change all "YourRootNameSpace" so not to clash with other libraries
+// that use LibLog
+#if LIBLOG_PROVIDERS_ONLY
+namespace QtSharp.CLI.LibLog
+#else
+namespace QtSharp.CLI.Logging
+#endif
+{
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+#if LIBLOG_PROVIDERS_ONLY
+ using LogProviders;
+#else
+ using LogProviders;
+#endif
+ using System;
+#if !LIBLOG_PROVIDERS_ONLY
+ using System.Diagnostics;
+#if !LIBLOG_PORTABLE
+ using System.Runtime.CompilerServices;
+#endif
+#endif
+
+#if LIBLOG_PROVIDERS_ONLY
+ internal
+#else
+ public
+#endif
+ delegate bool Logger(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters);
+
+#if !LIBLOG_PROVIDERS_ONLY
+ ///
+ /// Simple interface that represent a logger.
+ ///
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ interface ILog
+ {
+ ///
+ /// Log a message the specified log level.
+ ///
+ /// The log level.
+ /// The message function.
+ /// An optional exception.
+ /// Optional format parameters for the message generated by the messagefunc.
+ /// true if the message was logged. Otherwise false.
+ ///
+ /// Note to implementers: the message func should not be called if the loglevel is not enabled
+ /// so as not to incur performance penalties.
+ ///
+ /// To check IsEnabled call Log with only LogLevel and check the return value, no event will be written.
+ ///
+ bool Log(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters);
+ }
+#endif
+
+ ///
+ /// The log level.
+ ///
+#if LIBLOG_PROVIDERS_ONLY
+ internal
+#else
+ public
+#endif
+ enum LogLevel
+ {
+ Trace,
+ Debug,
+ Info,
+ Warn,
+ Error,
+ Fatal
+ }
+
+#if !LIBLOG_PROVIDERS_ONLY
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static partial class LogExtensions
+ {
+ public static bool IsDebugEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Debug, null);
+ }
+
+ public static bool IsErrorEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Error, null);
+ }
+
+ public static bool IsFatalEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Fatal, null);
+ }
+
+ public static bool IsInfoEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Info, null);
+ }
+
+ public static bool IsTraceEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Trace, null);
+ }
+
+ public static bool IsWarnEnabled(this ILog logger)
+ {
+ GuardAgainstNullLogger(logger);
+ return logger.Log(LogLevel.Warn, null);
+ }
+
+ public static void Debug(this ILog logger, Func messageFunc)
+ {
+ GuardAgainstNullLogger(logger);
+ logger.Log(LogLevel.Debug, WrapLogInternal(messageFunc));
+ }
+
+ public static void Debug(this ILog logger, string message)
+ {
+ if (logger.IsDebugEnabled())
+ {
+ logger.Log(LogLevel.Debug, message.AsFunc());
+ }
+ }
+
+ public static void Debug(this ILog logger, string message, params object[] args)
+ {
+ logger.DebugFormat(message, args);
+ }
+
+ public static void Debug(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.DebugException(message, exception, args);
+ }
+
+ public static void DebugFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsDebugEnabled())
+ {
+ logger.LogFormat(LogLevel.Debug, message, args);
+ }
+ }
+
+ public static void DebugException(this ILog logger, string message, Exception exception)
+ {
+ if (logger.IsDebugEnabled())
+ {
+ logger.Log(LogLevel.Debug, message.AsFunc(), exception);
+ }
+ }
+
+ public static void DebugException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsDebugEnabled())
+ {
+ logger.Log(LogLevel.Debug, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ public static void Error(this ILog logger, Func messageFunc)
+ {
+ GuardAgainstNullLogger(logger);
+ logger.Log(LogLevel.Error, WrapLogInternal(messageFunc));
+ }
+
+ public static void Error(this ILog logger, string message)
+ {
+ if (logger.IsErrorEnabled())
+ {
+ logger.Log(LogLevel.Error, message.AsFunc());
+ }
+ }
+
+ public static void Error(this ILog logger, string message, params object[] args)
+ {
+ logger.ErrorFormat(message, args);
+ }
+
+ public static void Error(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.ErrorException(message, exception, args);
+ }
+
+ public static void ErrorFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsErrorEnabled())
+ {
+ logger.LogFormat(LogLevel.Error, message, args);
+ }
+ }
+
+ public static void ErrorException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsErrorEnabled())
+ {
+ logger.Log(LogLevel.Error, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ public static void Fatal(this ILog logger, Func messageFunc)
+ {
+ logger.Log(LogLevel.Fatal, WrapLogInternal(messageFunc));
+ }
+
+ public static void Fatal(this ILog logger, string message)
+ {
+ if (logger.IsFatalEnabled())
+ {
+ logger.Log(LogLevel.Fatal, message.AsFunc());
+ }
+ }
+
+ public static void Fatal(this ILog logger, string message, params object[] args)
+ {
+ logger.FatalFormat(message, args);
+ }
+
+ public static void Fatal(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.FatalException(message, exception, args);
+ }
+
+ public static void FatalFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsFatalEnabled())
+ {
+ logger.LogFormat(LogLevel.Fatal, message, args);
+ }
+ }
+
+ public static void FatalException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsFatalEnabled())
+ {
+ logger.Log(LogLevel.Fatal, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ public static void Info(this ILog logger, Func messageFunc)
+ {
+ GuardAgainstNullLogger(logger);
+ logger.Log(LogLevel.Info, WrapLogInternal(messageFunc));
+ }
+
+ public static void Info(this ILog logger, string message)
+ {
+ if (logger.IsInfoEnabled())
+ {
+ logger.Log(LogLevel.Info, message.AsFunc());
+ }
+ }
+
+ public static void Info(this ILog logger, string message, params object[] args)
+ {
+ logger.InfoFormat(message, args);
+ }
+
+ public static void Info(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.InfoException(message, exception, args);
+ }
+
+ public static void InfoFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsInfoEnabled())
+ {
+ logger.LogFormat(LogLevel.Info, message, args);
+ }
+ }
+
+ public static void InfoException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsInfoEnabled())
+ {
+ logger.Log(LogLevel.Info, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ public static void Trace(this ILog logger, Func messageFunc)
+ {
+ GuardAgainstNullLogger(logger);
+ logger.Log(LogLevel.Trace, WrapLogInternal(messageFunc));
+ }
+
+ public static void Trace(this ILog logger, string message)
+ {
+ if (logger.IsTraceEnabled())
+ {
+ logger.Log(LogLevel.Trace, message.AsFunc());
+ }
+ }
+
+ public static void Trace(this ILog logger, string message, params object[] args)
+ {
+ logger.TraceFormat(message, args);
+ }
+
+ public static void Trace(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.TraceException(message, exception, args);
+ }
+
+ public static void TraceFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsTraceEnabled())
+ {
+ logger.LogFormat(LogLevel.Trace, message, args);
+ }
+ }
+
+ public static void TraceException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsTraceEnabled())
+ {
+ logger.Log(LogLevel.Trace, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ public static void Warn(this ILog logger, Func messageFunc)
+ {
+ GuardAgainstNullLogger(logger);
+ logger.Log(LogLevel.Warn, WrapLogInternal(messageFunc));
+ }
+
+ public static void Warn(this ILog logger, string message)
+ {
+ if (logger.IsWarnEnabled())
+ {
+ logger.Log(LogLevel.Warn, message.AsFunc());
+ }
+ }
+
+ public static void Warn(this ILog logger, string message, params object[] args)
+ {
+ logger.WarnFormat(message, args);
+ }
+
+ public static void Warn(this ILog logger, Exception exception, string message, params object[] args)
+ {
+ logger.WarnException(message, exception, args);
+ }
+
+ public static void WarnFormat(this ILog logger, string message, params object[] args)
+ {
+ if (logger.IsWarnEnabled())
+ {
+ logger.LogFormat(LogLevel.Warn, message, args);
+ }
+ }
+
+ public static void WarnException(this ILog logger, string message, Exception exception, params object[] formatParams)
+ {
+ if (logger.IsWarnEnabled())
+ {
+ logger.Log(LogLevel.Warn, message.AsFunc(), exception, formatParams);
+ }
+ }
+
+ // ReSharper disable once UnusedParameter.Local
+ private static void GuardAgainstNullLogger(ILog logger)
+ {
+ if (logger == null)
+ {
+ throw new ArgumentNullException("logger");
+ }
+ }
+
+ private static void LogFormat(this ILog logger, LogLevel logLevel, string message, params object[] args)
+ {
+ logger.Log(logLevel, message.AsFunc(), null, args);
+ }
+
+ // Avoid the closure allocation, see https://gist.github.com/AArnott/d285feef75c18f6ecd2b
+ private static Func AsFunc(this T value) where T : class
+ {
+ return value.Return;
+ }
+
+ private static T Return(this T value)
+ {
+ return value;
+ }
+
+ // Allow passing callsite-logger-type to LogProviderBase using messageFunc
+ internal static Func WrapLogSafeInternal(LoggerExecutionWrapper logger, Func messageFunc)
+ {
+ Func wrappedMessageFunc = () =>
+ {
+ try
+ {
+ return messageFunc();
+ }
+ catch (Exception ex)
+ {
+ logger.WrappedLogger(LogLevel.Error, () => LoggerExecutionWrapper.FailedToGenerateLogMessage, ex);
+ }
+ return null;
+ };
+ return wrappedMessageFunc;
+ }
+
+ // Allow passing callsite-logger-type to LogProviderBase using messageFunc
+ private static Func WrapLogInternal(Func messageFunc)
+ {
+ Func wrappedMessageFunc = () =>
+ {
+ return messageFunc();
+ };
+ return wrappedMessageFunc;
+ }
+ }
+#endif
+
+ ///
+ /// Represents a way to get a
+ ///
+#if LIBLOG_PROVIDERS_ONLY
+ internal
+#else
+ public
+#endif
+ interface ILogProvider
+ {
+ ///
+ /// Gets the specified named logger.
+ ///
+ /// Name of the logger.
+ /// The logger reference.
+ Logger GetLogger(string name);
+
+ ///
+ /// Opens a nested diagnostics context. Not supported in EntLib logging.
+ ///
+ /// The message to add to the diagnostics context.
+ /// A disposable that when disposed removes the message from the context.
+ IDisposable OpenNestedContext(string message);
+
+ ///
+ /// Opens a mapped diagnostics context. Not supported in EntLib logging.
+ ///
+ /// A key.
+ /// A value.
+ /// A disposable that when disposed removes the map from the context.
+ IDisposable OpenMappedContext(string key, object value, bool destructure = false);
+ }
+
+ ///
+ /// Provides a mechanism to create instances of objects.
+ ///
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+#if LIBLOG_PROVIDERS_ONLY
+ internal
+#else
+ public
+#endif
+ static class LogProvider
+ {
+#if !LIBLOG_PROVIDERS_ONLY
+ private const string NullLogProvider = "Current Log Provider is not set. Call SetCurrentLogProvider " +
+ "with a non-null value first.";
+ private static dynamic s_currentLogProvider;
+ private static Action s_onCurrentLogProviderSet;
+ private static Lazy s_resolvedLogProvider = new Lazy(() => ForceResolveLogProvider());
+
+ [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
+ static LogProvider()
+ {
+ IsDisabled = false;
+ }
+
+ ///
+ /// Sets the current log provider.
+ ///
+ /// The log provider.
+ public static void SetCurrentLogProvider(ILogProvider logProvider)
+ {
+ s_currentLogProvider = logProvider;
+
+ RaiseOnCurrentLogProviderSet();
+ }
+
+ ///
+ /// Gets or sets a value indicating whether this is logging is disabled.
+ ///
+ ///
+ /// true if logging is disabled; otherwise, false.
+ ///
+ public static bool IsDisabled { get; set; }
+
+ ///
+ /// Sets an action that is invoked when a consumer of your library has called SetCurrentLogProvider. It is
+ /// important that hook into this if you are using child libraries (especially ilmerged ones) that are using
+ /// LibLog (or other logging abstraction) so you adapt and delegate to them.
+ ///
+ ///
+ internal static Action OnCurrentLogProviderSet
+ {
+ set
+ {
+ s_onCurrentLogProviderSet = value;
+ RaiseOnCurrentLogProviderSet();
+ }
+ }
+
+ internal static ILogProvider CurrentLogProvider
+ {
+ get
+ {
+ return s_currentLogProvider;
+ }
+ }
+
+ ///
+ /// Gets a logger for the specified type.
+ ///
+ /// The type whose name will be used for the logger.
+ /// An instance of
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static ILog For()
+ {
+ return GetLogger(typeof(T));
+ }
+
+#if !LIBLOG_PORTABLE
+ ///
+ /// Gets a logger for the current class.
+ ///
+ /// An instance of
+ [MethodImpl(MethodImplOptions.NoInlining)]
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static ILog GetCurrentClassLogger()
+ {
+ var stackFrame = new StackFrame(1, false);
+ return GetLogger(stackFrame.GetMethod().DeclaringType);
+ }
+#endif
+
+ ///
+ /// Gets a logger for the specified type.
+ ///
+ /// The type whose name will be used for the logger.
+ /// If the type is null then this name will be used as the log name instead
+ /// An instance of
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static ILog GetLogger(Type type, string fallbackTypeName = "System.Object")
+ {
+ // If the type passed in is null then fallback to the type name specified
+ return GetLogger(type != null ? type.FullName : fallbackTypeName);
+ }
+
+ ///
+ /// Gets a logger with the specified name.
+ ///
+ /// The name.
+ /// An instance of
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static ILog GetLogger(string name)
+ {
+ ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider();
+ return logProvider == null
+ ? NoOpLogger.Instance
+ : (ILog)new LoggerExecutionWrapper(logProvider.GetLogger(name), () => IsDisabled);
+ }
+
+ ///
+ /// Opens a nested diagnostics context.
+ ///
+ /// A message.
+ /// An that closes context when disposed.
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "SetCurrentLogProvider")]
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static IDisposable OpenNestedContext(string message)
+ {
+ ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider();
+
+ return logProvider == null
+ ? new DisposableAction(() => { })
+ : logProvider.OpenNestedContext(message);
+ }
+
+ ///
+ /// Opens a mapped diagnostics context.
+ ///
+ /// A key.
+ /// A value.
+ /// An that closes context when disposed.
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "SetCurrentLogProvider")]
+#if LIBLOG_PUBLIC
+ public
+#else
+ internal
+#endif
+ static IDisposable OpenMappedContext(string key, object value, bool destructure = false)
+ {
+ ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider();
+
+ return logProvider == null
+ ? new DisposableAction(() => { })
+ : logProvider.OpenMappedContext(key, value, destructure);
+ }
+#endif
+
+#if LIBLOG_PROVIDERS_ONLY
+ private
+#else
+ internal
+#endif
+ delegate bool IsLoggerAvailable();
+
+#if LIBLOG_PROVIDERS_ONLY
+ private
+#else
+ internal
+#endif
+ delegate ILogProvider CreateLogProvider();
+
+#if LIBLOG_PROVIDERS_ONLY
+ private
+#else
+ internal
+#endif
+ static readonly List> LogProviderResolvers =
+ new List>
+ {
+ new Tuple(SerilogLogProvider.IsLoggerAvailable, () => new SerilogLogProvider()),
+ new Tuple(NLogLogProvider.IsLoggerAvailable, () => new NLogLogProvider()),
+ new Tuple(Log4NetLogProvider.IsLoggerAvailable, () => new Log4NetLogProvider()),
+ new Tuple(EntLibLogProvider.IsLoggerAvailable, () => new EntLibLogProvider()),
+ new Tuple(LoupeLogProvider.IsLoggerAvailable, () => new LoupeLogProvider()),
+ };
+
+#if !LIBLOG_PROVIDERS_ONLY
+ private static void RaiseOnCurrentLogProviderSet()
+ {
+ if (s_onCurrentLogProviderSet != null)
+ {
+ s_onCurrentLogProviderSet(s_currentLogProvider);
+ }
+ }
+#endif
+
+ internal static ILogProvider ResolveLogProvider()
+ {
+ return s_resolvedLogProvider.Value;
+ }
+
+ [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Console.WriteLine(System.String,System.Object,System.Object)")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ internal static ILogProvider ForceResolveLogProvider()
+ {
+ try
+ {
+ foreach (var providerResolver in LogProviderResolvers)
+ {
+ if (providerResolver.Item1())
+ {
+ return providerResolver.Item2();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+#if LIBLOG_PORTABLE
+ Debug.WriteLine(
+#else
+ Console.WriteLine(
+#endif
+ "Exception occurred resolving a log provider. Logging for this assembly {0} is disabled. {1}",
+ typeof(LogProvider).GetAssemblyPortable().FullName,
+ ex);
+ }
+ return null;
+ }
+
+#if !LIBLOG_PROVIDERS_ONLY
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class NoOpLogger : ILog
+ {
+ internal static readonly NoOpLogger Instance = new NoOpLogger();
+
+ public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters)
+ {
+ return false;
+ }
+ }
+#endif
+ }
+
+#if !LIBLOG_PROVIDERS_ONLY
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class LoggerExecutionWrapper : ILog
+ {
+ private readonly Logger _logger;
+ private readonly ICallSiteExtension _callsiteLogger;
+ private readonly Func _getIsDisabled;
+ internal const string FailedToGenerateLogMessage = "Failed to generate log message";
+
+ Func _lastExtensionMethod;
+
+ internal LoggerExecutionWrapper(Logger logger, Func getIsDisabled = null)
+ {
+ _logger = logger;
+ _callsiteLogger = new CallSiteExtension();
+ _getIsDisabled = getIsDisabled ?? (() => false);
+ }
+
+ internal Logger WrappedLogger
+ {
+ get { return _logger; }
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ public bool Log(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters)
+ {
+ if (_getIsDisabled())
+ {
+ return false;
+ }
+ if (messageFunc == null)
+ {
+ return _logger(logLevel, null);
+ }
+
+#if !LIBLOG_PORTABLE
+ // Callsite HACK - Using the messageFunc to provide the callsite-logger-type
+ var lastExtensionMethod = _lastExtensionMethod;
+ if (lastExtensionMethod == null || !lastExtensionMethod.Equals(messageFunc))
+ {
+ // Callsite HACK - Cache the last validated messageFunc as Equals is faster than type-check
+ lastExtensionMethod = null;
+ var methodType = messageFunc.Method.DeclaringType;
+ if (methodType == typeof(LogExtensions) || (methodType != null && methodType.DeclaringType == typeof(LogExtensions)))
+ {
+ lastExtensionMethod = messageFunc;
+ }
+ }
+
+ if (lastExtensionMethod != null)
+ {
+ // Callsite HACK - LogExtensions has called virtual ILog interface method to get here, callsite-stack is good
+ _lastExtensionMethod = lastExtensionMethod;
+ return _logger(logLevel, LogExtensions.WrapLogSafeInternal(this, messageFunc), exception, formatParameters);
+ }
+ else
+#endif
+ {
+ Func wrappedMessageFunc = () =>
+ {
+ try
+ {
+ return messageFunc();
+ }
+ catch (Exception ex)
+ {
+ _logger(LogLevel.Error, () => FailedToGenerateLogMessage, ex);
+ }
+ return null;
+ };
+
+ // Callsite HACK - Need to ensure proper callsite stack without inlining, so calling the logger within a virtual interface method
+ return _callsiteLogger.Log(_logger, logLevel, wrappedMessageFunc, exception, formatParameters);
+ }
+ }
+
+ interface ICallSiteExtension
+ {
+ bool Log(Logger logger, LogLevel logLevel, Func messageFunc, Exception exception, object[] formatParameters);
+ }
+
+ class CallSiteExtension : ICallSiteExtension
+ {
+ bool ICallSiteExtension.Log(Logger logger, LogLevel logLevel, Func messageFunc, Exception exception, object[] formatParameters)
+ {
+ return logger(logLevel, messageFunc, exception, formatParameters);
+ }
+ }
+ }
+#endif
+}
+
+#if LIBLOG_PROVIDERS_ONLY
+namespace QtSharp.CLI.LibLog.LogProviders
+#else
+namespace QtSharp.CLI.Logging.LogProviders
+#endif
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+#if !LIBLOG_PORTABLE
+ using System.Diagnostics;
+#endif
+ using System.Globalization;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.Reflection;
+#if !LIBLOG_PORTABLE
+ using System.Text;
+#endif
+ using System.Text.RegularExpressions;
+
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal abstract class LogProviderBase : ILogProvider
+ {
+ protected delegate IDisposable OpenNdc(string message);
+ protected delegate IDisposable OpenMdc(string key, object value, bool destructure);
+
+ private readonly Lazy _lazyOpenNdcMethod;
+ private readonly Lazy _lazyOpenMdcMethod;
+ private static readonly IDisposable NoopDisposableInstance = new DisposableAction();
+
+ protected LogProviderBase()
+ {
+ _lazyOpenNdcMethod
+ = new Lazy(GetOpenNdcMethod);
+ _lazyOpenMdcMethod
+ = new Lazy(GetOpenMdcMethod);
+ }
+
+ public abstract Logger GetLogger(string name);
+
+ public IDisposable OpenNestedContext(string message)
+ {
+ return _lazyOpenNdcMethod.Value(message);
+ }
+
+ public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
+ {
+ return _lazyOpenMdcMethod.Value(key, value, destructure);
+ }
+
+ protected virtual OpenNdc GetOpenNdcMethod()
+ {
+ return _ => NoopDisposableInstance;
+ }
+
+ protected virtual OpenMdc GetOpenMdcMethod()
+ {
+ return (_, __, ___) => NoopDisposableInstance;
+ }
+ }
+
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class NLogLogProvider : LogProviderBase
+ {
+ private readonly Func _getLoggerByNameDelegate;
+ private static bool s_providerIsAvailableOverride = true;
+
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "LogManager")]
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "NLog")]
+ public NLogLogProvider()
+ {
+ if (!IsLoggerAvailable())
+ {
+ throw new InvalidOperationException("NLog.LogManager not found");
+ }
+ _getLoggerByNameDelegate = GetGetLoggerMethodCall();
+ }
+
+ public static bool ProviderIsAvailableOverride
+ {
+ get { return s_providerIsAvailableOverride; }
+ set { s_providerIsAvailableOverride = value; }
+ }
+
+ public override Logger GetLogger(string name)
+ {
+ return new NLogLogger(_getLoggerByNameDelegate(name)).Log;
+ }
+
+ public static bool IsLoggerAvailable()
+ {
+ return ProviderIsAvailableOverride && GetLogManagerType() != null;
+ }
+
+ protected override OpenNdc GetOpenNdcMethod()
+ {
+ Type ndcContextType = Type.GetType("NLog.NestedDiagnosticsContext, NLog");
+ MethodInfo pushMethod = ndcContextType.GetMethodPortable("Push", typeof(string));
+ ParameterExpression messageParam = Expression.Parameter(typeof(string), "message");
+ MethodCallExpression pushMethodCall = Expression.Call(null, pushMethod, messageParam);
+ return Expression.Lambda(pushMethodCall, messageParam).Compile();
+ }
+
+ protected override OpenMdc GetOpenMdcMethod()
+ {
+ Type mdcContextType = Type.GetType("NLog.MappedDiagnosticsContext, NLog");
+
+ MethodInfo setMethod = mdcContextType.GetMethodPortable("Set", typeof(string), typeof(string));
+ MethodInfo removeMethod = mdcContextType.GetMethodPortable("Remove", typeof(string));
+ ParameterExpression keyParam = Expression.Parameter(typeof(string), "key");
+ ParameterExpression valueParam = Expression.Parameter(typeof(string), "value");
+
+ MethodCallExpression setMethodCall = Expression.Call(null, setMethod, keyParam, valueParam);
+ MethodCallExpression removeMethodCall = Expression.Call(null, removeMethod, keyParam);
+
+ Action set = Expression
+ .Lambda>(setMethodCall, keyParam, valueParam)
+ .Compile();
+ Action remove = Expression
+ .Lambda>(removeMethodCall, keyParam)
+ .Compile();
+
+ return (key, value, _) =>
+ {
+ set(key, value.ToString());
+ return new DisposableAction(() => remove(key));
+ };
+ }
+
+ private static Type GetLogManagerType()
+ {
+ return Type.GetType("NLog.LogManager, NLog");
+ }
+
+ private static Func GetGetLoggerMethodCall()
+ {
+ Type logManagerType = GetLogManagerType();
+ MethodInfo method = logManagerType.GetMethodPortable("GetLogger", typeof(string));
+ ParameterExpression nameParam = Expression.Parameter(typeof(string), "name");
+ MethodCallExpression methodCall = Expression.Call(null, method, nameParam);
+ return Expression.Lambda>(methodCall, nameParam).Compile();
+ }
+
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class NLogLogger
+ {
+ private readonly dynamic _logger;
+
+ private static Func _logEventInfoFact;
+
+ private static readonly object _levelTrace;
+ private static readonly object _levelDebug;
+ private static readonly object _levelInfo;
+ private static readonly object _levelWarn;
+ private static readonly object _levelError;
+ private static readonly object _levelFatal;
+
+ static NLogLogger()
+ {
+ try
+ {
+ var logEventLevelType = Type.GetType("NLog.LogLevel, NLog");
+ if (logEventLevelType == null)
+ {
+ throw new InvalidOperationException("Type NLog.LogLevel was not found.");
+ }
+
+ var levelFields = logEventLevelType.GetFieldsPortable().ToList();
+ _levelTrace = levelFields.First(x => x.Name == "Trace").GetValue(null);
+ _levelDebug = levelFields.First(x => x.Name == "Debug").GetValue(null);
+ _levelInfo = levelFields.First(x => x.Name == "Info").GetValue(null);
+ _levelWarn = levelFields.First(x => x.Name == "Warn").GetValue(null);
+ _levelError = levelFields.First(x => x.Name == "Error").GetValue(null);
+ _levelFatal = levelFields.First(x => x.Name == "Fatal").GetValue(null);
+
+ var logEventInfoType = Type.GetType("NLog.LogEventInfo, NLog");
+ if (logEventInfoType == null)
+ {
+ throw new InvalidOperationException("Type NLog.LogEventInfo was not found.");
+ }
+
+ ConstructorInfo loggingEventConstructor =
+ logEventInfoType.GetConstructorPortable(logEventLevelType, typeof(string), typeof(IFormatProvider), typeof(string), typeof(object[]), typeof(Exception));
+
+ ParameterExpression loggerNameParam = Expression.Parameter(typeof(string));
+ ParameterExpression levelParam = Expression.Parameter(typeof(object));
+ ParameterExpression messageParam = Expression.Parameter(typeof(string));
+ ParameterExpression exceptionParam = Expression.Parameter(typeof(Exception));
+ UnaryExpression levelCast = Expression.Convert(levelParam, logEventLevelType);
+
+ NewExpression newLoggingEventExpression =
+ Expression.New(loggingEventConstructor,
+ levelCast,
+ loggerNameParam,
+ Expression.Constant(null, typeof(IFormatProvider)),
+ messageParam,
+ Expression.Constant(null, typeof(object[])),
+ exceptionParam
+ );
+
+ _logEventInfoFact = Expression.Lambda>(newLoggingEventExpression,
+ loggerNameParam, levelParam, messageParam, exceptionParam).Compile();
+ }
+ catch { }
+ }
+
+ internal NLogLogger(dynamic logger)
+ {
+ _logger = logger;
+ }
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
+ public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters)
+ {
+ if (messageFunc == null)
+ {
+ return IsLogLevelEnable(logLevel);
+ }
+
+ var callsiteMessageFunc = messageFunc;
+ messageFunc = LogMessageFormatter.SimulateStructuredLogging(messageFunc, formatParameters);
+
+ if (_logEventInfoFact != null)
+ {
+ if (IsLogLevelEnable(logLevel))
+ {
+ Type callsiteLoggerType = typeof(NLogLogger);
+#if !LIBLOG_PORTABLE
+ // Callsite HACK - Extract the callsite-logger-type from the messageFunc
+ var methodType = callsiteMessageFunc.Method.DeclaringType;
+ if (methodType == typeof(LogExtensions) || (methodType != null && methodType.DeclaringType == typeof(LogExtensions)))
+ {
+ callsiteLoggerType = typeof(LogExtensions);
+ }
+ else if (methodType == typeof(LoggerExecutionWrapper) || (methodType != null && methodType.DeclaringType == typeof(LoggerExecutionWrapper)))
+ {
+ callsiteLoggerType = typeof(LoggerExecutionWrapper);
+ }
+#endif
+ var nlogLevel = this.TranslateLevel(logLevel);
+ var nlogEvent = _logEventInfoFact(_logger.Name, nlogLevel, messageFunc(), exception);
+ _logger.Log(callsiteLoggerType, nlogEvent);
+ return true;
+ }
+ return false;
+ }
+
+ if (exception != null)
+ {
+ return LogException(logLevel, messageFunc, exception);
+ }
+
+ switch (logLevel)
+ {
+ case LogLevel.Debug:
+ if (_logger.IsDebugEnabled)
+ {
+ _logger.Debug(messageFunc());
+ return true;
+ }
+ break;
+ case LogLevel.Info:
+ if (_logger.IsInfoEnabled)
+ {
+ _logger.Info(messageFunc());
+ return true;
+ }
+ break;
+ case LogLevel.Warn:
+ if (_logger.IsWarnEnabled)
+ {
+ _logger.Warn(messageFunc());
+ return true;
+ }
+ break;
+ case LogLevel.Error:
+ if (_logger.IsErrorEnabled)
+ {
+ _logger.Error(messageFunc());
+ return true;
+ }
+ break;
+ case LogLevel.Fatal:
+ if (_logger.IsFatalEnabled)
+ {
+ _logger.Fatal(messageFunc());
+ return true;
+ }
+ break;
+ default:
+ if (_logger.IsTraceEnabled)
+ {
+ _logger.Trace(messageFunc());
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
+ private bool LogException(LogLevel logLevel, Func messageFunc, Exception exception)
+ {
+ switch (logLevel)
+ {
+ case LogLevel.Debug:
+ if (_logger.IsDebugEnabled)
+ {
+ _logger.DebugException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ case LogLevel.Info:
+ if (_logger.IsInfoEnabled)
+ {
+ _logger.InfoException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ case LogLevel.Warn:
+ if (_logger.IsWarnEnabled)
+ {
+ _logger.WarnException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ case LogLevel.Error:
+ if (_logger.IsErrorEnabled)
+ {
+ _logger.ErrorException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ case LogLevel.Fatal:
+ if (_logger.IsFatalEnabled)
+ {
+ _logger.FatalException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ default:
+ if (_logger.IsTraceEnabled)
+ {
+ _logger.TraceException(messageFunc(), exception);
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ private bool IsLogLevelEnable(LogLevel logLevel)
+ {
+ switch (logLevel)
+ {
+ case LogLevel.Debug:
+ return _logger.IsDebugEnabled;
+ case LogLevel.Info:
+ return _logger.IsInfoEnabled;
+ case LogLevel.Warn:
+ return _logger.IsWarnEnabled;
+ case LogLevel.Error:
+ return _logger.IsErrorEnabled;
+ case LogLevel.Fatal:
+ return _logger.IsFatalEnabled;
+ default:
+ return _logger.IsTraceEnabled;
+ }
+ }
+
+ private object TranslateLevel(LogLevel logLevel)
+ {
+ switch (logLevel)
+ {
+ case LogLevel.Trace:
+ return _levelTrace;
+ case LogLevel.Debug:
+ return _levelDebug;
+ case LogLevel.Info:
+ return _levelInfo;
+ case LogLevel.Warn:
+ return _levelWarn;
+ case LogLevel.Error:
+ return _levelError;
+ case LogLevel.Fatal:
+ return _levelFatal;
+ default:
+ throw new ArgumentOutOfRangeException("logLevel", logLevel, null);
+ }
+ }
+ }
+ }
+
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class Log4NetLogProvider : LogProviderBase
+ {
+ private readonly Func _getLoggerByNameDelegate;
+ private static bool s_providerIsAvailableOverride = true;
+
+ [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "LogManager")]
+ public Log4NetLogProvider()
+ {
+ if (!IsLoggerAvailable())
+ {
+ throw new InvalidOperationException("log4net.LogManager not found");
+ }
+ _getLoggerByNameDelegate = GetGetLoggerMethodCall();
+ }
+
+ public static bool ProviderIsAvailableOverride
+ {
+ get { return s_providerIsAvailableOverride; }
+ set { s_providerIsAvailableOverride = value; }
+ }
+
+ public override Logger GetLogger(string name)
+ {
+ return new Log4NetLogger(_getLoggerByNameDelegate(name)).Log;
+ }
+
+ internal static bool IsLoggerAvailable()
+ {
+ return ProviderIsAvailableOverride && GetLogManagerType() != null;
+ }
+
+ protected override OpenNdc GetOpenNdcMethod()
+ {
+ Type logicalThreadContextType = Type.GetType("log4net.LogicalThreadContext, log4net");
+ PropertyInfo stacksProperty = logicalThreadContextType.GetPropertyPortable("Stacks");
+ Type logicalThreadContextStacksType = stacksProperty.PropertyType;
+ PropertyInfo stacksIndexerProperty = logicalThreadContextStacksType.GetPropertyPortable("Item");
+ Type stackType = stacksIndexerProperty.PropertyType;
+ MethodInfo pushMethod = stackType.GetMethodPortable("Push");
+
+ ParameterExpression messageParameter =
+ Expression.Parameter(typeof(string), "message");
+
+ // message => LogicalThreadContext.Stacks.Item["NDC"].Push(message);
+ MethodCallExpression callPushBody =
+ Expression.Call(
+ Expression.Property(Expression.Property(null, stacksProperty),
+ stacksIndexerProperty,
+ Expression.Constant("NDC")),
+ pushMethod,
+ messageParameter);
+
+ OpenNdc result =
+ Expression.Lambda(callPushBody, messageParameter)
+ .Compile();
+
+ return result;
+ }
+
+ protected override OpenMdc GetOpenMdcMethod()
+ {
+ Type logicalThreadContextType = Type.GetType("log4net.LogicalThreadContext, log4net");
+ PropertyInfo propertiesProperty = logicalThreadContextType.GetPropertyPortable("Properties");
+ Type logicalThreadContextPropertiesType = propertiesProperty.PropertyType;
+ PropertyInfo propertiesIndexerProperty = logicalThreadContextPropertiesType.GetPropertyPortable("Item");
+
+ MethodInfo removeMethod = logicalThreadContextPropertiesType.GetMethodPortable("Remove");
+
+ ParameterExpression keyParam = Expression.Parameter(typeof(string), "key");
+ ParameterExpression valueParam = Expression.Parameter(typeof(string), "value");
+
+ MemberExpression propertiesExpression = Expression.Property(null, propertiesProperty);
+
+ // (key, value) => LogicalThreadContext.Properties.Item[key] = value;
+ BinaryExpression setProperties = Expression.Assign(Expression.Property(propertiesExpression, propertiesIndexerProperty, keyParam), valueParam);
+
+ // key => LogicalThreadContext.Properties.Remove(key);
+ MethodCallExpression removeMethodCall = Expression.Call(propertiesExpression, removeMethod, keyParam);
+
+ Action set = Expression
+ .Lambda>(setProperties, keyParam, valueParam)
+ .Compile();
+
+ Action remove = Expression
+ .Lambda>(removeMethodCall, keyParam)
+ .Compile();
+
+ return (key, value, _) =>
+ {
+ set(key, value.ToString());
+ return new DisposableAction(() => remove(key));
+ };
+ }
+
+ private static Type GetLogManagerType()
+ {
+ return Type.GetType("log4net.LogManager, log4net");
+ }
+
+ private static Func GetGetLoggerMethodCall()
+ {
+ Type logManagerType = GetLogManagerType();
+ MethodInfo method = logManagerType.GetMethodPortable("GetLogger", typeof(string));
+ ParameterExpression nameParam = Expression.Parameter(typeof(string), "name");
+ MethodCallExpression methodCall = Expression.Call(null, method, nameParam);
+ return Expression.Lambda>(methodCall, nameParam).Compile();
+ }
+
+#if !LIBLOG_PORTABLE
+ [ExcludeFromCodeCoverage]
+#endif
+ internal class Log4NetLogger
+ {
+ private readonly dynamic _logger;
+ private static Type s_callerStackBoundaryType;
+ private static readonly object CallerStackBoundaryTypeSync = new object();
+
+ private static readonly object _levelDebug;
+ private static readonly object _levelInfo;
+ private static readonly object _levelWarn;
+ private static readonly object _levelError;
+ private static readonly object _levelFatal;
+ private static readonly Func