From 2ea90ef98abebc68d80724b9a1964d30cc4df2cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Aug 2018 19:25:55 +0900 Subject: [PATCH 1/4] Add sentry logging --- osu.Desktop/Program.cs | 22 +++++++ osu.Game/OsuGame.cs | 16 +++++ osu.Game/Screens/Select/PlaySongSelect.cs | 3 + osu.Game/Utils/RavenLogger.cs | 73 +++++++++++++++++++++++ osu.Game/osu.Game.csproj | 3 +- 5 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Utils/RavenLogger.cs diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index cc08e08653..4574fb6fc9 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -4,7 +4,10 @@ using System; using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.IPC; @@ -20,6 +23,8 @@ namespace osu.Desktop using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true)) { + host.ExceptionThrown += handleException; + if (!host.IsPrimaryInstance) { var importer = new ArchiveImportIPCChannel(host); @@ -45,5 +50,22 @@ namespace osu.Desktop return 0; } } + + private static int allowableExceptions = 1; + + /// + /// Allow a maximum of one unhandled exception, per second of execution. + /// + /// + /// + private static bool handleException(Exception arg) + { + bool continueExecution = Interlocked.Decrement(ref allowableExceptions) >= 0; + + Logger.Log($"Unhandled exception has been {(continueExecution ? "allowed" : "denied")} with {allowableExceptions} more allowable exceptions."); + + Task.Delay(1000).ContinueWith(_ => Interlocked.Increment(ref allowableExceptions)); + return Interlocked.Decrement(ref allowableExceptions) >= 0; + } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 025d5f50e3..3e6317348c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -36,6 +36,8 @@ using osu.Game.Skinning; using OpenTK.Graphics; using osu.Game.Overlays.Volume; using osu.Game.Screens.Select; +using osu.Game.Utils; +using LogLevel = osu.Framework.Logging.LogLevel; namespace osu.Game { @@ -65,6 +67,8 @@ namespace osu.Game private ScreenshotManager screenshotManager; + protected RavenLogger RavenLogger; + public virtual Storage GetStorageForStableInstall() => null; private Intro intro @@ -106,6 +110,8 @@ namespace osu.Game this.args = args; forwardLoggedErrorsToNotifications(); + + RavenLogger = new RavenLogger(this); } public void ToggleSettings() => settings.ToggleVisibility(); @@ -150,6 +156,8 @@ namespace osu.Game dependencies.CacheAs(this); + dependencies.Cache(RavenLogger); + dependencies.CacheAs(ruleset); dependencies.CacheAs>(ruleset); @@ -271,6 +279,12 @@ namespace osu.Game menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay))); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + RavenLogger.Dispose(); + } + protected override void LoadComplete() { // this needs to be cached before base.LoadComplete as it is used by MenuCursorContainer. @@ -599,6 +613,7 @@ namespace osu.Game private void screenAdded(Screen newScreen) { currentScreen = (OsuScreen)newScreen; + Logger.Log($"Screen changed → {currentScreen}"); newScreen.ModePushed += screenAdded; newScreen.Exited += screenRemoved; @@ -607,6 +622,7 @@ namespace osu.Game private void screenRemoved(Screen newScreen) { currentScreen = (OsuScreen)newScreen; + Logger.Log($"Screen changed ← {currentScreen}"); if (newScreen == null) Exit(); diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index a346911ca2..a73254627d 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -141,6 +142,8 @@ namespace osu.Game.Screens.Select { if (player != null) return false; + throw new Exception("this is a test!"); + // Ctrl+Enter should start map with autoplay enabled. if (GetContainingInputManager().CurrentState?.Keyboard.ControlPressed == true) { diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs new file mode 100644 index 0000000000..aadb70add8 --- /dev/null +++ b/osu.Game/Utils/RavenLogger.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using osu.Framework.Logging; +using SharpRaven; +using SharpRaven.Data; + +namespace osu.Game.Utils +{ + /// + /// Report errors to sentry. + /// + public class RavenLogger : IDisposable + { + private readonly RavenClient raven = new RavenClient("https://5e342cd55f294edebdc9ad604d28bbd3@sentry.io/1255255"); + + private readonly List tasks = new List(); + + public RavenLogger(OsuGame game) + { + raven.Release = game.Version; + + Logger.NewEntry += entry => + { + if (entry.Level < LogLevel.Verbose) return; + + if (entry.Exception != null) + queuePendingTask(raven.CaptureAsync(new SentryEvent(entry.Exception))); + else + raven.AddTrail(new Breadcrumb(entry.Target.ToString(), BreadcrumbType.Navigation) { Message = entry.Message }); + }; + } + + private void queuePendingTask(Task task) + { + lock (tasks) tasks.Add(task); + task.ContinueWith(_ => + { + lock (tasks) + tasks.Remove(task); + }); + } + + #region Disposal + + ~RavenLogger() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) + { + if (isDisposed) + return; + + isDisposed = true; + lock (tasks) Task.WaitAll(tasks.ToArray(), 5000); + } + + #endregion + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 89e80bd06b..9a7edb6ae2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,9 +18,10 @@ - + + \ No newline at end of file From 562a31713e04f23f23d1596bf74b09dad658c16b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Aug 2018 16:44:04 +0900 Subject: [PATCH 2/4] Fix regression in handling logic --- osu.Desktop/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index 4574fb6fc9..19ceade644 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -65,7 +65,7 @@ namespace osu.Desktop Logger.Log($"Unhandled exception has been {(continueExecution ? "allowed" : "denied")} with {allowableExceptions} more allowable exceptions."); Task.Delay(1000).ContinueWith(_ => Interlocked.Increment(ref allowableExceptions)); - return Interlocked.Decrement(ref allowableExceptions) >= 0; + return continueExecution; } } } From 9f55afe5692a91368df55f37e279630ceb5b78b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Aug 2018 16:44:12 +0900 Subject: [PATCH 3/4] Let user know automatic reporting happened --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 189a51dec9..6576529326 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -463,7 +463,7 @@ namespace osu.Game Schedule(() => notifications.Post(new SimpleNotification { Icon = entry.Level == LogLevel.Important ? FontAwesome.fa_exclamation_circle : FontAwesome.fa_bomb, - Text = entry.Message, + Text = entry.Message + (entry.Exception != null ? "\n\nThis error has been automatically reported to the devs." : string.Empty), })); } else if (recentLogCount == short_term_display_limit) From 6297ad95aa49c133c860f59d7c6cbeabbc9ad1eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Aug 2018 16:44:18 +0900 Subject: [PATCH 4/4] Remove test exception --- osu.Game/Screens/Select/PlaySongSelect.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index e83097637d..e914eb365e 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -143,8 +142,6 @@ namespace osu.Game.Screens.Select { if (player != null) return false; - throw new Exception("this is a test!"); - // Ctrl+Enter should start map with autoplay enabled. if (GetContainingInputManager().CurrentState?.Keyboard.ControlPressed == true) {