Skip to content

Commit e4707a8

Browse files
authored
test UnityLogExceptionTests (#167)
1 parent 9c69c9e commit e4707a8

File tree

4 files changed

+514
-167
lines changed

4 files changed

+514
-167
lines changed

Diff for: global.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"sdk": {
3+
"allowPrerelease": false
4+
}
5+
}

Diff for: src/Sentry.Unity/UnityEventProcessor.cs

+1-124
Original file line numberDiff line numberDiff line change
@@ -140,132 +140,9 @@ public void Process(Exception exception, SentryEvent sentryEvent)
140140
// TODO: At this point the original (Mono+.NET stack trace factories already ran)
141141
// Ideally this strategy would fit into the SDK hooks, even though this parse gives not only
142142
// a stacktrace but also the exception message and type so currently can't be hooked into StackTraceFactory
143-
sentryEvent.SentryExceptions = new[] { GetException(ule.LogString, ule.LogStackTrace) };
143+
sentryEvent.SentryExceptions = new[] { ule.ToSentryException() };
144144
sentryEvent.SetTag("source", "log");
145145
}
146146
}
147-
148-
private static SentryException GetException(string condition, string stackTrace)
149-
{
150-
var frames = new List<SentryStackFrame>();
151-
var exc = condition.Split(new char[] { ':' }, 2);
152-
var excType = exc[0];
153-
// TODO: condition may NOT contain ':' separator
154-
var excValue = exc.Length == 1 ? exc[0] : exc[1].Substring(1); // strip the space
155-
var stackList = stackTrace.Split('\n');
156-
157-
// The format is as follows:
158-
// Module.Class.Method[.Invoke] (arguments) (at filename:lineno)
159-
// where :lineno is optional, will be ommitted in builds
160-
for (var i = 0; i < stackList.Length; i++)
161-
{
162-
string functionName;
163-
string filename;
164-
int lineNo;
165-
166-
var item = stackList[i];
167-
if (item == string.Empty)
168-
{
169-
continue;
170-
}
171-
172-
var closingParen = item.IndexOf(')');
173-
174-
if (closingParen == -1)
175-
{
176-
functionName = item;
177-
lineNo = -1;
178-
filename = string.Empty;
179-
}
180-
else
181-
{
182-
try
183-
{
184-
functionName = item.Substring(0, closingParen + 1);
185-
if (item.Substring(closingParen + 1, 5) != " (at ")
186-
{
187-
// we did something wrong, failed the check
188-
Debug.Log("failed parsing " + item);
189-
functionName = item;
190-
lineNo = -1;
191-
filename = string.Empty;
192-
}
193-
else
194-
{
195-
var colon = item.LastIndexOf(':', item.Length - 1, item.Length - closingParen);
196-
if (closingParen == item.Length - 1)
197-
{
198-
filename = string.Empty;
199-
lineNo = -1;
200-
}
201-
else if (colon == -1)
202-
{
203-
filename = item.Substring(closingParen + 6, item.Length - closingParen - 7);
204-
lineNo = -1;
205-
}
206-
else
207-
{
208-
filename = item.Substring(closingParen + 6, colon - closingParen - 6);
209-
lineNo = Convert.ToInt32(item.Substring(colon + 1, item.Length - 2 - colon));
210-
}
211-
}
212-
}
213-
catch (Exception)
214-
{
215-
functionName = item;
216-
lineNo = -1;
217-
filename = string.Empty; // we have no clue
218-
}
219-
}
220-
221-
var filenameWithoutZeroes = StripZeroes(filename);
222-
frames.Add(new SentryStackFrame
223-
{
224-
FileName = TryResolveFileNameForMono(filenameWithoutZeroes),
225-
AbsolutePath = filenameWithoutZeroes,
226-
Function = functionName,
227-
LineNumber = lineNo,
228-
InApp = functionName != null
229-
&& !functionName.StartsWith("UnityEngine", StringComparison.Ordinal)
230-
&& !functionName.StartsWith("System", StringComparison.Ordinal)
231-
});
232-
}
233-
234-
frames.Reverse();
235-
236-
var stacktrace = new SentryStackTrace();
237-
foreach (var frame in frames)
238-
{
239-
stacktrace.Frames.Add(frame);
240-
}
241-
242-
return new SentryException
243-
{
244-
Stacktrace = stacktrace,
245-
Type = excType,
246-
Value = excValue
247-
};
248-
}
249-
250-
// https://github.com/getsentry/sentry-unity/issues/103
251-
private static string StripZeroes(string filename)
252-
=> filename.Equals("<00000000000000000000000000000000>", StringComparison.OrdinalIgnoreCase)
253-
? string.Empty
254-
: filename;
255-
256-
// TODO: discuss
257-
private static string TryResolveFileNameForMono(string fileName)
258-
{
259-
try
260-
{
261-
// throws on Mono for <1231231231> paths
262-
return Path.GetFileName(fileName);
263-
}
264-
catch
265-
{
266-
// mono path
267-
return "Unknown";
268-
}
269-
}
270147
}
271148
}

Diff for: src/Sentry.Unity/UnityLogException.cs

