@@ -27,7 +27,7 @@ namespace Datadog.Trace.Configuration;
2727/// code or via remote configuration. Note that the specific instance is immutable, but there may be a
2828/// new version in the lifetime of the application
2929/// </summary>
30- public class MutableSettings
30+ internal sealed class MutableSettings : IEquatable < MutableSettings >
3131{
3232 // we cached the static instance here, because is being used in the hotpath
3333 // by IsIntegrationEnabled method (called from all integrations)
@@ -368,6 +368,137 @@ void TrySetValue(int index)
368368 return httpErrorCodesArray ;
369369 }
370370
371+ public bool Equals ( MutableSettings ? other )
372+ {
373+ if ( other is null )
374+ {
375+ return false ;
376+ }
377+
378+ if ( ReferenceEquals ( this , other ) )
379+ {
380+ return true ;
381+ }
382+
383+ return TraceEnabled == other . TraceEnabled &&
384+ CustomSamplingRules == other . CustomSamplingRules &&
385+ CustomSamplingRulesIsRemote == other . CustomSamplingRulesIsRemote &&
386+ Nullable . Equals ( GlobalSamplingRate , other . GlobalSamplingRate ) &&
387+ LogsInjectionEnabled == other . LogsInjectionEnabled &&
388+ StartupDiagnosticLogEnabled == other . StartupDiagnosticLogEnabled &&
389+ Environment == other . Environment &&
390+ ServiceName == other . ServiceName &&
391+ ServiceVersion == other . ServiceVersion &&
392+ TracerMetricsEnabled == other . TracerMetricsEnabled &&
393+ #pragma warning disable 618 // App analytics is deprecated, but still used
394+ AnalyticsEnabled == other . AnalyticsEnabled &&
395+ #pragma warning restore 618
396+ MaxTracesSubmittedPerSecond == other . MaxTracesSubmittedPerSecond &&
397+ KafkaCreateConsumerScopeEnabled == other . KafkaCreateConsumerScopeEnabled &&
398+ GitRepositoryUrl == other . GitRepositoryUrl &&
399+ GitCommitSha == other . GitCommitSha &&
400+ // Do collection comparisons at the end, as generally more expensive
401+ AreEqual ( GlobalTags , other . GlobalTags ) &&
402+ AreEqual ( HeaderTags , other . HeaderTags ) &&
403+ AreEqual ( GrpcTags , other . GrpcTags ) &&
404+ AreEqual ( ServiceNameMappings , other . ServiceNameMappings ) &&
405+ DisabledIntegrationNames . SetEquals ( other . DisabledIntegrationNames ) &&
406+ // Could unroll the Linq, but prob not worth the hassle
407+ HttpServerErrorStatusCodes . SequenceEqual ( other . HttpServerErrorStatusCodes ) &&
408+ HttpClientErrorStatusCodes . SequenceEqual ( other . HttpClientErrorStatusCodes ) &&
409+ // Most expensive one
410+ AreEqualIntegrations ( Integrations , other . Integrations ) ;
411+
412+ static bool AreEqual ( ReadOnlyDictionary < string , string > ? dictionary1 , ReadOnlyDictionary < string , string > ? dictionary2 )
413+ {
414+ if ( dictionary1 == null || dictionary2 == null )
415+ {
416+ return ReferenceEquals ( dictionary1 , dictionary2 ) ;
417+ }
418+
419+ if ( dictionary1 . Count != dictionary2 . Count )
420+ {
421+ return false ;
422+ }
423+
424+ foreach ( var pair in dictionary1 )
425+ {
426+ if ( dictionary2 . TryGetValue ( pair . Key , out var value ) )
427+ {
428+ if ( ! string . Equals ( value , pair . Value ) )
429+ {
430+ return false ;
431+ }
432+ }
433+ else
434+ {
435+ return false ;
436+ }
437+ }
438+
439+ return true ;
440+ }
441+
442+ static bool AreEqualIntegrations ( IntegrationSettingsCollection integrations1 , IntegrationSettingsCollection integrations2 )
443+ {
444+ if ( integrations1 . Settings . Length != integrations2 . Settings . Length )
445+ {
446+ return false ;
447+ }
448+
449+ // They should be the exact same settings in both cases
450+ for ( var i = 0 ; i < integrations1 . Settings . Length ; i ++ )
451+ {
452+ var integration1 = integrations1 . Settings [ i ] ;
453+ var integration2 = integrations2 . Settings [ i ] ;
454+
455+ if ( ! integration1 . Equals ( integration2 ) )
456+ {
457+ return false ;
458+ }
459+ }
460+
461+ return true ;
462+ }
463+ }
464+
465+ public override bool Equals ( object ? obj )
466+ {
467+ return ReferenceEquals ( this , obj ) || ( obj is MutableSettings other && Equals ( other ) ) ;
468+ }
469+
470+ public override int GetHashCode ( )
471+ {
472+ // we can't easily include the collections in the hash code
473+ var hashCode = new HashCode ( ) ;
474+ hashCode . Add ( TraceEnabled ) ;
475+ hashCode . Add ( CustomSamplingRules ) ;
476+ hashCode . Add ( CustomSamplingRulesIsRemote ) ;
477+ hashCode . Add ( GlobalSamplingRate ) ;
478+ hashCode . Add ( LogsInjectionEnabled ) ;
479+ // hashCode.Add(GlobalTags);
480+ // hashCode.Add(HeaderTags);
481+ hashCode . Add ( StartupDiagnosticLogEnabled ) ;
482+ hashCode . Add ( Environment ) ;
483+ hashCode . Add ( ServiceName ) ;
484+ hashCode . Add ( ServiceVersion ) ;
485+ // hashCode.Add(DisabledIntegrationNames);
486+ // hashCode.Add(GrpcTags);
487+ hashCode . Add ( TracerMetricsEnabled ) ;
488+ // hashCode.Add(Integrations);
489+ #pragma warning disable 618 // App analytics is deprecated, but still used
490+ hashCode . Add ( AnalyticsEnabled ) ;
491+ #pragma warning restore 618
492+ hashCode . Add ( MaxTracesSubmittedPerSecond ) ;
493+ hashCode . Add ( KafkaCreateConsumerScopeEnabled ) ;
494+ // hashCode.Add(HttpServerErrorStatusCodes);
495+ // hashCode.Add(HttpClientErrorStatusCodes);
496+ // hashCode.Add(ServiceNameMappings);
497+ hashCode . Add ( GitRepositoryUrl ) ;
498+ hashCode . Add ( GitCommitSha ) ;
499+ return hashCode . ToHashCode ( ) ;
500+ }
501+
371502 internal bool IsErrorStatusCode ( int statusCode , bool serverStatusCode )
372503 {
373504 var source = serverStatusCode ? HttpServerErrorStatusCodes : HttpClientErrorStatusCodes ;
0 commit comments