Compare commits

..

1 Commits

Author SHA1 Message Date
Matthias Heil 90bca23d53 removed other projects 2026-04-05 10:34:49 +02:00
79 changed files with 31 additions and 1718 deletions
@@ -1,16 +0,0 @@
<Application x:Class="AvaloniaLoggingDI.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AvaloniaLoggingDI">
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>
@@ -1,171 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using AvaloniaLoggingDI.ViewModels;
using AvaloniaLoggingDI.Views;
using LogViewer.Avalonia;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using MsLogger.Core;
using RandomLogging.Service;
using System;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Threading;
using Icon = MsBox.Avalonia.Enums.Icon;
namespace AvaloniaLoggingDI;
public partial class App : Application
{
public override void Initialize()
=> AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
// catch all unhandled errors
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
HostApplicationBuilder builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder();
builder
/*
* Note: For information on launch profiles for debugging,
* see article: https://www.codeproject.com/Articles/5354478/NET-App-Settings-Demystified-Csharp-VB
*/
// Register the Random Logging Service
.AddRandomBackgroundService()
// visual debugging tools
.AddLogViewer()
// Microsoft Logger
//.Logging.AddDefaultDataStoreLogger();
// uncomment to use custom logging colors (note: System.Drawing namespace)
//
.Logging.AddDefaultDataStoreLogger(options =>
{
options.Colors[LogLevel.Trace] = new()
{
Foreground = Color.White,
Background = Color.DarkGray
};
options.Colors[LogLevel.Debug] = new()
{
Foreground = Color.White,
Background = Color.Gray
};
options.Colors[LogLevel.Information] = new()
{
Foreground = Color.White,
Background = Color.DodgerBlue
};
options.Colors[LogLevel.Warning] = new()
{
Foreground = Color.White,
Background = Color.Orchid
};
});
IServiceCollection services = builder.Services;
services
.AddSingleton<MainViewModel>()
.AddSingleton(service => new MainWindow
{
DataContext = service.GetRequiredService<MainViewModel>()
});
Host = builder.Build();
CancellationTokenSource = new();
try
{
LogStartingMode();
// set and show
desktop.MainWindow = Host.Services.GetRequiredService<MainWindow>();
desktop.ShutdownRequested += OnShutdownRequested;
// startup background services
_ = Host.StartAsync(CancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
// skip
}
catch (Exception ex)
{
ShowMessageBox("Unhandled Error", ex.Message);
return;
}
}
base.OnFrameworkInitializationCompleted();
}
private static void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove = BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
=> _ = Host?.StopAsync(CancellationTokenSource!.Token);
private IHost? Host { get; set; }
private CancellationTokenSource? CancellationTokenSource { get; set; }
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
=> ShowMessageBox("Unhandled Error", ((Exception)e.ExceptionObject).Message);
private static void ShowMessageBox(string title, string message)
{
var box = MessageBoxManager.GetMessageBoxStandard(
"Exception",
text: message,
ButtonEnum.Ok,
Icon.Stop
);
_ = box.ShowAsync().GetAwaiter();
}
private void LogStartingMode()
{
// Get the Launch mode
bool isDevelopment = string.Equals(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"), "debug",
StringComparison.OrdinalIgnoreCase);
// initialize a logger & EventId
ILogger<App> logger = Host!.Services.GetRequiredService<ILogger<App>>();
EventId eventId = new EventId(id: 0, name: Assembly.GetEntryAssembly()!.GetName().Name);
// log a test pattern for each log level
logger.TestPattern(eventId: eventId);
// log that we have started...
logger.Emit(eventId, LogLevel.Information, $"Running in {(isDevelopment ? "Debug" : "Release")} mode");
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

@@ -1,41 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\avalonia-logo.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.Production.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MessageBox.Avalonia" Version="3.3.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Background Services\RandomLogging.Service\RandomLogging.Service.csproj" />
<ProjectReference Include="..\..\Controls\LogViewer.Avalonia\LogViewer.Avalonia.csproj" />
<ProjectReference Include="..\..\Core\MsLogger.Core\MsLogger.Core.csproj" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\avalonia-logo.ico" />
</ItemGroup>
</Project>
@@ -1,21 +0,0 @@
using Avalonia;
using System;
namespace AvaloniaLoggingDI;
internal sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args)
=> BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
}
@@ -1,19 +0,0 @@
{
"profiles": {
"Development": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
},
"Staging": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Staging"
}
},
"Production": {
"commandName": "Project"
}
}
}
@@ -1,36 +0,0 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using AvaloniaLoggingDI.ViewModels;
using System;
using System.Diagnostics.CodeAnalysis;
namespace AvaloniaLoggingDI;
// <summary>
/// Given a view model, returns the corresponding view if possible.
/// </summary>
[RequiresUnreferencedCode(
"Default implementation of ViewLocator involves reflection which may be trimmed away.",
Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")]
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}
@@ -1,17 +0,0 @@
using LogViewer.Core.ViewModels;
namespace AvaloniaLoggingDI.ViewModels;
public class MainViewModel(LogViewerControlViewModel logViewer) : ViewModelBase
{
#region Constructor
#endregion
#region Properties
public LogViewerControlViewModel LogViewer { get; } = logViewer;
#endregion
}
@@ -1,7 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace AvaloniaLoggingDI.ViewModels;
public class ViewModelBase : ObservableObject
{
}
@@ -1,19 +0,0 @@
<Window x:Class="AvaloniaLoggingDI.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window"
xmlns:control="clr-namespace:LogViewer.Avalonia;assembly=LogViewer.Avalonia"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Title="AvaloniaLoggingDI-MsLogger"
Icon="/Assets/avalonia-logo.ico"
WindowStartupLocation="CenterScreen" Height="634" Width="600">
<control:LogViewerControl DataContext="{Binding LogViewer}" />
</Window>
@@ -1,8 +0,0 @@
using Avalonia.Controls;
namespace AvaloniaLoggingDI.Views;
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
}
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"System.Net.Http.HttpClient": "Trace"
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"System.Net.Http.HttpClient": "Warning"
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System.Net.Http.HttpClient": "Information"
}
}
}
@@ -1,9 +0,0 @@
<Application x:Class="AvaloniaLoggingNoDI.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Styles>
<FluentTheme/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>
@@ -1,42 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using AvaloniaLoggingNoDI.Views;
using System.Linq;
namespace AvaloniaLoggingNoDI;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow();
}
base.OnFrameworkInitializationCompleted();
}
private static void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

