UNITY) Is it possible to link custom debug log to script? - c#

I made a custom Debug.Log using Conditional attribute like this
[Conditional("DEBUG_BUILD"), Conditional("UNITY_EDITOR")]
public static void Print(object str)
{
UnityEngine.Debug.Log(str);
}
And I use it like this
void Something()
{
CustomDebug.Print("Error");
}
But when I click the console, It open the custom log script not the script that caused error.
I wonder if I can make link the console with error script.

It's simply returning the last most call in the stack, which is going to be the code in your custom Debug script.
You can get around this easily by compiling this into it's own assembly though, move your code to a Managed Unity DLL, then it will ignore the DLL level stack trace and only return the location your custom method was called from.

Maybe you can try Application.logMessageReceived to implement your custom debug log.
And you can use UnityEngine.Debug.Log() or MonoBehaviour.print() to record logs. It still can link to the scripts.

Related

How do I take a screenshot when there's an AssertionException? (Xamarin.UITest, C#)

I have built a Xamarin.UITest suite and I'm testing locally on a real Android device. I notice that one or two tests fail, but not necessarily the same tests. Whenever I try to re-run such tests to see why they're failing, they pass! Therefore I need to add functionality to see what's on the screen when a test fails. I don't seem to be able to find a guide specifically for this - just bits and pieces...
I've added EnableLocalScreenshots() to my StartApp() call, but I'm not sure of the next steps. So I have some questions:
Do I need to specify the location of where the screenshots are saved, or is this done automatically?
Do I need to explicitly write code to take a screenshot when there's an AssertionException, or is this what the screenshot functionality does by default?
If I need to write code to take a screenshot when there's an AssertionException, please can you point me to an example of this code so I can add it to my suite?
Thank you
EDIT: Re: Take screenshot on test failure + exceptions
I have tried the following in my Hooks.cs file:
[OneTimeTearDown]
public void OneTimeTearDown()
{
if (TestContext.CurrentContext.Result.Outcome == ResultState.Error || TestContext.CurrentContext.Result.Outcome == ResultState.Failure)
{
App.Screenshot(TestContext.CurrentContext.Test.Name);
}
}
Upon debugging this method, I find that it is never called. Not even if I use TearDown and AfterScenario attributes. So great - that Intellisense likes my code, bad - because it never gets called. It shouldn't be this hard!
I am using Specflow in this suite, could that be anything to do with why I'm getting this issue? This is why I can't implement the solution on the above thread as follows because Specflow manages the NUnit tests...
UITest(() =>
{
// Do your test steps here, including asserts etc.
// Any exceptions will be caught by the base class
// and screenshots will be taken
});
Ok so for me this was the answer.
Added [Binding] attribute above class (dumb error on my part)...
[Binding]
class TestInitialise : BasePage
Added [AfterScenario()] above my screenshot method, and made it a static method...
[AfterScenario()]
public static void TakeScreenshot()
Specified where to save the screenshot...
App.Screenshot(TestContext.CurrentContext.Test.Name).CopyTo(#"C:\Users\me\Desktop\" + TestContext.CurrentContext.Test.Name + ".png");
So I'm guessing App.Screenshot(string title) simply takes a screenshot and holds it in memory, but you actually need to save it somewhere explicitly to get it, rather than assuming it just saves to a default location.
That's that then!

Read and Write to the clipboard

I have this snippet on Windows (VS2017 Community) on Unity 5.6:
public static void setClipboardStr(string str)
{
try
{
if (Clipboard.ContainsText())
{
// ...doesn't matter if true or false -
// from here on, I can't copy+paste inside
// the game or outside until I close the app.
// If I had an error instead of try/catch or
// check if it contains text, the error will
// remain UNTIL I REBOOT (beyond the app closing).
}
}
catch(Exception ex)
{
Debug.LogError(ex);
}
}
Whenever I use Clipboard in any form, even when checking if it's text or not, it destroys the clipboard until I close the app. Now, is this a Unity bug? VS bug? Is there something I'm not understanding? What should I use, instead?
Clipboard.ContainsText is from the System.Windows.Forms namespace. These are not supported in Unity. One would be lucky to get it to compile and extremely luck to get work properly since Unity uses Mono. Also, this is not portable so don't use anything from this namespace in Unity.
What should I use, instead?
Write to clipboard:
GUIUtility.systemCopyBuffer = "Hello";
Read from clipboard:
string clipBoard = GUIUtility.systemCopyBuffer;
This should work. If not, you can implement your own clipboard API from scratch using their C++ API. You do have to do this for each platform.

How to make C# application crash

I want to test if my application crash dump can be debugged. But firstly, I need to generate a crash dump of my application. I'm using C# to code my app, and have tried with many exceptions and unsafe code etc. but don't get it.
Thanks!
Edit: Sorry, Just forgot something, I'm making the application with Unity3D, which handles exceptions for me automatically.
Edit 2: Thanks all for your answers. I've tested your suggestions in a standard C# application and it all works fine, but not in my Unity3D application (written with C#). It seems like Unity3D requires more effort to cause a crash, I might email Unity3D to get a answer. I will post here if I get it. Cheers!
The following will provide an unhandled exception and will ask for you to choose a debugger:
System.Diagnostics.Debugger.Launch()
StackOverflowException is a badass:
void PerformOverflow()
{
PerformOverflow();
}
Usage:
PerformOverflow();
Throw an exception :)
throw new Exception("Your exception here!");
For C# in Unity3D
There is UnityEngine.Diagnostics.Utils.ForceCrash (in Unity 2018.3)
This can be used with one of the following ForcedCrashCategory enum parameter:
AccessViolation
Cause a crash by performing an invalid memory
access.The invalid memory access is performed on each platform as
follows:
FatalError
Cause a crash using Unity's native fatal error
implementation.
Abort
Cause a crash by calling the abort() function.
PureVirtualFunction
Cause a crash by calling a pure virtual function
to raise an exception.
For older versions of Unity:
UnityEngine.Application.ForceCrash(int mode)
For even older versions (Unity 5):
UnityEngine.Application.CommitSuicide(int mode)
From my experience, mode 0 causes a "unity handled" crash (where the Unity crash dialog appears), and mode 2 causes a "hard" crash where the Windows error dialog appears.
This seems consistent with this post by Smilediver on mode:
0 - will simulate crash, 1 - will simulate a fatal error that Unity
has caught, 2 - will call abort().
(These methods are not documented as they were intended for Unity's internal use. They may also be marked [Obsolete] depending on your Unity version.)
Well. The only good 100% way actualy crash CLR is to inject a native exception into the managed world.
Calling the Kernel32.dll's RaiseException() directly will immediately crash ANY C# application, and Unity Editor as well.
[DllImport("kernel32.dll")]
static extern void RaiseException(uint dwExceptionCode, uint dwExceptionFlags, uint nNumberOfArguments, IntPtr lpArguments);
void start()
{
RaiseException(13, 0, 0, new IntPtr(1));
}
Happy crashing. Please note that in order to debug native and managed, you will need two instances of Visual Studio running. If you are developing native P/INVOKE plugin, set up it that Visual Studio Instance 1 is native debugger and uses Unity or your C# program as a Host program, and you attach to the Host program from another Visual Studio Instance.
Another option is to call
System.Environment.FailFast("Error happened")
A surefire way to do it is as follows:
ThreadPool.QueueUserWorkItem(new WaitCallback(ignored =>
{
throw new Exception();
}));
All the others can be handled by the top level ApplicationDomain.OnUnhandledException and the like.
This one will kill it dead (assuming .NET 2.0+, and not using 'legacyUnhandledExceptionPolicy': http://msdn.microsoft.com/en-us/library/ms228965.aspx).
None of the answers crashed my app the way I was looking for. So here is the approach that worked for me.
private void Form1_Load(object sender, EventArgs e)
{
object p = 0;
IntPtr pnt = (IntPtr)0x123456789;
Marshal.StructureToPtr(p, pnt, false);
}
public void Loop()
{
Loop();
}
//call this
Loop();
I think there was a code in earlier unity versions like
Application.commitSuicide(number Input);
Now it is replaced by
Application.ForceCrash(number input);
Till this point, I dont know what different numbers do in number input, but for me,
Application.ForceCrash(1);
does the job.
you could also divide by zero,
z = 0;
int divide = 1 / x;
int[] x = {0};
int blah = x[2];
will cause an exception just as well
It's easy enough to reproduce if you try to transform a null game object. For example, like this:
public static GameObject gameObjectCrash;
public void GenerateCrash()
{
gameObjectCrash.transform.rotation = Quaternion.Euler(90, 0, 0);
}
Use below code to close the application.
Environment.Exit(1);
Exit needs a parameter called exitcode. If exitcode=0 means there was no error. Supply a non-zero exit code to to reflect an error.

What's a good global exception handling strategy for Unity3D?

I'm looking into doing some Unity3D scripting stuff, and I'd like to set up global exception handling system. This is not for running in the release version of the game, the intention is to catch exceptions in user scripts and also in editor scripts and make sure they are forwarded to a database for analysis (and also to send email to relevant devs so they can fix their shizzle).
In a vanilla C# app I'd have a try-catch around the Main method. In WPF I'd hook one or more of the unhandled exception events. In Unity...?
So far the best I've been able to come up with is something like this:
using UnityEngine;
using System.Collections;
public abstract class BehaviourBase : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
try
{
performUpdate();
print("hello");
}
catch (System.Exception e)
{
print(e.ToString());
}
}
public abstract void performUpdate();
}
In other scripts, I derive BehaviourBase instead of MonoBehavior and implement performUpdate() instead of Update(). I haven't implemented a parallel version for Editor clases but I assume I'd have to do the same thing there.
I don't like this strategy, however, because I'll have to backport it to any scripts we grab from the community (and I'll have to enforce it on the team). The Editor scripts don't have a single point of entry comparable to MonoBehavior either, so I assume I'd have to implement exception safe versions of wizards, editors and so on.
I've seen suggestions about catching log messages (as opposed to exceptions) using Application.RegisterLogCallback, but this makes me uncomfortable because I'd need to parse the debug log string rather than having access to the actual exceptions and stacktraces.
So... what's the right thing to do?
Create an empty GameObject in your scene and attach this script to it:
using UnityEngine;
public class ExceptionManager : MonoBehaviour
{
void Awake()
{
Application.logMessageReceived += HandleException;
DontDestroyOnLoad(gameObject);
}
void HandleException(string logString, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
//handle here
}
}
}
make sure there is one instance.
The rest is up to you. You can also store the logs in file system, web server or cloud storage.
Note that DontDestroyOnLoad(gameObject) makes this GameObject persistent, by preventing it from being destroyed in case of scene change.
There is a working implementation of RegisterLogCallback that I found here: http://answers.unity3d.com/questions/47659/callback-for-unhandled-exceptions.html
In my own implementation I use it to call my own MessageBox.Show instead of writing to a log file. I just call SetupExceptionHandling from each of my scenes.
static bool isExceptionHandlingSetup;
public static void SetupExceptionHandling()
{
if (!isExceptionHandlingSetup)
{
isExceptionHandlingSetup = true;
Application.RegisterLogCallback(HandleException);
}
}
static void HandleException(string condition, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
MessageBox.Show(condition + "\n" + stackTrace);
}
}
I also now have the error handler email me via this routine, so I always know when my app crashes and get as much detail as possible.
internal static void ReportCrash(string message, string stack)
{
//Debug.Log("Report Crash");
var errorMessage = new StringBuilder();
errorMessage.AppendLine("FreeCell Quest " + Application.platform);
errorMessage.AppendLine();
errorMessage.AppendLine(message);
errorMessage.AppendLine(stack);
//if (exception.InnerException != null) {
// errorMessage.Append("\n\n ***INNER EXCEPTION*** \n");
// errorMessage.Append(exception.InnerException.ToString());
//}
errorMessage.AppendFormat
(
"{0} {1} {2} {3}\n{4}, {5}, {6}, {7}x {8}\n{9}x{10} {11}dpi FullScreen {12}, {13}, {14} vmem: {15} Fill: {16} Max Texture: {17}\n\nScene {18}, Unity Version {19}, Ads Disabled {18}",
SystemInfo.deviceModel,
SystemInfo.deviceName,
SystemInfo.deviceType,
SystemInfo.deviceUniqueIdentifier,
SystemInfo.operatingSystem,
Localization.language,
SystemInfo.systemMemorySize,
SystemInfo.processorCount,
SystemInfo.processorType,
Screen.currentResolution.width,
Screen.currentResolution.height,
Screen.dpi,
Screen.fullScreen,
SystemInfo.graphicsDeviceName,
SystemInfo.graphicsDeviceVendor,
SystemInfo.graphicsMemorySize,
SystemInfo.graphicsPixelFillrate,
SystemInfo.maxTextureSize,
Application.loadedLevelName,
Application.unityVersion,
GameSettings.AdsDisabled
);
//if (Main.Player != null) {
// errorMessage.Append("\n\n ***PLAYER*** \n");
// errorMessage.Append(XamlServices.Save(Main.Player));
//}
try {
using (var client = new WebClient()) {
var arguments = new NameValueCollection();
//if (loginResult != null)
// arguments.Add("SessionId", loginResult.SessionId.ToString());
arguments.Add("report", errorMessage.ToString());
var result = Encoding.ASCII.GetString(client.UploadValues(serviceAddress + "/ReportCrash", arguments));
//Debug.Log(result);
}
} catch (WebException e) {
Debug.Log("Report Crash: " + e.ToString());
}
}
Unity devs just do not provide us with tools like that. They catch exceptions internally in framework here and there and log them as strings, giving us Application.logMessageReceived[Threaded]. So, if you need exceptions to happen or be logged with your own processing (not unity's) I can think of:
do not use framework mechanics, but use your own so exception is not caught by framework
make your own class implementing UnityEngine.ILogHandler:
public interface ILogHandler
{
void LogFormat(LogType logType, Object context, string format, params object[] args);
void LogException(Exception exception, Object context);
}
And use it as said in official docs to log your exceptions. But that way you do not receive unhandled exceptions and exceptions logged from plugins (yes, someone do log exceptions in frameworks instead of throwing them)
Or you can make a suggestion/request to unity to make Debug.unityLogger (Debug.logger is deprecated in Unity 2017) have setter or other mechanism so we can pass our own.
Just set it with reflection. But it's temporary hack and will not work when unity change code.
var field = typeof(UnityEngine.Debug)
.GetField("s_Logger", BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null, your_debug_logger);
Note: To get correct stacktraces you need to set StackTraceLogType in editor settings/code to ScriptOnly (most times it's what you need, I wrote an article on how it work) And, when building for iOS, it is said that Script call optimization must be set to slow and safe
If interested, you can read how popular crash analytics tool works. If you look into crashlytics (crash report tool for android/ios), than you'll find out that it internally uses Application.logMessageReceived and AppDomain.CurrentDomain.UnhandledException events to log managed C# exceptions.
If interested in examples on unity framework catching exceptions, you may look at ExecuteEvents.Update And another article from me with testing it catching exception in button click listener can be found here.
Some summary on official ways to log unhandled exception:
I. Application.logMessageReceived is fired when exception happens on main thread. There are ways for it to happen:
exception caught in c# code and logged through Debug.LogException
exception caught in native code (probably c++ code when using il2cpp). In that case native code calls Application.CallLogCallback which results in firing Application.logMessageReceived
Note: StackTrace string will contain "rethrow" when original exception have inner exceptions
II. Application.logMessageReceivedThreaded is fired when exception happens on any thread, including main (it's said in docs) Note: it must be thread-safe
III. AppDomain.CurrentDomain.UnhandledException for example is fired when:
You call the following code in editor:
new Thread(() =>
{
Thread.Sleep(10000);
object o = null;
o.ToString();
}).Start();
But it causes crash on android 4.4.2 release build when using Unity 5.5.1f1
Note: I reproduced some bugs with unity missing stackframes when logging exceptions and assertions. I submited one of them.
You mentioned Application.RegisterLogCallback, have you tried implementing it? Because the logging callback passes back a stack trace, an error, and an error type (warning, error, etc).
The strategy you outline above would be tough to implement because MonoBehaviours don't just have a single entry point. You'd have to handle OnTriggerEvent, OnCollisionEvent, OnGUI, and so on. Each one wrapping its logic in an exception handler.
IMHO, exception handling is a bad idea here. If you don't immediately re-throw the exception, you'll end up propagating those errors in weird ways. Maybe Foo relies on Bar, and Bar on Baz. Say Baz throws an exception that is caught and logged. Then Bar throws an exception because the value it needs from Baz is incorrect. Finally Foo throws an exception because the value it was getting from Bar is invalid.
You can use a plugin called Reporter to receive an email of Debug Logs, Stack trace and screen capture on the moment of unhandled Error. Screen capture and stack trace are usually enough to figure out the reason of the Error. For stubborn sneaky Errors you should log more of suspicious data, build and wait again for the error.I Hope this helps.

Skipping lines of code after a flag is set

I have a fairly large program (C#) that needs its functionality expanded by adding an option to turn off logging. The program takes a directory location as an argument, where it stores the log. I want it to not log anything if args[0] is empty. Right now the program has lines like this nested all over it:
DiagnosticLog.WriteLine("\t\t----Verifying Plugins were installed correctly----");
My first idea was to just create and do a check for a global flag within that function and run that line if it wasn't set. That way I could avoid using the same if statement around each of these lines all over the code. Is there a more clever way of just "turning off" these lines during run-time?
You could implement a version of DiagnosticLog that doesn't actually log anything, and use it in stead of your logging version if you don't want to log. That's assuming you know whether or not you want to log when you create the instance of DiagnosticLog (which I gather from the way you ask, you do).
How about modifying your DiagnosticLog.WriteLine function to take a second parameter doActualLog (bool) which has as default value true? Make some very minor modifications to DiagnoticLog to take this value into account. You can then decide at instantiation of DiagnosticLog if you want actual logging to happen or not.
You could just add an enabled flag to DiagnosticLog that is true by default. If args[0] is empty, call DiagnosticLog.Disable() to set it to false. Then in WriteLine and any other logging functions, check enabled before doing the actual logging.
Why don't you just call a log function that checks to see if the arg is empty?
public void WriteLine(string log) {
if (!firstArgIsEmpty) {
// Print to file.
}
}
How about using a System.Diagnostics.TraceListener class in conjunction with a System.Diagnostics.TraceSwitch? The functionality you seem to be after is already baked in.
You could create a property
public bool Log { get; set; }
string logFilePath;
public string LogFilePath
{
get { return logFilePath; }
set
{
logFilePath = ValidateLogFilePath(value);
Log = logFilePath.Length > 0;
}
}
public void WriteLine(string line)
{
if (!Log)
return;
//...
}
If you make a boolean property to indicate whether logging is occuring, then you could also use it to skip other sections of code that are not necessary if logging is not occuring. This could be useful if you are building any long strings just for logging purposes.
if (DiagnosticLog.Log)
{
DiagnosticLog.WriteLine("The following plugins were not installed:\r\n\t" +
string.Join("\r\n\t", GetMissingPluginNames()));
}

Categories

Resources