179 lines
6.1 KiB
C#
179 lines
6.1 KiB
C#
using FATrace.WPLApp.Core;
|
|
using Prism.Commands;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Threading;
|
|
|
|
namespace FATrace.WPLApp.ViewModels
|
|
{
|
|
public class LogViewModel : NavigationViewModel
|
|
{
|
|
private readonly DispatcherTimer _timer;
|
|
|
|
public LogViewModel()
|
|
{
|
|
Levels = new ObservableCollection<string>(new[] { "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" });
|
|
_selectedDate = DateTime.Today;
|
|
_levelFilter = Levels.First();
|
|
_maxLines = 2000;
|
|
|
|
RefreshCommand = new DelegateCommand(async () => await LoadAsync(), () => !IsBusy).ObservesProperty(() => IsBusy);
|
|
OpenFolderCommand = new DelegateCommand(OpenFolder);
|
|
|
|
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
|
|
_timer.Tick += async (_, __) =>
|
|
{
|
|
if (AutoRefresh && !IsBusy)
|
|
await LoadAsync();
|
|
};
|
|
_timer.Start();
|
|
|
|
// 初始加载当日日志
|
|
_ = LoadAsync();
|
|
}
|
|
|
|
public ObservableCollection<string> Levels { get; }
|
|
|
|
private ObservableCollection<LogEntry> _items = new();
|
|
public ObservableCollection<LogEntry> Items { get => _items; set { _items = value; RaisePropertyChanged(); } }
|
|
|
|
private DateTime? _selectedDate;
|
|
public DateTime? SelectedDate { get => _selectedDate; set { _selectedDate = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
|
|
|
private string _levelFilter;
|
|
public string LevelFilter { get => _levelFilter; set { _levelFilter = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
|
|
|
private string _keyword;
|
|
public string Keyword { get => _keyword; set { _keyword = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
|
|
|
private bool _autoRefresh;
|
|
public bool AutoRefresh { get => _autoRefresh; set { _autoRefresh = value; RaisePropertyChanged(); } }
|
|
|
|
private int _maxLines;
|
|
public int MaxLines { get => _maxLines; set { _maxLines = value; RaisePropertyChanged(); } }
|
|
|
|
private bool _isBusy;
|
|
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
|
|
|
public DelegateCommand RefreshCommand { get; }
|
|
public DelegateCommand OpenFolderCommand { get; }
|
|
|
|
private string GetLogDirectory()
|
|
{
|
|
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
|
|
}
|
|
|
|
private string GetLogFilePath(DateTime? date)
|
|
{
|
|
var dir = GetLogDirectory();
|
|
var dt = date ?? DateTime.Today;
|
|
var file = dt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log";
|
|
return Path.Combine(dir, file);
|
|
}
|
|
|
|
private static bool PassLevel(string levelFilter, string level)
|
|
{
|
|
if (string.Equals(levelFilter, "ALL", StringComparison.OrdinalIgnoreCase)) return true;
|
|
return string.Equals(level, levelFilter, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private async Task LoadAsync()
|
|
{
|
|
if (IsBusy) return;
|
|
IsBusy = true;
|
|
try
|
|
{
|
|
var path = GetLogFilePath(SelectedDate);
|
|
var list = await Task.Run(() => ReadLogFile(path, MaxLines));
|
|
|
|
var filtered = list.Where(x => PassLevel(LevelFilter, x.Level)
|
|
&& (string.IsNullOrWhiteSpace(Keyword) || (x.Message?.IndexOf(Keyword, StringComparison.OrdinalIgnoreCase) >= 0)
|
|
|| (x.Logger?.IndexOf(Keyword, StringComparison.OrdinalIgnoreCase) >= 0)));
|
|
|
|
Items = new ObservableCollection<LogEntry>(filtered);
|
|
}
|
|
catch
|
|
{
|
|
Items = new ObservableCollection<LogEntry>();
|
|
}
|
|
finally
|
|
{
|
|
IsBusy = false;
|
|
}
|
|
}
|
|
|
|
private static IReadOnlyList<LogEntry> ReadLogFile(string path, int maxLines)
|
|
{
|
|
var result = new LinkedList<LogEntry>();
|
|
if (!File.Exists(path)) return result.ToList();
|
|
|
|
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
using var sr = new StreamReader(fs, Encoding.UTF8);
|
|
|
|
string? line;
|
|
while ((line = sr.ReadLine()) != null)
|
|
{
|
|
var entry = ParseLine(line);
|
|
result.AddLast(entry);
|
|
if (result.Count > maxLines) result.RemoveFirst();
|
|
}
|
|
return result.ToList();
|
|
}
|
|
|
|
private static LogEntry ParseLine(string line)
|
|
{
|
|
// layout: longdate|LEVEL|logger|threadid|message[|exception]
|
|
var parts = line.Split('|');
|
|
var entry = new LogEntry();
|
|
if (parts.Length >= 4)
|
|
{
|
|
entry.Time = parts[0];
|
|
entry.Level = parts[1];
|
|
entry.Logger = parts[2];
|
|
entry.ThreadId = parts[3];
|
|
if (parts.Length >= 5)
|
|
{
|
|
entry.Message = string.Join("|", parts.Skip(4));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
entry.Message = line;
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
private void OpenFolder()
|
|
{
|
|
var dir = GetLogDirectory();
|
|
Directory.CreateDirectory(dir);
|
|
try
|
|
{
|
|
Process.Start(new ProcessStartInfo
|
|
{
|
|
FileName = dir,
|
|
UseShellExecute = true
|
|
});
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
|
|
public class LogEntry
|
|
{
|
|
public string Time { get; set; }
|
|
public string Level { get; set; }
|
|
public string Logger { get; set; }
|
|
public string ThreadId { get; set; }
|
|
public string Message { get; set; }
|
|
}
|
|
}
|