using System.Diagnostics; using YLErp.Commons; using YLErp.Events; namespace YLErp.Forms { public partial class FormTraceLog : Form { readonly InnerTraceListener _traceListener; public FormTraceLog() { InitializeComponent(); _traceListener = new InnerTraceListener(richTextBox1); EventBus.Subscribe(_traceListener.HandleTraceEvent); Trace.Listeners.Clear(); Trace.Listeners.Add(_traceListener); } private void FormTraceLog_Load(object sender, EventArgs e) { } private void FormLog_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; Hide(); } } private void menuClearLog_Click(object sender, EventArgs e) { _traceListener.Reset(); } } class InnerTraceListener : TraceListener { const int MaxDataCount = 3000; const int MaxDataDiscardCount = 2000; const string UrlPrefix = "http://trace/"; readonly List _datalist; readonly RichTextBox _richTextBox; int _loopSeq; readonly Action _appendTextAction; public InnerTraceListener(RichTextBox richTextBox) { _richTextBox = richTextBox; _richTextBox.DetectUrls = true; _richTextBox.LinkClicked += richTextBox_LinkClicked; _datalist = new List(MaxDataCount + 100); _appendTextAction = text => _richTextBox.Text += text; } private void AppendTextInvoke(string text) { _richTextBox.BeginInvoke(_appendTextAction, text); } public void Reset() { lock (_datalist) { _loopSeq = 0; _datalist.Clear(); _richTextBox.Clear(); } } private void richTextBox_LinkClicked(object sender, LinkClickedEventArgs e) { if (!e.LinkText.StartsWith(UrlPrefix)) return; var text = e.LinkText.Substring(13); var index = text.IndexOf('/'); if (index < 0) return; var index2 = text.IndexOf('#', index + 1); var left = text.Substring(0, index); var right = text.Substring(index + 1, index2 - index - 1); lock (_datalist) { index = (int.Parse(left) - _loopSeq) * 2000 + int.Parse(right); if (index >= 0) { var json = JsonHelper.Serialize(_datalist[index]); var form = new FormJsonView(); form.SetJson(json); form.ShowDialog(); } } } public override void Write(string message) { AppendTextInvoke(message); } public override void WriteLine(string message) { AppendTextInvoke($"{DateTime.Now:G} [--]{message}{Environment.NewLine}"); } public override void WriteLine(string message, string category) { AppendTextInvoke($"{DateTime.Now:G} [{category}] {message}{Environment.NewLine}"); } public override void WriteLine(object obj, string category) { var wrap = obj as TraceDataWrap; if (wrap != null) { obj = wrap.Data; } if (obj is null) { AppendTextInvoke($"{DateTime.Now:G} [{category}] {UrlPrefix}null#{wrap?.DataDesc}{Environment.NewLine}"); return; } int curSeq = AddData(wrap?.Data ?? obj); AppendTextInvoke($"{DateTime.Now:G} [{category}] {UrlPrefix}{_loopSeq}/{curSeq}#{wrap?.DataDesc}{Environment.NewLine}"); } public void HandleTraceEvent(TraceEvent trace) { if (trace == null) return; if (trace.Data != null) { int curSeq = AddData(trace.Data); AppendTextInvoke($"{DateTime.Now:G} [{trace.Category}] {trace.Message} {UrlPrefix}{_loopSeq}/{curSeq}#{trace.DataDesc}{Environment.NewLine}"); } else { AppendTextInvoke($"{DateTime.Now:G} [{trace.Category}] {trace.Message}{Environment.NewLine}"); } } private int AddData(object data) { if (_datalist.Count > MaxDataCount) { _loopSeq++; _datalist.RemoveRange(0, MaxDataDiscardCount); } var count = _datalist.Count; _datalist.Add(data); return count; } } }