@@ -1,43 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\avalonia-logo.ico" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\avalonia-logo.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.Production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Background Services\RandomLogging.Service\RandomLogging.Service.csproj" />
<ProjectReference Include="..\..\Controls\LogViewer.Avalonia\LogViewer.Avalonia.csproj" />
<ProjectReference Include="..\..\Core\MsLogger.Core\MsLogger.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,10 +0,0 @@
using LogViewer.Core;
using LogDataStore = LogViewer.Avalonia.Logging.LogDataStore;
namespace AvaloniaLoggingNoDI.DataStores;
// Application-wide shared instance of the LogDataStore logging entries
public static class MainControlsDataStore
{
public static ILogDataStore DataStore { get; } = new LogDataStore();
}
@@ -1,30 +0,0 @@
using System;
using LogViewer.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
using MsLogger.Core;
using AvaloniaLoggingNoDI.DataStores;
namespace AvaloniaLoggingNoDI.Extensions;
public static class LoggerExtension
{
public static ILoggingBuilder AddDataStoreLogger(this ILoggingBuilder builder)
{
builder.AddConfiguration();
// We need to use a shared instance of the DataStore to pass to the LogViewerControl
builder.Services.AddSingleton(MainControlsDataStore.DataStore);
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, DataStoreLoggerProvider>());
return builder;
}
public static ILoggingBuilder AddDataStoreLogger(this ILoggingBuilder builder, Action<DataStoreLoggerConfiguration> configure)
{
builder.AddDataStoreLogger();
builder.Services.Configure(configure);
return builder;
}
}
@@ -1,88 +0,0 @@
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
namespace AvaloniaLoggingNoDI.Helpers;
public class AppSettings<TOption>
{
#region Constructors
public AppSettings(IConfigurationSection configSection, string? key = null)
{
ConfigSection = configSection;
// ReSharper disable once VirtualMemberCallInConstructor
GetValue(key);
}
#endregion
#region Properties
protected static AppSettings<TOption>? AppSetting { get; private set; }
// ReSharper disable once StaticMemberInGenericType
protected static IConfigurationSection? ConfigSection { get; private set; }
public TOption? Value { get; set; }
#endregion
#region Methods
#pragma warning disable CA1000 // Do not declare static members on generic types
public static TOption? Current(string section, string? key = null)
{
AppSetting = GetCurrentSettings(section, key);
return AppSetting.Value;
}
public static AppSettings<TOption> GetCurrentSettings(string section, string? key = null)
#pragma warning restore CA1000 // Do not declare static members on generic types
{
string env = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production";
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
IConfigurationRoot configuration = builder.Build();
if (string.IsNullOrEmpty(section))
section = "AppSettings"; // default
AppSettings<TOption> settings = new AppSettings<TOption>(configuration.GetSection(section), key);
return settings;
}
protected virtual void GetValue(string? key)
{
if (key is null)
{
// no key, so must be a class/strut object
Value = Activator.CreateInstance<TOption>();
ConfigSection!.Bind(Value);
return;
}
Type optionType = typeof(TOption);
if ((optionType == typeof(string) ||
optionType == typeof(int) ||
optionType == typeof(long) ||
optionType == typeof(decimal) ||
optionType == typeof(float) ||
optionType == typeof(double))
&& ConfigSection != null)
{
// we must be retrieving a value
Value = ConfigSection.GetValue<TOption>(key);
return;
}
// Could not find a supported type
throw new InvalidCastException($"Type {typeof(TOption).Name} is invalid");
}
#endregion
}
@@ -1,78 +0,0 @@
using System;
using System.Drawing;
using Microsoft.Extensions.Logging;
using AvaloniaLoggingNoDI.Extensions;
using System.Diagnostics;
namespace AvaloniaLoggingNoDI.Helpers;
// application-wide DataStoreLogger Factory ... returns a wired up Logger instance
public static class LoggingHelper
{
#region Constructors
static LoggingHelper()
{
// retrieve the log level from 'appsettings'
string value = AppSettings<string>.Current("Logging:LogLevel", "Default") ?? "Information";
var success = Enum.TryParse(value, out LogLevel logLevel);
Debug.Assert(success, $"Failed to parse log level from appsettings. Value: '{value}'");
// wire up the loggers
Factory = LoggerFactory.Create(builder => builder
// visual debugging tools
//.AddDataStoreLogger()
// uncomment to use custom logging colors (note: System.Drawing namespace)
//
.AddDataStoreLogger(options =>
{
options.Colors[LogLevel.Trace] = new()
{
Foreground = Color.White,
Background = Color.DarkGray
};
options.Colors[LogLevel.Debug] = new()
{
Foreground = Color.White,
Background = Color.Gray
};
options.Colors[LogLevel.Information] = new()
{
Foreground = Color.White,
Background = Color.DodgerBlue
};
options.Colors[LogLevel.Warning] = new()
{
Foreground = Color.White,
Background = Color.Orchid
};
})
// examples of adding other loggers...
.AddSimpleConsole(options =>
{
options.SingleLine = true;
options.TimestampFormat = "hh:mm:ss ";
})
// note:
// * The IDE will automatically add the Debugger Logger, even though not visible
// * Adding the DebugLogger is useful for remote debugging
//.AddDebug()
// set minimum log level from 'appsettings'
.SetMinimumLevel(logLevel));
}
#endregion
#region Properties
public static ILoggerFactory Factory { get; }
#endregion
}
@@ -1,21 +0,0 @@
using Avalonia;
using System;
namespace AvaloniaLoggingNoDI;
internal sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args)
=> BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
}
@@ -1,19 +0,0 @@
{
"profiles": {
"Development": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
},
"Staging": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Staging"
}
},
"Production": {
"commandName": "Project"
}
}
}
@@ -1,19 +0,0 @@
<Window x:Class="AvaloniaLoggingNoDI.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window"
xmlns:control="clr-namespace:LogViewer.Avalonia;assembly=LogViewer.Avalonia"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="AvaloniaLoggingNoDI-MsLogger"
Icon="/Assets/avalonia-logo.ico"
WindowStartupLocation="CenterScreen" Height="634" Width="600">
<control:LogViewerControl x:Name="LogViewerControl" />
</Window>
@@ -1,48 +0,0 @@
using Avalonia.Controls;
using AvaloniaLoggingNoDI.DataStores;
using AvaloniaLoggingNoDI.Helpers;
using LogViewer.Core;
using Microsoft.Extensions.Logging;
using RandomLogging.Service;
using System;
using System.Reflection;
using System.Threading;
namespace AvaloniaLoggingNoDI.Views;
public partial class MainWindow : Window, ILogDataStoreCore
{
public MainWindow()
{
InitializeComponent();
// Initialize service and pass in the Logger
RandomLoggingService service = new(new Logger<RandomLoggingService>(LoggingHelper.Factory));
// Get the Launch mode
bool isDevelopment = string.Equals(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"), "debug",
StringComparison.OrdinalIgnoreCase);
// initialize a logger & EventId
Logger<MainWindow> logger = new Logger<MainWindow>(LoggingHelper.Factory);
EventId eventId = new EventId(id: 0, name: Assembly.GetEntryAssembly()!.GetName().Name);
// log a test pattern for each log level
logger.TestPattern(eventId: eventId);
// log that we have started...
logger.Emit(eventId, LogLevel.Information, $"Running in {(isDevelopment ? "Debug" : "Release")} mode");
// Start generating log entries
_ = service.StartAsync(CancellationToken.None);
// manually wire up the logging to the view ... the control will show backlog entries...
DataStore = MainControlsDataStore.DataStore;
// we can't bind the controls' DataContext to a static object, so assign the DataStore to the Window
// and pass a reference to the Window itself
LogViewerControl.DataContext = this;
}
public ILogDataStore DataStore { get; init; }
}
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"System.Net.Http.HttpClient": "Trace"
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"System.Net.Http.HttpClient": "Warning"
}
}
}
@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System.Net.Http.HttpClient": "Information"
}
}
}
@@ -1,14 +0,0 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AvaloniaSerilogDI"
x:Class="AvaloniaSerilogDI.App">
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>
@@ -1,198 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using AvaloniaSerilogDI.ViewModels;
using AvaloniaSerilogDI.Views;
using LogViewer.Avalonia;
using LogViewer.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using RandomLogging.Service;
using Serilog;
using Serilog.Sinks.LogView.Core;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using Icon = MsBox.Avalonia.Enums.Icon;
namespace AvaloniaSerilogDI;
public static class ServicesExtension
{
public static TModel? TryGetService<TModel>(this IServiceProvider serviceProvider) where TModel : class
{
try
{
return (TModel?)serviceProvider.GetService(typeof(TModel));
}
catch (ObjectDisposedException)
{
// ignore as we do not care...
}
return default;
}
}
public partial class App : Application
{
#region Constructors
public override void Initialize()
=> AvaloniaXamlLoader.Load(this);
#endregion
private IHost? Host {get; set;}
private CancellationTokenSource? CancellationTokenSource { get; set;}
#region Methods
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
// catch all unhandled errors
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
HostApplicationBuilder builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder();
builder
// Register the Random Logging Service
.AddRandomBackgroundService()
// visual debugging tools
.AddLogViewer();
IServiceCollection services = builder.Services;
// Serilog Logger
// Azure: https://devblogs.microsoft.com/dotnet/asp-net-core-logging/
// ApplicationInsights: https://github.com/serilog-contrib/serilog-sinks-applicationinsights
// AmazonCloudWatch: https://blog.ivankahl.com/logging-dotnet-to-aws-cloudwatch-using-serilog/
// video: https://www.youtube.com/watch?v=nVAkSBpsuTk (How Structured Logging With Serilog Can Make Your Life Easier)
// video: https://www.youtube.com/watch?v=_iryZxv8Rxw (C# Logging with Serilog and Seq - Structured Logging Made Easy)
// ps: docker run -d --restart unless-stopped --name seq -e ACCEPT_EULA=Y -v c:\WIP\LogData:/data -p 8081:80 datalust/seq:latest
// docker rmi datalust/seq --force
// ref: https://stackoverflow.com/questions/66304596/how-to-dependency-inject-serilog-into-the-rest-of-my-classes-in-net-console-app
services.AddLogging(configure: cfg =>
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.WriteTo.DataStoreLoggerSink( dataStoreProvider: () => Host?.Services.TryGetService<ILogDataStore>()!,formatProvider: CultureInfo.InvariantCulture)
.CreateLogger();
cfg.ClearProviders().AddSerilog(Log.Logger);
});
services
.AddSingleton<MainViewModel>()
.AddSingleton(service => new MainWindow
{
DataContext = service.GetRequiredService<MainViewModel>()
});
Host = builder.Build();
CancellationTokenSource = new();
try
{
LogStartingMode();
// set and show
desktop.MainWindow = Host.Services.GetRequiredService<MainWindow>();
desktop.ShutdownRequested += OnShutdownRequested;
// startup background services
_ = Host.StartAsync(CancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
// skip
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
ShowMessageBox("Unhandled Error", ex.Message);
CleanUp();
return;
}
}
base.OnFrameworkInitializationCompleted();
}
private static void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove = BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
=> CleanUp();
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception exception = (Exception)e.ExceptionObject;
Log.Fatal(exception, "Application terminated unexpectedly");
ShowMessageBox("Unhandled Error", exception.Message);
CleanUp();
}
private static void ShowMessageBox(string title, string message)
{
var box = MessageBoxManager.GetMessageBoxStandard(
"Exception",
text: message,
ButtonEnum.Ok,
Icon.Stop
);
_ = box.ShowAsync().GetAwaiter();
}
private void LogStartingMode()
{
// Get the Launch mode
bool isDevelopment = string.Equals(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"), "debug",
StringComparison.OrdinalIgnoreCase);
// initialize a logger & EventId
ILogger<App> logger = Host!.Services.GetRequiredService<ILogger<App>>();
EventId eventId = new(id: 0, name: Assembly.GetEntryAssembly()!.GetName().Name);
// log a test pattern for each log level
logger.TestPattern(eventId: eventId);
// log that we have started...
logger.Emit(eventId, LogLevel.Information, $"Running in {(isDevelopment ? "Debug" : "Release")} mode");
}
private void CleanUp()
{
// tell the background services that we are shutting down
_ = Host?.StopAsync(CancellationTokenSource?.Token ?? CancellationToken.None);
// flush logs
Log.CloseAndFlush();
}
#endregion
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

