멀티쓰레드에서도 시간 정렬 값 제대로 유지된다.
파일 기록 버퍼, 로그 버퍼 2개로 나눠서 한쪽에선 응용단 로그들 계속 버퍼에 쌓고 한쪽에선 파일 기록 버퍼 다쓰면 버퍼 인덱스 바꿔서 다시 쓰기 시작
![viewimage.php?id=3dafdf21f7d335ab67b1d1&no=24b0d769e1d32ca73cef8efa11d028311f263ed599921c6ba339f17090466b661f407639228f4a0a0ad54dc1c3184b5f410a88dcbe45ca5279c92dff237d477a5c01]()
namespace API.Util.Logger
{
public class FileLogger : Singleton
{
private DateTimeOffset _time;
private LoggerPeriod _period;
private string _path;
private readonly string _moduleName;
private DoublePriorityQueue _queue;
private FileStream _fs;
private readonly object _append, _write;
public FileLogger()
{
_moduleName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName);
_queue =
new DoublePriorityQueue(Order.Descending);
_append =
new object();
_write =
new object();
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
}
private void CurrentDomain_ProcessExit(
object sender, EventArgs e)
{
Invoke(
null);
_queue.Swap();
Invoke(
null);
_fs.Close();
}
public void Init(LoggerPeriod period = LoggerPeriod.Infinitely,
string path =
"")
{
_period = period;
_path = path;
if (
string.IsNullOrEmpty(_path))
_path = Environment.CurrentDirectory;
_path +=
@"Log";
if (!Directory.Exists(_path))
Directory.CreateDirectory(_path);
CreateLogFile();
}
public void Write(
string message)
{
if (_fs ==
null)
throw new InvalidOperationException(
"LoggerPeriod Not Initialization");
try
{
Monitor.Enter(_append);
_queue.AppendQueue.Append(
new LogMessage() { Message = message });
if (_queue.ReadQueue.Count ==
0)
{
_queue.Swap();
ThreadPool.QueueUserWorkItem(Invoke);
}
}
finally
{
Monitor.Exit(_append);
}
}
private void WriteMessage(LogMessage message)
{
string format =
$"[{message.CreateTime.ToString("yyyy-MM-dd HH:mm:ss.fff
")}] { message.Message}
";
#if DEBUG
Trace.Write(format);
#endif
var bytes = Encoding.UTF8.GetBytes(format);
_fs.Write(bytes,
0, bytes.Count());
_fs.Flush();
}
private void CreateLogFile()
{
string fileName;
switch(_period)
{
case LoggerPeriod.Infinitely:
fileName =
"Log.log";
break;
case LoggerPeriod.Day:
fileName =
$"{DateTime.Now.ToString("yyyy-MM-dd
")}.log";
break;
case LoggerPeriod.Hour:
fileName =
$"{DateTime.Now.ToString("yyyy-MM-dd-HH
")}.log";
break;
default:
fileName =
null;
break;
}
_time = DateTimeOffset.Now;
if (
string.IsNullOrEmpty(fileName))
throw new InvalidOperationException(
"LoggerPeriod Not Initialization");
_fs =
new FileStream(
$@"{_path}{_moduleName} {fileName}", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
}
private void HourCompare()
{
if(DateTimeOffset.Now.Hour != _time.Hour)
{
while(_queue.ReadQueue.Count >
0)
{
var message = _queue.ReadQueue.Peek();
if (message.CreateTime.Hour != _time.Hour)
break;
message = _queue.ReadQueue.Read();
WriteMessage(message);
}
_fs.Close();
CreateLogFile();
}
}
private void DayCompare()
{
if (DateTimeOffset.Now.Day != _time.Day)
{
while (_queue.ReadQueue.Count >
0)
{
var message = _queue.ReadQueue.Peek();
if (message.CreateTime.Day != _time.Day)
break;
message = _queue.ReadQueue.Read();
WriteMessage(message);
}
_fs.Close();
CreateLogFile();
}
}
private void Invoke(
object state)
{
if(Monitor.TryEnter(_write))
{
try
{
while (_queue.ReadQueue.Count >
0)
{
switch (_period)
{
case LoggerPeriod.Day:
DayCompare();
break;
case LoggerPeriod.Hour:
HourCompare();
break;
}
var message = _queue.ReadQueue.Read();
WriteMessage(message);
}
}
finally
{
Monitor.Exit(_write);
}
}
}
}
}
댓글 0