Skip to content

feat: Implement SettingsService and SyslogService#2

Open
Azayzel wants to merge 1 commit intomasterfrom
v2.0.0/net10-migration
Open

feat: Implement SettingsService and SyslogService#2
Azayzel wants to merge 1 commit intomasterfrom
v2.0.0/net10-migration

Conversation

@Azayzel
Copy link
Copy Markdown
Owner

@Azayzel Azayzel commented Mar 5, 2026

  • Added SettingsService for managing application settings via Windows Registry.
  • Introduced AppSettings class to encapsulate settings like WatchLogs, EventFilter, SyslogServer, and RunOnStartup.
  • Implemented methods to Load and Save settings, including handling registry access and startup configuration.
  • Created SyslogService for sending syslog messages with support for TCP, TCP with TLS, and UDP protocols.
  • Added functionality to serialize syslog messages and test server connections.
  • Removed deprecated SysLogMessage and SyslogLocalMessageSerializer classes to streamline the codebase.
  • Updated SyslogTransport classes for improved error handling and connection management.
  • Added alerts.xml for logging error events and removed unnecessary app.config and package references.

- Added SettingsService for managing application settings via Windows Registry.
- Introduced AppSettings class to encapsulate settings like WatchLogs, EventFilter, SyslogServer, and RunOnStartup.
- Implemented methods to Load and Save settings, including handling registry access and startup configuration.
- Created SyslogService for sending syslog messages with support for TCP, TCP with TLS, and UDP protocols.
- Added functionality to serialize syslog messages and test server connections.
- Removed deprecated SysLogMessage and SyslogLocalMessageSerializer classes to streamline the codebase.
- Updated SyslogTransport classes for improved error handling and connection management.
- Added alerts.xml for logging error events and removed unnecessary app.config and package references.
@Azayzel Azayzel self-assigned this Mar 5, 2026
@Azayzel Azayzel requested a review from Copilot March 5, 2026 22:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is a major version migration (v1.x → v2.0.0) of the Jakkl Windows Syslog Agent, migrating from .NET Framework 4.5.2 to .NET 10 and introducing a clean, service-based architecture with dependency injection. It replaces legacy dependencies (MetroFramework UI, FontAwesome.Sharp, custom NotifyIconEx, RegHelper, SysLogMessage) with standard WinForms controls and Microsoft.Extensions services.

Changes:

  • Added three new service classes (SettingsService, SyslogService, EventMonitorService) implementing registry-based settings, syslog message sending, and Windows Event Log monitoring respectively.
  • Migrated the project from the old .NET Framework csproj format to the SDK-style .csproj targeting net10.0-windows, removing all legacy package references and build artifacts.
  • Refactored the Config.cs UI form and added Program.cs as a DI-based entry point; updated transport classes (SyslogEncryptedTcpSender, SyslogTcpSender) with cleanup and TLS improvements.

Reviewed changes

Copilot reviewed 28 out of 49 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
Services/SettingsService.cs New registry-backed settings service with HKLM/HKCU fallback
Services/SyslogService.cs New service for building and sending syslog messages via TCP/TLS/UDP
Services/EventMonitorService.cs New service for monitoring Windows Event Logs and writing alerts
Config.cs Fully rewritten WinForms UI using standard controls and DI
Program.cs New DI entry point using Microsoft.Extensions.DependencyInjection
Jakkl.csproj Migrated to SDK-style project targeting .NET 10
README.md Updated documentation reflecting v2.0.0 changes
Syslog/Transport/SyslogEncryptedTcpSender.cs Updated to use SslProtocols.None and null-safe certificate error handler
Syslog/Transport/SyslogTcpSender.cs Minor code style cleanup
Syslog/SyslogNetException.cs Removed obsolete [Serializable] and serialization constructor
alerts.xml Should-not-be-committed generated file with sensitive developer machine data
obj/ files Should-not-be-committed build artifacts with developer-specific absolute paths
.idea/ files Should-not-be-committed JetBrains Rider IDE configuration files
SysLogMessage.cs, RegHelper.cs, etc. Removed deprecated classes superseded by new services
.gitignore Improved to exclude build artifacts, IDE files, and OS files
Files not reviewed (5)
  • .idea/.idea.jakkl/.idea/.name: Language not supported
  • .idea/.idea.jakkl/.idea/encodings.xml: Language not supported
  • .idea/.idea.jakkl/.idea/indexLayout.xml: Language not supported
  • .idea/.idea.jakkl/.idea/projectSettingsUpdater.xml: Language not supported
  • .idea/.idea.jakkl/.idea/vcs.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

