diff --git a/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs b/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs
new file mode 100644
index 0000000..4f44952
--- /dev/null
+++ b/src/Core/ServiceWrapper/Logging/WrapperServiceEventLogProvider.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using winsw.Logging;
+
+namespace winsw.Logging
+{
+ ///
+ /// Implements caching of the WindowsService reference in WinSW.
+ ///
+ public class WrapperServiceEventLogProvider : IServiceEventLogProvider
+ {
+ public WrapperService service {get; set;}
+
+ public EventLog locate()
+ {
+ WrapperService _service = service;
+ if (_service != null && !_service.IsShuttingDown)
+ {
+ return _service.EventLog;
+ }
+
+ // By default return null
+ return null;
+ }
+ }
+}
diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs
index e769d4d..e09be8e 100644
--- a/src/Core/ServiceWrapper/Main.cs
+++ b/src/Core/ServiceWrapper/Main.cs
@@ -20,10 +20,11 @@ using WMI;
using ServiceType = WMI.ServiceType;
using winsw.Native;
using System.Reflection;
+using winsw.Logging;
namespace winsw
{
- public class WrapperService : ServiceBase, EventLogger, IEventWriter
+ public class WrapperService : ServiceBase, EventLogger
{
private SERVICE_STATUS _wrapperServiceStatus;
@@ -34,6 +35,7 @@ namespace winsw
internal WinSWExtensionManager ExtensionManager { private set; get; }
private static readonly ILog Log = LogManager.GetLogger("WinSW");
+ private static readonly WrapperServiceEventLogProvider eventLogProvider = new WrapperServiceEventLogProvider();
///
/// Indicates to the watch dog thread that we are going to terminate the process,
@@ -53,6 +55,13 @@ namespace winsw
get { return Assembly.GetExecutingAssembly().GetName().Version; }
}
+ ///
+ /// Indicates that the system is shutting down.
+ ///
+ public bool IsShuttingDown {
+ get { return _systemShuttingdown; }
+ }
+
public WrapperService(ServiceDescriptor descriptor)
{
_descriptor = descriptor;
@@ -63,6 +72,9 @@ namespace winsw
CanPauseAndContinue = false;
AutoLog = true;
_systemShuttingdown = false;
+
+ // Register the event log provider
+ eventLogProvider.service = this;
}
public WrapperService() : this (new ServiceDescriptor())
@@ -135,7 +147,7 @@ namespace winsw
}
catch (Exception e)
{
- WriteEvent("Thread failed unexpectedly",e);
+ Log.Error("Thread failed unexpectedly",e);
}
}).Start();
}
@@ -171,7 +183,7 @@ namespace winsw
}
catch (Exception e)
{
- WriteEvent("Failed to log event in Windows Event Log: " + message + "; Reason: ", e);
+ Log.Error("Failed to log event in Windows Event Log: " + message + "; Reason: ", e);
}
}
}
@@ -190,28 +202,11 @@ namespace winsw
}
catch (Exception e)
{
- WriteEvent("Failed to log event in Windows Event Log. Reason: ", e);
+ Log.Error("Failed to log event in Windows Event Log. Reason: ", e);
}
}
}
- private void WriteEvent(Exception exception)
- {
- //TODO: pass exception to logger
- WriteEvent(exception.Message + "\nStacktrace:" + exception.StackTrace, Level.Error);
- }
-
- private void WriteEvent(String message, Exception exception)
- {
- //TODO: pass exception to logger
- WriteEvent(message + "\nMessage:" + exception.Message + "\nStacktrace:" + exception.StackTrace, Level.Error);
- }
-
- private void WriteEvent(String message, Level logLevel = null, Exception ex = null)
- {
- Log.Logger.Log(GetType(), logLevel ?? Level.Info, message, ex);
- }
-
protected override void OnStart(string[] _)
{
_envs = _descriptor.EnvironmentVariables;
@@ -233,7 +228,7 @@ namespace winsw
catch (Exception e)
{
LogEvent("Failed to download " + d.From + " to " + d.To + "\n" + e.Message);
- WriteEvent("Failed to download " + d.From +" to "+d.To, e);
+ Log.Error("Failed to download " + d.From +" to "+d.To, e);
// but just keep going
}
}
@@ -250,23 +245,14 @@ namespace winsw
}
LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments);
- WriteEvent("Starting " + _descriptor.Executable + ' ' + startarguments);
+ Log.Info("Starting " + _descriptor.Executable + ' ' + startarguments);
// Load and start extensions
- ExtensionManager.LoadExtensions(this);
- try
- {
- ExtensionManager.OnStart(this);
- }
- catch (ExtensionException ex)
- {
- LogEvent("Failed to start extension " + ex.ExtensionId + "\n" + ex.Message, EventLogEntryType.Error);
- WriteEvent("Failed to start extension " + ex.ExtensionId, ex);
- //TODO: Exit on error?
- }
+ ExtensionManager.LoadExtensions();
+ ExtensionManager.FireOnWrapperStarted();
LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments);
- WriteEvent("Starting " + _descriptor.Executable + ' ' + startarguments);
+ Log.Info("Starting " + _descriptor.Executable + ' ' + startarguments);
StartProcess(_process, startarguments, _descriptor.Executable);
ExtensionManager.FireOnProcessStarted(_process);
@@ -288,7 +274,7 @@ namespace winsw
}
catch (Exception ex)
{
- WriteEvent("Shutdown exception", ex);
+ Log.Error("Shutdown exception", ex);
}
}
@@ -302,7 +288,7 @@ namespace winsw
}
catch (Exception ex)
{
- WriteEvent("Stop exception", ex);
+ Log.Error("Cannot stop exception", ex);
}
}
@@ -313,14 +299,14 @@ namespace winsw
{
string stoparguments = _descriptor.Stoparguments;
LogEvent("Stopping " + _descriptor.Id);
- WriteEvent("Stopping " + _descriptor.Id);
+ Log.Info("Stopping " + _descriptor.Id);
_orderlyShutdown = true;
if (stoparguments == null)
{
try
{
- WriteEvent("ProcessKill " + _process.Id);
+ Log.Debug("ProcessKill " + _process.Id);
ProcessHelper.StopProcessAndChildren(_process.Id, _descriptor.StopTimeout, _descriptor.StopParentProcessFirst);
ExtensionManager.FireOnProcessTerminated(_process);
}
@@ -345,29 +331,21 @@ namespace winsw
StartProcess(stopProcess, stoparguments, executable);
- WriteEvent("WaitForProcessToExit "+_process.Id+"+"+stopProcess.Id);
+ Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id);
WaitForProcessToExit(_process);
WaitForProcessToExit(stopProcess);
SignalShutdownComplete();
}
// Stop extensions
- try
- {
- ExtensionManager.OnStop(this);
- }
- catch (ExtensionException ex)
- {
- LogEvent("Failed to stop extension " + ex.ExtensionId + "\n" + ex.Message, EventLogEntryType.Error);
- WriteEvent("Failed to stop extension " + ex.ExtensionId, ex);
- }
+ ExtensionManager.FireBeforeWrapperStopped();
if (_systemShuttingdown && _descriptor.BeepOnShutdown)
{
Console.Beep();
}
- WriteEvent("Finished " + _descriptor.Id);
+ Log.Info("Finished " + _descriptor.Id);
}
private void WaitForProcessToExit(Process processoWait)
@@ -458,7 +436,7 @@ namespace winsw
ps.EnvironmentVariables[WinSWSystem.ENVVAR_NAME_SERVICE_ID.ToLower()] = _descriptor.Id;
processToStart.Start();
- WriteEvent("Started " + processToStart.Id);
+ Log.Info("Started " + processToStart.Id);
var priority = _descriptor.Priority;
if (priority != ProcessPriorityClass.Normal)
@@ -509,6 +487,7 @@ namespace winsw
try
{
Run(args);
+ Log.Info("Completed. Exit code is 0");
return 0;
}
catch (WmiException e)
@@ -554,7 +533,7 @@ namespace winsw
if (isCLIMode) // CLI mode, in-service mode otherwise
{
- Log.Debug("Starting ServiceWrapper in CLI mode");
+ Log.Info("Starting ServiceWrapper in the CLI mode");
// Get service info for the future use
Win32Services svc = new WmiRoot().GetCollection();
@@ -761,17 +740,25 @@ namespace winsw
throw new Exception("Unknown command: " + args[0]);
}
+ else
+ {
+ Log.Info("Starting ServiceWrapper in the service mode");
+ }
Run(new WrapperService());
}
private static void InitLoggers(ServiceDescriptor d, bool enableCLILogging)
{
+ // TODO: Make logging levels configurable
Level logLevel = Level.Debug;
+ Level eventLogLevel = Level.Warn;
// Legacy format from winsw-1.x: (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " - " + message);
PatternLayout pl = new PatternLayout { ConversionPattern = "%d %-5p - %m%n" };
pl.ActivateOptions();
+ List appenders = new List();
+
// wrapper.log
String wrapperLogPath = Path.Combine(d.LogDirectory, d.BaseName + ".wrapper.log");
var wrapperLog = new FileAppender
@@ -785,7 +772,7 @@ namespace winsw
Layout = pl
};
wrapperLog.ActivateOptions();
- BasicConfigurator.Configure(wrapperLog);
+ appenders.Add(wrapperLog);
// Also display logs in CLI if required
if (enableCLILogging)
@@ -794,11 +781,23 @@ namespace winsw
{
Name = "Wrapper console log",
Threshold = logLevel,
- Layout = pl
+ Layout = pl,
};
consoleAppender.ActivateOptions();
- ((Logger)Log.Logger).AddAppender(consoleAppender);
+ appenders.Add(consoleAppender);
}
+
+ // System log
+ var systemEventLogger = new ServiceEventLogAppender
+ {
+ Name = "System event log",
+ Threshold = eventLogLevel,
+ provider = eventLogProvider
+ };
+ systemEventLogger.ActivateOptions();
+ appenders.Add(systemEventLogger);
+
+ BasicConfigurator.Configure(appenders.ToArray());
}
private static string ReadPassword()
diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj
index c24abcf..b922705 100644
--- a/src/Core/ServiceWrapper/winsw.csproj
+++ b/src/Core/ServiceWrapper/winsw.csproj
@@ -79,6 +79,7 @@
+
diff --git a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs
index d1b0c40..ba1f8cf 100644
--- a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs
+++ b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs
@@ -9,17 +9,17 @@ namespace winsw.Extensions
public abstract String DisplayName { get; }
public WinSWExtensionDescriptor Descriptor { get; set; }
- public virtual void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger)
+ public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)
{
// Do nothing
}
- public virtual void OnStart(IEventWriter eventWriter)
+ public virtual void OnWrapperStarted()
{
// Do nothing
}
- public virtual void OnStop(IEventWriter eventWriter)
+ public virtual void BeforeWrapperStopped()
{
// Do nothing
}
diff --git a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs
index f3e1ef1..0f11987 100644
--- a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs
+++ b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs
@@ -29,14 +29,14 @@ namespace winsw.Extensions
///
/// Service descriptor
/// Configuration node
- void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger);
+ void Configure(ServiceDescriptor descriptor, XmlNode node);
///
/// Start handler. Called during startup of the service before the child process.
///
/// Logger
/// Any error during execution
- void OnStart(IEventWriter logger);
+ void OnWrapperStarted();
///
/// Handler, which is being invoked once the child process is started.
@@ -59,6 +59,6 @@ namespace winsw.Extensions
///
/// Logger
/// Any error during execution
- void OnStop(IEventWriter logger);
+ void BeforeWrapperStopped();
}
}
diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs
index 2312c77..51cfd1a 100644
--- a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs
+++ b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs
@@ -22,26 +22,43 @@ namespace winsw.Extensions
}
///
- /// Starts all extensions
+ /// Notifies all extensions that the wrapper is being started.
+ /// They are supposed to run the initialization logic.
+ /// If any extensions fails, WinSW startup should be interrupted.
///
- /// Start failure
- public void OnStart(IEventWriter logger)
+ /// Start failure
+ public void FireOnWrapperStarted()
{
foreach (var ext in Extensions)
{
- ext.Value.OnStart(logger);
+ try
+ {
+ ext.Value.OnWrapperStarted();
+ }
+ catch (ExtensionException ex)
+ {
+ Log.Fatal("onWrapperStarted() handler failed for " + ext.Value.DisplayName, ex);
+ throw ex; // Propagate error to stop the startup
+ }
}
}
///
- /// Stops all extensions
+ /// Notifies all extensions that the wrapper is being stopped.
+ /// If an error happens, further extensions will be tried
///
- /// Stop failure
- public void OnStop(IEventWriter logger)
+ public void FireBeforeWrapperStopped()
{
foreach (var ext in Extensions)
- {
- ext.Value.OnStop(logger);
+ {
+ try
+ {
+ ext.Value.BeforeWrapperStopped();
+ }
+ catch (ExtensionException ex)
+ {
+ Log.Error("beforeWrapperStopped() handler failed for " + ext.Value.DisplayName, ex);
+ }
}
}
@@ -86,17 +103,17 @@ namespace winsw.Extensions
//TODO: Implement loading of external extensions. Current version supports internal hack
#region Extension load management
- ///
+
/// Loads extensions according to the configuration file.
///
/// Logger
/// Loading failure
- public void LoadExtensions(IEventWriter logger)
+ public void LoadExtensions()
{
var extensionIds = ServiceDescriptor.ExtensionIds;
foreach (String extensionId in extensionIds)
{
- LoadExtension(extensionId, logger);
+ LoadExtension(extensionId);
}
}
@@ -106,7 +123,7 @@ namespace winsw.Extensions
/// Extension ID
/// Logger
/// Loading failure
- private void LoadExtension(string id, IEventWriter logger)
+ private void LoadExtension(string id)
{
if (Extensions.ContainsKey(id))
{
@@ -127,7 +144,7 @@ namespace winsw.Extensions
extension.Descriptor = descriptor;
try
{
- extension.Configure(ServiceDescriptor, configNode, logger);
+ extension.Configure(ServiceDescriptor, configNode);
}
catch (Exception ex)
{ // Consider any unexpected exception as fatal
@@ -135,11 +152,11 @@ namespace winsw.Extensions
throw ex;
}
Extensions.Add(id, extension);
- logger.LogEvent("Extension loaded: "+id, EventLogEntryType.Information);
+ Log.Info("Extension loaded: " + id);
}
else
{
- logger.LogEvent("Extension is disabled: " + id, EventLogEntryType.Warning);
+ Log.Warn("Extension is disabled: " + id);
}
}
diff --git a/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs b/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs
new file mode 100644
index 0000000..2c66d03
--- /dev/null
+++ b/src/Core/WinSWCore/Logging/IServiceEventLogProvider.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+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/Core/WinSWCore/Logging/ServiceEventLogAppender.cs b/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs
new file mode 100644
index 0000000..a1b864a
--- /dev/null
+++ b/src/Core/WinSWCore/Logging/ServiceEventLogAppender.cs
@@ -0,0 +1,43 @@
+using log4net.Appender;
+using log4net.Core;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace winsw.Logging
+{
+ ///
+ /// Implementes service Event log appender for log4j.
+ /// The implementation presumes that service gets initialized after the logging.
+ ///
+ public class ServiceEventLogAppender : AppenderSkeleton
+ {
+ public IServiceEventLogProvider provider { get; set; }
+
+ override protected void Append(LoggingEvent loggingEvent)
+ {
+ EventLog eventLog = provider.locate();
+ if (eventLog != null)
+ {
+ // We write the event iff the provider is ready
+ eventLog.WriteEntry(loggingEvent.RenderedMessage, toEventLogEntryType(loggingEvent.Level));
+ }
+ }
+
+ private static EventLogEntryType toEventLogEntryType(Level level)
+ {
+ if (level.Value >= Level.Error.Value)
+ {
+ return EventLogEntryType.Error;
+ }
+ if (level.Value >= Level.Warn.Value)
+ {
+ return EventLogEntryType.Warning;
+ }
+
+ // All other events will be posted as information
+ return EventLogEntryType.Information;
+ }
+ }
+}
diff --git a/src/Core/WinSWCore/Util/IEventWriter.cs b/src/Core/WinSWCore/Util/IEventWriter.cs
deleted file mode 100644
index 7f49dfa..0000000
--- a/src/Core/WinSWCore/Util/IEventWriter.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Diagnostics;
-
-namespace winsw.Util
-{
- public interface IEventWriter
- {
- void LogEvent(String message);
- void LogEvent(String message, EventLogEntryType type);
- }
-}
diff --git a/src/Core/WinSWCore/WinSWCore.csproj b/src/Core/WinSWCore/WinSWCore.csproj
index bac7cc4..219e5fe 100644
--- a/src/Core/WinSWCore/WinSWCore.csproj
+++ b/src/Core/WinSWCore/WinSWCore.csproj
@@ -54,12 +54,13 @@
+
+
-
@@ -71,6 +72,7 @@
+
diff --git a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs
index 1e436f3..0677549 100644
--- a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs
+++ b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs
@@ -43,7 +43,7 @@ namespace winsw.Plugins.RunawayProcessKiller
this.Pidfile = pidfile;
}
- public override void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger)
+ public override void Configure(ServiceDescriptor descriptor, XmlNode node)
{
// We expect the upper logic to process any errors
// TODO: a better parser API for types would be useful
@@ -57,7 +57,7 @@ namespace winsw.Plugins.RunawayProcessKiller
/// This method checks if the PID file is stored on the disk and then terminates runaway processes if they exist.
///
/// Unused logger
- public override void OnStart(IEventWriter logger)
+ public override void OnWrapperStarted()
{
// Read PID file from the disk
int pid;
diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs
index 97b36a9..c5cf9e9 100644
--- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs
+++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs
@@ -4,6 +4,7 @@ using System.Xml;
using System.Diagnostics;
using winsw.Extensions;
using winsw.Util;
+using log4net;
namespace winsw.Plugins.SharedDirectoryMapper
{
@@ -14,6 +15,8 @@ namespace winsw.Plugins.SharedDirectoryMapper
public override String DisplayName { get { return "Shared Directory Mapper"; } }
+ private static readonly ILog Logger = LogManager.GetLogger(typeof(SharedDirectoryMapper));
+
public SharedDirectoryMapper()
{
}
@@ -24,7 +27,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
_entries.Add(config);
}
- public override void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger)
+ public override void Configure(ServiceDescriptor descriptor, XmlNode node)
{
var nodes = XmlHelper.SingleNode(node, "mapping", false).SelectNodes("map");
if (nodes != null)
@@ -41,30 +44,30 @@ namespace winsw.Plugins.SharedDirectoryMapper
}
}
- public override void OnStart(IEventWriter eventWriter)
+ public override void OnWrapperStarted()
{
foreach (SharedDirectoryMapperConfig config in _entries)
{
if (config.EnableMapping)
{
- eventWriter.LogEvent(DisplayName + ": Mapping shared directory " + config.UNCPath + " to " + config.Label, EventLogEntryType.Information);
+ Logger.Info(DisplayName + ": Mapping shared directory " + config.UNCPath + " to " + config.Label);
try
{
_mapper.MapDirectory(config.Label, config.UNCPath);
}
catch (MapperException ex)
{
- HandleMappingError(config, eventWriter, ex);
+ HandleMappingError(config, ex);
}
}
else
{
- eventWriter.LogEvent(DisplayName + ": Mapping of " + config.Label + " is disabled", EventLogEntryType.Warning);
+ Logger.Warn(DisplayName + ": Mapping of " + config.Label + " is disabled");
}
}
}
- public override void OnStop(IEventWriter eventWriter)
+ public override void BeforeWrapperStopped()
{
foreach (SharedDirectoryMapperConfig config in _entries)
{
@@ -76,18 +79,16 @@ namespace winsw.Plugins.SharedDirectoryMapper
}
catch (MapperException ex)
{
- HandleMappingError(config, eventWriter, ex);
+ HandleMappingError(config, ex);
}
}
}
}
- private void HandleMappingError(SharedDirectoryMapperConfig config, IEventWriter eventWriter, MapperException ex) {
- String prefix = "Mapping of " + config.Label+ " ";
- eventWriter.LogEvent(prefix + "STDOUT: " + ex.Process.StandardOutput.ReadToEnd(), EventLogEntryType.Information);
- eventWriter.LogEvent(prefix + "STDERR: " + ex.Process.StandardError.ReadToEnd(), EventLogEntryType.Information);
-
- throw new ExtensionException(Descriptor.Id, DisplayName + ": " + prefix + "failed", ex);
+ private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) {
+ Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd()
+ + " \r\nSTDERR: " + ex.Process.StandardError.ReadToEnd(), ex);
+ throw new ExtensionException(Descriptor.Id, DisplayName + ": Mapping of " + config.Label + "failed", ex);
}
}
}
diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj
index 0b0632c..211e8b1 100644
--- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj
+++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj
@@ -11,6 +11,8 @@
SharedDirectoryMapper
v2.0
512
+ ..\..\
+ true
true
@@ -34,6 +36,9 @@
$(SolutionDir)..\winsw_key.snk
+
+ ..\..\packages\log4net.2.0.3\lib\net20-full\log4net.dll
+
@@ -50,7 +55,17 @@
WinSWCore
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+