| 
						
						
						
					 | 
				
				 | 
				
					@ -1,14 +1,9 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using Apewer.Internals; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using Apewer.Models; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using Apewer.Models; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Collections; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Collections.Generic; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Diagnostics; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.IO; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Text; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using System.Threading; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					using static System.ConsoleColor; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					{ | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -23,6 +18,9 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private int _reserved = -1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private LogCollector _collector = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private string _lastdate = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private Action<LogItem>[] _actions = new Action<LogItem>[0]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private List<Action<LogItem>> _actions_list = new List<Action<LogItem>>(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private object _locker = new object(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>当前日志记录器的名称。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public string Name { get; set; } | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -52,6 +50,19 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>使用自定义方法。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void UseAction(Action<LogItem> action) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (action != null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                lock (_actions_list) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    _actions_list.Add(action); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    _actions = _actions_list.ToArray(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>日志文件的保留天数(不包含今天)。指定 <see cref="FilePathGetter"/> 时此属性无效。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <remarks>默认值:-1,保留所有日志。</remarks>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public int FileReserved { get => _reserved; set => _reserved = value; } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -60,66 +71,67 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <remarks>默认值:NULL,删除文件。</remarks>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public LogCollector Collector { get => _collector; set => _collector = value; } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private void Invoke(Action action) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void Inbackground(Action action) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (Background) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                RuntimeUtility.InBackground(action, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                RuntimeUtility.InBackground(() => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    lock (_locker) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        action.Invoke(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                }, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            try { action.Invoke(); } catch { } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            lock (_locker) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                try { action.Invoke(); } catch { } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal void Colorful(object sender, string tag, Nullable<ConsoleColor> color, object[] content, Exception exception = null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal void Output(string tag, object[] content, Exception exception = null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!Enabled) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Invoke(() => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Inbackground(() => | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var item = new LogItem(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Sender = sender; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Logger = this; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Tag = tag; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Color = color; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Content = MergeContent(content); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Content = content; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                item.Exception = exception; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (UseConsole) ToConsole(item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var text = (UseConsole || UseFile) ? item.ToString() : null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (UseConsole) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    lock (ConsoleLocker) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        System.Console.WriteLine(text); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (UseFile) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var plain = ToText(item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    lock (_cache_locker) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (_cache_capacity > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            _cache_array[_cache_count] = plain; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            _cache_array[_cache_count] = text; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            _cache_count += 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            if (_cache_count == _cache_capacity) Flush(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            ToFile(plain, this); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            ToFile(text, this); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录异常。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal void InnerException(object sender, Exception exception) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!Enabled) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var type = null as string; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var content = null as string; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (exception != null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                try | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var actions = _actions; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                foreach (var action in actions) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    type = exception.GetType().Name; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    content = MergeContent(new object[] { type, exception.Message }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    action.Invoke(item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                catch { } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (content == null) content = "无效的 Exception 实例。"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            Colorful(sender, "Exception", DarkMagenta, new object[] { type, content }, exception); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>创建新实例。</summary>
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -183,94 +195,6 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取用于保存日志文件的路径。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static Func<Logger, string> FilePathGetter { get; set; } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static string MergeContent(object[] content) => TextUtility.Join(" | ", content); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static string FormatSender(object sender) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (sender == null) return null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (sender is string) return sender as string; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (sender is Type) return ((Type)sender).Name; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return sender.GetType().Name; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 向控制台输出。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static void ToConsole(LogItem item) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var hasTag = !string.IsNullOrEmpty(item.Tag); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var sender = FormatSender(item.Sender); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var colorful = item.Color != null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            lock (ConsoleLocker) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (!colorful) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.WriteLine(ToText(item)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.ResetColor(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.ForegroundColor = DarkGray; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.Write(item.Clock); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.ResetColor(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (hasTag) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write("  "); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (item.Color != null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        System.Console.BackgroundColor = item.Color.Value; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        System.Console.ForegroundColor = White; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(" "); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(item.Tag); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(" "); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.ResetColor(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (!string.IsNullOrEmpty(sender)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write("  <"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(sender); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(">"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (!string.IsNullOrEmpty(item.Content)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write("  "); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    System.Console.Write(item.Content); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                System.Console.WriteLine(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static string ToText(LogItem item) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var sb = new StringBuilder(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var sender = FormatSender(item.Sender); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            sb.Append(item.Clock); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!string.IsNullOrEmpty(item.Tag)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append("  ["); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append(item.Tag); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append("]"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!string.IsNullOrEmpty(sender)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append("  <"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append(sender); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append(">"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!string.IsNullOrEmpty(item.Content)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append("  "); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                sb.Append(item.Content); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return sb.ToString(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        // 向日志文件输出文本,文件名按日期自动生成。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static string ToFile(string plain, Logger logger, bool crlf = true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -287,7 +211,7 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>获取日志文件路径发生错误时返回 NULL 值。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <remarks>默认例:<br/>d:\app\log\1970-01-01.log<br/>d:\www\app_data\log\1970-01-01.log</remarks>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static string GetFilePath(Logger logger = null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        static string GetFilePath(Logger logger = null) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var getter = FilePathGetter; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (getter != null) try { return getter.Invoke(logger); } catch { } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -304,7 +228,10 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 文件不存在时创建新文件,无法创建时返回。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var now = DateTime.Now; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var date = now.Lucid(true, false, false, false); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var filePath = Path.Combine(logDir, date + FileExt); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var fileName = (logger == null || logger.Name.IsEmpty()) ? $"{date}{FileExt}" : $"{date}_{logger.Name}{FileExt}"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 写入文件。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var filePath = Path.Combine(logDir, fileName); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (!StorageUtility.FileExists(filePath)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                StorageUtility.WriteFile(filePath, TextUtility.Bom); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -314,6 +241,7 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // 检查过期文件。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (logger != null && getter == null && logger._reserved > -1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 每天执行一次。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (date != logger._lastdate) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    logger._lastdate = date; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -336,14 +264,30 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            var paths = StorageUtility.GetSubFiles(logDir); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            foreach (var path in paths) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var fileName = Path.GetFileNameWithoutExtension(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 文件名后缀
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var fileExt = Path.GetExtension(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileName.Length != 10) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileExt != FileExt) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 文件名格式
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var fileName = Path.GetFileName(path); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileName[4] != '-') continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileName[7] != '-') continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileExt != FileExt) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (fileName[10] != '.' && fileName[10] != '_') continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 确定文件名是属于当前的 Logger
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (logger.Name.IsEmpty()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (fileName.Length != 14) continue; // 2008-08-08.log
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (fileName.Length < 16) continue; // 2008-08-08_a.log
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    var loggerName = fileName.Substring(11, fileName.Length - 15); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (loggerName != logger.Name) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var dt = ClockUtility.ParseLucid(fileName); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // 从文件名解析日期
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var dt = ClockUtility.ParseLucid(fileName.Substring(0, 10)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (dt == null || !dt.HasValue) continue; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                var days = Convert.ToInt32(Convert.ToInt64((today - dt.Value).TotalMilliseconds) / 86400000L); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -359,14 +303,14 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region 默认实列。
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _default = new Logger("Apewer.Logger.Default", true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _console = new Logger("Apewer.Logger.Console", true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _web = new Logger("Apewer.Logger.Web", true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _default = new Logger(null, true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _console = new Logger(null, true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        private static Logger _web = new Logger(null, true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					#if DEBUG
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal static Logger _internals = new Logger("Apewer.Logger.Internals", true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal static Logger _internals = new Logger(null, true, false, true); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					#else
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal static Logger _internals = new Logger("Apewer.Logger.Internals", true, false, false); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        internal static Logger _internals = new Logger(null, true, false, false); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					#endif
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>内部的日志记录程序。</summary>
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -388,16 +332,10 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const string FileExt = ".log"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>使用 Logger.Default 写入日志,自动添加时间和日期,多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write(params object[] content) => Default.Colorful(null, null, null, content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write(params object[] content) => Default.Output(null, content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>使用 Logger.Default 写入日志,自动添加时间和日期,多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write<T>(params object[] content) => Default.Colorful(typeof(T), null, null, content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>使用 Logger.Default 写入日志,自动添加时间和日期。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write(Exception exception) => Default.InnerException(null, exception); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>使用 Logger.Default 写入日志,自动添加时间和日期。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write<T>(Exception exception) => Default.InnerException(typeof(T), exception); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void Write(Exception exception, params object[] content) => Default.Output(null, content, exception); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>压缩日志文件的内容,另存为 ZIP 文件,并删除原日志文件。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public static void CollectToZip(string path) | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -438,6 +376,29 @@ namespace Apewer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #region public
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录异常。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Exception<T>(T exception, params object[] content) where T : Exception => Output("Exception", content, exception); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录错误。多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Error(params object[] content) => Output("Error", content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录警告。多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Warning(params object[] content) => Output("Warning", content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录警告。多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Info(params object[] content) => Output("Info", content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录文本。多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Text(params object[] content) => Output(null, content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        /// <summary>记录调试。多个 Content 参数将以“ | ”分隔。</summary>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        [Conditional("DEBUG")] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        public void Debug(params object[] content) => Output("Debug", content, null); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        #endregion
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
					 | 
				
				 | 
				
					
  |