Adding support for exception instances in Services.NzbDrone
This commit is contained in:
parent
917ae0f999
commit
98faca17ee
|
@ -20,14 +20,13 @@ namespace NzbDrone.Common.Contract
|
|||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
{"ExType", Type.NullCheck()},
|
||||
{"Logger", Logger.NullCheck()},
|
||||
{"Message", LogMessage.NullCheck()},
|
||||
{"Str", String.NullCheck()}
|
||||
{"ExType", Type.NullSafe()},
|
||||
{"Logger", Logger.NullSafe()},
|
||||
{"Message", LogMessage.NullSafe()},
|
||||
{"Str", String.NullSafe()}
|
||||
};
|
||||
|
||||
return dic;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NzbDrone.Common.Contract
|
||||
{
|
||||
public class ExceptionReportResponse
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int ExceptionId { get; set; }
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace NzbDrone.Common.Contract
|
|||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
{"Title", Title.NullCheck()},
|
||||
{"Title", Title.NullSafe()},
|
||||
};
|
||||
|
||||
return dic;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Contract\ExceptionReportResponse.cs" />
|
||||
<Compile Include="StringExtention.cs" />
|
||||
<Compile Include="HttpProvider.cs" />
|
||||
<Compile Include="ConfigFileProvider.cs" />
|
||||
|
|
|
@ -6,15 +6,15 @@ namespace NzbDrone.Common
|
|||
public static class StringExtention
|
||||
{
|
||||
|
||||
public static object NullCheck(this object target)
|
||||
public static object NullSafe(this object target)
|
||||
{
|
||||
if (target != null) return target;
|
||||
return "[NULL]";
|
||||
}
|
||||
|
||||
public static string NullCheck(this string target)
|
||||
public static string NullSafe(this string target)
|
||||
{
|
||||
return ((object)target).NullCheck().ToString();
|
||||
return ((object)target).NullSafe().ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Contract;
|
||||
using NzbDrone.Services.Service.Repository.Reporting;
|
||||
using Services.PetaPoco;
|
||||
|
||||
namespace NzbDrone.Services.Service.Controllers
|
||||
{
|
||||
public class ExceptionController : Controller
|
||||
{
|
||||
private readonly IDatabase _database;
|
||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string OK = "OK";
|
||||
|
||||
public ExceptionController(IDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public JsonResult ReportNew(ExceptionReport exceptionReport)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exceptionId = GetExceptionDetailId(exceptionReport);
|
||||
|
||||
var exceptionInstance = new ExceptionInstance
|
||||
{
|
||||
ExceptionDetail = exceptionId,
|
||||
IsProduction = exceptionReport.IsProduction,
|
||||
LogMessage = exceptionReport.LogMessage,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
|
||||
_database.Insert(exceptionInstance);
|
||||
|
||||
return new JsonResult { Data = new ExceptionReportResponse { ExceptionId = exceptionId } };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.FatalException("Error has occurred while logging exception", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int GetExceptionDetailId(ExceptionReport exceptionReport)
|
||||
{
|
||||
var reportHash = Hash(exceptionReport.Version + exceptionReport.String + exceptionReport.Logger);
|
||||
var id = _database.FirstOrDefault<int>("SELECT Id FROM Exceptions WHERE Hash =@0", reportHash);
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
var exeptionDetail = new ExceptionDetail();
|
||||
exeptionDetail.Hash = reportHash;
|
||||
exeptionDetail.Logger = exceptionReport.Logger;
|
||||
exeptionDetail.String = exceptionReport.String;
|
||||
exeptionDetail.Type = exceptionReport.Type;
|
||||
exeptionDetail.Version = exceptionReport.Version;
|
||||
|
||||
id = Convert.ToInt32(_database.Insert(exeptionDetail));
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private static string Hash(string input)
|
||||
{
|
||||
uint mCrc = 0xffffffff;
|
||||
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(input);
|
||||
foreach (byte myByte in bytes)
|
||||
{
|
||||
mCrc ^= ((uint)(myByte) << 24);
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
if ((Convert.ToUInt32(mCrc) & 0x80000000) == 0x80000000)
|
||||
{
|
||||
mCrc = (mCrc << 1) ^ 0x04C11DB7;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCrc <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return String.Format("{0:x8}", mCrc);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ namespace NzbDrone.Services.Service.Controllers
|
|||
[HttpPost]
|
||||
public JsonResult ParseError(ParseErrorReport parseErrorReport)
|
||||
{
|
||||
logger.Trace(parseErrorReport.NullCheck());
|
||||
logger.Trace(parseErrorReport.NullSafe());
|
||||
|
||||
if (ParseErrorExists(parseErrorReport.Title))
|
||||
return Json(OK);
|
||||
|
@ -63,7 +63,7 @@ namespace NzbDrone.Services.Service.Controllers
|
|||
}
|
||||
catch (Exception)
|
||||
{
|
||||
logger.Trace(exceptionReport.NullCheck());
|
||||
logger.Trace(exceptionReport.NullSafe());
|
||||
throw;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace NzbDrone.Services.Service.Migrations
|
||||
{
|
||||
[Migration(20120229)]
|
||||
public class Migration20120229 : Migration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
|
||||
Database.AddTable("ExceptionInstances", new Column("Id", DbType.Int64, ColumnProperty.PrimaryKeyWithIdentity),
|
||||
new Column("ExceptionDetail", DbType.Int16, ColumnProperty.NotNull),
|
||||
new Column("LogMessage", DbType.String, 3000, ColumnProperty.NotNull),
|
||||
MigrationsHelper.TimestampColumn,
|
||||
MigrationsHelper.ProductionColumn);
|
||||
|
||||
Database.AddTable("Exceptions", new Column("Id", DbType.Int64, ColumnProperty.PrimaryKeyWithIdentity),
|
||||
new Column("Logger", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("Type", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("String", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("Hash", DbType.String, ColumnProperty.NotNull),
|
||||
MigrationsHelper.VersionColumn);
|
||||
|
||||
|
||||
Database.ExecuteNonQuery("ALTER TABLE ExceptionReports ALTER COLUMN String NTEXT");
|
||||
Database.ExecuteNonQuery("ALTER TABLE Exceptions ALTER COLUMN String NTEXT");
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -209,8 +209,12 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="App_Start\Logging.cs" />
|
||||
<Compile Include="App_Start\NinjectMVC3.cs" />
|
||||
<Compile Include="Controllers\ExceptionController.cs" />
|
||||
<Compile Include="Helpers\HtmlIncludeExtentions.cs" />
|
||||
<Compile Include="Migrations\Migration20120226.cs" />
|
||||
<Compile Include="Migrations\Migration20120229.cs" />
|
||||
<Compile Include="Repository\Reporting\ExceptionDetail.cs" />
|
||||
<Compile Include="Repository\Reporting\ExceptionInstance.cs" />
|
||||
<Compile Include="Services.PetaPoco.cs" />
|
||||
<Compile Include="Datastore\Connection.cs" />
|
||||
<Compile Include="Controllers\DailySeriesController.cs" />
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Services.PetaPoco;
|
||||
|
||||
namespace NzbDrone.Services.Service.Repository.Reporting
|
||||
{
|
||||
[TableName("Exceptions")]
|
||||
public class ExceptionDetail
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Logger { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string String { get; set; }
|
||||
public string Hash { get; set; }
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Services.PetaPoco;
|
||||
|
||||
namespace NzbDrone.Services.Service.Repository.Reporting
|
||||
{
|
||||
[TableName("ExceptionInstances")]
|
||||
public class ExceptionInstance
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public int ExceptionDetail { get; set; }
|
||||
public string LogMessage { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public bool IsProduction { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Contract;
|
||||
using NzbDrone.Services.Service.Controllers;
|
||||
using NzbDrone.Services.Service.Repository.Reporting;
|
||||
using NzbDrone.Services.Tests.Framework;
|
||||
|
||||
namespace NzbDrone.Services.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExceptionControllerFixture : ServicesTestBase
|
||||
{
|
||||
|
||||
ExceptionController Controller
|
||||
{
|
||||
get
|
||||
{
|
||||
return Mocker.Resolve<ExceptionController>();
|
||||
}
|
||||
}
|
||||
|
||||
private static ExceptionReport CreateExceptionReport()
|
||||
{
|
||||
return new ExceptionReport
|
||||
{
|
||||
IsProduction = true,
|
||||
Version = "1.1.2.323456",
|
||||
UGuid = Guid.NewGuid(),
|
||||
Logger = "NzbDrone.Logger.Name",
|
||||
LogMessage = @"Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message",
|
||||
String = @"Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message",
|
||||
|
||||
Type = typeof(InvalidOperationException).Name
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ReportNew_should_save_instance()
|
||||
{
|
||||
var exceptionReport = CreateExceptionReport();
|
||||
|
||||
WithRealDb();
|
||||
|
||||
Controller.ReportNew(exceptionReport);
|
||||
|
||||
var exceptionInstance = Db.Fetch<ExceptionInstance>();
|
||||
exceptionInstance.Should().HaveCount(1);
|
||||
exceptionInstance.Single().Id.Should().BeGreaterThan(0);
|
||||
exceptionInstance.Single().ExceptionDetail.Should().BeGreaterThan(0);
|
||||
exceptionInstance.Single().IsProduction.Should().Be(exceptionReport.IsProduction);
|
||||
exceptionInstance.Single().Timestamp.Should().BeWithin(TimeSpan.FromSeconds(4)).Before(DateTime.Now);
|
||||
exceptionInstance.Single().LogMessage.Should().Be(exceptionReport.LogMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReportNew_should_return_exception_id()
|
||||
{
|
||||
var exceptionReport = CreateExceptionReport();
|
||||
|
||||
WithRealDb();
|
||||
|
||||
var response = Controller.ReportNew(exceptionReport);
|
||||
|
||||
response.Data.Should().BeOfType<ExceptionReportResponse>();
|
||||
((ExceptionReportResponse)response.Data).ExceptionId.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Reporting_exception_more_than_once_should_create_single_detail_with_multiple_instances()
|
||||
{
|
||||
var exceptionReport = CreateExceptionReport();
|
||||
|
||||
WithRealDb();
|
||||
|
||||
var response1 = Controller.ReportNew(exceptionReport);
|
||||
var response2 = Controller.ReportNew(exceptionReport);
|
||||
var response3 = Controller.ReportNew(exceptionReport);
|
||||
|
||||
var detail = Db.Fetch<ExceptionDetail>();
|
||||
var instances = Db.Fetch<ExceptionInstance>();
|
||||
|
||||
detail.Should().HaveCount(1);
|
||||
instances.Should().HaveCount(3);
|
||||
|
||||
instances.Should().OnlyContain(c => c.ExceptionDetail == detail.Single().Id);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ExceptionControllerFixture.cs" />
|
||||
<Compile Include="ReportingControllerFixture.cs" />
|
||||
<Compile Include="Framework\ServicesTestBase.cs" />
|
||||
<Compile Include="Framework\TestDbHelper.cs" />
|
||||
|
|
|
@ -48,6 +48,24 @@ namespace NzbDrone.Services.Tests
|
|||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message",
|
||||
String = @"Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
Long message Long message Long messageLong messageLong messageLong messageLong messageLong messageLong messageLong messageLong message
|
||||
|
|
Loading…
Reference in New Issue