From 8b06b6157dce8fd410886a837f103e5b56006c6b Mon Sep 17 00:00:00 2001
From: Next Turn <45985406+nxtn@users.noreply.github.com>
Date: Sun, 27 Dec 2020 01:05:46 +0800
Subject: [PATCH] Backport logging updates (#755)
---
.../Logging/IServiceEventLogProvider.cs | 16 ---
src/WinSW.Core/ServiceDescriptor.cs | 6 +-
src/WinSW.Core/ServiceDescriptorYaml.cs | 6 +-
src/WinSW.Core/WinSW.Core.csproj | 13 +-
.../Logging/ServiceEventLogAppender.cs | 29 +++--
.../Logging/WrapperServiceEventLogProvider.cs | 4 +-
src/WinSW/Program.cs | 115 ++++++++----------
src/WinSW/WrapperService.cs | 6 +-
8 files changed, 83 insertions(+), 112 deletions(-)
delete mode 100644 src/WinSW.Core/Logging/IServiceEventLogProvider.cs
rename src/{WinSW.Core => WinSW}/Logging/ServiceEventLogAppender.cs (50%)
diff --git a/src/WinSW.Core/Logging/IServiceEventLogProvider.cs b/src/WinSW.Core/Logging/IServiceEventLogProvider.cs
deleted file mode 100644
index 0c79fd0..0000000
--- a/src/WinSW.Core/Logging/IServiceEventLogProvider.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Diagnostics;
-
-namespace WinSW.Logging
-{
- ///
- /// Indicates that the class may reference the event log
- ///
- public interface IServiceEventLogProvider
- {
- ///
- /// Locates Event Log for the service.
- ///
- /// Event Log or null if it is not avilable
- EventLog? Locate();
- }
-}
diff --git a/src/WinSW.Core/ServiceDescriptor.cs b/src/WinSW.Core/ServiceDescriptor.cs
index 5bd46bd..50baf24 100644
--- a/src/WinSW.Core/ServiceDescriptor.cs
+++ b/src/WinSW.Core/ServiceDescriptor.cs
@@ -39,10 +39,10 @@ namespace WinSW
// Currently there is no opportunity to alter the executable path
public virtual string ExecutablePath => Defaults.ExecutablePath;
- public ServiceDescriptor(string baseName, DirectoryInfo d)
+ public ServiceDescriptor(string baseName, string directory)
{
this.BaseName = baseName;
- this.BasePath = Path.Combine(d.FullName, this.BaseName);
+ this.BasePath = Path.Combine(directory, this.BaseName);
try
{
@@ -54,7 +54,7 @@ namespace WinSW
}
// register the base directory as environment variable so that future expansions can refer to this.
- Environment.SetEnvironmentVariable("BASE", d.FullName);
+ Environment.SetEnvironmentVariable("BASE", directory);
// ditto for ID
Environment.SetEnvironmentVariable("SERVICE_ID", this.Name);
diff --git a/src/WinSW.Core/ServiceDescriptorYaml.cs b/src/WinSW.Core/ServiceDescriptorYaml.cs
index 5305e72..2cd5b55 100644
--- a/src/WinSW.Core/ServiceDescriptorYaml.cs
+++ b/src/WinSW.Core/ServiceDescriptorYaml.cs
@@ -11,9 +11,9 @@ namespace WinSW
public static DefaultWinSWSettings Defaults { get; } = new DefaultWinSWSettings();
- public ServiceDescriptorYaml(string baseName, DirectoryInfo d)
+ public ServiceDescriptorYaml(string baseName, string directory)
{
- string basepath = Path.Combine(d.FullName, baseName);
+ string basepath = Path.Combine(directory, baseName);
using (var reader = new StreamReader(basepath + ".yml"))
{
@@ -23,7 +23,7 @@ namespace WinSW
this.Configurations = deserializer.Deserialize(file);
}
- Environment.SetEnvironmentVariable("BASE", d.FullName);
+ Environment.SetEnvironmentVariable("BASE", directory);
// ditto for ID
Environment.SetEnvironmentVariable("SERVICE_ID", this.Configurations.Name);
diff --git a/src/WinSW.Core/WinSW.Core.csproj b/src/WinSW.Core/WinSW.Core.csproj
index d64883e..88f4dbd 100644
--- a/src/WinSW.Core/WinSW.Core.csproj
+++ b/src/WinSW.Core/WinSW.Core.csproj
@@ -10,7 +10,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -19,19 +19,8 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/WinSW.Core/Logging/ServiceEventLogAppender.cs b/src/WinSW/Logging/ServiceEventLogAppender.cs
similarity index 50%
rename from src/WinSW.Core/Logging/ServiceEventLogAppender.cs
rename to src/WinSW/Logging/ServiceEventLogAppender.cs
index d2c1860..aa566e7 100644
--- a/src/WinSW.Core/Logging/ServiceEventLogAppender.cs
+++ b/src/WinSW/Logging/ServiceEventLogAppender.cs
@@ -8,18 +8,33 @@ namespace WinSW.Logging
/// Implementes service Event log appender for log4j.
/// The implementation presumes that service gets initialized after the logging.
///
- public class ServiceEventLogAppender : AppenderSkeleton
+ internal sealed class ServiceEventLogAppender : AppenderSkeleton
{
-#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
- public IServiceEventLogProvider Provider { get; set; }
-#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
+ private readonly WrapperServiceEventLogProvider provider;
+
+ internal ServiceEventLogAppender(WrapperServiceEventLogProvider provider)
+ {
+ this.provider = provider;
+ }
protected override void Append(LoggingEvent loggingEvent)
{
- var eventLog = this.Provider.Locate();
+ var eventLog = this.provider.Locate();
- // We write the event iff the provider is ready
- eventLog?.WriteEntry(loggingEvent.RenderedMessage, ToEventLogEntryType(loggingEvent.Level));
+ if (eventLog is not null)
+ {
+ eventLog.WriteEntry(loggingEvent.RenderedMessage, ToEventLogEntryType(loggingEvent.Level));
+ return;
+ }
+
+ try
+ {
+ using var backupLog = new EventLog("Application", ".", "Windows Service Wrapper");
+ backupLog.WriteEntry(loggingEvent.RenderedMessage, ToEventLogEntryType(loggingEvent.Level));
+ }
+ catch
+ {
+ }
}
private static EventLogEntryType ToEventLogEntryType(Level level)
diff --git a/src/WinSW/Logging/WrapperServiceEventLogProvider.cs b/src/WinSW/Logging/WrapperServiceEventLogProvider.cs
index c53fb30..1ed6f49 100644
--- a/src/WinSW/Logging/WrapperServiceEventLogProvider.cs
+++ b/src/WinSW/Logging/WrapperServiceEventLogProvider.cs
@@ -5,14 +5,14 @@ namespace WinSW.Logging
///
/// Implements caching of the WindowsService reference in WinSW.
///
- public class WrapperServiceEventLogProvider : IServiceEventLogProvider
+ internal sealed class WrapperServiceEventLogProvider
{
public WrapperService? Service { get; set; }
public EventLog? Locate()
{
var service = this.Service;
- if (service != null && !service.IsShuttingDown)
+ if (service is not null && !service.IsShuttingDown)
{
return service.EventLog;
}
diff --git a/src/WinSW/Program.cs b/src/WinSW/Program.cs
index ceca2b5..99b2767 100644
--- a/src/WinSW/Program.cs
+++ b/src/WinSW/Program.cs
@@ -6,9 +6,7 @@ using System.IO;
#if VNEXT
using System.IO.Pipes;
#endif
-#if NET
using System.Reflection;
-#endif
using System.Security.AccessControl;
using System.Security.Principal;
using System.ServiceProcess;
@@ -37,6 +35,15 @@ namespace WinSW
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
+ private static string ExecutablePath
+ {
+ get
+ {
+ using var current = Process.GetCurrentProcess();
+ return current.MainModule!.FileName!;
+ }
+ }
+
public static int Main(string[] args)
{
try
@@ -81,11 +88,7 @@ namespace WinSW
bool inConsoleMode = argsArray.Length > 0;
// If descriptor is not specified, initialize the new one (and load configs from there)
- descriptor ??= GetServiceDescriptor();
-
- // Configure the wrapper-internal logging.
- // STDOUT and STDERR of the child process will be handled independently.
- InitLoggers(descriptor, inConsoleMode);
+ descriptor ??= LoadConfigAndInitLoggers(inConsoleMode);
if (!inConsoleMode)
{
@@ -598,8 +601,6 @@ namespace WinSW
// [DoesNotReturn]
void Elevate()
{
- using var current = Process.GetCurrentProcess();
-
#if VNEXT
string? stdinName = Console.IsInputRedirected ? Guid.NewGuid().ToString() : null;
string? stdoutName = Console.IsOutputRedirected ? Guid.NewGuid().ToString() : null;
@@ -624,7 +625,7 @@ namespace WinSW
{
UseShellExecute = true,
Verb = "runas",
- FileName = current.MainModule!.FileName!,
+ FileName = ExecutablePath,
Arguments = arguments,
WindowStyle = ProcessWindowStyle.Hidden,
};
@@ -664,7 +665,7 @@ namespace WinSW
}
}
- private static void InitLoggers(IWinSWConfiguration descriptor, bool enableConsoleLogging)
+ private static IWinSWConfiguration LoadConfigAndInitLoggers(bool inConsoleMode)
{
// TODO: Make logging levels configurable
var fileLogLevel = Level.Debug;
@@ -674,15 +675,47 @@ namespace WinSW
var consoleLogLevel = Level.Info;
var eventLogLevel = Level.Warn;
- // Legacy format from winsw-1.x: (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " - " + message);
var layout = new PatternLayout { ConversionPattern = "%d %-5p - %m%n" };
layout.ActivateOptions();
- var appenders = new List();
+ var repository = LogManager.GetRepository(Assembly.GetExecutingAssembly());
+
+ if (inConsoleMode)
+ {
+ var consoleAppender = new ConsoleAppender
+ {
+ Name = "Wrapper console log",
+ Threshold = consoleLogLevel,
+ Layout = layout,
+ };
+ consoleAppender.ActivateOptions();
+
+ BasicConfigurator.Configure(repository, consoleAppender);
+ }
+ else
+ {
+ var eventLogAppender = new ServiceEventLogAppender(WrapperService.eventLogProvider)
+ {
+ Name = "Wrapper event log",
+ Threshold = eventLogLevel,
+ };
+ eventLogAppender.ActivateOptions();
+
+ BasicConfigurator.Configure(repository, eventLogAppender);
+ }
+
+ string executablePath = ExecutablePath;
+ string directory = Path.GetDirectoryName(executablePath)!;
+ string baseName = Path.GetFileNameWithoutExtension(executablePath);
+
+ IWinSWConfiguration config =
+ File.Exists(Path.Combine(directory, baseName + ".xml")) ? new ServiceDescriptor(baseName, directory) :
+ File.Exists(Path.Combine(directory, baseName + ".yml")) ? new ServiceDescriptorYaml(baseName, directory).Configurations :
+ throw new FileNotFoundException($"Unable to locate {baseName}.[xml|yml] file within executable directory");
// .wrapper.log
- string wrapperLogPath = Path.Combine(descriptor.LogDirectory, descriptor.BaseName + ".wrapper.log");
- var wrapperLog = new FileAppender
+ string wrapperLogPath = Path.Combine(config.LogDirectory, config.BaseName + ".wrapper.log");
+ var fileAppender = new FileAppender
{
AppendToFile = true,
File = wrapperLogPath,
@@ -692,37 +725,11 @@ namespace WinSW
LockingModel = new FileAppender.MinimalLock(),
Layout = layout,
};
- wrapperLog.ActivateOptions();
- appenders.Add(wrapperLog);
+ fileAppender.ActivateOptions();
- // console log
- if (enableConsoleLogging)
- {
- var consoleAppender = new ConsoleAppender
- {
- Name = "Wrapper console log",
- Threshold = consoleLogLevel,
- Layout = layout,
- };
- consoleAppender.ActivateOptions();
- appenders.Add(consoleAppender);
- }
+ BasicConfigurator.Configure(repository, fileAppender);
- // event log
- var systemEventLogger = new ServiceEventLogAppender
- {
- Name = "Wrapper event log",
- Threshold = eventLogLevel,
- Provider = WrapperService.eventLogProvider,
- };
- systemEventLogger.ActivateOptions();
- appenders.Add(systemEventLogger);
-
- BasicConfigurator.Configure(
-#if NET
- LogManager.GetRepository(Assembly.GetExecutingAssembly()),
-#endif
- appenders.ToArray());
+ return config;
}
internal static unsafe bool IsProcessElevated()
@@ -776,26 +783,6 @@ namespace WinSW
}
}
- private static IWinSWConfiguration GetServiceDescriptor()
- {
- string executablePath = new DefaultWinSWSettings().ExecutablePath;
- string baseName = Path.GetFileNameWithoutExtension(executablePath);
-
- var d = new DirectoryInfo(Path.GetDirectoryName(executablePath)!);
-
- if (File.Exists(Path.Combine(d.FullName, baseName + ".xml")))
- {
- return new ServiceDescriptor(baseName, d);
- }
-
- if (File.Exists(Path.Combine(d.FullName, baseName + ".yml")))
- {
- return new ServiceDescriptorYaml(baseName, d).Configurations;
- }
-
- throw new FileNotFoundException($"Unable to locate { baseName }.[xml|yml] file within executable directory");
- }
-
private static void PrintHelp()
{
Console.WriteLine("A wrapper binary that can be used to host executables as Windows services");
diff --git a/src/WinSW/WrapperService.cs b/src/WinSW/WrapperService.cs
index fa51f20..d45fb0a 100644
--- a/src/WinSW/WrapperService.cs
+++ b/src/WinSW/WrapperService.cs
@@ -28,11 +28,7 @@ namespace WinSW
internal WinSWExtensionManager ExtensionManager { get; private set; }
- private static readonly ILog Log = LogManager.GetLogger(
-#if NET
- Assembly.GetExecutingAssembly(),
-#endif
- "WinSW");
+ private static readonly ILog Log = LogManager.GetLogger(typeof(WrapperService));
internal static readonly WrapperServiceEventLogProvider eventLogProvider = new();