From 36ee7d3bfa12833aba1174c9af1959eedcf17471 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 13 Mar 2024 09:50:37 +0000 Subject: [PATCH] feat: Add helper methods to obtain ActivitySources --- Google.Api.Gax.Tests/ActivitySourcesTest.cs | 47 ++++++++++++++++++ Google.Api.Gax/ActivitySources.cs | 54 +++++++++++++++++++++ Google.Api.Gax/VersionHeaderBuilder.cs | 5 +- 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 Google.Api.Gax.Tests/ActivitySourcesTest.cs create mode 100644 Google.Api.Gax/ActivitySources.cs diff --git a/Google.Api.Gax.Tests/ActivitySourcesTest.cs b/Google.Api.Gax.Tests/ActivitySourcesTest.cs new file mode 100644 index 00000000..7547328a --- /dev/null +++ b/Google.Api.Gax.Tests/ActivitySourcesTest.cs @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Google LLC All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file or at + * https://developers.google.com/open-source/licenses/bsd + */ + +using Xunit; + +namespace Google.Api.Gax.Tests; + +public class ActivitySourcesTest +{ + [Fact] + public void NameIsType() + { + var source = ActivitySources.FromType(); + // Hard-coded to makeit obvious in the test what the value will actually look like. + Assert.Equal("Google.Api.Gax.Tests.ActivitySourcesTest", source.Name); + } + + [Fact] + public void Caching() + { + var source1 = ActivitySources.FromType(); + var source2 = ActivitySources.FromType(); + var source3 = ActivitySources.FromType(typeof(ActivitySourcesTest)); + var source4 = ActivitySources.FromType(); + + Assert.Same(source1, source2); + Assert.Same(source1, source3); + Assert.NotSame(source1, source4); + } + + [Fact] + public void Version_VersionedAssembly() + { + // Deliberately use a type in the main assembly, so that it's got a real version. + var source = ActivitySources.FromType(); + Assert.NotEmpty(source.Version); + // We don't try to parse this as a System.Version, as that would fail for betas etc. + var majorVersion = int.Parse(source.Version.Split('.')[0]); + // This doesn't need to be changed when we bump the version of GAX - it's just checking + // that we've got a real version rather than a default of 1.0. + Assert.True(majorVersion >= 4); + } +} diff --git a/Google.Api.Gax/ActivitySources.cs b/Google.Api.Gax/ActivitySources.cs new file mode 100644 index 00000000..529188a5 --- /dev/null +++ b/Google.Api.Gax/ActivitySources.cs @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Google LLC All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file or at + * https://developers.google.com/open-source/licenses/bsd + */ + +using System.Collections.Concurrent; +using System.Diagnostics; + +namespace Google.Api.Gax; + +// Note: currently internal until we're ready to roll out OpenTelemetry support "properly". + +/// +/// Helper methods for obtaining values. +/// Note that while some conventions suggest a single activity source per assembly, libraries for Google Cloud APIs +/// use an activity source per client type, for simpler filtering. These can easily be obtained via the static +/// properties on the client type itself, but this class allows a more generic approach where necessary. +/// +internal static class ActivitySources +{ + private static readonly ConcurrentDictionary s_activitySources = new(); + + /// + /// Returns an named after the given type (typically an API client). + /// + /// + /// Multiple calls to this method (or ) for the same + /// type will return the same cached activity source. + /// + /// The client type to obtain an activity source for. Must not be null. + /// An named after the given client type. + public static ActivitySource FromType(System.Type type) + { + GaxPreconditions.CheckNotNull(type, nameof(type)); + return s_activitySources.GetOrAdd(type, CreateActivitySource); + } + + /// + /// Returns an named after the given type (typically an API client). + /// + /// + /// Multiple calls to this method (or ) for the same + /// type will return the same cached activity source. + /// + /// The type to obtain an activity source for. + /// An named after the given type. + public static ActivitySource FromType() => FromType(typeof(T)); + + private static ActivitySource CreateActivitySource(System.Type type) => + // TODO: Move FormatAssemblyVersion to a separate type? It's odd to call into VersionHeaderBuilder here. + new ActivitySource(type.FullName, VersionHeaderBuilder.FormatAssemblyVersion(type)); +} diff --git a/Google.Api.Gax/VersionHeaderBuilder.cs b/Google.Api.Gax/VersionHeaderBuilder.cs index 45da1240..bdf75977 100644 --- a/Google.Api.Gax/VersionHeaderBuilder.cs +++ b/Google.Api.Gax/VersionHeaderBuilder.cs @@ -93,7 +93,10 @@ private static string GetEntryAssemblyVersionOrNull() } } - private static string FormatAssemblyVersion(System.Type type) + /// + /// Formats the version of the assembly containing the specified type, in a "generally informative" way. + /// + internal static string FormatAssemblyVersion(System.Type type) { // Prefer AssemblyInformationalVersion, then AssemblyFileVersion, // then AssemblyVersion.