diff --git a/IISExpress/AppServer/applicationhost.config b/IISExpress/AppServer/applicationhost.config index 7dee0612b..39716f173 100644 --- a/IISExpress/AppServer/applicationhost.config +++ b/IISExpress/AppServer/applicationhost.config @@ -1,4 +1,4 @@ - + - - + + @@ -156,7 +156,7 @@ - + diff --git a/NzbDrone.Core.Test/Fixtures.cs b/NzbDrone.Core.Test/Fixtures.cs index c72442d7c..0f35747e4 100644 --- a/NzbDrone.Core.Test/Fixtures.cs +++ b/NzbDrone.Core.Test/Fixtures.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test [SetUp] public void Setup() { - CentralDispatch.ConfigureNlog(); + Instrumentation.Setup(); } } } \ No newline at end of file diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index a62ef5b12..c8412f920 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core string connectionString = String.Format("Data Source={0};Version=3;", Path.Combine(AppPath, "nzbdrone.db")); var provider = ProviderFactory.GetProvider(connectionString, "System.Data.SQLite"); - provider.Log = new SonicTrace(); + provider.Log = new Instrumentation.NlogWriter(); provider.LogParams = true; _kernel.Bind().To().InSingletonScope(); @@ -62,60 +62,14 @@ namespace NzbDrone.Core { get { - if (_kernel == null) { BindKernel(); } - return _kernel; } } - public static void ConfigureNlog() - { - // Step 1. Create configuration object - var config = new LoggingConfiguration(); - - string callSight = "${callsite:className=false:fileName=true:includeSourcePath=false:methodName=true}"; - - // Step 2. Create targets and add them to the configuration - var debuggerTarget = new DebuggerTarget - { - Layout = callSight + "- ${logger}: ${message}" - }; - - - var consoleTarget = new ColoredConsoleTarget - { - Layout = callSight + ": ${message}" - }; - - - var fileTarget = new FileTarget - { - FileName = "${basedir}/test.log", - Layout = "${message}" - }; - - config.AddTarget("debugger", debuggerTarget); - config.AddTarget("console", consoleTarget); - //config.AddTarget("file", fileTarget); - - // Step 3. Set target properties - // Step 4. Define rules - //LoggingRule fileRule = new LoggingRule("*", LogLevel.Trace, fileTarget); - LoggingRule debugRule = new LoggingRule("*", LogLevel.Trace, debuggerTarget); - LoggingRule consoleRule = new LoggingRule("*", LogLevel.Trace, consoleTarget); - - //config.LoggingRules.Add(fileRule); - config.LoggingRules.Add(debugRule); - config.LoggingRules.Add(consoleRule); - - // Step 5. Activate the configuration - LogManager.Configuration = config; - } - private static void ForceMigration(IRepository repository) { repository.GetPaged(0, 1); diff --git a/NzbDrone.Core/Instrumentation.cs b/NzbDrone.Core/Instrumentation.cs new file mode 100644 index 000000000..47564b0ee --- /dev/null +++ b/NzbDrone.Core/Instrumentation.cs @@ -0,0 +1,114 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using Exceptioneer.WindowsFormsClient; +using NLog; +using NLog.Config; +using NLog.Targets; + +namespace NzbDrone.Core +{ + public static class Instrumentation + { + public static void Setup() + { + // Step 1. Create configuration object + var config = new LoggingConfiguration(); + + const string callSight = "${callsite:className=false:fileName=false:includeSourcePath=false:methodName=true}"; + string layout = string.Concat("[${logger}](", callSight, "): ${message}"); + // Step 2. Create targets and add them to the configuration + var debuggerTarget = new DebuggerTarget + { + Layout = layout + }; + + var consoleTarget = new ColoredConsoleTarget + { + Layout = layout + }; + + var fileTarget = new FileTarget + { + FileName = "${basedir}/test.log", + Layout = layout + }; + + config.AddTarget("debugger", debuggerTarget); + config.AddTarget("console", consoleTarget); + //config.AddTarget("file", fileTarget); + + // Step 3. Set target properties + // Step 4. Define rules + //LoggingRule fileRule = new LoggingRule("*", LogLevel.Trace, fileTarget); + var debugRule = new LoggingRule("*", LogLevel.Trace, debuggerTarget); + var consoleRule = new LoggingRule("*", LogLevel.Trace, consoleTarget); + + //config.LoggingRules.Add(fileRule); + config.LoggingRules.Add(debugRule); + config.LoggingRules.Add(consoleRule); + + // Step 5. Activate the configuration + LogManager.Configuration = config; + } + + public static void LogEpicException(Exception e) + { + try + { + LogManager.GetLogger("EPICFAIL").FatalException("Unhandled Exception", e); + } + catch (Exception totalFailException) + { + Console.WriteLine("TOTAL FAIL:{0}", totalFailException); + Console.WriteLine(e.ToString()); + } + + PublishExceptoion(e); + } + + + private static bool PublishExceptoion(Exception e) + { + //Don't publish exceptions when debugging the app. + if (Debugger.IsAttached) + return false; + + return new Client + { + ApiKey = "43BBF60A-EB2A-4C1C-B09E-422ADF637265", + ApplicationName = "NZBDrone", + CurrentException = e + }.Submit(); + } + + public class NlogWriter : TextWriter + { + private static readonly Logger Logger = LogManager.GetLogger("DB"); + + + public override void Write(char[] buffer, int index, int count) + { + Write(new string(buffer, index, count)); + } + + public override void Write(string value) + { + DbAction(value); + } + + private static void DbAction(string value) + { + Logger.Trace(value); + } + + public override Encoding Encoding + { + get { return Encoding.Default; } + } + } + } + + +} diff --git a/NzbDrone.Core/Libraries/Exceptioneer.WindowsFormsClient.dll b/NzbDrone.Core/Libraries/Exceptioneer.WindowsFormsClient.dll new file mode 100644 index 000000000..52635882f Binary files /dev/null and b/NzbDrone.Core/Libraries/Exceptioneer.WindowsFormsClient.dll differ diff --git a/NzbDrone.Core/Libraries/log4net.dll b/NzbDrone.Core/Libraries/log4net.dll deleted file mode 100644 index ffc57e112..000000000 Binary files a/NzbDrone.Core/Libraries/log4net.dll and /dev/null differ diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index f4505ffa4..8d1e439ae 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -125,6 +125,10 @@ False Libraries\Castle.Core.dll + + False + Libraries\Exceptioneer.WindowsFormsClient.dll + @@ -150,6 +154,7 @@ + @@ -158,7 +163,6 @@ - @@ -211,6 +215,7 @@ + diff --git a/NzbDrone.Core/SonicTrace.cs b/NzbDrone.Core/SonicTrace.cs deleted file mode 100644 index 74fdf78d0..000000000 --- a/NzbDrone.Core/SonicTrace.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - *Source:http://stackoverflow.com/questions/1520945/nlog-to-output-db-out - *DamienG - */ - -using System; -using System.IO; -using System.Text; -using NLog; - -namespace NzbDrone.Core -{ - class SonicTrace : TextWriter - { - private static readonly Logger Logger = LogManager.GetLogger("DB"); - - - public override void Write(char[] buffer, int index, int count) - { - Write(new string(buffer, index, count)); - } - - public override void Write(string value) - { - DbAction(value); - } - - private static void DbAction(string value) - { - Logger.Trace(value); - } - - public override Encoding Encoding - { - get { return Encoding.Default; } - } - } - -} \ No newline at end of file diff --git a/NzbDrone.Web/Global.asax.cs b/NzbDrone.Web/Global.asax.cs index 5f3cc374b..550b09dbc 100644 --- a/NzbDrone.Web/Global.asax.cs +++ b/NzbDrone.Web/Global.asax.cs @@ -1,10 +1,13 @@ -using System.Web.Mvc; +using System; +using System.Diagnostics; +using System.Web; +using System.Web.Mvc; using System.Web.Routing; using Ninject; using Ninject.Web.Mvc; +using NLog; using NzbDrone.Core; - namespace NzbDrone.Web { public class MvcApplication : NinjectHttpApplication @@ -21,12 +24,11 @@ namespace NzbDrone.Web "{controller}/{action}/{id}", // URL with parameters new { controller = "Series", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); - } protected override void OnApplicationStarted() { - CentralDispatch.ConfigureNlog(); + Instrumentation.Setup(); AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); base.OnApplicationStarted(); @@ -35,9 +37,15 @@ namespace NzbDrone.Web protected override IKernel CreateKernel() { return CentralDispatch.NinjectKernel; - } + // ReSharper disable InconsistentNaming + protected void Application_Error(object sender, EventArgs e) + { + Instrumentation.LogEpicException(Server.GetLastError()); + } + + } } \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index 3cb0eae85..a3833f209 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -260,16 +260,7 @@ - False - True - 21704 - / - http://localhost/NzbDrone - False - False - - - False + True diff --git a/NzbDrone.Web/Views/Shared/Error.aspx b/NzbDrone.Web/Views/Shared/Error.aspx index 1df0032b0..515fe7e5d 100644 --- a/NzbDrone.Web/Views/Shared/Error.aspx +++ b/NzbDrone.Web/Views/Shared/Error.aspx @@ -11,15 +11,3 @@
<%:Model.Exception.ToString()%> - diff --git a/NzbDrone.Web/Web.config b/NzbDrone.Web/Web.config index ff2401b1b..0754d47f3 100644 --- a/NzbDrone.Web/Web.config +++ b/NzbDrone.Web/Web.config @@ -21,13 +21,9 @@ - + - diff --git a/NzbDrone.vshost.exe b/NzbDrone.vshost.exe new file mode 100644 index 000000000..bb84a51ac Binary files /dev/null and b/NzbDrone.vshost.exe differ diff --git a/NzbDrone/Config.cs b/NzbDrone/Config.cs new file mode 100644 index 000000000..23ea03835 --- /dev/null +++ b/NzbDrone/Config.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using NLog; +using NLog.Config; +using NLog.Targets; + +namespace NzbDrone +{ + class Config + { + private static string _projectRoot = string.Empty; + internal static string ProjectRoot + { + get + { + if (string.IsNullOrEmpty(_projectRoot)) + { + var appDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + + while (appDir.GetDirectories("iisexpress").Length == 0) + { + if (appDir.Parent == null) throw new ApplicationException("Can't fine IISExpress folder."); + appDir = appDir.Parent; + } + + _projectRoot = appDir.FullName; + } + + return _projectRoot; + } + + } + + internal static void ConfigureNlog() + { + var config = new LoggingConfiguration(); + + var debuggerTarget = new DebuggerTarget + { + Layout = "${logger}: ${message}" + }; + + + var consoleTarget = new ColoredConsoleTarget + { + Layout = "${logger}: ${message}" + }; + + + config.AddTarget("debugger", debuggerTarget); + config.AddTarget("console", consoleTarget); + //config.AddTarget("file", fileTarget); + + // Step 3. Set target properties + // Step 4. Define rules + //LoggingRule fileRule = new LoggingRule("*", LogLevel.Trace, fileTarget); + var debugRule = new LoggingRule("*", LogLevel.Trace, debuggerTarget); + var consoleRule = new LoggingRule("*", LogLevel.Trace, consoleTarget); + + //config.LoggingRules.Add(fileRule); + config.LoggingRules.Add(debugRule); + config.LoggingRules.Add(consoleRule); + + // Step 5. Activate the configuration + LogManager.Configuration = config; + } + + internal static int Port + { + get { return Convert.ToInt32(ConfigurationManager.AppSettings.Get("port")); } + } + + } +} diff --git a/NzbDrone/IISController.cs b/NzbDrone/IISController.cs new file mode 100644 index 000000000..1d59bcbcb --- /dev/null +++ b/NzbDrone/IISController.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Web.Administration; +using NLog; + +namespace NzbDrone +{ + class IISController + { + public static Process IISProcess { get; private set; } + private static readonly Logger IISLogger = LogManager.GetLogger("IISExpress"); + private static readonly Logger Logger = LogManager.GetLogger("IISController"); + private static readonly string IISFolder = Path.Combine(Config.ProjectRoot, @"IISExpress\"); + private static readonly string IISExe = Path.Combine(IISFolder, @"iisexpress.exe"); + + + internal static string AppUrl + { + get { return string.Format("http://localhost:{0}/", Config.Port); } + } + + internal static Process StartIIS() + { + Logger.Info("Preparing IISExpress Server..."); + IISProcess = new Process(); + + IISProcess.StartInfo.FileName = IISExe; + IISProcess.StartInfo.Arguments = "/config:IISExpress\\Appserver\\applicationhost.config"; + IISProcess.StartInfo.WorkingDirectory = Config.ProjectRoot; + + IISProcess.StartInfo.UseShellExecute = false; + IISProcess.StartInfo.RedirectStandardOutput = true; + IISProcess.StartInfo.RedirectStandardError = true; + IISProcess.StartInfo.CreateNoWindow = true; + + IISProcess.OutputDataReceived += ((s, e) => IISLogger.Trace(e.Data)); + IISProcess.ErrorDataReceived += ((s, e) => IISLogger.Fatal(e.Data)); + + //Set Variables for the config file. + Environment.SetEnvironmentVariable("NZBDRONE_PATH", Config.ProjectRoot); + UpdateIISConfig(); + + Logger.Info("Starting process. [{0}]", IISProcess.StartInfo.FileName); + IISProcess.Start(); + + IISProcess.BeginErrorReadLine(); + IISProcess.BeginOutputReadLine(); + return IISProcess; + } + + internal static void StopIIS() + { + KillProcess(IISProcess); + } + + internal static void KillOrphaned() + { + Logger.Trace("================================================"); + Logger.Info("Finding orphaned IIS Processes."); + foreach (var process in Process.GetProcessesByName("IISExpress")) + { + Logger.Trace("-------------------------"); + string processPath = process.MainModule.FileName; + Logger.Info("[{0}]IIS Process found. Path:{1}", process.Id, processPath); + if (CleanPath(processPath) == CleanPath(IISExe)) + { + Logger.Info("[{0}]Process is considered orphaned.", process.Id); + KillProcess(process); + } + else + { + Logger.Info("[{0}]Process has a different start-up path. skipping.", process.Id); + } + Logger.Trace("-------------------------"); + } + Logger.Trace("================================================"); + } + + + + private static void KillProcess(Process process) + { + if (process == null) return; + + Logger.Info("[{0}]Killing process", process.Id); + process.Kill(); + Logger.Info("[{0}]Waiting for exit", process.Id); + process.WaitForExit(); + Logger.Info("[{0}]Process terminated successfully", process.Id); + } + + private static void UpdateIISConfig() + { + Logger.Info(@"Configuring server to: [http://localhost:{0}]", Config.Port); + var serverManager = new ServerManager(Path.Combine(IISFolder, @"AppServer\applicationhost.config")); + serverManager.Sites["NZBDrone"].Bindings[0].BindingInformation = string.Format("*:{0}:", Config.Port); + serverManager.CommitChanges(); + } + + private static string CleanPath(string path) + { + return path.ToLower().Replace("\\", "").Replace("//", "//"); + } + } +} diff --git a/NzbDrone/Microsoft.Web.Administration.dll b/NzbDrone/Microsoft.Web.Administration.dll new file mode 100644 index 000000000..07c9a8670 Binary files /dev/null and b/NzbDrone/Microsoft.Web.Administration.dll differ diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj index c52ec3931..c5ce0d972 100644 --- a/NzbDrone/NzbDrone.csproj +++ b/NzbDrone/NzbDrone.csproj @@ -13,6 +13,21 @@ v4.0 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true x86 @@ -34,25 +49,72 @@ 4 + + True + + + True + + + False + ..\NzbDrone.Core\Libraries\Exceptioneer.WindowsFormsClient.dll + + + True + False ..\NzbDrone.Core\Libraries\NLog.dll + + + + + + + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 3.1 + true + + + + + +