Как захватить MVXTrace в инструменте сообщения об ошибках

Я использую MvvmCross и играю с некоторыми способами, чтобы получить MvxTrace в моем инструменте для составления отчетов. В этом случае я использую Raygun. Raygun дает мне возможность включать дополнительные сообщения в сообщение об ошибке, которое я хочу выдать, и именно это, я думаю, я должен использовать, чтобы это произошло. В основном я хочу сделать что-то вроде этого в коде:

var client = new RaygunClient();
var tags = new List<string> { "myTag" };
var customData = new Dictionary<int, string>() { {1, "**MVXTrace stuff here**"} };
client.Send(exception, tags, customData);

Как я могу подключить это? Я запутался, когда смотрю на настройку Trace. Я предполагаю, что мне нужно что-то сделать с моим файлом DebugTrace, который я использую для инъекции. Прямо сейчас это выглядит так:

public class DebugTrace : IMvxTrace
{
    public void Trace(MvxTraceLevel level, string tag, Func<string> message)
    {
        Debug.WriteLine(tag + ":" + level + ":" + message());
    }

    public void Trace(MvxTraceLevel level, string tag, string message)
    {
        Debug.WriteLine(tag + ":" + level + ":" + message);
    }

    public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
    {
        try
        {
            Debug.WriteLine(string.Format(tag + ":" + level + ":" + message, args));
        }
        catch (FormatException)
        {
            Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1} {2}", level, message);
        }
    }
}

Могу ли я сделать что-то, что подключается к логике IMvxTrace, чтобы прикрепить внутренние исключения и т. Д. К моему RaygunClient? Мне трудно понять, что вызывает конкретные ошибки, потому что, если я оставлю все как есть, я получу ошибки, которые выглядят так:

[MvxException: Failed to construct and initialize ViewModel for type MyProject.Core.ViewModels.SignatureViewModel from locator MvxDefaultViewModelLocator - check MvxTrace for more information]

Cirrious.MvvmCross.ViewModels.MvxViewModelLoader.LoadViewModel(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request, IMvxBundle savedState, IMvxViewModelLocator viewModelLocator):0

Cirrious.MvvmCross.ViewModels.MvxViewModelLoader.LoadViewModel(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request, IMvxBundle savedState):0

Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.ViewModelFromRequest(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest viewModelRequest, IMvxBundle savedState):0

Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.CreateViewModelFromIntent(Android.Content.Intent intent, IMvxBundle savedState):0

Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.Load(Android.Content.Intent intent, IMvxBundle savedState, System.Type viewModelTypeHint):0

Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions.LoadViewModel(IMvxAndroidView androidView, IMvxBundle savedState):0

Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions+<>c__DisplayClass3.<OnViewCreate>b__1():0

Cirrious.MvvmCross.Views.MvxViewExtensionMethods.OnViewCreate(IMvxView view, System.Func`1 viewModelLoader):0

Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions.OnViewCreate(IMvxAndroidView androidView, Android.OS.Bundle bundle):0

Cirrious.MvvmCross.Droid.Views.MvxActivityAdapter.EventSourceOnCreateCalled(System.Object sender, Cirrious.CrossCore.Core.MvxValueEventArgs`1 eventArgs):0

(wrapper delegate-invoke) System.EventHandler`1<Cirrious.CrossCore.Core.MvxValueEventArgs`1<Android.OS.Bundle>>:invoke_void__this___object_TEventArgs (object,Cirrious.CrossCore.Core.MvxValueEventArgs`1<Android.OS.Bundle>)

Cirrious.CrossCore.Core.MvxDelegateExtensionMethods.Raise[Bundle](System.EventHandler`1 eventHandler, System.Object sender, Android.OS.Bundle value):0

Cirrious.CrossCore.Droid.Views.MvxEventSourceActivity.OnCreate(Android.OS.Bundle bundle):0

MyProject.Droid.Views.SignatureView.OnCreate(Android.OS.Bundle bundle):0

Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState):0

(wrapper dynamic-method) object:3af7783d-a44d-471c-84a6-662ebfaea4ae (intptr,intptr,intptr)

Как было сказано в этом сообщении, было бы очень полезно, если бы я мог заставить MvxTrace с ним точно отследить, почему не удалось инициализировать эту ViewModel. Какие-либо предложения?

2 ответа

Решение

Вот что я сделал, чтобы заставить это работать на меня:

