csharp/Abc-Arbitrage/ZeroLog/src/ZeroLog/ConfigResolvers/HierarchicalResolver.cs

HierarchicalResolver.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZeroLog.Appenders;
using ZeroLog.Config;

namespace ZeroLog.ConfigResolvers
{
    public clast HierarchicalResolver : IConfigurationResolver
    {
        private Node? _root;
        private Encoding AppenderEncoding { get; set; } = LogManager.DefaultEncoding;

        public IEnumerable GetAllAppenders()
        {
            var appenders = new HashSet();
            AddAppenders(_root);
            return appenders;

            void AddAppenders(Node? node)
            {
                if (node == null)
                    return;

                appenders.UnionWith(node.Appenders);
                foreach (var childNode in node.Children.Values)
                    AddAppenders(childNode);
            }
        }

        public LogConfig ResolveLogConfig(string name)
        {
            var node = Resolve(name);

            return new LogConfig
            {
                Appenders = node.Appenders.ToArray(),
                Level = node.Level,
                LogEventPoolExhaustionStrategy = node.LogEventPoolExhaustionStrategy,
                LogEventArgumentExhaustionStrategy = node.LogEventArgumentExhaustionStrategy
            };
        }

        public event Action? Updated;

        [Obsolete]
        public void Build(ZeroLogConfiguration config)
        {
            Build((IHierarchicalConfiguration)config);
        }

        public void Build(IHierarchicalConfiguration config)
        {
            var oldRoot = _root;
            var newRoot = new Node();

            foreach (var loggerWithAppenders in CreateLoggersWithAppenders(config).OrderBy(x => x.logger.Name))
            {
                AddNode(newRoot, loggerWithAppenders.logger, loggerWithAppenders.appenders);
            }

            ApplyEncodingToAllAppenders(newRoot);

            _root = newRoot;

            Updated?.Invoke();

            oldRoot?.Dispose();
        }

        private static List CreateLoggersWithAppenders(IHierarchicalConfiguration config)
        {
            var appendersByNames = config.Appenders.Where(x => x.Name != null).ToDictionary(x => x.Name!, CreateAppender);

            var loggerWithAppenders = new List();

            config.RootLogger.Name = string.Empty;
            config.RootLogger.IncludeParentAppenders = false;

            loggerWithAppenders.Add((config.RootLogger, config.RootLogger.AppenderReferences?.Select(x => appendersByNames[x]).ToArray() ?? new IAppender[0]));

            foreach (var loggerDefinition in config.Loggers)
            {
                loggerWithAppenders.Add((loggerDefinition, loggerDefinition.AppenderReferences?.Select(x => appendersByNames[x]).ToArray() ?? new IAppender[0]));
            }

            return loggerWithAppenders;
        }

        private static IAppender CreateAppender(AppenderDefinition appenderDefinition)
        {
            var appender = AppenderFactory.CreateAppender(appenderDefinition);
            return new GuardedAppender(appender, TimeSpan.FromSeconds(15));
        }

        private static void AddNode(Node root, LoggerDefinition logger, IAppender[] appenders)
        {
            var parts = logger.Name?.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty();
            var node = root;
            var path = "";

            foreach (var part in parts)
            {
                path = (path + "." + part).Trim('.');

                if (!node.Children.ContainsKey(part))
                {
                    node.Children[part] = new Node
                    {
                        Appenders = node.Appenders,
                        Level = node.Level,
                        LogEventPoolExhaustionStrategy = node.LogEventPoolExhaustionStrategy,
                        LogEventArgumentExhaustionStrategy = node.LogEventArgumentExhaustionStrategy
                    };
                }

                node = node.Children[part];
            }

            node.Appenders = (logger.IncludeParentAppenders ? appenders.Union(node.Appenders) : appenders).Distinct();
            node.LogEventPoolExhaustionStrategy = logger.LogEventPoolExhaustionStrategy;
            node.LogEventArgumentExhaustionStrategy = logger.LogEventArgumentExhaustionStrategy;
            node.Level = logger.Level;
        }

        private Node Resolve(string name)
        {
            var parts = name.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            var node = _root ?? throw new InvalidOperationException("The configuration has not been built");

            foreach (var part in parts)
            {
                if (!node.Children.ContainsKey(part))
                    break;

                node = node.Children[part];
            }

            return node;
        }

        public void Initialize(Encoding encoding)
        {
            AppenderEncoding = encoding;

            ApplyEncodingToAllAppenders(_root);
        }

        private void ApplyEncodingToAllAppenders(Node? node)
        {
            if (node is null)
                return;

            if (AppenderEncoding != null && node.Appenders != null)
            {
                foreach (var appender in node.Appenders)
                {
                    appender.SetEncoding(AppenderEncoding);
                }
            }

            foreach (var n in node.Children)
            {
                ApplyEncodingToAllAppenders(n.Value);
            }
        }

        public void Dispose()
        {
            _root?.Dispose();
        }

        private clast Node : IDisposable
        {
            public readonly Dictionary Children = new Dictionary();
            public IEnumerable Appenders = Enumerable.Empty();
            public Level Level;
            public LogEventPoolExhaustionStrategy LogEventPoolExhaustionStrategy;
            public LogEventArgumentExhaustionStrategy LogEventArgumentExhaustionStrategy;

            public void Dispose()
            {
                foreach (var appender in Appenders)
                    appender.Dispose();

                foreach (var child in Children.Values)
                    child.Dispose();
            }
        }
    }
}