[성현모] Http, Socket 통신 추가
This commit is contained in:
112
Projects/SystemX.Core/SystemX.Core/Communication/Http.cs
Normal file
112
Projects/SystemX.Core/SystemX.Core/Communication/Http.cs
Normal file
@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.Communication
|
||||
{
|
||||
public class Http
|
||||
{
|
||||
/// <summary>
|
||||
/// PostJsonAsync
|
||||
/// </summary>
|
||||
/// <param name="url">https://127.0.0.1:443</param>
|
||||
/// <param name="timeOutSeconds">Range 5~30 secconds</param>
|
||||
public virtual async Task<RESPONSE?> PostJsonAsync<REQUEST, RESPONSE>(string url, REQUEST request, short timeOutSeconds = 5) where REQUEST : class where RESPONSE : class
|
||||
{
|
||||
RESPONSE? response = default(RESPONSE);
|
||||
Guid guid = Guid.NewGuid();
|
||||
|
||||
using (HttpClient httpClient = new HttpClient(GetClientHandler()))
|
||||
{
|
||||
int retry = 0;
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
try
|
||||
{
|
||||
var timeOutSec = SetTimeout(timeOutSeconds);
|
||||
httpClient.Timeout = new TimeSpan(0, 0, timeOutSec);
|
||||
httpClient.BaseAddress = new Uri($"{url}");
|
||||
|
||||
Log4net.WriteLine($"[POST] Request({guid})::{url}{Environment.NewLine}{request?.ToJson()}", LogType.HTTP);
|
||||
|
||||
DateTime requestTime = DateTime.Now;
|
||||
var res = await httpClient.PostAsJsonAsync(url, request);
|
||||
response = await res.Content.ReadFromJsonAsync<RESPONSE>();
|
||||
|
||||
Log4net.WriteLine($"[POST] Rseponse({guid}) ({(DateTime.Now - requestTime).TotalSeconds} sec)::{url}{Environment.NewLine}{response?.ToJson()}", LogType.HTTP);
|
||||
break;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine(e);
|
||||
retry += 1;
|
||||
}
|
||||
|
||||
if (retry > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetJsonAsnyc
|
||||
/// </summary>
|
||||
/// <param name="url">https://127.0.0.1:443</param>
|
||||
/// <param name="timeOutSeconds">Range 5~30 secconds</param>
|
||||
public virtual async Task<RESPONSE?> GetJsonAsync<RESPONSE>(string url, short timeOutSeconds = 10) where RESPONSE : class
|
||||
{
|
||||
RESPONSE? response = default(RESPONSE);
|
||||
Guid guid = Guid.NewGuid();
|
||||
|
||||
using (HttpClient httpClient = new HttpClient(GetClientHandler()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeOutSec = SetTimeout(timeOutSeconds);
|
||||
httpClient.Timeout = new TimeSpan(0, 0, timeOutSec);
|
||||
httpClient.BaseAddress = new Uri($"{url}");
|
||||
|
||||
Log4net.WriteLine($"[GET] Request({guid})::{url}", LogType.HTTP);
|
||||
|
||||
DateTime requestTime = DateTime.Now;
|
||||
response = await httpClient.GetFromJsonAsync<RESPONSE>(url);
|
||||
|
||||
Log4net.WriteLine($"[GET] Rseponse({guid}) ({(DateTime.Now - requestTime).TotalSeconds} sec)::{url}", LogType.HTTP);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected HttpClientHandler GetClientHandler()
|
||||
{
|
||||
HttpClientHandler clientHandler = new HttpClientHandler();
|
||||
clientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
return clientHandler;
|
||||
}
|
||||
|
||||
protected short SetTimeout(short timeOutSeconds)
|
||||
{
|
||||
short timeoutMin = 5;
|
||||
short timeoutMax = 30;
|
||||
|
||||
timeOutSeconds = Math.Clamp(timeOutSeconds, timeoutMin, timeoutMax);
|
||||
|
||||
return timeOutSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Collections.Specialized.BitVector32;
|
||||
|
||||
namespace SystemX.Core.Communication
|
||||
{
|
||||
public class Listener
|
||||
{
|
||||
Socket _listenSocket;
|
||||
Func<Session> _sessionFactory;
|
||||
|
||||
public void Init(IPEndPoint endPoint, Func<Session> sessionFactory, int register = 10, int backlog = 100)
|
||||
{
|
||||
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
_sessionFactory += sessionFactory;
|
||||
|
||||
_listenSocket.Bind(endPoint);
|
||||
|
||||
// backlog : 최대 대기수
|
||||
_listenSocket.Listen(backlog);
|
||||
|
||||
for (int i = 0; i < register; i++)
|
||||
{
|
||||
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
|
||||
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
|
||||
RegisterAccept(args);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAccept(SocketAsyncEventArgs args)
|
||||
{
|
||||
args.AcceptSocket = null;
|
||||
|
||||
bool pending = _listenSocket.AcceptAsync(args);
|
||||
if (pending == false)
|
||||
OnAcceptCompleted(null, args);
|
||||
}
|
||||
|
||||
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
if (args.SocketError == SocketError.Success)
|
||||
{
|
||||
Session session = _sessionFactory.Invoke();
|
||||
session.Start(args.AcceptSocket);
|
||||
session.OnConnected(args.AcceptSocket.RemoteEndPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4net.WriteLine(args.SocketError.ToString(), LogType.Error);
|
||||
}
|
||||
|
||||
RegisterAccept(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.Communication
|
||||
{
|
||||
public class RecvBuffer
|
||||
{
|
||||
// [r][][w][][][][][][][]
|
||||
ArraySegment<byte> _buffer;
|
||||
int _readPos;
|
||||
int _writePos;
|
||||
|
||||
public RecvBuffer(int bufferSize)
|
||||
{
|
||||
_buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
|
||||
}
|
||||
|
||||
public int DataSize { get { return _writePos - _readPos; } }
|
||||
public int FreeSize { get { return _buffer.Count - _writePos; } }
|
||||
|
||||
public ArraySegment<byte> ReadSegment
|
||||
{
|
||||
get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _readPos, DataSize); }
|
||||
}
|
||||
|
||||
public ArraySegment<byte> WriteSegment
|
||||
{
|
||||
get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _writePos, FreeSize); }
|
||||
}
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
int dataSize = DataSize;
|
||||
if (dataSize == 0)
|
||||
{
|
||||
// 남은 데이터가 없으면 복사하지 않고 커서 위치만 리셋
|
||||
_readPos = _writePos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 남은 찌끄레기가 있으면 시작 위치로 복사
|
||||
Array.Copy(_buffer.Array, _buffer.Offset + _readPos, _buffer.Array, _buffer.Offset, dataSize);
|
||||
_readPos = 0;
|
||||
_writePos = dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnRead(int numOfBytes)
|
||||
{
|
||||
if (numOfBytes > DataSize)
|
||||
return false;
|
||||
|
||||
_readPos += numOfBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnWrite(int numOfBytes)
|
||||
{
|
||||
if (numOfBytes > FreeSize)
|
||||
return false;
|
||||
|
||||
_writePos += numOfBytes;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.Communication
|
||||
{
|
||||
public abstract class PacketSession : Session
|
||||
{
|
||||
public static readonly int HeaderSize = 2;
|
||||
|
||||
// [size(2)][packetId(2)][ ... ][size(2)][packetId(2)][ ... ]
|
||||
public sealed override int OnRecv(ArraySegment<byte> buffer)
|
||||
{
|
||||
int processLen = 0;
|
||||
int packetCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// 최소한 헤더는 파싱할 수 있는지 확인
|
||||
if (buffer.Count < HeaderSize)
|
||||
break;
|
||||
|
||||
// 패킷이 완전체로 도착했는지 확인
|
||||
ushort dataSize = BitConverter.ToUInt16(buffer.Array, buffer.Offset);
|
||||
if (buffer.Count < dataSize)
|
||||
break;
|
||||
|
||||
// 여기까지 왔으면 패킷 조립 가능
|
||||
OnRecvPacket(new ArraySegment<byte>(buffer.Array, buffer.Offset, dataSize));
|
||||
packetCount++;
|
||||
|
||||
processLen += dataSize;
|
||||
buffer = new ArraySegment<byte>(buffer.Array, buffer.Offset + dataSize, buffer.Count - dataSize);
|
||||
}
|
||||
|
||||
return processLen;
|
||||
}
|
||||
|
||||
public abstract void OnRecvPacket(ArraySegment<byte> buffer);
|
||||
}
|
||||
|
||||
public abstract class Session
|
||||
{
|
||||
Socket _socket;
|
||||
int _disconnected = 0;
|
||||
|
||||
RecvBuffer _recvBuffer = new RecvBuffer(65535);
|
||||
|
||||
object _lock = new object();
|
||||
Queue<ArraySegment<byte>> _sendQueue = new Queue<ArraySegment<byte>>();
|
||||
List<ArraySegment<byte>> _pendingList = new List<ArraySegment<byte>>();
|
||||
SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs();
|
||||
SocketAsyncEventArgs _recvArgs = new SocketAsyncEventArgs();
|
||||
|
||||
public abstract void OnConnected(EndPoint endPoint);
|
||||
public abstract int OnRecv(ArraySegment<byte> buffer);
|
||||
public abstract void OnSend(int numOfBytes);
|
||||
public abstract void OnDisconnected(EndPoint endPoint);
|
||||
|
||||
void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_sendQueue.Clear();
|
||||
_pendingList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(Socket socket)
|
||||
{
|
||||
Log4net.WriteLine("Session Start");
|
||||
|
||||
_socket = socket;
|
||||
|
||||
_recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted);
|
||||
_sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
|
||||
|
||||
RegisterRecv();
|
||||
}
|
||||
|
||||
public void Send(List<ArraySegment<byte>> sendBuffList)
|
||||
{
|
||||
if (sendBuffList.Count == 0)
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (ArraySegment<byte> sendBuff in sendBuffList)
|
||||
_sendQueue.Enqueue(sendBuff);
|
||||
|
||||
if (_pendingList.Count == 0)
|
||||
RegisterSend();
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(ArraySegment<byte> sendBuff)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_sendQueue.Enqueue(sendBuff);
|
||||
if (_pendingList.Count == 0)
|
||||
RegisterSend();
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _disconnected, 1) == 1)
|
||||
return;
|
||||
|
||||
OnDisconnected(_socket.RemoteEndPoint);
|
||||
_socket.Shutdown(SocketShutdown.Both);
|
||||
_socket.Close();
|
||||
Clear();
|
||||
}
|
||||
|
||||
#region 네트워크 통신
|
||||
|
||||
void RegisterSend()
|
||||
{
|
||||
if (_disconnected == 1)
|
||||
return;
|
||||
|
||||
while (_sendQueue.Count > 0)
|
||||
{
|
||||
ArraySegment<byte> buff = _sendQueue.Dequeue();
|
||||
_pendingList.Add(buff);
|
||||
}
|
||||
_sendArgs.BufferList = _pendingList;
|
||||
|
||||
try
|
||||
{
|
||||
bool pending = _socket.SendAsync(_sendArgs);
|
||||
if (pending == false)
|
||||
OnSendCompleted(null, _sendArgs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine($"RegisterSend Failed {e}", LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSendCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
_sendArgs.BufferList = null;
|
||||
_pendingList.Clear();
|
||||
|
||||
OnSend(_sendArgs.BytesTransferred);
|
||||
|
||||
if (_sendQueue.Count > 0)
|
||||
RegisterSend();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine($"OnSendCompleted Failed {e}", LogType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterRecv()
|
||||
{
|
||||
if (_disconnected == 1)
|
||||
return;
|
||||
|
||||
_recvBuffer.Clean();
|
||||
ArraySegment<byte> segment = _recvBuffer.WriteSegment;
|
||||
_recvArgs.SetBuffer(segment.Array, segment.Offset, segment.Count);
|
||||
|
||||
try
|
||||
{
|
||||
bool pending = _socket.ReceiveAsync(_recvArgs);
|
||||
if (pending == false)
|
||||
OnRecvCompleted(null, _recvArgs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine($"RegisterRecv Failed {e}", LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
void OnRecvCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Write 커서 이동
|
||||
if (_recvBuffer.OnWrite(args.BytesTransferred) == false)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
// 컨텐츠 쪽으로 데이터를 넘겨주고 얼마나 처리했는지 받는다
|
||||
int processLen = OnRecv(_recvBuffer.ReadSegment);
|
||||
if (processLen < 0 || _recvBuffer.DataSize < processLen)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read 커서 이동
|
||||
if (_recvBuffer.OnRead(processLen) == false)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterRecv();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log4net.WriteLine($"OnRecvCompleted Failed {e}", LogType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
Projects/SystemX.Core/SystemX.Core/DB/DataBase.cs
Normal file
33
Projects/SystemX.Core/SystemX.Core/DB/DataBase.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.DB
|
||||
{
|
||||
public class DataBase
|
||||
{
|
||||
[JsonPropertyName("IP")]
|
||||
public string? IP { get; set; }
|
||||
|
||||
[JsonPropertyName("Port")]
|
||||
public int Port { get; set; }
|
||||
|
||||
[JsonPropertyName("DBName")]
|
||||
public string? DBName { get; set; }
|
||||
|
||||
[JsonPropertyName("DBID")]
|
||||
public int DBID { get; set; }
|
||||
|
||||
[JsonPropertyName("DBContext")]
|
||||
public string? DBContext { get; set; }
|
||||
|
||||
[JsonPropertyName("UserID")]
|
||||
public string? UserID { get; set; }
|
||||
|
||||
[JsonPropertyName("Password")]
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
}
|
||||
106
Projects/SystemX.Core/SystemX.Core/DB/EFCore.cs
Normal file
106
Projects/SystemX.Core/SystemX.Core/DB/EFCore.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.DB
|
||||
{
|
||||
public static class EFCore
|
||||
{
|
||||
/// <summary>
|
||||
/// Get SqlServer Connection String
|
||||
/// </summary>
|
||||
public static string ConvertToConnectionString(this DataBase dbConfig)
|
||||
{
|
||||
return $"server={dbConfig.IP},{dbConfig.Port}; user id={dbConfig.UserID}; password={dbConfig.Password}; database={dbConfig.DBName}; TrustServerCertificate=true;";
|
||||
}
|
||||
|
||||
public static IEnumerable<TEntity>? GetEntity<TEntity>(this DbContext dbContext) where TEntity : class
|
||||
{
|
||||
IEnumerable<TEntity>? entity = default;
|
||||
|
||||
var type = dbContext.GetType();
|
||||
try
|
||||
{
|
||||
foreach (var prop in type.GetProperties())
|
||||
{
|
||||
string propertyFullName = $"{prop.PropertyType.FullName}";
|
||||
if (propertyFullName.ToLower().Contains(typeof(TEntity).Name.ToLower()))
|
||||
{
|
||||
entity = prop.GetValue(dbContext) as IEnumerable<TEntity>;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4net.WriteLine(ex);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
#region Transaction
|
||||
public static IDbContextTransaction CreateTransaction(this DbContext dbContext)
|
||||
{
|
||||
return dbContext.Database.BeginTransaction();
|
||||
}
|
||||
|
||||
public static bool CloseTransaction(this DbContext dbContext, IDbContextTransaction transaction)
|
||||
{
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
dbContext.SaveChanges();
|
||||
transaction.Commit();
|
||||
result = true;
|
||||
|
||||
Log4net.WriteLine("Transaction Commit", LogType.Debug);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
transaction.Rollback();
|
||||
Log4net.WriteLine("Transaction Rollback", LogType.Error);
|
||||
Log4net.WriteLine(ex);
|
||||
}
|
||||
transaction.Dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Transaction Async
|
||||
public static async Task<IDbContextTransaction> CreateTransactionAsync(this DbContext dbContext)
|
||||
{
|
||||
return await dbContext.Database.BeginTransactionAsync();
|
||||
}
|
||||
|
||||
public static async Task<bool> CloseTransactionAsync(this DbContext dbContext, IDbContextTransaction transaction)
|
||||
{
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
await dbContext.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
result = true;
|
||||
|
||||
Log4net.WriteLine("Transaction Commit", LogType.Debug);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
Log4net.WriteLine("Transaction Rollback", LogType.Error);
|
||||
Log4net.WriteLine(ex);
|
||||
}
|
||||
await transaction.DisposeAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -7,240 +7,239 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemX.Core.Log4net
|
||||
|
||||
#region LogType
|
||||
public enum LogType
|
||||
{
|
||||
#region LogType
|
||||
public enum LogType
|
||||
//default level
|
||||
Info = 0,
|
||||
Warn = 1,
|
||||
Error = 2,
|
||||
Debug = 3,
|
||||
Fatal = 4,
|
||||
|
||||
//custom level
|
||||
DB = 10,
|
||||
|
||||
HTTP = 20,
|
||||
SOCKET = 21,
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CustomLevel
|
||||
public static class Log4netCustomLevel
|
||||
{
|
||||
public static readonly log4net.Core.Level DB = new log4net.Core.Level(10010, LogType.DB.ToString());
|
||||
public static readonly log4net.Core.Level HTTP = new log4net.Core.Level(10020, LogType.HTTP.ToString());
|
||||
public static readonly log4net.Core.Level SOCKET = new log4net.Core.Level(10021, LogType.SOCKET.ToString());
|
||||
|
||||
public static void SetCustomLevel(ILoggerRepository repo)
|
||||
{
|
||||
//default level
|
||||
Info = 0,
|
||||
Warn = 1,
|
||||
Error = 2,
|
||||
Debug = 3,
|
||||
Fatal = 4,
|
||||
|
||||
//custom level
|
||||
DB = 10,
|
||||
|
||||
HTTP = 20,
|
||||
SOCKET = 21,
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CustomLevel
|
||||
public static class Log4netCustomLevel
|
||||
{
|
||||
public static readonly log4net.Core.Level DB = new log4net.Core.Level(10010, LogType.DB.ToString());
|
||||
public static readonly log4net.Core.Level HTTP = new log4net.Core.Level(10020, LogType.HTTP.ToString());
|
||||
public static readonly log4net.Core.Level SOCKET = new log4net.Core.Level(10021, LogType.SOCKET.ToString());
|
||||
|
||||
public static void SetCustomLevel(ILoggerRepository repo)
|
||||
{
|
||||
repo.LevelMap.Add(DB);
|
||||
repo.LevelMap.Add(HTTP);
|
||||
repo.LevelMap.Add(SOCKET);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static class Log4net
|
||||
{
|
||||
private static ILog? Manager;
|
||||
|
||||
private static ILoggerRepository repo = LogManager.GetRepository();
|
||||
|
||||
public static bool IsConfigLoad { get; set; } = false;
|
||||
|
||||
|
||||
|
||||
static Log4net()
|
||||
{
|
||||
Console.WriteLine("log4net constructor");
|
||||
if (File.Exists("./log4net.config") == false)
|
||||
{
|
||||
File.WriteAllText("log4net.config", Config);
|
||||
}
|
||||
|
||||
IsConfigLoad = OpenConfig(@"./log4net.config");
|
||||
}
|
||||
|
||||
private static bool OpenConfig(string path)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
Log4netCustomLevel.SetCustomLevel(repo);
|
||||
|
||||
if (File.Exists(path) == false)
|
||||
result = false;
|
||||
|
||||
log4net.Config.XmlConfigurator.Configure(new FileInfo(path));
|
||||
Manager = LogManager.GetLogger("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Log4net Init Error");
|
||||
Console.WriteLine(e.Message);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void WriteLine<T>(T log, LogType logType = LogType.Info)
|
||||
{
|
||||
if (IsConfigLoad == false)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"[Log4net Initialize Error] {log}");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Info:
|
||||
{
|
||||
Manager?.Info(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Warn:
|
||||
{
|
||||
Manager?.Warn(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Error:
|
||||
{
|
||||
Manager?.Error(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Debug:
|
||||
{
|
||||
Manager?.Debug(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Fatal:
|
||||
{
|
||||
Manager?.Fatal(log);
|
||||
break;
|
||||
}
|
||||
case LogType.DB:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.DB, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LogType.HTTP:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.HTTP, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LogType.SOCKET:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.SOCKET, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteLine(Exception? ex)
|
||||
{
|
||||
WriteLine(ex?.Message, LogType.Error);
|
||||
}
|
||||
|
||||
|
||||
#region Config
|
||||
static string Config = @$"<?xml version=""1.0"" encoding=""utf-8"" ?>
|
||||
<configuration>
|
||||
<log4net>
|
||||
<root>
|
||||
<level value=""ALL""/>
|
||||
<appender-ref ref=""Console""/>
|
||||
<appender-ref ref=""file""/>
|
||||
<appender-ref ref=""fatal_file""/>
|
||||
</root>
|
||||
|
||||
<appender name=""Console"" type=""log4net.Appender.ManagedColoredConsoleAppender"">
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %-6level: %message%newline"" />
|
||||
</layout>
|
||||
<mapping>
|
||||
<level value=""FATAL"" />
|
||||
<foreColor value=""White"" />
|
||||
<backColor value=""Red"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""ERROR"" />
|
||||
<foreColor value=""Red"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""WARN"" />
|
||||
<foreColor value=""Yellow"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""INFO"" />
|
||||
<foreColor value=""Green"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""DEBUG"" />
|
||||
<foreColor value=""Blue"" />
|
||||
</mapping>
|
||||
|
||||
<mapping>
|
||||
<level value=""DB"" />
|
||||
<foreColor value=""DarkMagenta"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""HTTP"" />
|
||||
<foreColor value=""DarkYellow"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""SOCKET"" />
|
||||
<foreColor value=""DarkCyan"" />
|
||||
</mapping>
|
||||
</appender>
|
||||
|
||||
<appender name=""file"" type=""log4net.Appender.RollingFileAppender"">
|
||||
<file value=""log/"" />
|
||||
<datepattern value=""yyyy////MM////yyyy-MM-dd'.log'""/>
|
||||
<appendToFile value=""true"" />
|
||||
<rollingStyle value=""Date"" />
|
||||
<staticLogFileName value=""false"" />
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %level %logger - %message%newline"" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name=""fatal_file"" type=""log4net.Appender.RollingFileAppender"">
|
||||
<file value=""log/"" />
|
||||
<datepattern value=""yyyy////MM////yyyy-MM-dd'_fatal.log'""/>
|
||||
<appendToFile value=""true"" />
|
||||
<rollingStyle value=""Date"" />
|
||||
<staticLogFileName value=""false"" />
|
||||
<filter type=""log4net.Filter.LevelRangeFilter"">
|
||||
<param name=""LevelMin"" value=""FATAL"" />
|
||||
<param name=""LevelMax"" value=""FATAL"" />
|
||||
</filter>
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %level %logger - %message%newline"" />
|
||||
</layout>
|
||||
</appender>
|
||||
</log4net>
|
||||
</configuration>";
|
||||
#endregion
|
||||
repo.LevelMap.Add(DB);
|
||||
repo.LevelMap.Add(HTTP);
|
||||
repo.LevelMap.Add(SOCKET);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static class Log4net
|
||||
{
|
||||
private static ILog? Manager;
|
||||
|
||||
private static ILoggerRepository repo = LogManager.GetRepository();
|
||||
|
||||
public static bool IsConfigLoad { get; set; } = false;
|
||||
|
||||
|
||||
|
||||
static Log4net()
|
||||
{
|
||||
Console.WriteLine("log4net constructor");
|
||||
if (File.Exists("./log4net.config") == false)
|
||||
{
|
||||
File.WriteAllText("log4net.config", Config);
|
||||
}
|
||||
|
||||
IsConfigLoad = OpenConfig(@"./log4net.config");
|
||||
}
|
||||
|
||||
private static bool OpenConfig(string path)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
Log4netCustomLevel.SetCustomLevel(repo);
|
||||
|
||||
if (File.Exists(path) == false)
|
||||
result = false;
|
||||
|
||||
log4net.Config.XmlConfigurator.Configure(new FileInfo(path));
|
||||
Manager = LogManager.GetLogger("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Log4net Init Error");
|
||||
Console.WriteLine(e.Message);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void WriteLine<T>(T log, LogType logType = LogType.Info)
|
||||
{
|
||||
if (IsConfigLoad == false)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"[Log4net Initialize Error] {log}");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Info:
|
||||
{
|
||||
Manager?.Info(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Warn:
|
||||
{
|
||||
Manager?.Warn(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Error:
|
||||
{
|
||||
Manager?.Error(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Debug:
|
||||
{
|
||||
Manager?.Debug(log);
|
||||
break;
|
||||
}
|
||||
case LogType.Fatal:
|
||||
{
|
||||
Manager?.Fatal(log);
|
||||
break;
|
||||
}
|
||||
case LogType.DB:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.DB, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LogType.HTTP:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.HTTP, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LogType.SOCKET:
|
||||
{
|
||||
Type? t = MethodBase.GetCurrentMethod()?.DeclaringType;
|
||||
if (t != null)
|
||||
{
|
||||
Manager?.Logger.Log(t, Log4netCustomLevel.SOCKET, log, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteLine(Exception? ex)
|
||||
{
|
||||
WriteLine(ex?.Message, LogType.Error);
|
||||
}
|
||||
|
||||
|
||||
#region Config
|
||||
static string Config = @$"<?xml version=""1.0"" encoding=""utf-8"" ?>
|
||||
<configuration>
|
||||
<log4net>
|
||||
<root>
|
||||
<level value=""ALL""/>
|
||||
<appender-ref ref=""Console""/>
|
||||
<appender-ref ref=""file""/>
|
||||
<appender-ref ref=""fatal_file""/>
|
||||
</root>
|
||||
|
||||
<appender name=""Console"" type=""log4net.Appender.ManagedColoredConsoleAppender"">
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %-6level: %message%newline"" />
|
||||
</layout>
|
||||
<mapping>
|
||||
<level value=""FATAL"" />
|
||||
<foreColor value=""White"" />
|
||||
<backColor value=""Red"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""ERROR"" />
|
||||
<foreColor value=""Red"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""WARN"" />
|
||||
<foreColor value=""Yellow"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""INFO"" />
|
||||
<foreColor value=""Green"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""DEBUG"" />
|
||||
<foreColor value=""Blue"" />
|
||||
</mapping>
|
||||
|
||||
<mapping>
|
||||
<level value=""DB"" />
|
||||
<foreColor value=""DarkMagenta"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""HTTP"" />
|
||||
<foreColor value=""DarkYellow"" />
|
||||
</mapping>
|
||||
<mapping>
|
||||
<level value=""SOCKET"" />
|
||||
<foreColor value=""DarkCyan"" />
|
||||
</mapping>
|
||||
</appender>
|
||||
|
||||
<appender name=""file"" type=""log4net.Appender.RollingFileAppender"">
|
||||
<file value=""log/"" />
|
||||
<datepattern value=""yyyy////MM////yyyy-MM-dd'.log'""/>
|
||||
<appendToFile value=""true"" />
|
||||
<rollingStyle value=""Date"" />
|
||||
<staticLogFileName value=""false"" />
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %level %logger - %message%newline"" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name=""fatal_file"" type=""log4net.Appender.RollingFileAppender"">
|
||||
<file value=""log/"" />
|
||||
<datepattern value=""yyyy////MM////yyyy-MM-dd'_fatal.log'""/>
|
||||
<appendToFile value=""true"" />
|
||||
<rollingStyle value=""Date"" />
|
||||
<staticLogFileName value=""false"" />
|
||||
<filter type=""log4net.Filter.LevelRangeFilter"">
|
||||
<param name=""LevelMin"" value=""FATAL"" />
|
||||
<param name=""LevelMax"" value=""FATAL"" />
|
||||
</filter>
|
||||
<layout type=""log4net.Layout.PatternLayout"">
|
||||
<conversionPattern value=""[%date] [%thread] %level %logger - %message%newline"" />
|
||||
</layout>
|
||||
</appender>
|
||||
</log4net>
|
||||
</configuration>";
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
log4net 지정 가능 색상
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="log4net" Version="3.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.15" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
15
Projects/SystemX.Core/SystemX.Core/Utils/DateTimeUtils.cs
Normal file
15
Projects/SystemX.Core/SystemX.Core/Utils/DateTimeUtils.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class DateTimeUtils
|
||||
{
|
||||
public static long ToUnixTime(this DateTime dateTime)
|
||||
{
|
||||
DateTimeOffset dto = new DateTimeOffset(dateTime.ToUniversalTime());
|
||||
return dto.ToUnixTimeSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SystemX.Core.Log4net;
|
||||
|
||||
public static class JsonUtils
|
||||
{
|
||||
Reference in New Issue
Block a user