mirror of
https://github.com/sebastian-heinz/mhf-server.git
synced 2025-04-03 13:28:30 +08:00
368 lines
11 KiB
C#
368 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Arrowgene.Services.Buffers;
|
|
using Arrowgene.Services.Logging;
|
|
using Mhf.Cli.Argument;
|
|
using Mhf.Server.Logging;
|
|
|
|
namespace Mhf.Cli
|
|
{
|
|
public class LogWriter : ISwitchConsumer
|
|
{
|
|
private readonly object _consoleLock;
|
|
private readonly HashSet<ushort> _packetIdWhitelist;
|
|
private readonly HashSet<ushort> _packetIdBlacklist;
|
|
private readonly ILogger _logger;
|
|
private readonly Queue<Log> _logQueue;
|
|
private bool _paused;
|
|
private bool _continueing;
|
|
|
|
public LogWriter()
|
|
{
|
|
_logger = LogProvider.Logger(this);
|
|
_packetIdWhitelist = new HashSet<ushort>();
|
|
_packetIdBlacklist = new HashSet<ushort>();
|
|
_logQueue = new Queue<Log>();
|
|
_consoleLock = new object();
|
|
Switches = new List<ISwitchProperty>();
|
|
_paused = false;
|
|
_continueing = false;
|
|
Reset();
|
|
LoadSwitches();
|
|
LogProvider.GlobalLogWrite += LogProviderOnGlobalLogWrite;
|
|
}
|
|
|
|
public List<ISwitchProperty> Switches { get; }
|
|
|
|
/// <summary>
|
|
/// --max-packet-size=64
|
|
/// </summary>
|
|
public int MaxPacketSize { get; set; }
|
|
|
|
/// <summary>
|
|
/// --no-data=true
|
|
/// </summary>
|
|
public bool NoData { get; set; }
|
|
|
|
/// <summary>
|
|
/// --log-level=2
|
|
/// </summary>
|
|
public int MinLogLevel { get; set; }
|
|
|
|
public void Reset()
|
|
{
|
|
MaxPacketSize = -1;
|
|
NoData = false;
|
|
MinLogLevel = (int) LogLevel.Debug;
|
|
_packetIdWhitelist.Clear();
|
|
_packetIdBlacklist.Clear();
|
|
}
|
|
|
|
public void WhitelistPacket(ushort packetId)
|
|
{
|
|
if (_packetIdWhitelist.Contains(packetId))
|
|
{
|
|
_logger.Error($"PacketId:{packetId} is already whitelisted");
|
|
return;
|
|
}
|
|
|
|
_packetIdWhitelist.Add(packetId);
|
|
}
|
|
|
|
public void BlacklistPacket(ushort packetId)
|
|
{
|
|
if (_packetIdBlacklist.Contains(packetId))
|
|
{
|
|
_logger.Error($"PacketId:{packetId} is already blacklisted");
|
|
return;
|
|
}
|
|
|
|
_packetIdBlacklist.Add(packetId);
|
|
}
|
|
|
|
public void Pause()
|
|
{
|
|
_paused = true;
|
|
}
|
|
|
|
public void Continue()
|
|
{
|
|
_continueing = true;
|
|
while (_logQueue.TryDequeue(out Log log))
|
|
{
|
|
WriteLog(log);
|
|
}
|
|
|
|
_paused = false;
|
|
_continueing = false;
|
|
}
|
|
|
|
private void LoadSwitches()
|
|
{
|
|
Switches.Add(
|
|
new SwitchProperty<bool>(
|
|
"--no-data",
|
|
"--no-data=true (true|false)",
|
|
"Don't display packet data",
|
|
bool.TryParse,
|
|
(result => NoData = result)
|
|
)
|
|
);
|
|
Switches.Add(
|
|
new SwitchProperty<int>(
|
|
"--max-packet-size",
|
|
"--max-packet-size=64 (integer)",
|
|
"Don't display packet data",
|
|
int.TryParse,
|
|
(result => MaxPacketSize = result)
|
|
)
|
|
);
|
|
Switches.Add(
|
|
new SwitchProperty<int>(
|
|
"--log-level",
|
|
"--log-level=20 (integer) [Debug=10, Info=20, Error=30]",
|
|
"Only display logs of the same level or above",
|
|
int.TryParse,
|
|
(result => MinLogLevel = result)
|
|
)
|
|
);
|
|
Switches.Add(
|
|
new SwitchProperty<object>(
|
|
"--clear",
|
|
"--clear",
|
|
"Resets all switches to default",
|
|
SwitchProperty<object>.NoOp,
|
|
result => Reset()
|
|
)
|
|
);
|
|
Switches.Add(
|
|
new SwitchProperty<List<ushort>>(
|
|
"--b-list",
|
|
"--b-list=1000,2000,0xAA (PacketId[0xA|10])",
|
|
"A blacklist that does not logs packets specified",
|
|
TryParsePacketIdList,
|
|
results => { AssinPacketIdList(results, BlacklistPacket); }
|
|
)
|
|
);
|
|
Switches.Add(
|
|
new SwitchProperty<List<ushort>>(
|
|
"--w-list",
|
|
"--w-list=1000,2000,0xAA (PacketId[0xA|10])",
|
|
"A whitelist that only logs packets specified",
|
|
TryParsePacketIdList,
|
|
results => { AssinPacketIdList(results, WhitelistPacket); }
|
|
)
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// parses strings like "1:1000,2000,3:4000" into ServerType and PacketId
|
|
/// </summary>
|
|
private bool TryParsePacketIdList(string value, out List<ushort> result)
|
|
{
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
result = null;
|
|
return false;
|
|
}
|
|
|
|
string[] values = value.Split(",");
|
|
|
|
result = new List<ushort>();
|
|
foreach (string entry in values)
|
|
{
|
|
NumberStyles numberStyles;
|
|
String entryStr;
|
|
if (entry.StartsWith("0x"))
|
|
{
|
|
entryStr = entry.Substring(2);
|
|
numberStyles = NumberStyles.HexNumber;
|
|
}
|
|
else
|
|
{
|
|
entryStr = entry;
|
|
numberStyles = NumberStyles.Integer;
|
|
}
|
|
|
|
|
|
if (!ushort.TryParse(entryStr, numberStyles, null, out ushort val))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
result.Add(val);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void AssinPacketIdList(List<ushort> results, Action<ushort> addToPacketList)
|
|
{
|
|
foreach (ushort entry in results)
|
|
{
|
|
addToPacketList(entry);
|
|
}
|
|
}
|
|
|
|
private void LogProviderOnGlobalLogWrite(object sender, LogWriteEventArgs logWriteEventArgs)
|
|
{
|
|
while (_continueing)
|
|
{
|
|
Thread.Sleep(10000);
|
|
}
|
|
|
|
if (_paused)
|
|
{
|
|
_logQueue.Enqueue(logWriteEventArgs.Log);
|
|
return;
|
|
}
|
|
|
|
WriteLog(logWriteEventArgs.Log);
|
|
}
|
|
|
|
private void WriteLog(Log log)
|
|
{
|
|
ConsoleColor consoleColor;
|
|
string text;
|
|
|
|
object tag = log.Tag;
|
|
if (tag is MhfLogPacket logPacket)
|
|
{
|
|
switch (logPacket.LogType)
|
|
{
|
|
case MhfLogType.PacketIn:
|
|
consoleColor = ConsoleColor.Green;
|
|
break;
|
|
case MhfLogType.PacketOut:
|
|
consoleColor = ConsoleColor.Blue;
|
|
break;
|
|
case MhfLogType.PacketUnhandled:
|
|
consoleColor = ConsoleColor.Red;
|
|
break;
|
|
default:
|
|
consoleColor = ConsoleColor.Gray;
|
|
break;
|
|
}
|
|
|
|
text = CreatePacketLog(logPacket);
|
|
}
|
|
else
|
|
{
|
|
LogLevel logLevel = log.LogLevel;
|
|
if ((int) logLevel < MinLogLevel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (logLevel)
|
|
{
|
|
case LogLevel.Debug:
|
|
consoleColor = ConsoleColor.DarkCyan;
|
|
break;
|
|
case LogLevel.Info:
|
|
consoleColor = ConsoleColor.Cyan;
|
|
break;
|
|
case LogLevel.Error:
|
|
consoleColor = ConsoleColor.Red;
|
|
break;
|
|
default:
|
|
consoleColor = ConsoleColor.Gray;
|
|
break;
|
|
}
|
|
|
|
text = log.ToString();
|
|
}
|
|
|
|
if (text == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lock (_consoleLock)
|
|
{
|
|
Console.ForegroundColor = consoleColor;
|
|
Console.WriteLine(text);
|
|
Console.ResetColor();
|
|
}
|
|
}
|
|
|
|
private bool ExcludeLog(ushort packetId)
|
|
{
|
|
bool useWhitelist = _packetIdWhitelist.Count > 0;
|
|
bool whitelisted = _packetIdWhitelist.Contains(packetId);
|
|
bool blacklisted = _packetIdBlacklist.Contains(packetId);
|
|
|
|
if (useWhitelist && whitelisted)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (useWhitelist)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (blacklisted)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private string CreatePacketLog(MhfLogPacket logPacket)
|
|
{
|
|
ushort packetId = logPacket.Id;
|
|
|
|
if (ExcludeLog(packetId))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int dataSize = logPacket.Data.Size;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append($"{logPacket.ClientIdentity} Packet Log");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append("----------");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append($"[{logPacket.TimeStamp:HH:mm:ss}][Typ:{logPacket.LogType}]");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append(
|
|
$"[Id:0x{logPacket.Id:X2}|{logPacket.Id}][BodyLen:{logPacket.Data.Size}][{logPacket.PacketIdName}]");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append(logPacket.Header.ToLogText());
|
|
sb.Append(Environment.NewLine);
|
|
|
|
if (!NoData)
|
|
{
|
|
IBuffer data = logPacket.Data;
|
|
int maxPacketSize = MaxPacketSize;
|
|
if (maxPacketSize > 0 && dataSize > maxPacketSize)
|
|
{
|
|
data = data.Clone(0, maxPacketSize);
|
|
|
|
sb.Append($"- Truncated Data showing {maxPacketSize} of {dataSize} bytes");
|
|
sb.Append(Environment.NewLine);
|
|
}
|
|
|
|
sb.Append("ASCII:");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append(data.ToAsciiString(true));
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append("HEX:");
|
|
sb.Append(Environment.NewLine);
|
|
sb.Append(data.ToHexString(' '));
|
|
sb.Append(Environment.NewLine);
|
|
}
|
|
|
|
sb.Append("----------");
|
|
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|