Skip to content

Commit 1a13ccc

Browse files
committed
Basic implementation of JSON serializer + library adjustment
1 parent 9d50828 commit 1a13ccc

File tree

474 files changed

+762
-59397
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

474 files changed

+762
-59397
lines changed

Runtime/BacktraceClient.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,9 @@ public Action<BacktraceReport> OnClientReportLimitReached
141141

142142
/// <summary>
143143
/// Get custom client attributes. Every argument stored in dictionary will be send to Backtrace API.
144-
/// Backtrace unity-plugin allows you to store in attributes only primitive values. Plugin will skip loading
145-
/// complex object.
144+
/// Backtrace unity-plugin allows you to store in attributes only string values.
146145
/// </summary>
147-
public readonly Dictionary<string, object> Attributes;
146+
public readonly Dictionary<string, string> Attributes;
148147

149148

150149
/// <summary>
@@ -201,7 +200,6 @@ public void Refresh()
201200

202201
#endif
203202

204-
Annotations.GameObjectDepth = Configuration.GameObjectDepth;
205203
HandleUnhandledExceptions();
206204
_reportLimitWatcher = new ReportLimitWatcher(Convert.ToUInt32(Configuration.ReportPerMin));
207205

@@ -256,7 +254,7 @@ public void SetClientReportLimit(uint reportPerMin)
256254
/// <param name="message">Report message</param>
257255
/// <param name="attachmentPaths">List of attachments</param>
258256
/// <param name="attributes">List of report attributes</param
259-
public void Send(string message, List<string> attachmentPaths = null, Dictionary<string, object> attributes = null)
257+
public void Send(string message, List<string> attachmentPaths = null, Dictionary<string, string> attributes = null)
260258
{
261259
if (Enabled == false)
262260
{
@@ -292,7 +290,7 @@ public void Send(string message, List<string> attachmentPaths = null, Dictionary
292290
/// <param name="exception">Report exception</param>
293291
/// <param name="attachmentPaths">List of attachments</param>
294292
/// <param name="attributes">List of report attributes</param
295-
public void Send(Exception exception, List<string> attachmentPaths = null, Dictionary<string, object> attributes = null)
293+
public void Send(Exception exception, List<string> attachmentPaths = null, Dictionary<string, string> attributes = null)
296294
{
297295
if (Enabled == false)
298296
{
@@ -341,7 +339,7 @@ public void Send(BacktraceReport report, Action<BacktraceResult> sendCallback =
341339
_onClientReportLimitReached.Invoke(report);
342340

343341
if (sendCallback != null)
344-
sendCallback.Invoke(BacktraceResult.OnLimitReached(report));
342+
sendCallback.Invoke(BacktraceResult.OnLimitReached());
345343

346344
_reportLimitWatcher.DisplayReportLimitHitMessage();
347345
return;
@@ -360,14 +358,16 @@ private void SendReport(BacktraceReport report, Action<BacktraceResult> sendCall
360358
//create a JSON payload instance
361359
BacktraceData data = null;
362360

363-
data = (record != null ? record.BacktraceData : null) ?? report.ToBacktraceData(Attributes);
361+
data = (record != null ? record.BacktraceData : null) ?? report.ToBacktraceData(Attributes, Configuration.GameObjectDepth);
364362
//valid user custom events
365363
data = (BeforeSend != null ? BeforeSend.Invoke(data) : null) ?? data;
366364

367365
if (BacktraceApi == null)
368366
{
369367
if (record != null)
368+
{
370369
record.Dispose();
370+
}
371371

372372
Debug.LogWarning("Backtrace API doesn't exist. Please validate client token or server url!");
373373
return;

Runtime/BacktraceDatabase.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void Reload()
121121
Enable = false;
122122
return;
123123
}
124-
124+
125125

126126
//setup database object
127127
DatabaseSettings = new BacktraceDatabaseSettings(Configuration);
@@ -143,7 +143,7 @@ public void Reload()
143143
_reportLimitWatcher = new ReportLimitWatcher(Convert.ToUInt32(Configuration.ReportPerMin));
144144

145145
}
146-
146+
147147
/// <summary>
148148
/// Backtrace database on disable event
149149
/// </summary>
@@ -234,7 +234,7 @@ public void Clear()
234234
/// <summary>
235235
/// Add new report to BacktraceDatabase
236236
/// </summary>
237-
public BacktraceDatabaseRecord Add(BacktraceReport backtraceReport, Dictionary<string, object> attributes, MiniDumpType miniDumpType = MiniDumpType.Normal)
237+
public BacktraceDatabaseRecord Add(BacktraceReport backtraceReport, Dictionary<string, string> attributes, MiniDumpType miniDumpType = MiniDumpType.Normal)
238238
{
239239
if (!Enable || backtraceReport == null)
240240
{
@@ -247,7 +247,7 @@ public BacktraceDatabaseRecord Add(BacktraceReport backtraceReport, Dictionary<s
247247
{
248248
return null;
249249
}
250-
var data = backtraceReport.ToBacktraceData(attributes);
250+
var data = backtraceReport.ToBacktraceData(attributes, Configuration.GameObjectDepth);
251251
return BacktraceDatabaseContext.Add(data, miniDumpType);
252252
}
253253

@@ -292,7 +292,7 @@ private void FlushRecord(BacktraceDatabaseRecord record)
292292
{
293293
return;
294294
}
295-
var backtraceData = record.BacktraceData;
295+
var backtraceData = record.BacktraceDataJson;
296296
Delete(record);
297297
if (backtraceData == null)
298298
{
@@ -308,10 +308,10 @@ record = BacktraceDatabaseContext.FirstOrDefault();
308308

309309
private void SendData(BacktraceDatabaseRecord record)
310310
{
311-
var backtraceData = record!=null ? record.BacktraceData : null;
311+
var backtraceData = record != null ? record.BacktraceDataJson : null;
312312
//check if report exists on hard drive
313313
// to avoid situation when someone manually remove data
314-
if (backtraceData == null || backtraceData.Report == null)
314+
if (string.IsNullOrEmpty(backtraceData))
315315
{
316316
Delete(record);
317317
}
@@ -330,7 +330,7 @@ private void SendData(BacktraceDatabaseRecord record)
330330
BacktraceDatabaseContext.IncrementBatchRetry();
331331
return;
332332
}
333-
bool limitHit = _reportLimitWatcher.WatchReport(new DateTime().Timestamp());
333+
bool limitHit = _reportLimitWatcher.WatchReport(new DateTime().Timestamp());
334334
if (!limitHit)
335335
{
336336
_reportLimitWatcher.DisplayReportLimitHitMessage();

Runtime/Extensions/DictionaryExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ internal static class DictionaryExtensions
1515
/// <param name="source">Source dictionary (dictionary from report)</param>
1616
/// <param name="toMerge">merged dictionary (</param>
1717
/// <returns>Merged dictionary</returns>
18-
internal static Dictionary<string, object> Merge(
19-
this Dictionary<string, object> source, Dictionary<string, object> toMerge)
18+
internal static Dictionary<string, string> Merge(
19+
this Dictionary<string, string> source, Dictionary<string, string> toMerge)
2020
{
2121
if (source == null)
2222
{
@@ -26,7 +26,7 @@ internal static Dictionary<string, object> Merge(
2626
{
2727
throw new ArgumentException("toMerge");
2828
}
29-
var result = new Dictionary<string, object>(source);
29+
var result = new Dictionary<string, string>(source);
3030
foreach (var record in toMerge)
3131
{
3232
if (!result.ContainsKey(record.Key))

Runtime/Interfaces/IBacktraceAPI.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ public interface IBacktraceApi
1515
/// <param name="data">Library diagnostic data</param>
1616
IEnumerator Send(BacktraceData data, Action<BacktraceResult> callback = null);
1717

18+
/// <summary>
19+
/// Send diagnostic report to Backtrace API
20+
/// </summary>
21+
/// <param name="json">Library diagnostic data in JSON format</param>
22+
/// <param name="callback">Coroutine callback</param>
23+
/// <returns></returns>
24+
IEnumerator Send(string json, Action<BacktraceResult> callback = null);
25+
1826
/// <summary>
1927
/// Set an event executed when received bad request, unauthorize request or other information from server
2028
/// </summary>
@@ -29,5 +37,6 @@ public interface IBacktraceApi
2937
/// Setup custom request method
3038
/// </summary>
3139
Func<string, BacktraceData, BacktraceResult> RequestHandler { get; set; }
40+
3241
}
3342
}

Runtime/Interfaces/IBacktraceDatabase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public interface IBacktraceDatabase
4343
/// <summary>
4444
/// Add new report to Database
4545
/// </summary>
46-
BacktraceDatabaseRecord Add(BacktraceReport backtraceReport, Dictionary<string, object> attributes, MiniDumpType miniDumpType = MiniDumpType.Normal);
46+
BacktraceDatabaseRecord Add(BacktraceReport backtraceReport, Dictionary<string, string> attributes, MiniDumpType miniDumpType = MiniDumpType.Normal);
4747

4848
/// <summary>
4949
/// Get all records stored in Database
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Json/BacktraceJObject.cs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Globalization;
5+
using System.Text;
6+
7+
namespace Backtrace.Unity.Json
8+
{
9+
/// <summary>
10+
/// Backtrace JSON object representation
11+
/// </summary>
12+
public class BacktraceJObject
13+
{
14+
/// <summary>
15+
/// JSON object source
16+
/// </summary>
17+
public readonly Dictionary<string, object> Source = new Dictionary<string, object>();
18+
19+
public BacktraceJObject() : this(null) { }
20+
public BacktraceJObject(Dictionary<string, object> source)
21+
{
22+
if (source == null)
23+
{
24+
return;
25+
}
26+
Source = source;
27+
}
28+
29+
public object this[string key]
30+
{
31+
get
32+
{
33+
return Source[key];
34+
}
35+
set
36+
{
37+
Source[key] = value;
38+
}
39+
}
40+
41+
/// <summary>
42+
/// Convert BacktraceJObject to JSON
43+
/// </summary>
44+
/// <returns>BacktraceJObject JSON representation</returns>
45+
public string ToJson()
46+
{
47+
var stringBuilder = new StringBuilder();
48+
stringBuilder.AppendLine("{");
49+
50+
foreach (var entry in Source)
51+
{
52+
if (stringBuilder.Length != 3)
53+
{
54+
stringBuilder.Append(",");
55+
stringBuilder.AppendLine();
56+
}
57+
var key = EscapeKey(entry.Key);
58+
stringBuilder.AppendFormat("\"{0}\":", key);
59+
60+
var value = entry.Value;
61+
var jsonValue = ConvertValue(value);
62+
stringBuilder.Append(jsonValue);
63+
}
64+
65+
stringBuilder.AppendLine();
66+
stringBuilder.AppendLine("}");
67+
68+
return stringBuilder.ToString();
69+
}
70+
71+
/// <summary>
72+
/// Escape special characters in string
73+
/// </summary>
74+
/// <param name="value">string to escape</param>
75+
/// <returns>escaped string</returns>
76+
private string EscapeKey(string value)
77+
{
78+
var output = new StringBuilder(value.Length);
79+
foreach (char c in value)
80+
{
81+
switch (c)
82+
{
83+
case '\\':
84+
output.AppendFormat("{0}{0}", '\\');
85+
break;
86+
87+
case '"':
88+
output.AppendFormat("{0}{1}", '\\', '"');
89+
break;
90+
case '\b':
91+
output.Append("\\b");
92+
break;
93+
case '\t':
94+
output.Append("\\t");
95+
break;
96+
case '\n':
97+
output.Append("\\n");
98+
break;
99+
case '\f':
100+
output.Append("\\f");
101+
break;
102+
case '\r':
103+
output.Append("\\r");
104+
break;
105+
default:
106+
output.Append(c);
107+
break;
108+
}
109+
}
110+
111+
return output.ToString();
112+
}
113+
114+
115+
/// <summary>
116+
/// Convert object to json value
117+
/// </summary>
118+
/// <param name="value">object value</param>
119+
/// <returns>json value</returns>
120+
private string ConvertValue(object value)
121+
{
122+
if (value == null)
123+
{
124+
return "null";
125+
}
126+
127+
var analysedType = value.GetType();
128+
129+
if (analysedType == typeof(bool))
130+
{
131+
return ((bool)value).ToString().ToLower();
132+
}
133+
else if (analysedType == typeof(double))
134+
{
135+
return Convert.ToDouble(value, CultureInfo.CurrentCulture).ToString();
136+
}
137+
else if (analysedType == typeof(float))
138+
{
139+
return Convert.ToDouble(value, CultureInfo.CurrentCulture).ToString();
140+
}
141+
else if (analysedType == typeof(int))
142+
{
143+
return Convert.ToInt32(value, CultureInfo.CurrentCulture).ToString();
144+
}
145+
else if (analysedType == typeof(long))
146+
{
147+
return Convert.ToInt64(value, CultureInfo.CurrentCulture).ToString();
148+
}
149+
else if (analysedType == typeof(string))
150+
{
151+
return string.Format("\"{0}\"", EscapeKey(value as string));
152+
}
153+
else if (value is IEnumerable)
154+
{
155+
var collection = (value as IEnumerable);
156+
var builder = new StringBuilder();
157+
builder.Append('[');
158+
int index = 0;
159+
foreach (var item in collection)
160+
{
161+
if (index != 0)
162+
{
163+
builder.Append(',');
164+
}
165+
builder.Append(ConvertValue(item));
166+
index++;
167+
}
168+
builder.Append(']');
169+
return builder.ToString();
170+
}
171+
else if (Guid.TryParse(value.ToString(), out Guid guidResult))
172+
{
173+
return string.Format("\"{0}\"", guidResult.ToString());
174+
}
175+
else
176+
{
177+
//check if this is json inner object
178+
var backtraceJObjectValue = value as BacktraceJObject;
179+
if (backtraceJObjectValue != null)
180+
{
181+
return backtraceJObjectValue.ToJson();
182+
}
183+
184+
return "null";
185+
}
186+
187+
}
188+
}
189+
}

Runtime/JsonNet/Linq/BacktraceJObject.cs.meta renamed to Runtime/Json/BacktraceJObject.cs.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)