Apply Cleanse to Exception Data as well.

pull/1754/head
Taloth Saldono 7 years ago
parent 924fe80997
commit b70d167911

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Common.Extensions
{
public static class ExceptionExtensions
{
public static T WithData<T>(this T ex, string key, string value) where T : Exception
{
ex.AddData(key, value);
return ex;
}
public static T WithData<T>(this T ex, string key, int value) where T : Exception
{
ex.AddData(key, value.ToString());
return ex;
}
public static T WithData<T>(this T ex, string key, Http.HttpUri value) where T : Exception
{
ex.AddData(key, value.ToString());
return ex;
}
public static T WithData<T>(this T ex, Http.HttpResponse response, int maxSampleLength = 512) where T : Exception
{
if (response == null || response.Content == null) return ex;
var contentSample = response.Content.Substring(0, Math.Min(response.Content.Length, 512));
if (response.Headers != null)
{
ex.AddData("ContentType", response.Headers.ContentType ?? string.Empty);
}
ex.AddData("ContentLength", response.Content.Length.ToString());
ex.AddData("ContentSample", contentSample);
return ex;
}
private static void AddData(this Exception ex, string key, string value)
{
if (value.IsNullOrWhiteSpace()) return;
ex.Data[key] = value;
}
}
}

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Common.Instrumentation
{
public class CleansingJsonVisitor : JsonVisitor
{
public override void Visit(JArray json)
{
for (var i = 0; i < json.Count; i++)
{
if (json[i].Type == JTokenType.String)
{
var text = json[i].Value<string>();
json[i] = new JValue(CleanseLogMessage.Cleanse(text));
}
}
foreach (JToken token in json)
{
Visit(token);
}
}
public override void Visit(JProperty property)
{
if (property.Value.Type == JTokenType.String)
{
property.Value = CleanseValue(property.Value as JValue);
}
else
{
base.Visit(property);
}
}
private JValue CleanseValue(JValue value)
{
var text = value.Value<string>();
var cleansed = CleanseLogMessage.Cleanse(text);
return new JValue(cleansed);
}
}
}

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
namespace NzbDrone.Common.Instrumentation.Sentry
{
public class SentryPacketCleanser
{
public void CleansePacket(SonarrSentryPacket packet)
{
packet.Message = CleanseLogMessage.Cleanse(packet.Message);
if (packet.Fingerprint != null)
{
for (var i = 0; i < packet.Fingerprint.Length; i++)
{
packet.Fingerprint[i] = CleanseLogMessage.Cleanse(packet.Fingerprint[i]);
}
}
if (packet.Extra != null)
{
var target = JObject.FromObject(packet.Extra);
new CleansingJsonVisitor().Visit(target);
packet.Extra = target;
}
}
}
}

@ -111,18 +111,10 @@ namespace NzbDrone.Common.Instrumentation.Sentry
return;
}
var extras = logEvent.Properties.ToDictionary(x => x.Key.ToString(), x => CleanseLogMessage.Cleanse(x.Value.ToString()));
var extras = logEvent.Properties.ToDictionary(x => x.Key.ToString(), x => x.Value.ToString());
_client.Logger = logEvent.LoggerName;
string cleansedMessage = CleanseLogMessage.Cleanse(logEvent.Message);
string cleansedFormattedMessage = cleansedMessage;
if (logEvent.Parameters != null)
{
cleansedFormattedMessage = CleanseLogMessage.Cleanse(string.Format(logEvent.Message, logEvent.Parameters));
}
var sentryMessage = new SentryMessage(cleansedFormattedMessage);
var sentryMessage = new SentryMessage(logEvent.Message, logEvent.Parameters);
var sentryEvent = new SentryEvent(logEvent.Exception)
{
@ -133,7 +125,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
logEvent.Level.ToString(),
logEvent.LoggerName,
cleansedMessage
logEvent.Message
}
};

