<commit_before>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Text.Formatting;
using System.Threading;
using System.Threading.Tasks;
using ZeroLog.Appenders;
using ZeroLog.ConfigResolvers;
using ZeroLog.Utils;

namespace ZeroLog
{
    public class LogManager : IInternalLogManager
    {
        private static readonly IInternalLogManager _defaultLogManager = new NoopLogManager();
        private static IInternalLogManager _logManager = _defaultLogManager;

        private readonly ConcurrentBag<Log> _loggers;
        private readonly ConcurrentQueue<IInternalLogEvent> _queue;
        private readonly ObjectPool<IInternalLogEvent> _pool;

        private readonly BufferSegmentProvider _bufferSegmentProvider;
        private readonly IConfigurationResolver _configResolver;
        private readonly Task _writeTask;

        private bool _isRunning;
        private readonly Encoding _encoding = Encoding.UTF8;

        internal LogManager(IConfigurationResolver configResolver, LogManagerConfiguration configuration)
        {
            _configResolver = configResolver;
            _loggers = new ConcurrentBag<Log>();
            _queue = new ConcurrentQueue<IInternalLogEvent>(new ConcurrentQueueCapacityInitializer(configuration.LogEventQueueSize));

            _bufferSegmentProvider = new BufferSegmentProvider(configuration.LogEventQueueSize * configuration.LogEventBufferSize, configuration.LogEventBufferSize);
            _pool = new ObjectPool<IInternalLogEvent>(configuration.LogEventQueueSize, () => new LogEvent(_bufferSegmentProvider.GetSegment()));

            configResolver.Initialize(_encoding);
            configResolver.Updated += () =>
            {
                foreach (var logger in _loggers)
                {
                    logger.ResetConfiguration();
                }
            };

            _isRunning = true;
            _writeTask = Task.Factory.StartNew(WriteToAppenders, TaskCreationOptions.LongRunning);
        }

        public Level Level => _configResolver.ResolveLevel("");

        public static ILogManager ConfigureAndWatch(string filepath)
        {
            return Configurator.ConfigureAndWatch(filepath);
        }

        public static ILogManager Initialize(IConfigurationResolver configResolver, LogManagerConfiguration configuration)
        {
            if (_logManager != _defaultLogManager)
                throw new ApplicationException("LogManager is already initialized");

            _logManager = new LogManager(configResolver, configuration);
            return _logManager;
        }

        public static ILogManager Initialize(IEnumerable<IAppender> appenders, LogManagerConfiguration configuration)
        {
            if (_logManager != _defaultLogManager)
                throw new ApplicationException("LogManager is already initialized");

            var dummyResolver = new DummyResolver(appenders, configuration.Level, configuration.LogEventPoolExhaustionStrategy);
            _logManager = new LogManager(dummyResolver, configuration);
            return _logManager;
        }

        public static ILogManager Initialize(IEnumerable<IAppender> appenders, int logEventQueueSize = 1024, int logEventBufferSize = 128, Level level = Level.Finest, LogEventPoolExhaustionStrategy exhaustionStrategy = LogEventPoolExhaustionStrategy.Default)
        {
            return Initialize(appenders, new LogManagerConfiguration
            {
                LogEventQueueSize = logEventQueueSize,
                LogEventBufferSize = logEventBufferSize,
                Level = level,
                LogEventPoolExhaustionStrategy = exhaustionStrategy
            });
        }

        public static void Shutdown()
        {
            var logManager = _logManager;
            _logManager = _defaultLogManager;

            logManager?.Dispose();
        }

        public void Dispose()
        {
            if (!_isRunning)
                return;

            _isRunning = false;
            _writeTask.Wait(15000);

            _configResolver.Dispose();
            _bufferSegmentProvider.Dispose();
        }

        public static ILog GetLogger(Type type)
        {
            return GetLogger(type.FullName);
        }

        public static ILog GetLogger(string name)
        {
            if (_logManager == null)
                throw new ApplicationException("LogManager is not yet initialized, please call LogManager.Initialize()");

            var log = _logManager.GetNewLog(_logManager, name);
            return log;
        }

        void IInternalLogManager.Enqueue(IInternalLogEvent logEvent)
        {
            _queue.Enqueue(logEvent);
        }

        ILog IInternalLogManager.GetNewLog(IInternalLogManager logManager, string name)
        {
            var logger = new Log(logManager, name);
            _loggers.Add(logger);
            return logger;
        }

        public IList<IAppender> ResolveAppenders(string name)
            => _configResolver.ResolveAppenders(name);

        public LogEventPoolExhaustionStrategy ResolveLogEventPoolExhaustionStrategy(string name)
            => _configResolver.ResolveExhaustionStrategy(name);

        public Level ResolveLevel(string name)
            => _configResolver.ResolveLevel(name);

