using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using JD.Core.ProjectManaging;
using JD.LogService;
using Packager.Tasks;
using TeaBox;
using Directory = System.IO.Directory;
using File = System.IO.File;
using LogCategory = JD.LogService.LogCategory;
namespace Packager
{
///
/// Message logging mechanism for the tool
///
public class MessageLogger : ILogger
{
public delegate void MessageEvent(MessageLogger sender, string message);
private readonly object _lock = new object();
public string LogFilePath { get; }
public string LoggedObjectName { get; }
public MessageLogger(string loggedObjectName)
{
LoggedObjectName = loggedObjectName;
var logFileDirectory = Path.Combine(DataPath.Value, "output", "temp", nameof(Packager));
if (!Directory.Exists(logFileDirectory))
{
Directory.CreateDirectory(logFileDirectory);
}
Thread.Sleep(1); // avoid colliding file names
var logFileName = $"{DateTime.Now.ToString("yyyyMMdd_HHmmss_fff", CultureInfo.InvariantCulture)}" +
$"_pid_{Process.GetCurrentProcess().Id}_{loggedObjectName}.txt";
LogFilePath = Path.Combine(logFileDirectory, logFileName);
LogInfo("Log file created.");
// delete log files older than 48 hours
var existingLogFiles = Directory.EnumerateFiles(logFileDirectory, "*.txt", SearchOption.TopDirectoryOnly);
var logsToDelete = existingLogFiles.Select(f => new System.IO.FileInfo(f))
.Where(fi => fi.LastAccessTime < DateTime.Now.AddHours(-48));
foreach (var logPath in logsToDelete.Select(f => f.FullName))
{
LogInfo($"Deleting old log file at \"{logPath}\"");
File.Delete(logPath);
}
}
public void Log(LogEvent @event)
{
switch (@event.Category)
{
case LogCategory.Message:
LogInfo(@event.Message);
break;
case LogCategory.Error:
LogError(@event.Message);
break;
case LogCategory.Warning:
LogWarning(@event.Message);
break;
default:
var ex = new ArgumentOutOfRangeException(typeof(LogCategory).Name, @event.Category, "Value of log category was unhandled");
LogException(ex);
throw ex;
}
}
public event MessageEvent OnInfoLogged;
public event MessageEvent OnWarningLogged;
public event MessageEvent OnErrorLogged;
///
/// Makes the current MessageLogger able to catches log events from the given cookerWrapper.
///
public void AttachCookerWrapper(cookerWrapper cookerWrapper)
{
cookerWrapper.onLogCook += OnCookerWrapperLog;
cookerWrapper.onProgress += OnCookerWrapperProgress;
cookerWrapper.onErrorCook += OnCookerWrapperCookingError;
cookerWrapper.onLogError += OnCookerWrapperError;
cookerWrapper.onLogFatal += OnCookerWrapperFatalError;
}
///
/// Stop catching log events from the given cookerWrapper.
///
public void DetachCookerWrapper(cookerWrapper cookerWrapper)
{
cookerWrapper.onLogCook += OnCookerWrapperLog;
cookerWrapper.onProgress += OnCookerWrapperProgress;
cookerWrapper.onErrorCook += OnCookerWrapperCookingError;
cookerWrapper.onLogError += OnCookerWrapperError;
cookerWrapper.onLogFatal += OnCookerWrapperFatalError;
}
private void OnCookerWrapperFatalError(string progress)
{
this.LogError("Cooker wrapper encoutered a FATAL ERROR: " + progress);
}
private void OnCookerWrapperError(string progress)
{
this.LogError("Cooker wrapper encoutered an error: " + progress);
}
private void OnCookerWrapperCookingError(string text, bool errordescribed)
{
this.LogError("Cooker wrapper encoutered an error while cooking: " + text);
}
private void OnCookerWrapperProgress(float progress)
{
this.LogInfo(progress.ToString(CultureInfo.InvariantCulture));
}
private void OnCookerWrapperLog(string progress)
{
this.LogInfo(progress);
}
public void LogInfo(string message)
{
var text = $"\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff", CultureInfo.InvariantCulture)} INFO: {message}";
Console.WriteLine(text);
WriteToLogFile(text);
OnInfoLogged?.Invoke(this, message);
}
public void LogWarning(string message)
{
var text = $"\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff", CultureInfo.InvariantCulture)} WARNING: {message}";
Console.WriteLine(text);
WriteToLogFile(text);
OnWarningLogged?.Invoke(this, message);
}
public void LogError(string message)
{
var text = $"\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff", CultureInfo.InvariantCulture)} ERROR: {message}";
Console.WriteLine(text);
WriteToLogFile(text);
OnErrorLogged?.Invoke(this, message);
}
public void LogException(Exception exception)
{
var text = $"\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff", CultureInfo.InvariantCulture)} EXCEPTION: {exception.Message}";
text += "\n" + exception.StackTrace;
Console.Error.WriteLine(text);
WriteToLogFile(text);
}
public void LogTaskMessage(Task task, string message, LogCategory messageCategory)
{
switch (messageCategory)
{
case LogCategory.Message:
LogInfo($"[{task.InstanceName}] {message}");
break;
case LogCategory.Error:
LogError($"[{task.InstanceName}] {message}");
break;
case LogCategory.Warning:
LogWarning($"[{task.InstanceName}] {message}");
break;
default:
var ex = new ArgumentOutOfRangeException(typeof(LogCategory).Name, messageCategory, "Value of log category was unhandled");
LogError(ex.Message);
throw ex;
}
}
public void LogEndedTask(Task task)
{
var time = task.ElapsedTime;
var timeString = (time.Minutes > 0 ? $"{time.Minutes} minute{(time.Minutes > 1 ? "s" : "")} " : "") +
$"{time.Seconds} second{(time.Seconds > 1 ? "s" : "")}";
string endTaskMessage = $"[COMPLETED] (took {timeString})";
LogTaskMessage(task, endTaskMessage, LogCategory.Message);
}
public void LogStartedTask(Task task)
{
var startTaskMessage = $"[STARTED]";
LogTaskMessage(task, startTaskMessage, LogCategory.Message);
}
private void WriteToLogFile(string text)
{
lock (_lock)
{
File.AppendAllText(LogFilePath, text);
}
}
}
}