diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9ffa88947b..22617cbebc 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1196,6 +1196,9 @@ namespace osu.Game { if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database || entry.Target == null) return; + if (entry.Exception is SentryOnlyDiagnosticsException) + return; + const int short_term_display_limit = 3; if (recentLogCount < short_term_display_limit) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index c09018e8ca..884310e44c 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -15,6 +15,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Input.Handlers; using osu.Game.Screens.Play; +using osu.Game.Utils; namespace osu.Game.Rulesets.UI { @@ -29,6 +30,7 @@ namespace osu.Game.Rulesets.UI public ReplayInputHandler? ReplayInputHandler { get; set; } public bool AllowBackwardsSeeks { get; set; } + private double? lastBackwardsSeekLogTime; /// /// The number of CPU milliseconds to spend at most during seek catch-up. @@ -163,10 +165,17 @@ namespace osu.Game.Rulesets.UI // time should never go backwards". If it does, we stop running gameplay until it returns to normal. if (!hasReplayAttached && FrameStablePlayback && proposedTime > referenceClock.CurrentTime && !AllowBackwardsSeeks) { - Logger.Log($"Denying backwards seek during gameplay (reference: {referenceClock.CurrentTime:N2} stable: {proposedTime:N2})"); + if (lastBackwardsSeekLogTime == null || Math.Abs(Clock.CurrentTime - lastBackwardsSeekLogTime.Value) > 1000) + { + lastBackwardsSeekLogTime = Clock.CurrentTime; - if (parentGameplayClock is GameplayClockContainer gcc) - Logger.Log($"{gcc.ChildrenOfType().Single().GetSnapshot()}"); + string loggableContent = $"Denying backwards seek during gameplay (reference: {referenceClock.CurrentTime:N2} stable: {proposedTime:N2})"; + + if (parentGameplayClock is GameplayClockContainer gcc) + loggableContent += $"\n{gcc.ChildrenOfType().Single().GetSnapshot()}"; + + Logger.Error(new SentryOnlyDiagnosticsException("backwards seek"), loggableContent); + } state = PlaybackState.NotValid; return; diff --git a/osu.Game/Utils/SentryOnlyDiagnosticsException.cs b/osu.Game/Utils/SentryOnlyDiagnosticsException.cs new file mode 100644 index 0000000000..1659b8a213 --- /dev/null +++ b/osu.Game/Utils/SentryOnlyDiagnosticsException.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Utils +{ + /// + /// Log to sentry without showing an error notification to the user. + /// + /// + /// This can be used to convey important diagnostics to us developers without + /// getting in the user's way. Should be used sparingly. + internal class SentryOnlyDiagnosticsException : Exception + { + public SentryOnlyDiagnosticsException(string message) + : base(message) + { + } + } +}