Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions Src/StackifyLib/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,30 @@ public static void LoadSettings()
ApiLog = apiLog.Equals(bool.TrueString, StringComparison.CurrentCultureIgnoreCase);
}

var loggingJsonMaxFields = Get("Stackify.Logging.JsonMaxFields", "50");
if (string.IsNullOrWhiteSpace(loggingJsonMaxFields) == false)
var loggingMaxDepth = Get("Stackify.Logging.MaxDepth", "5");
if (string.IsNullOrWhiteSpace(loggingMaxDepth) == false)
{
if (int.TryParse(loggingJsonMaxFields, out int maxFields) && maxFields > 0 && maxFields < 100)
if (int.TryParse(loggingMaxDepth, out var maxDepth) && maxDepth > 0 && maxDepth < 10)
{
LoggingJsonMaxFields = maxFields;
LoggingMaxDepth = maxDepth;
}
}

var loggingMaxFields = Get("Stackify.Logging.MaxFields", "50");
if (string.IsNullOrWhiteSpace(loggingMaxFields) == false)
{
if (int.TryParse(loggingMaxFields, out var maxFields) && maxFields > 0 && maxFields < 100)
{
LoggingMaxFields = maxFields;
}
}

var loggingMaxStrLength = Get("Stackify.Logging.MaxStringLength", "32766");
if (string.IsNullOrWhiteSpace(loggingMaxStrLength) == false)
{
if (int.TryParse(loggingMaxStrLength, out var maxStrLen) && maxStrLen > 0 && maxStrLen < 32766)
{
LoggingMaxStringLength = maxStrLen;
}
}
}
Expand Down Expand Up @@ -150,7 +168,11 @@ public static void LoadSettings()

public static bool? ApiLog { get; set; }

public static int LoggingJsonMaxFields { get; set; } = 50;
public static int LoggingMaxDepth { get; set; } = 5;

public static int LoggingMaxFields { get; set; } = 50;

public static int LoggingMaxStringLength { get; set; } = 32766;


/// <summary>
Expand Down
7 changes: 4 additions & 3 deletions Src/StackifyLib/Internal/Logs/LogClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Net;
using System.Threading;
using StackifyLib.Internal.Serialization;

