Skip to content

Commit

Permalink
feat: Add helper methods to obtain ActivitySources
Browse files Browse the repository at this point in the history
  • Loading branch information
jskeet committed Apr 11, 2024
1 parent 165f332 commit 36ee7d3
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
47 changes: 47 additions & 0 deletions Google.Api.Gax.Tests/ActivitySourcesTest.cs
Original file line number Diff line number Diff line change
@@ -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<ActivitySourcesTest>();
// 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<ActivitySourcesTest>();
var source2 = ActivitySources.FromType<ActivitySourcesTest>();
var source3 = ActivitySources.FromType(typeof(ActivitySourcesTest));
var source4 = ActivitySources.FromType<PollingTest>();

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<Expiration>();
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);
}
}
54 changes: 54 additions & 0 deletions Google.Api.Gax/ActivitySources.cs
Original file line number Diff line number Diff line change
@@ -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".

/// <summary>
/// Helper methods for obtaining <see cref="ActivitySource"/> 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.
/// </summary>
internal static class ActivitySources
{
private static readonly ConcurrentDictionary<System.Type, ActivitySource> s_activitySources = new();

/// <summary>
/// Returns an <see cref="ActivitySource"/> named after the given type (typically an API client).
/// </summary>
/// <remarks>
/// Multiple calls to this method (or <see cref="FromType{T}()"/>) for the same
/// type will return the same cached activity source.
/// </remarks>
/// <param name="type">The client type to obtain an activity source for. Must not be null.</param>
/// <returns>An <see cref="ActivitySource"/> named after the given client type.</returns>
public static ActivitySource FromType(System.Type type)
{
GaxPreconditions.CheckNotNull(type, nameof(type));
return s_activitySources.GetOrAdd(type, CreateActivitySource);
}

/// <summary>
/// Returns an <see cref="ActivitySource"/> named after the given type (typically an API client).
/// </summary>
/// <remarks>
/// Multiple calls to this method (or <see cref="FromType(System.Type)"/>) for the same
/// type will return the same cached activity source.
/// </remarks>
/// <typeparam name="T">The type to obtain an activity source for.</typeparam>
/// <returns>An <see cref="ActivitySource"/> named after the given type.</returns>
public static ActivitySource FromType<T>() => 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));
}
5 changes: 4 additions & 1 deletion Google.Api.Gax/VersionHeaderBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ private static string GetEntryAssemblyVersionOrNull()
}
}

private static string FormatAssemblyVersion(System.Type type)
/// <summary>
/// Formats the version of the assembly containing the specified type, in a "generally informative" way.
/// </summary>
internal static string FormatAssemblyVersion(System.Type type)
{
// Prefer AssemblyInformationalVersion, then AssemblyFileVersion,
// then AssemblyVersion.
Expand Down

0 comments on commit 36ee7d3

Please sign in to comment.