@@ -1,51 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\avalonia-logo.ico" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\avalonia-logo.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.Production.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.5" />
<PackageReference Include="Serilog" Version="4.3.1" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageReference Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="10.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="10.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="10.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0" />
<PackageReference Include="MessageBox.Avalonia" Version="3.3.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Background Services\RandomLogging.Service\RandomLogging.Service.csproj" />
<ProjectReference Include="..\..\Controls\LogViewer.Avalonia\LogViewer.Avalonia.csproj" />
<ProjectReference Include="..\..\Core\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,20 +0,0 @@
using Avalonia;
using System;
namespace AvaloniaSerilogDI;
internal sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace();
}
@@ -1,19 +0,0 @@
{
"profiles": {
"Development": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
},
"Staging": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Staging"
}
},
"Production": {
"commandName": "Project"
}
}
}
@@ -1,36 +0,0 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using AvaloniaSerilogDI.ViewModels;
using System;
using System.Diagnostics.CodeAnalysis;
namespace AvaloniaSerilogDI;
// <summary>
/// Given a view model, returns the corresponding view if possible.
/// </summary>
[RequiresUnreferencedCode(
"Default implementation of ViewLocator involves reflection which may be trimmed away.",
Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")]
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}
@@ -1,17 +0,0 @@
using LogViewer.Core.ViewModels;
namespace AvaloniaSerilogDI.ViewModels;
public class MainViewModel(LogViewerControlViewModel logViewer) : ViewModelBase
{
#region Constructor
#endregion
#region Properties
public LogViewerControlViewModel LogViewer { get; } = logViewer;
#endregion
}
@@ -1,7 +0,0 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace AvaloniaSerilogDI.ViewModels;
public class ViewModelBase : ObservableObject
{
}
@@ -1,19 +0,0 @@
<Window x:Class="AvaloniaSerilogDI.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window"
xmlns:control="clr-namespace:LogViewer.Avalonia;assembly=LogViewer.Avalonia"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Title="AvaloniaLoggingDI-Serilog"
Icon="/Assets/avalonia-logo.ico"
WindowStartupLocation="CenterScreen" Height="634" Width="600">
<control:LogViewerControl DataContext="{Binding LogViewer}" />
</Window>
@@ -1,8 +0,0 @@
using Avalonia.Controls;
namespace AvaloniaSerilogDI.Views;
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
}
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
@@ -1,45 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"System.Net.Http.HttpClient": "Trace"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"LevelSwitches": { "controlSwitch": "Verbose" },
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Verbose"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {EventId} | {Message:lj} {NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.txt",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"outputTemplate": "{Timestamp:G} {Message}{NewLine:1}{Exception:1}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.json",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"formatter": "Serilog.Formatting.Json.JsonFormatter"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ]
}
}
@@ -1,46 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"System.Net.Http.HttpClient": "Warning"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"LevelSwitches": { "controlSwitch": "Warning" },
"MinimumLevel": {
"Default": "Warning",
"Override": {
"Microsoft": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {EventId.Name} | {Message:lj} {NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.txt",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"outputTemplate": "{Timestamp:G} {Message}{NewLine:1}{Exception:1}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.json",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"formatter": "Serilog.Formatting.Json.JsonFormatter"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ]
}
}
@@ -1,46 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System.Net.Http.HttpClient": "Information"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"LevelSwitches": { "controlSwitch": "Information" },
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {EventId.Name} | {Message:lj} {NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.txt",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"outputTemplate": "{Timestamp:G} {Message}{NewLine:1}{Exception:1}"
}
},
{
"Name": "File",
"Args": {
"path": "c:\\WIP\\LogData\\log-.json",
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"formatter": "Serilog.Formatting.Json.JsonFormatter"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ]
}
}
@@ -45,6 +45,5 @@
<ItemGroup>
<ProjectReference Include="..\..\Background Services\RandomLogging.Service\RandomLogging.Service.csproj" />
<ProjectReference Include="..\..\Controls\LogViewer.Avalonia\LogViewer.Avalonia.csproj" />
<ProjectReference Include="..\..\Core\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,4 +1,4 @@
using LogViewer.Core;
using Serilog.Sinks.LogView.Core.Logging;
using LogDataStore = LogViewer.Avalonia.Logging.LogDataStore;
namespace AvaloniaSerilogNoDI.DataStores;
@@ -2,7 +2,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Sinks.LogView.Core;
using Serilog.Sinks.LogView.Core.Extensions;
using System;
using System.Drawing;
using System.Globalization;
@@ -1,9 +1,9 @@
using Avalonia.Controls;
using AvaloniaSerilogNoDI.DataStores;
using AvaloniaSerilogNoDI.Helpers;
using LogViewer.Core;
using Microsoft.Extensions.Logging;
using RandomLogging.Service;
using Serilog.Sinks.LogView.Core.Logging;
using System;
using System.ComponentModel;
using System.Reflection;
@@ -10,7 +10,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\LogViewer.Core\LogViewer.Core.csproj" />
<ProjectReference Include="..\..\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,4 +1,6 @@
namespace LogViewer.Core.ViewModels;
using Serilog.Sinks.LogView.Core.Logging;
namespace LogViewer.Avalonia.Extensions;
public class LogViewerControlViewModel(ILogDataStore dataStore) : ILogDataStoreCore
{
@@ -1,10 +1,9 @@
using LogViewer.Core;
using LogViewer.Core.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog.Sinks.LogView.Core.Logging;
using LogDataStore = LogViewer.Avalonia.Logging.LogDataStore;
namespace LogViewer.Avalonia;
namespace LogViewer.Avalonia.Extensions;
public static class ServicesExtension
{
@@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\LogViewer.Core\LogViewer.Core.csproj" />
<ProjectReference Include="..\..\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,7 +1,7 @@
using System.Collections.Specialized;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using LogViewer.Core;
using Serilog.Sinks.LogView.Core.Logging;
namespace LogViewer.Avalonia;
@@ -1,12 +1,13 @@
using Avalonia.Threading;
using Serilog.Sinks.LogView.Core.Logging;
namespace LogViewer.Avalonia.Logging;
public class LogDataStore : Core.LogDataStore
public class LogDataStore : Serilog.Sinks.LogView.Core.Logging.LogDataStore
{
#region Methods
public override async void AddEntry(Core.LogModel logModel)
public override async void AddEntry(LogModel logModel)
=> await Dispatcher.UIThread.InvokeAsync(() => base.AddEntry(logModel));
#endregion
@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
</ItemGroup>
</Project>
@@ -1,58 +0,0 @@
using System.Diagnostics;
using LogViewer.Core;
using Microsoft.Extensions.Logging;
namespace MsLogger.Core;
public class DataStoreLogger: ILogger
{
// ref: https://learn.microsoft.com/en-us/dotnet/core/extensions/custom-logging-provider
#region Constructor
public DataStoreLogger(string name, Func<DataStoreLoggerConfiguration> getCurrentConfig, ILogDataStore dataStore)
{
(_name, _getCurrentConfig) = (name, getCurrentConfig);
_dataStore = dataStore;
}
#endregion
#region Fields
private readonly ILogDataStore _dataStore;
private readonly string _name;
private readonly Func<DataStoreLoggerConfiguration> _getCurrentConfig;
#endregion
#region methods
public IDisposable BeginScope<TState>(TState state) where TState : notnull => default!;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception, string> formatter)
{
// check if we are logging for passed log level
if (!IsEnabled(logLevel))
return;
DataStoreLoggerConfiguration config = _getCurrentConfig();
_dataStore.AddEntry(new()
{
Timestamp = DateTime.UtcNow,
LogLevel = logLevel,
// do we override the default EventId if it exists?
EventId = eventId.Id == 0 && config.EventId != 0 ? config.EventId : eventId,
State = state,
Exception = exception?.Message ?? (logLevel == LogLevel.Error ? state?.ToString() ?? "" : ""),
Color = config.Colors[logLevel],
});
Debug.WriteLine($"--- [{logLevel.ToString()[..3]}] {_name} - {formatter(state, exception!)}");
}
#endregion
}
@@ -1,49 +0,0 @@
using System.Collections.Concurrent;
using LogViewer.Core;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace MsLogger.Core;
public class DataStoreLoggerProvider: ILoggerProvider
{
#region Constructor
public DataStoreLoggerProvider(IOptionsMonitor<DataStoreLoggerConfiguration> config, ILogDataStore dataStore)
{
DataStore = dataStore;
_currentConfig = config.CurrentValue;
OnChangeToken = config.OnChange(updatedConfig => _currentConfig = updatedConfig);
}
#endregion
#region fields
private DataStoreLoggerConfiguration _currentConfig;
private IDisposable? OnChangeToken { get; }
protected ILogDataStore DataStore { get; }
protected ConcurrentDictionary<string, DataStoreLogger> Loggers { get; } = new();
#endregion
#region Methods
public ILogger CreateLogger(string categoryName)
=> Loggers.GetOrAdd(categoryName, name => new DataStoreLogger(name, GetCurrentConfig, DataStore));
protected DataStoreLoggerConfiguration GetCurrentConfig()
=> _currentConfig;
public void Dispose()
{
GC.SuppressFinalize(this);
Loggers.Clear();
OnChangeToken?.Dispose();
}
#endregion
}
@@ -1,22 +0,0 @@
using LogViewer.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
namespace MsLogger.Core;
public static class ServicesExtension
{
public static ILoggingBuilder AddDefaultDataStoreLogger(this ILoggingBuilder builder)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, DataStoreLoggerProvider>());
return builder;
}
public static ILoggingBuilder AddDefaultDataStoreLogger(this ILoggingBuilder builder, Action<DataStoreLoggerConfiguration> configure)
{
builder.AddDefaultDataStoreLogger();
builder.Services.Configure(configure);
return builder;
}
}
@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LogViewer.Core\LogViewer.Core.csproj" />
</ItemGroup>
</Project>
-7
View File
@@ -1,7 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
-21
View File
@@ -1,21 +0,0 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Mvvm.Core;
public class ObservableObject : INotifyPropertyChanged
{
protected bool Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<TValue>.Default.Equals(field, newValue)) return false;
field = newValue;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
-3
View File
@@ -1,3 +0,0 @@
namespace Mvvm.Core;
public class ViewModel : ObservableObject { /* skip */ }
@@ -3,6 +3,7 @@ using LogViewer.Core;
using Microsoft.Extensions.Logging;
using Serilog.Core;
using System.Globalization;
using Serilog.Sinks.LogView.Core.Logging;
namespace Serilog.Sinks.LogView.Core;
@@ -1,7 +1,8 @@
using Serilog.Configuration;
using LogViewer.Core;
using Serilog.Sinks.LogView.Core.Logging;
namespace Serilog.Sinks.LogView.Core;
namespace Serilog.Sinks.LogView.Core.Extensions;
public static class DataStoreLoggerSinkExtensions
{
@@ -1,5 +1,6 @@
using System.Drawing;
using Microsoft.Extensions.Logging;
using Serilog.Sinks.LogView.Core.Logging;
namespace LogViewer.Core;
@@ -1,6 +1,6 @@
using System.Collections.ObjectModel;
namespace LogViewer.Core;
namespace Serilog.Sinks.LogView.Core.Logging;
public interface ILogDataStore
{
@@ -1,4 +1,4 @@
namespace LogViewer.Core;
namespace Serilog.Sinks.LogView.Core.Logging;
public interface ILogDataStoreCore
{
@@ -1,6 +1,6 @@
using System.Collections.ObjectModel;
namespace LogViewer.Core;
namespace Serilog.Sinks.LogView.Core.Logging;
public class LogDataStore : ILogDataStore
{
@@ -1,6 +1,6 @@
using System.Drawing;
namespace LogViewer.Core;
namespace Serilog.Sinks.LogView.Core.Logging;
public class LogEntryColor
{
@@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
namespace LogViewer.Core;
namespace Serilog.Sinks.LogView.Core.Logging;
public class LogModel
{
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -6,10 +6,7 @@
<ItemGroup>
<PackageReference Include="Serilog" Version="4.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LogViewer.Core\LogViewer.Core.csproj" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
</ItemGroup>
</Project>
-22
View File
@@ -1,22 +0,0 @@
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<LangVersion>latest</LangVersion>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<BinDir>$(MSBuildThisFileDirectory)bin</BinDir>
<RestorePackagesPath>$(MSBuildThisFileDirectory)packages</RestorePackagesPath>
<OutputDirectory>$(MSBuildProjectName)</OutputDirectory>
<OutputDirectory Condition=" '$(AssemblyName)' != '' ">$(AssemblyName)</OutputDirectory>
<OutputPath>$(BinDir)\$(Configuration)\$(MSBuildProjectName)\</OutputPath>
<BaseIntermediateOutputPath>$(BinDir)\obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="*.DotSettings" />
<None Remove="packages.lock.json" />
</ItemGroup>
</Project>
+5 -58
View File
@@ -3,16 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.4.11626.88
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{A3BEB004-4DF7-4281-9A08-8A7BCD4E3CC9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogViewer.Core", "CSharp\Core\LogViewer.Core\LogViewer.Core.csproj", "{34F75D8B-6F15-4DE4-8335-FED83557EB8E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{42E99803-0A95-4172-9079-3B8BF8CBDE9F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{E589E611-C328-4D4F-817D-A91D5A1019FB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Background Services", "Background Services", "{0CDEA51D-46FE-4767-BA2E-8F14582A926D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{006FDAED-6319-4976-B8BA-8D94E4574139}"
ProjectSection(SolutionItems) = preProject
LICENSE = LICENSE
@@ -21,25 +13,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RandomLogging.Service", "CSharp\Background Services\RandomLogging.Service\RandomLogging.Service.csproj", "{18BA2294-FE64-481F-A86F-F5FD84438B66}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MsLogger.Core", "CSharp\Core\MsLogger.Core\MsLogger.Core.csproj", "{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LoggerProviders", "LoggerProviders", "{23CB559B-2361-4ED6-8A26-D1B1C2005D65}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MsLogger", "MsLogger", "{8635B709-1D5A-4445-AC45-F99EE264634F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serilog", "Serilog", "{578FF757-F837-4C23-B2CA-3CF8B016F6A9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Sinks.LogView.Core", "CSharp\Core\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj", "{69763AFC-6182-402D-9418-6A48404C89A0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaLoggingDI", "CSharp\Applications\AvaloniaLoggingDI\AvaloniaLoggingDI.csproj", "{EA97953E-1223-40D5-A568-8932FDC3105E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogViewer.Avalonia", "CSharp\Controls\LogViewer.Avalonia\LogViewer.Avalonia.csproj", "{C34C889C-4EB3-45F6-83DE-70252D1D67D5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaSerilogDI", "CSharp\Applications\AvaloniaSerilogDI\AvaloniaSerilogDI.csproj", "{BCB0601D-E042-4949-8172-7A35A619519C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaSerilogNoDI", "CSharp\Applications\AvaloniaSerilogNoDI\AvaloniaSerilogNoDI.csproj", "{4E892500-CF59-43A9-9A27-80D8EE028821}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaLoggingNoDI", "CSharp\Applications\AvaloniaLoggingNoDI\AvaloniaLoggingNoDI.csproj", "{85C96F55-572A-4FDF-A028-12D27A48FB4D}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serilog.Sinks.LogView.Core", "CSharp\Serilog.Sinks.LogView.Core\Serilog.Sinks.LogView.Core.csproj", "{8CCB028B-541F-69E5-085B-EE77E55737E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -47,59 +25,28 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{34F75D8B-6F15-4DE4-8335-FED83557EB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34F75D8B-6F15-4DE4-8335-FED83557EB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34F75D8B-6F15-4DE4-8335-FED83557EB8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34F75D8B-6F15-4DE4-8335-FED83557EB8E}.Release|Any CPU.Build.0 = Release|Any CPU
{18BA2294-FE64-481F-A86F-F5FD84438B66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18BA2294-FE64-481F-A86F-F5FD84438B66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18BA2294-FE64-481F-A86F-F5FD84438B66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18BA2294-FE64-481F-A86F-F5FD84438B66}.Release|Any CPU.Build.0 = Release|Any CPU
{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E}.Release|Any CPU.Build.0 = Release|Any CPU
{69763AFC-6182-402D-9418-6A48404C89A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69763AFC-6182-402D-9418-6A48404C89A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69763AFC-6182-402D-9418-6A48404C89A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69763AFC-6182-402D-9418-6A48404C89A0}.Release|Any CPU.Build.0 = Release|Any CPU
{EA97953E-1223-40D5-A568-8932FDC3105E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA97953E-1223-40D5-A568-8932FDC3105E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA97953E-1223-40D5-A568-8932FDC3105E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA97953E-1223-40D5-A568-8932FDC3105E}.Release|Any CPU.Build.0 = Release|Any CPU
{C34C889C-4EB3-45F6-83DE-70252D1D67D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C34C889C-4EB3-45F6-83DE-70252D1D67D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C34C889C-4EB3-45F6-83DE-70252D1D67D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C34C889C-4EB3-45F6-83DE-70252D1D67D5}.Release|Any CPU.Build.0 = Release|Any CPU
{BCB0601D-E042-4949-8172-7A35A619519C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCB0601D-E042-4949-8172-7A35A619519C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCB0601D-E042-4949-8172-7A35A619519C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCB0601D-E042-4949-8172-7A35A619519C}.Release|Any CPU.Build.0 = Release|Any CPU
{4E892500-CF59-43A9-9A27-80D8EE028821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E892500-CF59-43A9-9A27-80D8EE028821}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E892500-CF59-43A9-9A27-80D8EE028821}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E892500-CF59-43A9-9A27-80D8EE028821}.Release|Any CPU.Build.0 = Release|Any CPU
{85C96F55-572A-4FDF-A028-12D27A48FB4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85C96F55-572A-4FDF-A028-12D27A48FB4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85C96F55-572A-4FDF-A028-12D27A48FB4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85C96F55-572A-4FDF-A028-12D27A48FB4D}.Release|Any CPU.Build.0 = Release|Any CPU
{8CCB028B-541F-69E5-085B-EE77E55737E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8CCB028B-541F-69E5-085B-EE77E55737E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CCB028B-541F-69E5-085B-EE77E55737E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CCB028B-541F-69E5-085B-EE77E55737E4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{34F75D8B-6F15-4DE4-8335-FED83557EB8E} = {A3BEB004-4DF7-4281-9A08-8A7BCD4E3CC9}
{18BA2294-FE64-481F-A86F-F5FD84438B66} = {0CDEA51D-46FE-4767-BA2E-8F14582A926D}
{0EDAAABD-495D-43A4-BDFB-A0506CAAC07E} = {23CB559B-2361-4ED6-8A26-D1B1C2005D65}
{23CB559B-2361-4ED6-8A26-D1B1C2005D65} = {A3BEB004-4DF7-4281-9A08-8A7BCD4E3CC9}
{8635B709-1D5A-4445-AC45-F99EE264634F} = {42E99803-0A95-4172-9079-3B8BF8CBDE9F}
{578FF757-F837-4C23-B2CA-3CF8B016F6A9} = {42E99803-0A95-4172-9079-3B8BF8CBDE9F}
{69763AFC-6182-402D-9418-6A48404C89A0} = {23CB559B-2361-4ED6-8A26-D1B1C2005D65}
{EA97953E-1223-40D5-A568-8932FDC3105E} = {8635B709-1D5A-4445-AC45-F99EE264634F}
{C34C889C-4EB3-45F6-83DE-70252D1D67D5} = {E589E611-C328-4D4F-817D-A91D5A1019FB}
{BCB0601D-E042-4949-8172-7A35A619519C} = {578FF757-F837-4C23-B2CA-3CF8B016F6A9}
{4E892500-CF59-43A9-9A27-80D8EE028821} = {578FF757-F837-4C23-B2CA-3CF8B016F6A9}
{85C96F55-572A-4FDF-A028-12D27A48FB4D} = {8635B709-1D5A-4445-AC45-F99EE264634F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D6A9B467-ED50-40DB-9FFB-5BE745F08DDB}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

@@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>Avalonia.Resources</RootNamespace>
<TargetFramework>net7.0</TargetFramework>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.18" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
</Project>
-18
View File
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>