C3032
2025-12-20 15492363f898704b51afce5f1c88fa3b754cbabc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using SmartScanner.ViewModel;
 
namespace SmartScanner
{
    /// <summary>
    /// 优化的日志自动保存服务
    /// 功能:批量保存24小时内每一条日志到D盘02 LBLog文件夹
    /// 触发条件:最多100条或5秒内批量保存一次
    /// </summary>
    public class LogAutoSaveService
    {
        private readonly ObservableCollection<LogEntry> _logEntries;
        private Timer _cleanupTimer;
        private Timer _batchSaveTimer;
        private const int CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1小时清理一次
        private const int BATCH_SAVE_INTERVAL_MS = 5000; // 5秒批量保存一次
        private const int MAX_BATCH_SIZE = 100; // 最多100条日志批量保存
        private readonly string _logDirectory = @"D:\02 LBLog";
        private bool _isSaving = false;
        private readonly object _fileLock = new object();
        private readonly object _bufferLock = new object();
        private string _currentLogFilePath;
        private readonly Queue<LogEntry> _logBuffer = new Queue<LogEntry>(); // 日志缓冲区
        private int _bufferCount = 0; // 缓冲区计数
 
        public LogAutoSaveService(ObservableCollection<LogEntry> logEntries)
        {
            _logEntries = logEntries ?? throw new ArgumentNullException(nameof(logEntries));
            
            // 创建日志目录
            if (!Directory.Exists(_logDirectory))
            {
                Directory.CreateDirectory(_logDirectory);
            }
            
            // 初始化当前日志文件路径
            InitializeCurrentLogFile();
            
            // 启动批量保存定时器
            _batchSaveTimer = new Timer(OnBatchSaveTimerElapsed, null, BATCH_SAVE_INTERVAL_MS, BATCH_SAVE_INTERVAL_MS);
            
            // 启动清理定时器
            _cleanupTimer = new Timer(OnCleanupTimerElapsed, null, CLEANUP_INTERVAL_MS, CLEANUP_INTERVAL_MS);
        }
 
        /// <summary>
        /// 初始化当前日志文件路径
        /// </summary>
        private void InitializeCurrentLogFile()
        {
            string currentDate = DateTime.Now.ToString("yyyyMMdd");
            string fileName = $"Log_{currentDate}.txt";
            _currentLogFilePath = Path.Combine(_logDirectory, fileName);
        }
 
        /// <summary>
        /// 添加日志到缓冲区,延迟批量保存
        /// </summary>
        public void LogAdded(LogEntry logEntry)
        {
            if (_isSaving) return;
            
            lock (_bufferLock)
            {
                _logBuffer.Enqueue(logEntry);
                _bufferCount++;
                
                // 如果缓冲区达到最大大小,立即触发保存
                if (_bufferCount >= MAX_BATCH_SIZE)
                {
                    Task.Run(() => SaveBatchAsync());
                }
            }
        }
 
        /// <summary>
        /// 批量保存定时器回调
        /// </summary>
        private void OnBatchSaveTimerElapsed(object state)
        {
            if (!_isSaving && _bufferCount > 0)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
 
        /// <summary>
        /// 异步批量保存日志
        /// </summary>
        private async Task SaveBatchAsync()
        {
            if (_isSaving) return;
            
            _isSaving = true;
            
            try
            {
                // 检查是否需要切换到新文件
                await CheckAndSwitchLogFileAsync();
                
                // 获取缓冲区中的所有日志
                List<LogEntry> batchToSave;
                lock (_bufferLock)
                {
                    if (_bufferCount == 0)
                    {
                        _isSaving = false;
                        return;
                    }
                    
                    batchToSave = new List<LogEntry>(_logBuffer);
                    _logBuffer.Clear();
                    _bufferCount = 0;
                }
                
                // 批量保存到文件
                await SaveBatchToFileAsync(batchToSave);
                
                Console.WriteLine($"批量保存了 {batchToSave.Count} 条日志到文件");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量保存失败: {ex.Message}");
            }
            finally
            {
                _isSaving = false;
            }
        }
 
        /// <summary>
        /// 批量保存日志到文件
        /// </summary>
        private async Task SaveBatchToFileAsync(List<LogEntry> batch)
        {
            await Task.Run(() =>
            {
                lock (_fileLock)
                {
                    try
                    {
                        using (StreamWriter writer = new StreamWriter(_currentLogFilePath, true, Encoding.UTF8))
                        {
                            foreach (var entry in batch)
                            {
                                string logLine = $"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{entry.Level}] {entry.Message}";
                                writer.WriteLine(logLine);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"批量保存到文件失败: {ex.Message}");
                    }
                }
            });
        }
 
        /// <summary>
        /// 检查是否需要切换到新的日志文件
        /// </summary>
        private async Task CheckAndSwitchLogFileAsync()
        {
            await Task.Run(() =>
            {
                string currentDate = DateTime.Now.ToString("yyyyMMdd");
                string fileName = $"Log_{currentDate}.txt";
                string newFilePath = Path.Combine(_logDirectory, fileName);
 
                // 如果日期变化,切换到新文件
                if (_currentLogFilePath != newFilePath)
                {
                    _currentLogFilePath = newFilePath;
                }
            });
        }
 
        private void OnCleanupTimerElapsed(object state)
        {
            // 清理超过48小时的日志文件
            if (!_isSaving)
            {
                Task.Run(() => CleanupOldLogFilesAsync());
            }
        }
 
        /// <summary>
        /// 清理超过48小时的日志文件
        /// </summary>
        private async Task CleanupOldLogFilesAsync()
        {
            await Task.Run(() =>
            {
                try
                {
                    if (Directory.Exists(_logDirectory))
                    {
                        var files = Directory.GetFiles(_logDirectory, "Log_*.txt");
                        DateTime cutoffTime = DateTime.Now.AddHours(-48);
 
                        foreach (string file in files)
                        {
                            try
                            {
                                FileInfo fileInfo = new FileInfo(file);
                                if (fileInfo.LastWriteTime < cutoffTime)
                                {
                                    File.Delete(file);
                                    Console.WriteLine($"清理过期日志文件: {file}");
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"清理文件失败 {file}: {ex.Message}");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"清理过期日志文件失败: {ex.Message}");
                }
            });
        }
 
        /// <summary>
        /// 手动保存当前所有日志
        /// </summary>
        public void ForceSave()
        {
            if (!_isSaving)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
 
        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            _batchSaveTimer?.Dispose();
            _batchSaveTimer = null;
            _cleanupTimer?.Dispose();
            _cleanupTimer = null;
            
            // 保存最后的日志
            if (!_isSaving && _bufferCount > 0)
            {
                ForceSave();
            }
        }
 
        /// <summary>
        /// 获取保存统计信息
        /// </summary>
        public string GetStatus()
        {
            try
            {
                string currentFileInfo = "";
                if (File.Exists(_currentLogFilePath))
                {
                    FileInfo fileInfo = new FileInfo(_currentLogFilePath);
                    currentFileInfo = $", 当前文件大小: {fileInfo.Length / 1024} KB";
                }
                
                return $"自动保存服务运行中 - 缓冲区: {_bufferCount} 条{currentFileInfo}";
            }
            catch
            {
                return $"自动保存服务运行中 - 缓冲区: {_bufferCount} 条";
            }
        }
    }
}