Kit.Core/LibCommon/Kit.Core.Helpers/Log/CallStackLog.cs

223 lines
6.4 KiB
C#

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Kit.Helpers.Log
{
public interface ICallStackLog
{
string LogMessage { get; }
ICallStackLog NextLevel();
void FinishLevel();
void BeginCall(string message);
void EndCall();
}
public class EmptyCallStackLog : ICallStackLog
{
public string LogMessage
{
get { return ""; }
}
public ICallStackLog NextLevel()
{
return CallStackLog.Empty;
}
public void FinishLevel()
{
return;
}
public void BeginCall(string message)
{
return;
}
public void EndCall()
{
return;
}
}
public class CallStackLog : ICallStackLog
{
protected ConcurrentDictionary<string, long> Logs { get; }
protected ConcurrentBag<CallStackLog> ChildCallStackLogs { get; set; }
protected readonly int _level;
protected readonly string _path;
protected string _currentCall;
protected int _number;
protected readonly Stopwatch _stopwatch = new Stopwatch();
public static ICallStackLog Empty { get { return new EmptyCallStackLog(); } }
protected string Number
{
get
{
return _number.ToString("D5");
}
}
public CallStackLog()
{
Logs = new ConcurrentDictionary<string, long>();
ChildCallStackLogs = new ConcurrentBag<CallStackLog>();
_level = 0;
_path = "";
_number = 1;
}
public CallStackLog(int level, string path)
{
Logs = new ConcurrentDictionary<string, long>();
ChildCallStackLogs = new ConcurrentBag<CallStackLog>();
_level = level;
_path = path;
_number = 1;
}
public string LogMessage
{
get
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var logLine in Logs.OrderBy(x => x.Key))
{
string time = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:0.000}", logLine.Value / 1000.0f);
stringBuilder.AppendLine(logLine.Key + $". Time - {time} ms");
}
return stringBuilder.ToString();
}
}
public ConcurrentDictionary<string, long> GetLogs
{
get {
return this.Logs;
}
}
public ICallStackLog NextLevel()
{
var childCallStackLog = new CallStackLog(_level + 1, _path + this.Number + ".");
ChildCallStackLogs.Add(childCallStackLog);
return childCallStackLog;
}
public void FinishLevel()
{
foreach (CallStackLog childCallStackLog in ChildCallStackLogs)
{
lock (Logs)
{
foreach (var logLine in childCallStackLog.Logs)
{
if (Logs.ContainsKey(logLine.Key))
{
Logs[logLine.Key] += logLine.Value;
}
else
{
Logs[logLine.Key] = logLine.Value;
}
}
}
}
ChildCallStackLogs = new ConcurrentBag<CallStackLog>();
}
public void BeginCall(string message)
{
_currentCall = message;
_stopwatch.Restart();
}
public void EndCall()
{
_stopwatch.Stop();
lock (Logs)
{
long ticksByMicrosecond = Stopwatch.Frequency / (1000L * 1000L);
long microSeconds = _stopwatch.ElapsedTicks / ticksByMicrosecond;
Logs.TryAdd($"{_path}{this.Number} {_currentCall.ToStringOrEmpty()}", microSeconds);
_number++;
}
}
}
public class CallStackLogFile : ICallStackLog
{
protected object _lock = new object();
protected ConcurrentBag<CallStackLogFile> ChildCallStackLogs { get; set; }
protected readonly int _level;
protected readonly string _path;
protected string _currentCall;
protected int _number;
protected readonly Stopwatch _stopwatch = new Stopwatch();
protected readonly StreamWriter _writer;
public static ICallStackLog Empty { get { return new EmptyCallStackLog(); } }
protected string Number
{
get
{
return _number.ToString("D5");
}
}
public CallStackLogFile(StreamWriter writer)
{
_writer = writer;
ChildCallStackLogs = new ConcurrentBag<CallStackLogFile>();
_level = 0;
_path = "";
_number = 1;
}
public CallStackLogFile(StreamWriter writer, int level, string path)
{
_writer = writer;
ChildCallStackLogs = new ConcurrentBag<CallStackLogFile>();
_level = level;
_path = path;
_number = 1;
}
public string LogMessage => string.Empty;
public ICallStackLog NextLevel()
{
var childCallStackLog = new CallStackLogFile(_writer, _level + 1, _path + this.Number + ".");
ChildCallStackLogs.Add(childCallStackLog);
return childCallStackLog;
}
public void FinishLevel()
{
ChildCallStackLogs = new ConcurrentBag<CallStackLogFile>();
}
public void BeginCall(string message)
{
_currentCall = message;
_stopwatch.Restart();
}
public void EndCall()
{
_stopwatch.Stop();
lock (_lock)
{
long microSeconds = _stopwatch.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
string time = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:0.000}", microSeconds / 1000.0f);
_writer?.WriteLine($"{_path}{this.Number} {_currentCall.ToStringOrEmpty()}. Time - {time} ms");
_number++;
}
}
}
}