+169-43
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,169 @@
1-
using System;
2-
using Sentry.Protocol;
3-
using UnityEngine;
4-
5-
namespace Sentry.Unity
6-
{
7-
/// <summary>
8-
/// An exception raised through the Unity logging callback
9-
/// </summary>
10-
/// <remarks>
11-
/// <see cref="Application.logMessageReceived"/>
12-
/// </remarks>
13-
internal class UnityLogException : Exception
14-
{
15-
public string LogString { get; }
16-
public string LogStackTrace { get; }
17-
18-
public UnityLogException(string logString, string logStackTrace)
19-
{
20-
LogString = logString;
21-
LogStackTrace = logStackTrace;
22-
Data[Mechanism.MechanismKey] = "unity.log";
23-
}
24-
25-
private UnityLogException() : base()
26-
{
27-
LogString = "";
28-
LogStackTrace = "";
29-
}
30-
31-
private UnityLogException(string message) : base(message)
32-
{
33-
LogString = "";
34-
LogStackTrace = "";
35-
}
36-
37-
private UnityLogException(string message, Exception innerException) : base(message, innerException)
38-
{
39-
LogString = "";
40-
LogStackTrace = "";
41-
}
42-
}
43-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using Sentry.Protocol;
5+
using UnityEngine;
6+
7+
namespace Sentry.Unity
8+
{
9+
/// <summary>
10+
/// An exception raised through the Unity logging callback
11+
/// </summary>
12+
/// <remarks>
13+
/// <see cref="Application.logMessageReceived"/>
14+
/// </remarks>
15+
internal class UnityLogException : Exception
16+
{
17+
public string LogString { get; }
18+
public string LogStackTrace { get; }
19+
20+
public UnityLogException(string logString, string logStackTrace)
21+
{
22+
LogString = logString;
23+
LogStackTrace = logStackTrace;
24+
Data[Mechanism.MechanismKey] = "unity.log";
25+
}
26+
27+
private UnityLogException() : base()
28+
{
29+
LogString = "";
30+
LogStackTrace = "";
31+
}
32+
33+
private UnityLogException(string message) : base(message)
34+
{
35+
LogString = "";
36+
LogStackTrace = "";
37+
}
38+
39+
private UnityLogException(string message, Exception innerException) : base(message, innerException)
40+
{
41+
LogString = "";
42+
LogStackTrace = "";
43+
}
44+
45+
public SentryException ToSentryException()
46+
{
47+
var frames = new List<SentryStackFrame>();
48+
var exc = LogString.Split(new char[] { ':' }, 2);
49+
var excType = exc[0];
50+
// TODO: condition may NOT contain ':' separator
51+
var excValue = exc.Length == 1 ? exc[0] : exc[1].Substring(1); // strip the space
52+
var stackList = LogStackTrace.Split('\n');
53+
54+
// The format is as follows:
55+
// Module.Class.Method[.Invoke] (arguments) (at filename:lineno)
56+
// where :lineno is optional, will be ommitted in builds
57+
for (var i = 0; i < stackList.Length; i++)
58+
{
59+
string functionName;
60+
string filename;
61+
int lineNo;
62+
63+
var item = stackList[i].TrimEnd('\r');
64+
if (item == string.Empty)
65+
{
66+
continue;
67+
}
68+
69+
var closingParen = item.IndexOf(')');
70+
71+
if (closingParen == -1)
72+
{
73+
functionName = item;
74+
lineNo = -1;
75+
filename = string.Empty;
76+
}
77+
else
78+
{
79+
try
80+
{
81+
functionName = item.Substring(0, closingParen + 1);
82+
if (item.Substring(closingParen + 1, 5) != " (at ")
83+
{
84+
// we did something wrong, failed the check
85+
Debug.Log("failed parsing " + item);
86+
functionName = item;
87+
lineNo = -1;
88+
filename = string.Empty;
89+
}
90+
else
91+
{
92+
var colon = item.LastIndexOf(':', item.Length - 1, item.Length - closingParen);
93+
if (closingParen == item.Length - 1)
94+
{
95+
filename = string.Empty;
96+
lineNo = -1;
97+
}
98+
else if (colon == -1)
99+
{
100+
filename = item.Substring(closingParen + 6, item.Length - closingParen - 7);
101+
lineNo = -1;
102+
}
103+
else
104+
{
105+
filename = item.Substring(closingParen + 6, colon - closingParen - 6);
106+
lineNo = Convert.ToInt32(item.Substring(colon + 1, item.Length - 2 - colon));
107+
}
108+
}
109+
}
110+
catch (Exception)
111+
{
112+
functionName = item;
113+
lineNo = -1;
114+
filename = string.Empty; // we have no clue
115+
}
116+
}
117+
118+
var filenameWithoutZeroes = StripZeroes(filename);
119+
frames.Add(new SentryStackFrame
120+
{
121+
FileName = TryResolveFileNameForMono(filenameWithoutZeroes),
122+
AbsolutePath = filenameWithoutZeroes,
123+
Function = functionName,
124+
LineNumber = lineNo,
125+
InApp = functionName != null
126+
&& !functionName.StartsWith("UnityEngine", StringComparison.Ordinal)
127+
&& !functionName.StartsWith("System", StringComparison.Ordinal)
128+
});
129+
}
130+
131+
frames.Reverse();
132+
133+
var stacktrace = new SentryStackTrace();
134+
foreach (var frame in frames)
135+
{
136+
stacktrace.Frames.Add(frame);
137+
}
138+
139+
return new SentryException
140+
{
141+
Stacktrace = stacktrace,
142+
Type = excType,
143+
Value = excValue
144+
};
145+
}
146+
147+
// https://github.com/getsentry/sentry-unity/issues/103
148+
private static string StripZeroes(string filename)
149+
=> filename.Equals("<00000000000000000000000000000000>", StringComparison.OrdinalIgnoreCase)
150+
? string.Empty
151+
: filename;
152+
153+
// TODO: discuss
154+
private static string TryResolveFileNameForMono(string fileName)
155+
{
156+
try
157+
{
158+
// throws on Mono for <1231231231> paths
159+
return Path.GetFileName(fileName);
160+
}
161+
catch
162+
{
163+
// mono path
164+
return "Unknown";
165+
}
166+
}
167+
}
168+
}
169+

0 commit comments

Comments
 (0)