namespace StackifyLib.Internal.Logs
{
Expand Down Expand Up @@ -315,11 +316,11 @@ internal HttpClient.StackifyWebResponse SendLogsByGroups(LogMsg[] messages)

var groups = SplitLogsToGroups(messages);

string jsonData = JsonConvert.SerializeObject(groups, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
var jdn = new JsonDotNetSerializer(new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore });

var jsonData = jdn.SafeSerializeObject(groups);

string urlToUse = (_HttpClient.BaseAPIUrl) + "Log/SaveMultipleGroups";

var urlToUse = (_HttpClient.BaseAPIUrl) + "Log/SaveMultipleGroups";

if (!_ServicePointSet)
{
Expand Down
58 changes: 58 additions & 0 deletions Src/StackifyLib/Internal/Serialization/JsonDotNetSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;

namespace StackifyLib.Internal.Serialization
{
public class JsonDotNetSerializer
{
private readonly JsonSerializerSettings _settings;
private readonly int _maxDepth;
private readonly int _maxFields;
private readonly int _maxStringLength;


public JsonDotNetSerializer(JsonSerializerSettings settings = null, int? maxDepth = null, int? maxFields = null, int? maxStringLength = null)
{
_settings = settings;

_maxDepth = maxDepth ?? Config.LoggingMaxDepth;
_maxFields = maxFields ?? Config.LoggingMaxFields;
_maxStringLength = maxStringLength ?? Config.LoggingMaxStringLength;
}


/// <summary>
/// Serialize an object to JSON with limitations on MaxDepth and MaxStringLength as provided in the ctor.
///
/// Note, Serialization does not currently consider MaxFields.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public string SafeSerializeObject(object obj)
{
string r;

using (var writer = new StringWriter())
{
using (var jsonWriter = new SafeJsonTextWriter(writer, _maxStringLength))
{
// ReSharper disable AccessToDisposedClosure
bool IncludeDepth() => jsonWriter.CurrentDepth <= _maxDepth;
// ReSharper restore AccessToDisposedClosure

var resolver = new ShouldSerializeContractResolver(IncludeDepth);
var serializer = JsonSerializer.CreateDefault(_settings);
serializer.ContractResolver = resolver;

serializer.Serialize(jsonWriter, obj);
r = writer.ToString();
}
}

return r;
}
}
}
49 changes: 49 additions & 0 deletions Src/StackifyLib/Internal/Serialization/SafeJsonTextReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace StackifyLib.Internal.Serialization
{
internal class SafeJsonTextReader : JsonTextReader
{
private readonly int _maxStringLength;

public int CurrentDepth { get; private set; }
public decimal CurrentFields { get; private set; } = 1;


public SafeJsonTextReader(TextReader reader, int maxStringLength) : base(reader)
{
_maxStringLength = maxStringLength;
}


public override bool Read()
{
CurrentDepth = Path.Count(c => c == '.') + 1;
CurrentFields += .5M;

return base.Read();
}

public override string ReadAsString()
{
var value = base.ReadAsString();

if (value != null)
{
if (value.Length > _maxStringLength)
{
value = value.Substring(0, _maxStringLength);
}
}

return value;
}
}
}
46 changes: 46 additions & 0 deletions Src/StackifyLib/Internal/Serialization/SafeJsonTextWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;

namespace StackifyLib.Internal.Serialization
{
internal class SafeJsonTextWriter : JsonTextWriter
{
private readonly int _maxStringLength;

public int CurrentDepth { get; private set; }


public SafeJsonTextWriter(TextWriter writer, int maxStringLength) : base(writer)
{
_maxStringLength = maxStringLength;
}


public override void WriteStartObject()
{
CurrentDepth++;

base.WriteStartObject();
}

public override void WriteEndObject()
{
CurrentDepth--;

base.WriteEndObject();
}

public override void WriteValue(string value)
{
if (value.Length > _maxStringLength)
{
value = value.Substring(0, _maxStringLength);
}

base.WriteValue(value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace StackifyLib.Internal.Serialization
{
internal class ShouldDeserializeContractResolver : DefaultContractResolver
{
private readonly Func<bool> _include;

public ShouldDeserializeContractResolver(Func<bool> include)
{
_include = include;
}

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);

property.ShouldDeserialize = obj => _include();

return property;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace StackifyLib.Internal.Serialization
{
internal class ShouldSerializeContractResolver : DefaultContractResolver
{
private readonly Func<bool> _include;

public ShouldSerializeContractResolver(Func<bool> include)
{
_include = include;
}

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);

property.ShouldSerialize = obj => _include();

return property;
}
}
}
26 changes: 14 additions & 12 deletions Src/StackifyLib/Utils/HelperFunctions.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StackifyLib.Internal.Serialization;


namespace StackifyLib.Utils
{
public class HelperFunctions
{
static List<string> _BadTypes = new List<string>() { "log4net.Util.SystemStringFormat", "System.Object[]" };
static JsonSerializer serializer = new JsonSerializer { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
static JsonSerializerSettings serializerSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
private static readonly List<string> BadTypes = new List<string> { "log4net.Util.SystemStringFormat", "System.Object[]" };
private static readonly JsonSerializer Serializer = new JsonSerializer { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };

/// <summary>
/// Trying to serialize something that the user passed in. Sometimes this is used to serialize what we know is additional debug and sometimes it is the primary logged item. This is why the serializeSimpleTypes exists. For additional debug stuff we always serialize it. For the primary logged object we won't because it doesn't make any sense to put a string in the json as well as the main message. It's meant for objects.
Expand Down Expand Up @@ -68,9 +69,9 @@ public static string SerializeDebugData(object logObject, bool serializeSimpleTy
{

}
else if (!_BadTypes.Contains(t.ToString()))
else if (!BadTypes.Contains(t.ToString()))
{
var token = JToken.FromObject(logObject, serializer);
var token = JToken.FromObject(logObject, Serializer);

if (token is JObject)
{
Expand All @@ -92,7 +93,7 @@ public static string SerializeDebugData(object logObject, bool serializeSimpleTy

if (type.IsArray)
{
var array = (Array) logObject;
var array = (Array)logObject;

if (array.Length > 0)
{
Expand Down Expand Up @@ -160,9 +161,9 @@ public static string SerializeDebugData(object logObject, bool serializeSimpleTy
}
catch (Exception ex)
{
lock (_BadTypes)
lock (BadTypes)
{
_BadTypes.Add(t.ToString());
BadTypes.Add(t.ToString());
}
Utils.StackifyAPILogger.Log(ex.ToString());
}
Expand All @@ -187,7 +188,7 @@ public static string SerializeDebugData(object logObject, bool serializeSimpleTy
}
else
{
props.Add(prop.Key, JObject.FromObject(prop.Value, serializer));
props.Add(prop.Key, JObject.FromObject(prop.Value, Serializer));
}

}
Expand All @@ -204,10 +205,11 @@ public static string SerializeDebugData(object logObject, bool serializeSimpleTy

if (jObject != null)
{
jObject = GetPrunedObject(jObject, Config.LoggingMaxFields);

jObject = GetPrunedObject(jObject, Config.LoggingJsonMaxFields);
var jdn = new JsonDotNetSerializer(SerializerSettings);

return JsonConvert.SerializeObject(jObject, serializerSettings);
return jdn.SafeSerializeObject(jObject);
}

return null;
Expand Down
Loading