@ -6,6 +6,13 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
public class SonarrJsonPacketFactory : IJsonPacketFactory
{
private readonly SentryPacketCleanser _cleanser;
public SonarrJsonPacketFactory()
{
_cleanser = new SentryPacketCleanser();
}
private static string ShortenPath(string path)
{
@ -37,6 +44,8 @@ namespace NzbDrone.Common.Instrumentation.Sentry
frame.Filename = ShortenPath(frame.Filename);
}
}
_cleanser.CleansePacket(packet);
}
catch (Exception)
{
@ -46,7 +55,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry
return packet;
}
[Obsolete]
public JsonPacket Create(string project, SentryMessage message, ErrorLevel level = ErrorLevel.Info, IDictionary<string, string> tags = null,
string[] fingerprint = null, object extra = null)
@ -61,4 +69,4 @@ namespace NzbDrone.Common.Instrumentation.Sentry
throw new NotImplementedException();
}
}
}
}

@ -136,6 +136,7 @@
<Compile Include="Extensions\Base64Extensions.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
<Compile Include="Crypto\HashConverter.cs" />
<Compile Include="Extensions\ExceptionExtensions.cs" />
<Compile Include="Extensions\Int64Extensions.cs" />
<Compile Include="Extensions\ObjectExtensions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
@ -175,12 +176,14 @@
<Compile Include="Extensions\IEnumerableExtensions.cs" />
<Compile Include="Http\UserAgentBuilder.cs" />
<Compile Include="Instrumentation\CleanseLogMessage.cs" />
<Compile Include="Instrumentation\CleansingJsonVisitor.cs" />
<Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" />
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
<Compile Include="Instrumentation\LogEventExtensions.cs" />
<Compile Include="Instrumentation\NzbDroneFileTarget.cs" />
<Compile Include="Instrumentation\NzbDroneLogger.cs" />
<Compile Include="Instrumentation\Sentry\SentryDebounce.cs" />
<Compile Include="Instrumentation\Sentry\SentryPacketCleanser.cs" />
<Compile Include="Instrumentation\Sentry\SentryTarget.cs" />
<Compile Include="Instrumentation\Sentry\MachineNameUserFactory.cs" />
<Compile Include="Instrumentation\Sentry\SonarrJsonPacketFactory.cs" />
@ -205,6 +208,7 @@
<Compile Include="Serializer\HttpUriConverter.cs" />
<Compile Include="Serializer\IntConverter.cs" />
<Compile Include="Serializer\Json.cs" />
<Compile Include="Serializer\JsonVisitor.cs" />
<Compile Include="ServiceFactory.cs" />
<Compile Include="ServiceProvider.cs" />
<Compile Include="Extensions\StringExtensions.cs" />

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
namespace NzbDrone.Common.Serializer
{
public class JsonVisitor
{
protected void Dispatch(JToken json)
{
switch (json.Type)
{
case JTokenType.Object:
Visit(json as JObject);
break;
case JTokenType.Array:
Visit(json as JArray);
break;
case JTokenType.Raw:
Visit(json as JRaw);
break;
case JTokenType.Constructor:
Visit(json as JConstructor);
break;
case JTokenType.Property:
Visit(json as JProperty);
break;
case JTokenType.Comment:
case JTokenType.Integer:
case JTokenType.Float:
case JTokenType.String:
case JTokenType.Boolean:
case JTokenType.Null:
case JTokenType.Undefined:
case JTokenType.Date:
case JTokenType.Bytes:
case JTokenType.Guid:
case JTokenType.Uri:
case JTokenType.TimeSpan:
Visit(json as JValue);
break;
default:
break;
}
}
public virtual void Visit(JToken json)
{
Dispatch(json);
}
public virtual void Visit(JContainer json)
{
Dispatch(json);
}
public virtual void Visit(JArray json)
{
foreach (JToken token in json)
{
Visit(token);
}
}
public virtual void Visit(JConstructor json)
{
}
public virtual void Visit(JObject json)
{
foreach (JProperty property in json.Properties())
{
Visit(property);
}
}
public virtual void Visit(JProperty property)
{
Visit(property.Value);
}
public virtual void Visit(JValue value)
{
}
}
}

