mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Refactor logging. Update submodule.
This commit is contained in:
parent
db19e92823
commit
c647e03aea
@ -142,7 +142,7 @@ else
|
||||
|
||||
private async Task ClearAllLogs()
|
||||
{
|
||||
var result = await JsInterop.Confirm("Are you sure you want to delete all logs?");
|
||||
var result = await JsInterop.Confirm("Are you sure you want to delete all previous logs? Today's logs are retained.");
|
||||
if (result)
|
||||
{
|
||||
using (var _ = LoaderService.ShowLoader("Deleting logs"))
|
||||
|
||||
@ -205,7 +205,7 @@ services.AddScoped<IExpiringTokenService, ExpiringTokenService>();
|
||||
services.AddScoped<IScriptScheduleDispatcher, ScriptScheduleDispatcher>();
|
||||
services.AddSingleton<IOtpProvider, OtpProvider>();
|
||||
services.AddSingleton<IEmbeddedServerDataSearcher, EmbeddedServerDataSearcher>();
|
||||
services.AddSingleton<ILogsManager>(LogsManager.Default);
|
||||
services.AddSingleton<ILogsManager, LogsManager>();
|
||||
services.AddSingleton(WeakReferenceMessenger.Default);
|
||||
|
||||
services.AddRemoteControlServer(config =>
|
||||
@ -331,7 +331,7 @@ void ConfigureSerilog(WebApplicationBuilder webAppBuilder)
|
||||
dataRetentionDays = retentionSetting;
|
||||
}
|
||||
|
||||
var logPath = LogsManager.Default.GetLogsDirectory();
|
||||
var logPath = LogsManager.DefaultLogsDirectory;
|
||||
|
||||
void ApplySharedLoggerConfig(LoggerConfiguration loggerConfiguration)
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using Nihs.SimpleMessenger;
|
||||
using Immense.RemoteControl.Shared.Primitives;
|
||||
using Nihs.SimpleMessenger;
|
||||
using Remotely.Server.Models.Messages;
|
||||
using Remotely.Shared.Primitives;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Immense.RemoteControl.Shared.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Remotely.Shared.Extensions;
|
||||
using Serilog;
|
||||
using System;
|
||||
@ -17,28 +18,105 @@ namespace Remotely.Server.Services
|
||||
{
|
||||
public interface ILogsManager
|
||||
{
|
||||
string GetLogsDirectory();
|
||||
Task<FileInfo> ZipAllLogs();
|
||||
Task DeleteLogs();
|
||||
|
||||
IAsyncEnumerable<string> GetLogs(
|
||||
DateTimeOffset startDate,
|
||||
DateTimeOffset startDate,
|
||||
DateTimeOffset endDate,
|
||||
string messageFilter,
|
||||
LogLevel? logLevelFilter);
|
||||
|
||||
string GetLogsDirectory();
|
||||
Task<FileInfo> ZipAllLogs();
|
||||
}
|
||||
|
||||
public class LogsManager : ILogsManager
|
||||
{
|
||||
public static LogsManager Default { get; } = new();
|
||||
private static readonly ReadOnlyDictionary<string, LogLevel> _logLevelMap = new(new Dictionary<string, LogLevel>()
|
||||
{
|
||||
["[VRB]"] = LogLevel.Trace,
|
||||
["[DBG]"] = LogLevel.Debug,
|
||||
["[INF]"] = LogLevel.Information,
|
||||
["[WRN]"] = LogLevel.Warning,
|
||||
["[ERR]"] = LogLevel.Error,
|
||||
["[FTL]"] = LogLevel.Critical
|
||||
});
|
||||
|
||||
public static string DefaultLogsDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
var logsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
|
||||
if (Directory.Exists("/remotely-data"))
|
||||
{
|
||||
logsDir = "/remotely-data/logs";
|
||||
}
|
||||
return logsDir;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteLogs()
|
||||
{
|
||||
var logsDir = GetLogsDirectory();
|
||||
|
||||
var files = Directory.GetFiles(logsDir);
|
||||
|
||||
if (!files.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await foreach (var file in files.ToAsyncEnumerable())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (new FileInfo(file).LastWriteTime.Date == DateTime.Today)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
File.Delete(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete log file: {file}. Message: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<string> GetLogs(
|
||||
DateTimeOffset startDate,
|
||||
DateTimeOffset endDate,
|
||||
string messageFilter,
|
||||
LogLevel? logLevelFilter)
|
||||
{
|
||||
var fromDate = startDate.UtcDateTime.Date;
|
||||
var toDate = endDate.UtcDateTime.Date.AddDays(1);
|
||||
|
||||
var result = new StringBuilder();
|
||||
var logsDir = GetLogsDirectory();
|
||||
|
||||
var files = Directory
|
||||
.GetFiles(logsDir)
|
||||
.Select(x => new FileInfo(x))
|
||||
.Where(x =>
|
||||
x.LastWriteTimeUtc >= fromDate &&
|
||||
x.LastWriteTimeUtc <= toDate)
|
||||
.OrderBy(x => x.LastWriteTimeUtc);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var linesAsync = GetLines(file, messageFilter, logLevelFilter);
|
||||
await foreach (var line in linesAsync)
|
||||
{
|
||||
yield return line;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLogsDirectory()
|
||||
{
|
||||
var logsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
|
||||
if (Directory.Exists("/remotely-data"))
|
||||
{
|
||||
logsDir = "/remotely-data/logs";
|
||||
}
|
||||
return Directory.CreateDirectory(logsDir).FullName;
|
||||
return Directory.CreateDirectory(DefaultLogsDirectory).FullName;
|
||||
}
|
||||
|
||||
public async Task<FileInfo> ZipAllLogs()
|
||||
@ -64,71 +142,6 @@ namespace Remotely.Server.Services
|
||||
|
||||
return new FileInfo(zipFilePath);
|
||||
}
|
||||
|
||||
public async Task DeleteLogs()
|
||||
{
|
||||
var logsDir = GetLogsDirectory();
|
||||
|
||||
var files = Directory.GetFiles(logsDir);
|
||||
|
||||
if (!files.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await foreach (var file in files.ToAsyncEnumerable())
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete log file: {file}. Message: {ex.Message}");
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Attempting to zero out log contents.");
|
||||
using var fs = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
fs.SetLength(0);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
Console.WriteLine($"Failed to clear log contents: {file}. Message: {ex2.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<string> GetLogs(
|
||||
DateTimeOffset startDate,
|
||||
DateTimeOffset endDate,
|
||||
string messageFilter,
|
||||
LogLevel? logLevelFilter)
|
||||
{
|
||||
var fromDate = startDate.UtcDateTime.Date;
|
||||
var toDate = endDate.UtcDateTime.Date.AddDays(1);
|
||||
|
||||
var result = new StringBuilder();
|
||||
var logsDir = GetLogsDirectory();
|
||||
|
||||
var files = Directory
|
||||
.GetFiles(logsDir)
|
||||
.Select(x => new FileInfo(x))
|
||||
.Where(x =>
|
||||
x.LastWriteTimeUtc >= fromDate &&
|
||||
x.LastWriteTimeUtc <= toDate);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var linesAsync = GetLines(file, messageFilter, logLevelFilter);
|
||||
await foreach (var line in linesAsync)
|
||||
{
|
||||
yield return line;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<string> GetLines(
|
||||
FileInfo file,
|
||||
string messageFilter,
|
||||
@ -192,15 +205,5 @@ namespace Remotely.Server.Services
|
||||
logLevel = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly ReadOnlyDictionary<string, LogLevel> _logLevelMap = new(new Dictionary<string, LogLevel>()
|
||||
{
|
||||
["[VRB]"] = LogLevel.Trace,
|
||||
["[DBG]"] = LogLevel.Debug,
|
||||
["[INF]"] = LogLevel.Information,
|
||||
["[WRN]"] = LogLevel.Warning,
|
||||
["[ERR]"] = LogLevel.Error,
|
||||
["[FTL]"] = LogLevel.Critical
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,32 +70,24 @@ namespace Remotely.Server.Services.RcImplementations
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case SessionSwitchReasonEx.ConsoleDisconnect:
|
||||
case SessionSwitchReasonEx.RemoteConnect:
|
||||
case SessionSwitchReasonEx.RemoteDisconnect:
|
||||
case SessionSwitchReasonEx.SessionLogoff:
|
||||
case SessionSwitchReasonEx.SessionLock:
|
||||
case SessionSwitchReasonEx.SessionRemoteControl:
|
||||
return _serviceHub.Clients
|
||||
.Client(ex.AgentConnectionId)
|
||||
.SendAsync("RestartScreenCaster",
|
||||
ex.ViewerList,
|
||||
ex.UnattendedSessionId,
|
||||
ex.AccessKey,
|
||||
ex.UserConnectionId,
|
||||
ex.RequesterUserName,
|
||||
ex.OrganizationName,
|
||||
ex.OrganizationId);
|
||||
case SessionSwitchReasonEx.ConsoleConnect:
|
||||
case SessionSwitchReasonEx.SessionUnlock:
|
||||
case SessionSwitchReasonEx.SessionLogon:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_logger.LogDebug("Windows session changed during remote control. " +
|
||||
"Reason: {reason}. " +
|
||||
"Current Session ID: {sessionId}. " +
|
||||
"Session Info: {@sesisonInfo}",
|
||||
reason,
|
||||
currentSessionId,
|
||||
session);
|
||||
|
||||
return Task.CompletedTask;
|
||||
return _serviceHub.Clients
|
||||
.Client(ex.AgentConnectionId)
|
||||
.SendAsync("RestartScreenCaster",
|
||||
ex.ViewerList,
|
||||
ex.UnattendedSessionId,
|
||||
ex.AccessKey,
|
||||
ex.UserConnectionId,
|
||||
ex.RequesterUserName,
|
||||
ex.OrganizationName,
|
||||
ex.OrganizationId);
|
||||
}
|
||||
|
||||
public Task RestartScreenCaster(RemoteControlSession session, HashSet<string> viewerList)
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Shared.Primitives;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IDisposable"/> that lets you provide a
|
||||
/// callback, which will be invoked when the object is disposed.
|
||||
/// </summary>
|
||||
public sealed class CallbackDisposable : IDisposable
|
||||
{
|
||||
private readonly Action _callback;
|
||||
private readonly Action<Exception> _exceptionHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Create anew instance where exceptions will be caught and suppressed.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public CallbackDisposable(Action callback)
|
||||
: this(callback, (_) => { })
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance where exceptions will be caught and passed to the supplied handler.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public CallbackDisposable(
|
||||
Action callback,
|
||||
Action<Exception> exceptionHandler)
|
||||
{
|
||||
_callback = callback;
|
||||
_exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
_callback.Invoke();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_exceptionHandler.Invoke(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Shared.Primitives;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IAsyncDisposable"/> that lets you provide a
|
||||
/// callback, which will be invoked when the object is disposed.
|
||||
/// </summary>
|
||||
public sealed class CallbackDisposableAsync : IAsyncDisposable
|
||||
{
|
||||
private readonly Func<ValueTask> _callback;
|
||||
private readonly Func<Exception, ValueTask> _exceptionHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Create anew instance where exceptions will be caught and suppressed.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public CallbackDisposableAsync(Func<ValueTask> callback)
|
||||
: this(callback, (_) => ValueTask.CompletedTask)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance where exceptions will be caught and passed to the supplied handler.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public CallbackDisposableAsync(
|
||||
Func<ValueTask> callback,
|
||||
Func<Exception, ValueTask> exceptionHandler)
|
||||
{
|
||||
_callback = callback;
|
||||
_exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return _callback.Invoke();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return _exceptionHandler.Invoke(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,6 +188,11 @@ namespace Remotely.Shared.Services
|
||||
$"[Thread ID: {Environment.CurrentManagedThreadId}]\t" +
|
||||
$"[{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}]\t";
|
||||
|
||||
if (exception is not null)
|
||||
{
|
||||
entry += $"[Exception: {exception.GetType().Name}]\t";
|
||||
}
|
||||
|
||||
entry += scopeStack.Any() ?
|
||||
$"[{categoryName} => {string.Join(" => ", scopeStack)}]\t" :
|
||||
$"[{categoryName}]\t";
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 51063504e723f2ee5a8fe4e672855d905a3f0eca
|
||||
Subproject commit f7083733b34b4ad1a207f1103a4e35c0376411d1
|
||||
Loading…
Reference in New Issue
Block a user