11using System ;
2+ using System . Collections . Generic ;
23using System . IO ;
34using System . Linq ;
45using System . Text ;
@@ -7,113 +8,150 @@ namespace ozakboy.NLOG.Core
78{
89 /// <summary>
910 /// 日誌檔案處理類別,負責日誌檔案的建立、寫入和管理
11+ /// 支援單次寫入和批次寫入
1012 /// </summary>
1113 static class LogText
1214 {
1315 private static object lockMe = new object ( ) ;
1416
1517 /// <summary>
16- /// 建立或是新增LOG紀錄
18+ /// 建立或是新增單條LOG紀錄
1719 /// </summary>
18- /// <param name="level"></param>
19- /// <param name="name"></param>
20- /// <param name="Message"></param>
21- /// <param name="arg"></param>
22- internal static void Add_LogText ( LogLevel level , string name , string Message , object [ ] arg )
20+ internal static void Add_LogText ( LogLevel level , string name , string message , object [ ] args )
21+ {
22+ var logItem = new LogItem
23+ {
24+ Level = level ,
25+ Name = name ,
26+ Message = message ,
27+ Args = args
28+ } ;
29+
30+ Add_BatchLogText ( new [ ] { logItem } ) ;
31+ }
32+
33+
34+ /// <summary>
35+ /// 批次寫入多條日誌
36+ /// </summary>
37+ internal static void Add_BatchLogText ( IEnumerable < LogItem > logItems )
2338 {
2439 try
2540 {
26- // 使用 lock 避免多執行敘執行時 檔案被佔用問題
2741 lock ( lockMe )
2842 {
43+ // 按日誌級別和名稱分組
44+ var groupedLogs = logItems . GroupBy ( item => new { item . Level , item . Name } ) ;
2945
30- string LogPath = $ "{ AppDomain . CurrentDomain . BaseDirectory } \\ { LogConfiguration . Current . LogPath } \\ { DateTime . Now . ToString ( "yyyyMMdd" ) } \\ { LogConfiguration . Current . TypeDirectories . GetPathForType ( level ) } \\ ";
31-
32- CheckDirectoryExistCreate ( LogPath ) ;
33-
34- if ( string . IsNullOrEmpty ( name ) ) name = level . ToString ( ) ;
46+ foreach ( var group in groupedLogs )
47+ {
48+ var level = group . Key . Level ;
49+ var name = string . IsNullOrEmpty ( group . Key . Name ) ? level . ToString ( ) : group . Key . Name ;
3550
36- var LogFilePath = CheckFileExistCreate ( LogPath , name ) ;
51+ // 獲取日誌檔案資訊
52+ var fileInfo = GetLogFileInfo ( level , name ) ;
3753
38- FIleWriteLine ( arg , LogFilePath , Message ) ;
54+ // 批次寫入檔案
55+ WriteLogsToFile ( fileInfo , group ) ;
56+ }
3957
58+ // 清理過期日誌(只在批次處理完成後執行一次)
4059 Remove_TimeOutLogText ( ) ;
4160 }
4261 }
4362 catch ( Exception ex )
4463 {
45- Console . WriteLine ( $ "{ DateTime . Now . ToString ( " yyyy/MM/dd HH:mm:ss" ) } >>LogText Add_LogText Error:{ ex . Message } ") ;
64+ Console . WriteLine ( $ "{ DateTime . Now : yyyy/MM/dd HH:mm:ss} >>LogText Add_BatchLogText Error:{ ex . Message } ") ;
4665 }
4766 }
4867
68+
4969 /// <summary>
50- /// 判斷有無資料表 若沒有建立資料表
70+ /// 獲取日誌檔案資訊
5171 /// </summary>
52- /// <param name="LogPath"></param>
53- private static void CheckDirectoryExistCreate ( string LogPath )
72+ private static LogFileInfo GetLogFileInfo ( LogLevel level , string name )
5473 {
55- if ( ! Directory . Exists ( LogPath ) )
74+ var baseDir = AppDomain . CurrentDomain . BaseDirectory ;
75+ var logPath = Path . Combine ( baseDir , LogConfiguration . Current . LogPath ,
76+ DateTime . Now . ToString ( "yyyyMMdd" ) ,
77+ LogConfiguration . Current . TypeDirectories . GetPathForType ( level ) ) ;
78+
79+ var fileInfo = new LogFileInfo
5680 {
57- Directory . CreateDirectory ( LogPath ) ;
81+ DirectoryPath = logPath
82+ } ;
83+
84+ // 確保目錄存在
85+ if ( ! Directory . Exists ( logPath ) )
86+ {
87+ Directory . CreateDirectory ( logPath ) ;
5888 }
89+
90+ // 確定檔案路徑和是否需要新檔案
91+ DetermineLogFile ( fileInfo , name ) ;
92+
93+ return fileInfo ;
5994 }
6095
6196 /// <summary>
62- /// 判斷有無檔案或檔案過大,若沒有或檔案過大則建立新檔案
97+ /// 確定日誌檔案路徑和狀態
6398 /// </summary>
64- /// <param name="_LogPath">檔案路徑</param>
65- /// <param name="_FileName">檔案名稱</param>
66- private static string CheckFileExistCreate ( string _LogPath , string _FileName )
99+ private static void DetermineLogFile ( LogFileInfo fileInfo , string name )
67100 {
68- var LogFIleName = $ "{ _FileName } _Log.txt";
69- var SearchFIleName = $ "{ _FileName } *";
70- FileExistCreate ( _LogPath + LogFIleName ) ;
71-
72- DirectoryInfo di = new DirectoryInfo ( _LogPath ) ;
73- var Files = di . GetFiles ( SearchFIleName ) . OrderBy ( x => x . LastWriteTimeUtc ) . ToArray ( ) ;
74- var NowWriteFile = Files [ Files . Length - 1 ] ;
75- if ( NowWriteFile . Length > LogConfiguration . Current . MaxFileSize )
101+ var logFileName = $ "{ name } _Log.txt";
102+ var searchPattern = $ "{ name } *";
103+ var di = new DirectoryInfo ( fileInfo . DirectoryPath ) ;
104+ var files = di . GetFiles ( searchPattern ) . OrderBy ( x => x . LastWriteTimeUtc ) . ToArray ( ) ;
105+
106+ if ( files . Length == 0 )
76107 {
77- var FileNameSplits = NowWriteFile . Name . Replace ( "_" + _FileName , "" ) . Split ( '_' ) ;
78- if ( ! FileNameSplits [ 1 ] . Contains ( "part" ) )
79- {
80- LogFIleName = $ "{ _FileName } _part{ 1 } _Log.txt";
81- }
82- else
108+ fileInfo . FilePath = Path . Combine ( fileInfo . DirectoryPath , logFileName ) ;
109+ fileInfo . RequiresNewFile = true ;
110+ return ;
111+ }
112+
113+ var currentFile = files . Last ( ) ;
114+ if ( currentFile . Length > LogConfiguration . Current . MaxFileSize )
115+ {
116+ var splits = currentFile . Name . Replace ( "_" + name , "" ) . Split ( '_' ) ;
117+ int nextPart = 1 ;
118+
119+ if ( splits . Length > 1 && splits [ 1 ] . StartsWith ( "part" ) )
83120 {
84- var Part = Convert . ToInt32 ( FileNameSplits [ 1 ] . Replace ( "part" , "" ) ) ;
85- LogFIleName = $ "{ _FileName } _part{ Part + 1 } _Log.txt";
121+ nextPart = int . Parse ( splits [ 1 ] . Replace ( "part" , "" ) ) + 1 ;
86122 }
87- FileExistCreate ( _LogPath + LogFIleName ) ;
123+
124+ logFileName = $ "{ name } _part{ nextPart } _Log.txt";
125+ fileInfo . RequiresNewFile = true ;
88126 }
89127 else
90128 {
91- LogFIleName = NowWriteFile . Name ;
129+ logFileName = currentFile . Name ;
130+ fileInfo . RequiresNewFile = false ;
92131 }
93- return _LogPath + LogFIleName ;
132+
133+ fileInfo . FilePath = Path . Combine ( fileInfo . DirectoryPath , logFileName ) ;
94134 }
95135
136+
96137 /// <summary>
97- /// 判斷有無檔案,若沒有則建立新檔案
138+ /// 批次寫入日誌到檔案
98139 /// </summary>
99- /// <param name="_LogFilePath"></param>
100- private static void FileExistCreate ( string _LogFilePath )
140+ private static void WriteLogsToFile ( LogFileInfo fileInfo , IEnumerable < LogItem > logs )
101141 {
102- if ( ! File . Exists ( _LogFilePath ) )
142+ // 如果需要新檔案,先創建
143+ if ( fileInfo . RequiresNewFile )
103144 {
104- using ( FileStream fileStream = new FileStream ( _LogFilePath , FileMode . Create ) )
105- {
106- fileStream . Close ( ) ;
107- }
145+ using ( File . Create ( fileInfo . FilePath ) ) { }
108146 }
109- }
110147
111- private static void FIleWriteLine ( object [ ] arg , string _filePath , string _Message )
112- {
113- using ( StreamWriter sw = new StreamWriter ( _filePath , true , Encoding . UTF8 ) )
148+ // 批次寫入所有日誌
149+ using ( var writer = new StreamWriter ( fileInfo . FilePath , true , Encoding . UTF8 ) )
114150 {
115- sw . WriteLine ( _Message , arg ) ;
116- sw . Close ( ) ;
151+ foreach ( var log in logs )
152+ {
153+ writer . WriteLine ( string . Format ( log . Message , log . Args ) ) ;
154+ }
117155 }
118156 }
119157
@@ -124,7 +162,7 @@ private static void Remove_TimeOutLogText()
124162 {
125163 try
126164 {
127- string logBasePath = $ " { AppDomain . CurrentDomain . BaseDirectory } \\ { LogConfiguration . Current . LogPath } \\ " ;
165+ string logBasePath = Path . Combine ( AppDomain . CurrentDomain . BaseDirectory , LogConfiguration . Current . LogPath ) ;
128166 // 確保目錄存在
129167 if ( ! Directory . Exists ( logBasePath ) )
130168 return ;
@@ -150,5 +188,21 @@ private static void Remove_TimeOutLogText()
150188
151189 }
152190 }
191+
192+
193+ #region Class
194+
195+ /// <summary>
196+ /// 日誌檔案資訊類
197+ /// </summary>
198+ private class LogFileInfo
199+ {
200+ public string DirectoryPath { get ; set ; }
201+ public string FilePath { get ; set ; }
202+ public bool RequiresNewFile { get ; set ; }
203+ }
204+
205+
206+ #endregion
153207 }
154208}
0 commit comments