193 lines
5.2 KiB
C#
193 lines
5.2 KiB
C#
|
|
using System.Collections.Concurrent;
|
|
using System.Diagnostics;
|
|
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
|
|
{
|
|
if (_number <= 9)
|
|
return "0" + _number;
|
|
return _number.ToString();
|
|
}
|
|
}
|
|
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))
|
|
{
|
|
stringBuilder.AppendLine(logLine.Key + $". Time - {logLine.Value} 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;
|
|
continue;
|
|
}
|
|
|
|
Logs.TryAdd(logLine.Key, logLine.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
ChildCallStackLogs = new ConcurrentBag<CallStackLog>();
|
|
}
|
|
|
|
public void BeginCall(string message)
|
|
{
|
|
_currentCall = message;
|
|
_stopwatch.Restart();
|
|
}
|
|
|
|
public void EndCall()
|
|
{
|
|
_stopwatch.Stop();
|
|
lock (Logs)
|
|
{
|
|
Logs.TryAdd($"{_path}{this.Number} {_currentCall.ToStringOrEmpty()}", _stopwatch.ElapsedMilliseconds);
|
|
_number++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public class CallStackLogDB: CallStackLog, IDisposable
|
|
{
|
|
protected string _sessionKey;
|
|
protected LogMessageType _type;
|
|
protected string _target;
|
|
protected string _action;
|
|
protected DateTime _dateCreated;
|
|
private bool disposed = false;
|
|
public CallStackLogDB(string sessionKey, LogMessageType type, string target, string action):base()
|
|
{
|
|
_sessionKey = sessionKey;
|
|
_type = type;
|
|
_target = target;
|
|
_action = action;
|
|
_dateCreated = DateTime.UtcNow;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
// подавляем финализацию
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!disposed)
|
|
{
|
|
if (disposing)
|
|
{
|
|
this.Logs.TryAdd($"Full Time", Convert.ToInt64((DateTime.UtcNow - _dateCreated).TotalMilliseconds));
|
|
|
|
Kit.Helpers.Log.LoggerDB.Commit(this._sessionKey, this._type, this._target, this._action, _dateCreated, this.Logs.ToDictionary(x => x.Key, x => x.Value));
|
|
}
|
|
// освобождаем неуправляемые объекты
|
|
disposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|