@ -243,6 +243,7 @@ namespace NzbDrone.Core.Indexers
catch (CloudFlareCaptchaException ex)
{
_indexerStatusService.RecordFailure(Definition.Id);
ex.WithData("FeedUrl", url);
if (ex.IsExpired)
{
_logger.Error(ex, "Expired CAPTCHA token for {0}, please refresh in indexer settings.", this);
@ -257,11 +258,11 @@ namespace NzbDrone.Core.Indexers
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Warn(ex, "{0}", url);
}
catch (Exception feedEx)
catch (Exception ex)
{
_indexerStatusService.RecordFailure(Definition.Id);
feedEx.Data.Add("FeedUrl", url);
_logger.Error(feedEx, "An error occurred while processing feed. {0}", url);
ex.WithData("FeedUrl", url);
_logger.Error(ex, "An error occurred while processing feed. {0}", url);
}
return CleanupReleases(releases);

@ -69,6 +69,8 @@ namespace NzbDrone.Core.Indexers.Newznab
catch (XmlException ex)
{
_logger.Debug(ex, "Failed to parse newznab api capabilities for {0}.", indexerSettings.Url);
ex.WithData(response);
throw;
}
catch (Exception ex)

@ -65,12 +65,14 @@ namespace NzbDrone.Core.Indexers
}
catch (UnsupportedFeedException itemEx)
{
itemEx.Data.Add("Item", item.Title());
itemEx.WithData("FeedUrl", indexerResponse.Request.Url);
itemEx.WithData("ItemTitle", item.Title());
throw;
}
catch (Exception itemEx)
{
itemEx.Data.Add("Item", item.Title());
itemEx.WithData("FeedUrl", indexerResponse.Request.Url);
itemEx.WithData("ItemTitle", item.Title());
_logger.Error(itemEx, "An error occurred while processing feed item from {0}", indexerResponse.Request.Url);
}
}
@ -95,8 +97,7 @@ namespace NzbDrone.Core.Indexers
var contentSample = indexerResponse.Content.Substring(0, Math.Min(indexerResponse.Content.Length, 512));
_logger.Debug("Truncated response content (originally {0} characters): {1}", indexerResponse.Content.Length, contentSample);
ex.Data.Add("ContentLength", indexerResponse.Content.Length);
ex.Data.Add("ContentSample", contentSample);
ex.WithData(indexerResponse.HttpResponse);
throw;
}

@ -40,23 +40,31 @@ namespace NzbDrone.Core.Indexers.TorrentRss
{
_logger.Debug("Evaluating TorrentRss feed '{0}'", indexerSettings.BaseUrl);
var requestGenerator = new TorrentRssIndexerRequestGenerator { Settings = indexerSettings };
var request = requestGenerator.GetRecentRequests().GetAllTiers().First().First();
HttpResponse httpResponse = null;
try
{
httpResponse = _httpClient.Execute(request.HttpRequest);
var requestGenerator = new TorrentRssIndexerRequestGenerator { Settings = indexerSettings };
var request = requestGenerator.GetRecentRequests().GetAllTiers().First().First();
HttpResponse httpResponse = null;
try
{
httpResponse = _httpClient.Execute(request.HttpRequest);
}
catch (Exception ex)
{
_logger.Warn(ex, string.Format("Unable to connect to indexer {0}: {1}", request.Url, ex.Message));
return null;
}
var indexerResponse = new IndexerResponse(request, httpResponse);
return GetParserSettings(indexerResponse, indexerSettings);
}
catch (Exception ex)
{
_logger.Warn(ex, string.Format("Unable to connect to indexer {0}: {1}", request.Url, ex.Message));
return null;
ex.WithData("FeedUrl", indexerSettings.BaseUrl);
throw;
}
var indexerResponse = new IndexerResponse(request, httpResponse);
return GetParserSettings(indexerResponse, indexerSettings);
}
}
private TorrentRssIndexerParserSettings GetParserSettings(IndexerResponse response, TorrentRssIndexerSettings indexerSettings)
{
@ -140,7 +148,7 @@ namespace NzbDrone.Core.Indexers.TorrentRss
_logger.Trace("Feed doesn't have Seeders in Description, disabling option.");
parser.ParseSeedersInDescription = settings.ParseSeedersInDescription = false;
}
if (!releases.Any(r => r.Size < ValidSizeThreshold))
{
_logger.Trace("Feed has valid size in enclosure.");

Loading…
Cancel
Save