From 7882f6d4d84ff549dbf2ec575245a2edcf2a0124 Mon Sep 17 00:00:00 2001 From: richard elms Date: Wed, 16 Jul 2025 14:56:07 +0200 Subject: [PATCH 1/8] initial changes --- .../Scripts/Internal/AppStartHandler.cs | 2 ++ .../Scripts/Internal/AppStartSpanControl.cs | 35 +++++++++++++++++++ .../Internal/AppStartSpanControl.cs.meta | 11 ++++++ .../Scripts/Internal/SpanControlRegistry.cs | 27 ++++++++++++++ .../Internal/SpanControlRegistry.cs.meta | 11 ++++++ .../Scripts/Public/BugsnagPerformance.cs | 8 ++++- .../Scripts/Public/SpanControl.cs | 20 +++++++++++ .../Scripts/Public/SpanControl.cs.meta | 11 ++++++ 8 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs.meta create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs.meta create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs create mode 100644 BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs.meta diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartHandler.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartHandler.cs index 6b2c97a7..9402a008 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartHandler.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartHandler.cs @@ -98,6 +98,8 @@ private static Span CreateAppStartSpan(string name, string category) return _spanFactory.CreateAutoAppStartSpan(name, category, category.Equals(APP_START_CATEGORY)); } + internal Span GetAppStartSpan() => _rootSpan; + internal void SubsystemRegistration() { _rootSpan = CreateAppStartSpan(UNITY_RUNTIME_SPAN_NAME, APP_START_CATEGORY); diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs new file mode 100644 index 00000000..68a71cd2 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BugsnagUnityPerformance +{ + internal class AppStartSpanControl : IAppStartSpanControl + { + private readonly Span _span; + + public AppStartSpanControl(Span span) + { + _span = span; + } + + public void SetType(string type) + { + if (_span != null && !_span.Ended) + { + _span.Name = "[AppStart/UnityRuntime]" + type; + _span.SetAttributeInternal("bugsnag.app_start.name", type); + } + } + + public void ClearType() + { + if (_span != null && !_span.Ended) + { + _span.Name = "[AppStart/UnityRuntime]"; + _span.SetAttributeInternal("bugsnag.app_start.name", (string)null); + } + } + } +} \ No newline at end of file diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs.meta b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs.meta new file mode 100644 index 00000000..f7cceee3 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 091fec30c1eaf4904a3a2fd41ff27fdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs new file mode 100644 index 00000000..138e0c49 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BugsnagUnityPerformance +{ + internal class SpanControlRegistry + { + private readonly AppStartHandler _appStartHandler; + + public SpanControlRegistry(AppStartHandler handler) + { + _appStartHandler = handler; + } + + public T GetSpanControl(ISpanQuery query) where T : class + { + if (query is SpanType.AppStartQuery) + { + var span = _appStartHandler.GetAppStartSpan(); + return span != null ? new AppStartSpanControl(span) as T : null; + } + + return null; + } + } +} \ No newline at end of file diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs.meta b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs.meta new file mode 100644 index 00000000..735bcc86 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb1c316aab9d248eb8d8d65f0c14a613 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/BugsnagPerformance.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/BugsnagPerformance.cs index ebb5764d..98fdf66c 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/BugsnagPerformance.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/BugsnagPerformance.cs @@ -32,6 +32,7 @@ public class BugsnagPerformance private SystemMetricsCollector _systemMetricsCollector; private static List> _potentiallyOpenSpans = new List>(); private Func _networkRequestCallback; + private static SpanControlRegistry _spanControlRegistry; private static Dictionary, Span> _networkSpans = new Dictionary, Span>(); @@ -44,7 +45,6 @@ internal class SceneLoadSpanContainer { public List Spans = new List(); } - public static void Start(PerformanceConfiguration configuration) { #if BUGSNAG_DEBUG @@ -122,6 +122,11 @@ public static Span StartNetworkSpan(string url, HttpVerb httpVerb, SpanOptions s return _sharedInstance._spanFactory.CreateManualNetworkSpan(url, httpVerb, spanOptions); } + public static T GetSpanControl(ISpanQuery query) where T : class + { + return _spanControlRegistry?.GetSpanControl(query); + } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void SubsystemRegistration() { @@ -141,6 +146,7 @@ private BugsnagPerformance() _tracer = new Tracer(_sampler, _delivery, _frameMetricsCollector, _systemMetricsCollector); _spanFactory = new SpanFactory(_tracer.OnSpanEnd, _frameMetricsCollector); _appStartHandler = new AppStartHandler(_spanFactory); + _spanControlRegistry = new SpanControlRegistry(_appStartHandler); _pValueUpdater = new PValueUpdater(_delivery, _sampler); } diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs new file mode 100644 index 00000000..43625626 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; + +namespace BugsnagUnityPerformance +{ + public interface IAppStartSpanControl + { + void SetType(string type); + void ClearType(); + } + public static class SpanType + { + public static readonly AppStartQuery AppStart = new AppStartQuery(); + + public class AppStartQuery : ISpanQuery { } + } + + public interface ISpanQuery { } + +} \ No newline at end of file diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs.meta b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs.meta new file mode 100644 index 00000000..be095ee2 --- /dev/null +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53c031b6db4b2466fabaa567c9ee5dbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 88f6e2d111cff09970a2d2c7c8fe9421d38e3c3e Mon Sep 17 00:00:00 2001 From: richard elms Date: Mon, 4 Aug 2025 17:46:16 +0200 Subject: [PATCH 2/8] added e2e tests --- .../Scripts/Internal/AppStartSpanControl.cs | 15 ++++------ features/app_start_spans.feature | 16 ++++++++++ .../mazerunner/Assets/Scenes/MainScene.unity | 29 +++++++++++++++++++ .../AppStart/AppStartClearCustomisation.cs | 18 ++++++++++++ .../AppStartClearCustomisation.cs.meta | 11 +++++++ .../AppStart/AppStartCustomisation.cs | 17 +++++++++++ .../AppStart/AppStartCustomisation.cs.meta | 11 +++++++ 7 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs create mode 100644 features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs.meta create mode 100644 features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs create mode 100644 features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs.meta diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs index 68a71cd2..d3ceec12 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - namespace BugsnagUnityPerformance { internal class AppStartSpanControl : IAppStartSpanControl { + private const string APP_START_SPAN_PREFIX = "[AppStart/UnityRuntime]"; + private const string APP_START_NAME_ATTRIBUTE = "bugsnag.app_start.name"; private readonly Span _span; public AppStartSpanControl(Span span) @@ -18,8 +15,8 @@ public void SetType(string type) { if (_span != null && !_span.Ended) { - _span.Name = "[AppStart/UnityRuntime]" + type; - _span.SetAttributeInternal("bugsnag.app_start.name", type); + _span.Name = APP_START_SPAN_PREFIX + type; + _span.SetAttributeInternal(APP_START_NAME_ATTRIBUTE, type); } } @@ -27,8 +24,8 @@ public void ClearType() { if (_span != null && !_span.Ended) { - _span.Name = "[AppStart/UnityRuntime]"; - _span.SetAttributeInternal("bugsnag.app_start.name", (string)null); + _span.Name = APP_START_SPAN_PREFIX; + _span.SetAttributeInternal(APP_START_NAME_ATTRIBUTE, (string)null); } } } diff --git a/features/app_start_spans.feature b/features/app_start_spans.feature index 18ee1b84..69b90695 100644 --- a/features/app_start_spans.feature +++ b/features/app_start_spans.feature @@ -57,3 +57,19 @@ Scenario: App Start Off * the trace "Bugsnag-Span-Sampling" header equals "1:1" * the trace payload field "resourceSpans.0.scopeSpans.0.spans.0.name" equals "AppStartOff" +Scenario: App Start Customisation + When I run the game in the "AppStartCustomisation" state + And I wait for 4 spans + Then the trace Bugsnag-Integrity header is valid + And the trace "Bugsnag-Api-Key" header equals "a35a2a72bd230ac0aa0f52715bbdc6aa" + * the trace "Bugsnag-Span-Sampling" header equals "1:4" + * the trace payload field "resourceSpans.0.scopeSpans.0.spans.3.name" equals "[AppStart/UnityRuntime]ColdStart" + +Scenario: App Start Clear Customisation + When I run the game in the "AppStartClearCustomisation" state + And I wait for 4 spans + Then the trace Bugsnag-Integrity header is valid + And the trace "Bugsnag-Api-Key" header equals "a35a2a72bd230ac0aa0f52715bbdc6aa" + * the trace "Bugsnag-Span-Sampling" header equals "1:4" + * the trace payload field "resourceSpans.0.scopeSpans.0.spans.3.name" equals "[AppStart/UnityRuntime]" + diff --git a/features/fixtures/mazerunner/Assets/Scenes/MainScene.unity b/features/fixtures/mazerunner/Assets/Scenes/MainScene.unity index fce8c61f..bf1aaf16 100644 --- a/features/fixtures/mazerunner/Assets/Scenes/MainScene.unity +++ b/features/fixtures/mazerunner/Assets/Scenes/MainScene.unity @@ -1108,6 +1108,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ef6b6638c32824cd09e5bc90ba6c791c, type: 3} m_Name: m_EditorClassIdentifier: + ShouldStartNotifier: 0 --- !u!114 &1124192959 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1120,6 +1121,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 31195cb4a65c4458eb5d46cb119e51bf, type: 3} m_Name: m_EditorClassIdentifier: + ShouldStartNotifier: 0 --- !u!1 &1294582013 GameObject: m_ObjectHideFlags: 0 @@ -1550,6 +1552,8 @@ GameObject: - component: {fileID: 2053587487} - component: {fileID: 2053587489} - component: {fileID: 2053587488} + - component: {fileID: 2053587490} + - component: {fileID: 2053587491} m_Layer: 0 m_Name: AppStart m_TagString: Untagged @@ -1611,6 +1615,31 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: ShouldStartNotifier: 0 +--- !u!114 &2053587490 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053587485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe103c8e2fc0e4d429f29e72dddcbaae, type: 3} + m_Name: + m_EditorClassIdentifier: + ShouldStartNotifier: 0 +--- !u!114 &2053587491 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053587485} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3c87ca81bf59a4b64969be3ff3117a53, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &2126837005 GameObject: m_ObjectHideFlags: 0 diff --git a/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs new file mode 100644 index 00000000..464069fa --- /dev/null +++ b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs @@ -0,0 +1,18 @@ +using BugsnagUnityPerformance; + +public class AppStartClearCustomisation : Scenario +{ + public override void PreparePerformanceConfig(string apiKey, string host) + { + base.PreparePerformanceConfig(apiKey, host); + SetMaxBatchSize(4); + Configuration.AutoInstrumentAppStart = AutoInstrumentAppStartSetting.START_ONLY; + } + + public override void Run() + { + BugsnagPerformance.GetSpanControl(SpanType.AppStart)?.SetType("ColdStart"); + BugsnagPerformance.GetSpanControl(SpanType.AppStart)?.ClearType(); + BugsnagPerformance.ReportAppStarted(); + } +} diff --git a/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs.meta b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs.meta new file mode 100644 index 00000000..935ab5d7 --- /dev/null +++ b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartClearCustomisation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c87ca81bf59a4b64969be3ff3117a53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs new file mode 100644 index 00000000..14dbd962 --- /dev/null +++ b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs @@ -0,0 +1,17 @@ +using BugsnagUnityPerformance; + +public class AppStartCustomisation : Scenario +{ + public override void PreparePerformanceConfig(string apiKey, string host) + { + base.PreparePerformanceConfig(apiKey, host); + SetMaxBatchSize(4); + Configuration.AutoInstrumentAppStart = AutoInstrumentAppStartSetting.START_ONLY; + } + + public override void Run() + { + BugsnagPerformance.GetSpanControl(SpanType.AppStart)?.SetType("ColdStart"); + BugsnagPerformance.ReportAppStarted(); + } +} diff --git a/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs.meta b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs.meta new file mode 100644 index 00000000..3f05bada --- /dev/null +++ b/features/fixtures/mazerunner/Assets/Scripts/Scenarios/AppStart/AppStartCustomisation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe103c8e2fc0e4d429f29e72dddcbaae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From e38db8de9318f2376863cdb084eb8789d44de036 Mon Sep 17 00:00:00 2001 From: richard elms Date: Tue, 5 Aug 2025 10:14:52 +0200 Subject: [PATCH 3/8] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84a3a5c6..a83745e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## TBD +### Additions + +- Allow app start span customisation. [#196](https://github.com/bugsnag/bugsnag-unity-performance/pull/196) + ### Bug Fixes - Fix issue where CPU metrics where reported when no valid CPU data was avaliable. [#193](https://github.com/bugsnag/bugsnag-unity-performance/pull/193) From fcc3e3a1ff8f27aea05d1e95807fc2a8699064a0 Mon Sep 17 00:00:00 2001 From: Richard Elms Date: Tue, 5 Aug 2025 10:22:06 +0200 Subject: [PATCH 4/8] Update CHANGELOG.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a83745e5..7a2a4a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ### Bug Fixes -- Fix issue where CPU metrics where reported when no valid CPU data was avaliable. [#193](https://github.com/bugsnag/bugsnag-unity-performance/pull/193) +- Fix issue where CPU metrics were reported when no valid CPU data was available. [#193](https://github.com/bugsnag/bugsnag-unity-performance/pull/193) ## v1.10.0 (2025-06-03) From 740dceae12381c6aae7577abd6f7e258bde8c876 Mon Sep 17 00:00:00 2001 From: richard elms Date: Tue, 5 Aug 2025 10:23:32 +0200 Subject: [PATCH 5/8] remove unused imports --- .../Scripts/Internal/SpanControlRegistry.cs | 4 ---- .../Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs | 3 --- 2 files changed, 7 deletions(-) diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs index 138e0c49..302f5edf 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/SpanControlRegistry.cs @@ -1,7 +1,3 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - namespace BugsnagUnityPerformance { internal class SpanControlRegistry diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs index 43625626..12afb4d4 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs @@ -1,6 +1,3 @@ -using System.Collections; -using System.Collections.Generic; - namespace BugsnagUnityPerformance { public interface IAppStartSpanControl From 662b0b34e7cb412959c347c7287682d0767073e0 Mon Sep 17 00:00:00 2001 From: richard elms Date: Mon, 11 Aug 2025 16:09:18 +0200 Subject: [PATCH 6/8] review changes --- .../BugsnagPerformance/Scripts/Public/SpanControl.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs index 12afb4d4..78393297 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/SpanControl.cs @@ -5,13 +5,12 @@ public interface IAppStartSpanControl void SetType(string type); void ClearType(); } - public static class SpanType - { - public static readonly AppStartQuery AppStart = new AppStartQuery(); - - public class AppStartQuery : ISpanQuery { } - } public interface ISpanQuery { } + public static class SpanType + { + public static readonly ISpanQuery AppStart = new AppStartQuery(); + internal sealed class AppStartQuery : ISpanQuery { } + } } \ No newline at end of file From dd341c9c28310bf4715c3431fcbc575afb81ed33 Mon Sep 17 00:00:00 2001 From: richard elms Date: Tue, 12 Aug 2025 13:49:52 +0200 Subject: [PATCH 7/8] thread safe refactor --- .../Scripts/Internal/AppStartSpanControl.cs | 18 +----- .../BugsnagPerformance/Scripts/Public/Span.cs | 59 +++++++++++++------ 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs index d3ceec12..e2da5a9f 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs @@ -3,30 +3,18 @@ namespace BugsnagUnityPerformance internal class AppStartSpanControl : IAppStartSpanControl { private const string APP_START_SPAN_PREFIX = "[AppStart/UnityRuntime]"; - private const string APP_START_NAME_ATTRIBUTE = "bugsnag.app_start.name"; private readonly Span _span; - public AppStartSpanControl(Span span) - { - _span = span; - } + public AppStartSpanControl(Span span) => _span = span; public void SetType(string type) { - if (_span != null && !_span.Ended) - { - _span.Name = APP_START_SPAN_PREFIX + type; - _span.SetAttributeInternal(APP_START_NAME_ATTRIBUTE, type); - } + _span?.TrySetAppStartType(type, APP_START_SPAN_PREFIX); } public void ClearType() { - if (_span != null && !_span.Ended) - { - _span.Name = APP_START_SPAN_PREFIX; - _span.SetAttributeInternal(APP_START_NAME_ATTRIBUTE, (string)null); - } + _span?.TrySetAppStartType(null, APP_START_SPAN_PREFIX); } } } \ No newline at end of file diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs index 0f2a2e68..0293f16e 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs @@ -31,6 +31,7 @@ public class Span : ISpanContext private const string MEMORY_SPACES_ART_SIZE_KEY = "bugsnag.system.memory.spaces.art.size"; private const string MEMORY_SPACES_ART_USED_KEY = "bugsnag.system.memory.spaces.art.used"; private const string MEMORY_SPACES_ART_MEAN_KEY = "bugsnag.system.memory.spaces.art.mean"; + private const string APP_START_NAME_KEY = "bugsnag.app_start.name"; private const double CPU_METRICS_MIN_THRESHOLD = 0.0001; public string Name { get; internal set; } @@ -42,7 +43,7 @@ public class Span : ISpanContext public DateTimeOffset EndTime { get; internal set; } internal double samplingProbability { get; private set; } internal bool Ended; - private object _endLock = new object(); + private readonly object _endLock = new object(); private OnSpanEnd _onSpanEnd; internal bool IsAppStartSpan; internal bool WasDiscarded; @@ -52,6 +53,8 @@ public class Span : ISpanContext private int _customAttributeCount; private int _maxCustomAttributes; internal bool IsFrozenFrameSpan; + private readonly object _attributesLock = new object(); + public Span(string name, SpanKind kind, string id, string traceId, string parentSpanId, DateTimeOffset startTime, @@ -190,12 +193,15 @@ public void UpdateSamplingProbability(double value) internal void SetAttributeInternal(string key, bool value) => SetAttributeWithoutChecks(key, value); private void SetAttributeWithoutChecks(string key, object value) { - if (value == null) + lock (_attributesLock) { - _attributes.Remove(key); - return; + if (value == null) + { + _attributes.Remove(key); + return; + } + _attributes[key] = value; } - _attributes[key] = value; } @@ -215,28 +221,45 @@ private void SetAttributeWithChecks(string key, object value) MainThreadDispatchBehaviour.LogWarning($"Attempting to set attribute: {key} on span: {Name} after the span has ended."); return; } - - if (_attributes.ContainsKey(key)) + lock (_attributesLock) { - if (value == null) + if (_attributes.ContainsKey(key)) { - _attributes.Remove(key); - _customAttributeCount--; + if (value == null) + { + _attributes.Remove(key); + _customAttributeCount--; + } + else + { + _attributes[key] = value; + } + return; } - else + + if (_customAttributeCount >= _maxCustomAttributes) { - _attributes[key] = value; + DroppedAttributesCount++; + return; } - return; + _attributes[key] = value; + _customAttributeCount++; } + } - if (_customAttributeCount >= _maxCustomAttributes) + internal bool TrySetAppStartType(string? type, string namePrefix = "[AppStart/UnityRuntime]") + { + lock (_endLock) { - DroppedAttributesCount++; - return; + if (Ended) return false; + Name = type == null ? namePrefix : namePrefix + type; + lock (_attributesLock) + { + if (type == null) _attributes.Remove(APP_START_NAME_KEY); + else _attributes[APP_START_NAME_KEY] = type; + } + return true; } - _attributes[key] = value; - _customAttributeCount++; } internal Dictionary GetAttributes() => new Dictionary(_attributes); From 1da450a2b16528c21fc52b19a0e4c1bfbd88db02 Mon Sep 17 00:00:00 2001 From: richard elms Date: Wed, 13 Aug 2025 07:54:48 +0200 Subject: [PATCH 8/8] small refac --- .../Scripts/Internal/AppStartSpanControl.cs | 6 +++--- .../BugsnagPerformance/Scripts/Public/Span.cs | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs index e2da5a9f..071031ec 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Internal/AppStartSpanControl.cs @@ -2,19 +2,19 @@ namespace BugsnagUnityPerformance { internal class AppStartSpanControl : IAppStartSpanControl { - private const string APP_START_SPAN_PREFIX = "[AppStart/UnityRuntime]"; + private const string Prefix = "[AppStart/UnityRuntime]"; private readonly Span _span; public AppStartSpanControl(Span span) => _span = span; public void SetType(string type) { - _span?.TrySetAppStartType(type, APP_START_SPAN_PREFIX); + _span?.TryUpdateAppStartSpan(type, Prefix); } public void ClearType() { - _span?.TrySetAppStartType(null, APP_START_SPAN_PREFIX); + _span?.TryUpdateAppStartSpan(null, Prefix); } } } \ No newline at end of file diff --git a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs index 0293f16e..4770b231 100644 --- a/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs +++ b/BugsnagPerformance/Assets/BugsnagPerformance/Scripts/Public/Span.cs @@ -247,11 +247,14 @@ private void SetAttributeWithChecks(string key, object value) } } - internal bool TrySetAppStartType(string? type, string namePrefix = "[AppStart/UnityRuntime]") + internal bool TryUpdateAppStartSpan(string? type, string namePrefix = "[AppStart/UnityRuntime]") { lock (_endLock) { - if (Ended) return false; + if (Ended) + { + return false; + } Name = type == null ? namePrefix : namePrefix + type; lock (_attributesLock) { @@ -262,7 +265,13 @@ internal bool TrySetAppStartType(string? type, string namePrefix = "[AppStart/Un } } - internal Dictionary GetAttributes() => new Dictionary(_attributes); + internal Dictionary GetAttributes() + { + lock (_attributesLock) + { + return new Dictionary(_attributes); + } + } internal void SetCallbackComplete() {