        IInternalLogEvent IInternalLogManager.AllocateLogEvent(LogEventPoolExhaustionStrategy logEventPoolExhaustionStrategy, IInternalLogEvent notifyPoolExhaustionLogEvent, Level level, Log log)
        {
            IInternalLogEvent Initialize(IInternalLogEvent l)
            {
                l.Initialize(level, log);
                return l;<commit_msg>Replace ConcurrentBag by ConcurrentQueue to avoid thread local storage<commit_after>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Text.Formatting;
using System.Threading;
using System.Threading.Tasks;
using ZeroLog.Appenders;
using ZeroLog.ConfigResolvers;
using ZeroLog.Utils;

namespace ZeroLog
{
    public class LogManager : IInternalLogManager
    {
        private static readonly IInternalLogManager _defaultLogManager = new NoopLogManager();
        private static IInternalLogManager _logManager = _defaultLogManager;

        private readonly ConcurrentQueue<Log> _loggers;
        private readonly ConcurrentQueue<IInternalLogEvent> _queue;
        private readonly ObjectPool<IInternalLogEvent> _pool;

        private readonly BufferSegmentProvider _bufferSegmentProvider;
        private readonly IConfigurationResolver _configResolver;
        private readonly Task _writeTask;

        private bool _isRunning;
        private readonly Encoding _encoding = Encoding.UTF8;

        internal LogManager(IConfigurationResolver configResolver, LogManagerConfiguration configuration)
        {
            _configResolver = configResolver;
            _loggers = new ConcurrentQueue<Log>();
            _queue = new ConcurrentQueue<IInternalLogEvent>(new ConcurrentQueueCapacityInitializer(configuration.LogEventQueueSize));

            _bufferSegmentProvider = new BufferSegmentProvider(configuration.LogEventQueueSize * configuration.LogEventBufferSize, configuration.LogEventBufferSize);
            _pool = new ObjectPool<IInternalLogEvent>(configuration.LogEventQueueSize, () => new LogEvent(_bufferSegmentProvider.GetSegment()));

            configResolver.Initialize(_encoding);
            configResolver.Updated += () =>
            {
                foreach (var logger in _loggers)
                {
                    logger.ResetConfiguration();
                }
            };

            _isRunning = true;
            _writeTask = Task.Factory.StartNew(WriteToAppenders, TaskCreationOptions.LongRunning);
        }

        public Level Level => _configResolver.ResolveLevel("");

        public static ILogManager ConfigureAndWatch(string filepath)
        {
            return Configurator.ConfigureAndWatch(filepath);
        }

        public static ILogManager Initialize(IConfigurationResolver configResolver, LogManagerConfiguration configuration)
        {
            if (_logManager != _defaultLogManager)
                throw new ApplicationException("LogManager is already initialized");

            _logManager = new LogManager(configResolver, configuration);
            return _logManager;
        }

        public static ILogManager Initialize(IEnumerable<IAppender> appenders, LogManagerConfiguration configuration)
        {
            if (_logManager != _defaultLogManager)
                throw new ApplicationException("LogManager is already initialized");

            var dummyResolver = new DummyResolver(appenders, configuration.Level, configuration.LogEventPoolExhaustionStrategy);
            _logManager = new LogManager(dummyResolver, configuration);
            return _logManager;
        }

        public static ILogManager Initialize(IEnumerable<IAppender> appenders, int logEventQueueSize = 1024, int logEventBufferSize = 128, Level level = Level.Finest, LogEventPoolExhaustionStrategy exhaustionStrategy = LogEventPoolExhaustionStrategy.Default)
        {
            return Initialize(appenders, new LogManagerConfiguration
            {
                LogEventQueueSize = logEventQueueSize,
                LogEventBufferSize = logEventBufferSize,
                Level = level,
                LogEventPoolExhaustionStrategy = exhaustionStrategy
            });
        }

        public static void Shutdown()
        {
            var logManager = _logManager;
            _logManager = _defaultLogManager;

            logManager?.Dispose();
        }

        public void Dispose()
        {
            if (!_isRunning)
                return;

            _isRunning = false;
            _writeTask.Wait(15000);

            _configResolver.Dispose();
            _bufferSegmentProvider.Dispose();
        }

        public static ILog GetLogger(Type type)
        {
            return GetLogger(type.FullName);
        }

        public static ILog GetLogger(string name)
        {
            if (_logManager == null)
                throw new ApplicationException("LogManager is not yet initialized, please call LogManager.Initialize()");

            var log = _logManager.GetNewLog(_logManager, name);
            return log;
        }

        void IInternalLogManager.Enqueue(IInternalLogEvent logEvent)
        {
            _queue.Enqueue(logEvent);
        }

        ILog IInternalLogManager.GetNewLog(IInternalLogManager logManager, string name)
        {
            var logger = new Log(logManager, name);
            _loggers.Enqueue(logger);
            return logger;
        }

        public IList<IAppender> ResolveAppenders(string name)
            => _configResolver.ResolveAppenders(name);

        public LogEventPoolExhaustionStrategy ResolveLogEventPoolExhaustionStrategy(string name)
            => _configResolver.ResolveExhaustionStrategy(name);

        public Level ResolveLevel(string name)
            => _configResolver.ResolveLevel(name);

        IInternalLogEvent IInternalLogManager.AllocateLogEvent(LogEventPoolExhaustionStrategy logEventPoolExhaustionStrategy, IInternalLogEvent notifyPoolExhaustionLogEvent, Level level, Log log)
        {
            IInternalLogEvent Initialize(IInternalLogEvent l)
            {
                l.Initialize(level, log);
                return l;
{'fraction_non_alphanumeric': 0.06283178139413453, 'fraction_numerical': 0.002262640327212601, 'mean_word_length': 2.605898964543458, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2979934', 'n_tokens_mistral': 2714, 'n_tokens_neox': 2624, 'n_words': 601}