У меня есть BaseView, который я использую для всех моих действий на Android. Я использую этот BaseView для подключения и регистрации необработанных исключений следующим образом:

    public abstract class BaseView : MvxActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
        AndroidEnvironment.UnhandledExceptionRaiser += HandleAndroidException;
    }

    protected void HandleUnhandledException(object sender, UnhandledExceptionEventArgs args)
    {
        var e = (Exception)args.ExceptionObject;
        Mvx.Trace(MvxTraceLevel.Error, "Exception: {0}", e.ToLongString());
        var logReader = new AndroidLogReader();
        var logMessages = logReader.ReadLog("mvx:E");
        var customData = new Dictionary<string, string> { { "logMessage", logMessages } };
        var session = SessionController.Instance;
        var user = new RaygunIdentifierMessage(session.UserName + " " + session.Company);
        var rayMessage = RaygunMessageBuilder.New
            .SetEnvironmentDetails()
            .SetMachineName(Environment.MachineName)
            .SetClientDetails()
            .SetExceptionDetails(e)
            .SetUser(user)
            .SetUserCustomData(customData)
            .Build();
        RaygunClient.Current.Send(rayMessage);
    }

    protected void HandleAndroidException(object sender, RaiseThrowableEventArgs e)
    {
        var exception = e.Exception;
        Mvx.Trace(MvxTraceLevel.Error, "Exception: {0}", e.Exception.ToLongString());
        var logReader = new AndroidLogReader();
        var logMessages = logReader.ReadLog("mvx:E");
        var customData = new Dictionary<string, string> { { "logMessage", logMessages } };
        var session = SessionController.Instance;
        var user = new RaygunIdentifierMessage(session.UserName + " " + session.Company);
        var rayMessage = RaygunMessageBuilder.New
            .SetEnvironmentDetails()
            .SetMachineName(Environment.MachineName)
            .SetClientDetails()
            .SetExceptionDetails(exception)
            .SetUser(user)
            .SetUserCustomData(customData)
            .Build();
        RaygunClient.Current.Send(rayMessage);
    }
}

Мой DebugTrace.cs выглядит так:

    public class DebugTrace : IMvxTrace
{
    public void Trace(MvxTraceLevel level, string tag, Func<string> message)
    {
        Trace(level, tag, message());
    }

    public void Trace(MvxTraceLevel level, string tag, string message)
    {
        switch (level)
        {
            case MvxTraceLevel.Diagnostic:
                Log.Debug(tag, message);
                break;
            case MvxTraceLevel.Warning:
                Log.Warn(tag, message);
                break;
            case MvxTraceLevel.Error:
                Log.Error(tag, message);
                break;
            default:
                Log.Info(tag, message);
                break;
        }
    }

    public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
    {
        try
        {
            Trace(level, tag, string.Format(message, args));
        }
        catch (FormatException)
        {
            Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1} {2}", level, message);
        }
    }
}

А мой AndroidLogReader выглядит так:

    public class AndroidLogReader
{
    public string ReadLog(string tag)
    {
        var cmd = "logcat -d";
        if (!string.IsNullOrEmpty(tag))
        {
            cmd += " -s " + tag;
        }

        var process = Java.Lang.Runtime.GetRuntime().Exec(cmd);
        using (var sr = new StreamReader(process.InputStream))
        {
            return sr.ReadToEnd();
        }
    }
}

Теперь, когда все это работает, я получаю пользовательские данные, прикрепленные ко всем ошибкам Raygun, включая трассировку стека для всех ошибок Mvx. Большое спасибо @Kiliman за то, что он указал мне на строительные блоки, чтобы заставить это работать!

Вот как я это делаю на Android. Я использую Android.Util.Log учебный класс. После этого сообщения будут записываться в журнал устройств Android.

public class DebugTrace : IMvxTrace
{
    public void Trace(MvxTraceLevel level, string tag, Func<string> message)
    {
        Trace(level, tag, message());
    }

    public void Trace(MvxTraceLevel level, string tag, string message)
    {
        switch (level)
        {
            case MvxTraceLevel.Diagnostic:
                Log.Debug(tag, message);
                break;
            case MvxTraceLevel.Warning:
                Log.Warn(tag, message);
                break;
            case MvxTraceLevel.Error:
                Log.Error(tag, message);
                break;
            default:
                Log.Info(tag, message);
                break;
        }
    }

    public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
    {
        try
        {
            Trace(level, tag, string.Format(message, args));
        }
        catch (FormatException)
        {
            Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1}", level, message);
        }
    }
}

Затем вы можете получить журнал, используя следующее:

public class AndroidLogReader
{
    public string ReadLog(string tag)
    {
        var cmd = "logcat -d";
        if (!string.IsNullOrEmpty(tag)) cmd += " -s " + tag;

        var process = Java.Lang.Runtime.GetRuntime().Exec(cmd);
        using (var sr = new StreamReader(process.InputStream))
        {
            return sr.ReadToEnd();
        }
    }
}
Другие вопросы по тегам