5. Select the transport protocol (TCP+TLS recommended)
6. Click **Apply**

All settings are saved to the Windows Registry under `HKLM\SOFTWARE\Jakkl`.
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README states "All settings are saved to the Windows Registry under HKLM\SOFTWARE\Jakkl", but the SettingsService.CreateSettingsKey() falls back to HKCU\SOFTWARE\Jakkl when the user doesn't have admin rights. For most users running without admin rights, settings will actually be stored in HKCU, making this documentation inaccurate. The documentation should reflect that settings are stored in HKLM when possible and fall back to HKCU.

Suggested change
All settings are saved to the Windows Registry under `HKLM\SOFTWARE\Jakkl`.
Settings are saved to the Windows Registry under `HKLM\SOFTWARE\Jakkl` when running with administrative privileges, or under `HKCU\SOFTWARE\Jakkl` when running without.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
jakkl No newline at end of file
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JetBrains Rider IDE configuration files under .idea/ are being committed in this PR, but .idea/ has been added to .gitignore in the same PR. These files (.name, vcs.xml, encodings.xml, indexLayout.xml, projectSettingsUpdater.xml) contain IDE-specific developer preferences and should not be version-controlled. They should be removed from the repository and are already excluded by the updated .gitignore.

Suggested change
jakkl

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +89
public async Task<bool> TestConnectionAsync()
{
return await Task.Run(() =>
{
try
{
using (var client = new TcpClient(Server, Port))
{
return client.Connected;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Connection test failed for {Server}:{Port}", Server, Port);
return false;
}
});
}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TestConnectionAsync method always uses TCP (via TcpClient) to test the connection, regardless of the configured Protocol property. When the protocol is set to SyslogProtocol.Udp, a TCP connection test is misleading because UDP is connectionless and doesn't require a TCP handshake. The test should either test via UDP socket or at least skip the test with an informative message when the protocol is UDP.

Copilot uses AI. Check for mistakes.

// Quick and nasty way to avoid logging framework dependency
public static Action<string> CertificateErrorHandler = err => { };
public static Action<string> CertificateErrorHandler { get; set; }
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CertificateErrorHandler static property has been changed from a field with a default no-op handler (err => { }) to a property with no initial value (defaults to null). The null-conditional call CertificateErrorHandler?.Invoke(...) safely handles null, so no exception is thrown when unset. However, certificate errors will now be silently swallowed with no feedback unless a handler is assigned. Callers may not be aware that they need to explicitly assign this handler to receive certificate error notifications, which could make TLS connection issues harder to diagnose.

Suggested change
public static Action<string> CertificateErrorHandler { get; set; }
public static Action<string> CertificateErrorHandler { get; set; } = err => { };

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +24
var logDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Jakkl");
Directory.CreateDirectory(logDir);
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logDir variable is created and the directory is created on disk, but logDir is never actually used for anything (e.g., it's not passed to the file logger). The directory creation is dead code — logging only goes to the console via AddSimpleConsole. Either add a file-based logger that writes to logDir, or remove this unused block.

Copilot uses AI. Check for mistakes.
DefaultSeverity,
Environment.MachineName,
"Jakkl",
System.Diagnostics.Process.GetCurrentProcess().Id.ToString(),
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System.Diagnostics.Process.GetCurrentProcess().Id.ToString() is called on every invocation of SendAsync. The process ID is constant for the lifetime of the application, so this creates unnecessary overhead per message, including allocating a new Process object each time. It should be evaluated once and cached, e.g., as a static field or evaluated in the constructor:
private static readonly string _processId = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();

Copilot uses AI. Check for mistakes.
- Migrated from .NET Framework 4.5.2 to **.NET 10**
- Replaced MetroFramework UI with standard WinForms controls
- Replaced custom NotifyIconEx with built-in `NotifyIcon`
- Added dependency injection with `Microsoft.Extensions.Logging`
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The breaking changes entry says "Added dependency injection with Microsoft.Extensions.Logging", but dependency injection comes from Microsoft.Extensions.DependencyInjection, not from Microsoft.Extensions.Logging. The Microsoft.Extensions.Logging package provides the logging abstractions. This is a minor inaccuracy in the documentation.

Suggested change
- Added dependency injection with `Microsoft.Extensions.Logging`
- Added dependency injection with `Microsoft.Extensions.DependencyInjection` and logging via `Microsoft.Extensions.Logging`

Copilot uses AI. Check for mistakes.
{
try
{
const string filename = "alerts.xml";
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alerts.xml file written by LogToAlertFile uses a relative path ("alerts.xml"), which means it will be written to the application's current working directory. This is typically the directory where the executable is located or from where it was launched, which may be a system directory (e.g., C:\Windows\System32) when the app runs on startup. This can cause access-denied errors or write the file to an unexpected location. The file path should use a known writable location such as Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) combined with the application name, consistent with how logDir is set up in Program.cs.

Suggested change
const string filename = "alerts.xml";
var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var alertsDir = System.IO.Path.Combine(appDataDir, "Jakkl");
System.IO.Directory.CreateDirectory(alertsDir);
var filename = System.IO.Path.Combine(alertsDir, "alerts.xml");

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +36
<?xml version="1.0" encoding="utf-8"?>
<alerts>
<alert time="3:09 PM" type="Error" category="(0)" source="Application" eventid="0" user="">The description for Event ID '0' in Source 'Application' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event:'Unable to log .NET application events. The source Jakkl was not found on computer ., but some or all event logs could not be searched. To create the source, you need permission to read all event logs to make sure that the new source name is unique. Inaccessible logs: Security.'</alert>
<alert time="3:14 PM" type="Error" category="(0)" source=".NET Runtime" eventid="1026" user="">Application: Jakl_FileManager.exe
CoreCLR Version: 4.6.30527.2
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileLoadException: Could not load file or assembly 'C:\Users\joshl\source\repos\Jakl-FileManager\Jakl-FileManager\bin\x86\Debug\AppX\entrypoint\Jakl_FileManager.exe'. Access is denied.
</alert>
<alert time="3:14 PM" type="Error" category="Application Crashing Events" source="Application Error" eventid="1000" user="DESKTOP-QVUMF60\joshl">Faulting application name: Jakl_FileManager.exe, version: 1.0.0.0, time stamp: 0x5d362223
Faulting module name: KERNELBASE.dll, version: 10.0.22621.6133, time stamp: 0xdb4e0d32
Exception code: 0xe0434352
Fault offset: 0x0014e702
Faulting process id: 0x0x18b48
Faulting application start time: 0x0x1dcacdca9349318
Faulting application path: C:\Users\joshl\source\repos\Jakl-FileManager\Jakl-FileManager\bin\x86\Debug\AppX\Jakl_FileManager.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: a2868e1e-96c1-4ae9-b60e-da5624e698be
Faulting package full name: 2C5726EB-AFCB-4DB5-AFBB-903D39DE8FFE_1.0.0.0_x86__fje2dntmbqe7c
Faulting package-relative application ID: App</alert>
<alert time="3:19 PM" type="Error" category="(0)" source=".NET Runtime" eventid="1026" user="">Application: AadManager.exe
CoreCLR Version: 4.6.30527.2
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileLoadException: Could not load file or assembly 'C:\Users\joshl\source\repos\AadManager\AadManager\bin\x64\Debug\AppX\entrypoint\AadManager.exe'. Access is denied.
</alert>
<alert time="3:19 PM" type="Error" category="Application Crashing Events" source="Application Error" eventid="1000" user="DESKTOP-QVUMF60\joshl">Faulting application name: AadManager.exe, version: 1.0.0.0, time stamp: 0x601d0adf
Faulting module name: KERNELBASE.dll, version: 10.0.22621.6060, time stamp: 0x5dcc5c14
Exception code: 0xe0434352
Fault offset: 0x000000000006055c
Faulting process id: 0x0x21e60
Faulting application start time: 0x0x1dcacdd5c053ed6
Faulting application path: C:\Users\joshl\source\repos\AadManager\AadManager\bin\x64\Debug\AppX\AadManager.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: f245a4cc-1905-4651-80d6-9e1570d14c09
Faulting package full name: 4F0F1495-7D10-4DDD-BE7D-10F108EA90ED_1.0.0.0_x64__fje2dntmbqe7c
Faulting package-relative application ID: App</alert>
<alert time="3:19 PM" type="Error" category="(0)" source="DCOM" eventid="10010" user="DESKTOP-QVUMF60\joshl">The description for Event ID '10010' in Source 'DCOM' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event:'4F0F1495-7D10-4DDD-BE7D-10F108EA90ED_1.0.0.0_x64__fje2dntmbqe7c!App.AppX2qz7atwx8d5hfzmcc2persmq5pfffs0x.mca'</alert>
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alerts.xml file has been committed to the repository. This file contains real error event data that was captured during development, including full local file paths (e.g., C:\Users\joshl\source\repos\...), machine names (DESKTOP-QVUMF60), and package GUIDs from the developer's machine. This is potentially sensitive developer information and is also a generated file that should not be version-controlled. It should be removed from the repository and added to .gitignore.

Suggested change
<?xml version="1.0" encoding="utf-8"?>
<alerts>
<alert time="3:09 PM" type="Error" category="(0)" source="Application" eventid="0" user="">The description for Event ID '0' in Source 'Application' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event:'Unable to log .NET application events. The source Jakkl was not found on computer ., but some or all event logs could not be searched. To create the source, you need permission to read all event logs to make sure that the new source name is unique. Inaccessible logs: Security.'</alert>
<alert time="3:14 PM" type="Error" category="(0)" source=".NET Runtime" eventid="1026" user="">Application: Jakl_FileManager.exe
CoreCLR Version: 4.6.30527.2
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileLoadException: Could not load file or assembly 'C:\Users\joshl\source\repos\Jakl-FileManager\Jakl-FileManager\bin\x86\Debug\AppX\entrypoint\Jakl_FileManager.exe'. Access is denied.
</alert>
<alert time="3:14 PM" type="Error" category="Application Crashing Events" source="Application Error" eventid="1000" user="DESKTOP-QVUMF60\joshl">Faulting application name: Jakl_FileManager.exe, version: 1.0.0.0, time stamp: 0x5d362223
Faulting module name: KERNELBASE.dll, version: 10.0.22621.6133, time stamp: 0xdb4e0d32
Exception code: 0xe0434352
Fault offset: 0x0014e702
Faulting process id: 0x0x18b48
Faulting application start time: 0x0x1dcacdca9349318
Faulting application path: C:\Users\joshl\source\repos\Jakl-FileManager\Jakl-FileManager\bin\x86\Debug\AppX\Jakl_FileManager.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: a2868e1e-96c1-4ae9-b60e-da5624e698be
Faulting package full name: 2C5726EB-AFCB-4DB5-AFBB-903D39DE8FFE_1.0.0.0_x86__fje2dntmbqe7c
Faulting package-relative application ID: App</alert>
<alert time="3:19 PM" type="Error" category="(0)" source=".NET Runtime" eventid="1026" user="">Application: AadManager.exe
CoreCLR Version: 4.6.30527.2
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileLoadException: Could not load file or assembly 'C:\Users\joshl\source\repos\AadManager\AadManager\bin\x64\Debug\AppX\entrypoint\AadManager.exe'. Access is denied.
</alert>
<alert time="3:19 PM" type="Error" category="Application Crashing Events" source="Application Error" eventid="1000" user="DESKTOP-QVUMF60\joshl">Faulting application name: AadManager.exe, version: 1.0.0.0, time stamp: 0x601d0adf
Faulting module name: KERNELBASE.dll, version: 10.0.22621.6060, time stamp: 0x5dcc5c14
Exception code: 0xe0434352
Fault offset: 0x000000000006055c
Faulting process id: 0x0x21e60
Faulting application start time: 0x0x1dcacdd5c053ed6
Faulting application path: C:\Users\joshl\source\repos\AadManager\AadManager\bin\x64\Debug\AppX\AadManager.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: f245a4cc-1905-4651-80d6-9e1570d14c09
Faulting package full name: 4F0F1495-7D10-4DDD-BE7D-10F108EA90ED_1.0.0.0_x64__fje2dntmbqe7c
Faulting package-relative application ID: App</alert>
<alert time="3:19 PM" type="Error" category="(0)" source="DCOM" eventid="10010" user="DESKTOP-QVUMF60\joshl">The description for Event ID '10010' in Source 'DCOM' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event:'4F0F1495-7D10-4DDD-BE7D-10F108EA90ED_1.0.0.0_x64__fje2dntmbqe7c!App.AppX2qz7atwx8d5hfzmcc2persmq5pfffs0x.mca'</alert>
<?xml version="1.0" encoding="utf-8"?>
<!--
Placeholder alerts file.
This file previously contained machine-specific diagnostic data
(local file paths, machine names, package IDs) captured from a
developer machine. That data has been removed because it should
not be committed to source control.
If a sample structure is needed for tests or documentation,
add only synthetic, non-sensitive data here.
-->
<alerts>

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +40
G:\Repos\syslog-windows-agent\bin\Release\Jakkl.exe.config
G:\Repos\syslog-windows-agent\bin\Release\Jakkl.exe
G:\Repos\syslog-windows-agent\bin\Release\AdamsLair.WinForms.dll
G:\Repos\syslog-windows-agent\bin\Release\CheckComboBox.dll
G:\Repos\syslog-windows-agent\bin\Release\FB.Mvc.CheckBoxList.dll
G:\Repos\syslog-windows-agent\bin\Release\FontAwesome.Sharp.dll
G:\Repos\syslog-windows-agent\bin\Release\MetroFramework.dll
G:\Repos\syslog-windows-agent\bin\Release\MetroFramework.Fonts.dll
G:\Repos\syslog-windows-agent\bin\Release\PopupControl.dll
G:\Repos\syslog-windows-agent\bin\Release\AdamsLair.WinForms.pdb
G:\Repos\syslog-windows-agent\bin\Release\AdamsLair.WinForms.xml
G:\Repos\syslog-windows-agent\bin\Release\PopupControl.pdb
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.csproj.AssemblyReference.cache
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.JakklConfig.resources
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.NotifyIconEx.resources
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.Properties.Resources.resources
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.csproj.GenerateResource.cache
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.csproj.CoreCompileInputs.cache
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.csproj.CopyComplete
G:\Repos\syslog-windows-agent\obj\Release\Jakkl.exe
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build artifact files under obj/ have been committed to the repository. These files (obj/Release/Jakkl.csproj.FileListAbsolute.txt, obj/Debug/Jakkl.csproj.FileListAbsolute.txt, etc.) contain absolute local file paths from the developer's machine (e.g., G:\Repos\syslog-windows-agent\...), which are developer-specific and should not be version-controlled. The updated .gitignore now excludes obj/, but these files should be removed from the repository (e.g., via git rm --cached).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants