Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[build] Use compiler constant to toggle experimental public apis #4735

Merged
merged 31 commits into from
Aug 10, 2023

Conversation

CodeBlanch
Copy link
Member

@CodeBlanch CodeBlanch commented Aug 2, 2023

What this PR does is move the Log Bridge artifacts (Logger, LoggerProvider, etc.) and Exemplar artifacts under a compiler constant/switch that will make them public or internal based on a build property. For pre-release builds (alpha/beta/rc) these things will be marked public and for stable releases they will be marked internal. The goal being to allow us to expose experimental things in order to gather feedback while reserving the right to make changes.

@codecov
Copy link

codecov bot commented Aug 2, 2023

Codecov Report

Merging #4735 (a112fc7) into main (a4fae4f) will decrease coverage by 0.02%.
The diff coverage is 75.00%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4735      +/-   ##
==========================================
- Coverage   82.08%   82.07%   -0.02%     
==========================================
  Files         313      313              
  Lines       12784    12784              
==========================================
- Hits        10494    10492       -2     
- Misses       2290     2292       +2     
Files Changed Coverage Δ
...endencyInjectionLoggerProviderBuilderExtensions.cs 100.00% <ø> (ø)
...encyInjectionLoggingServiceCollectionExtensions.cs 100.00% <ø> (ø)
...c/OpenTelemetry.Api/Logs/LogRecordAttributeList.cs 3.53% <ø> (ø)
src/OpenTelemetry.Api/Logs/LogRecordData.cs 88.00% <ø> (ø)
...nTelemetry.Api/Logs/LogRecordSeverityExtensions.cs 0.00% <ø> (ø)
src/OpenTelemetry.Api/Logs/Logger.cs 100.00% <ø> (ø)
src/OpenTelemetry.Api/Logs/LoggerProvider.cs 66.66% <ø> (ø)
...rc/OpenTelemetry.Api/Logs/LoggerProviderBuilder.cs 100.00% <ø> (ø)
...porter.Console/ConsoleExporterLoggingExtensions.cs 0.00% <ø> (ø)
...rter.InMemory/InMemoryExporterLoggingExtensions.cs 66.66% <ø> (ø)
... and 11 more

... and 2 files with indirect coverage changes

Comment on lines +58 to +59
<ExposeExperimentalFeatures Condition="'$(MinVerPreRelease)' != ''">true</ExposeExperimentalFeatures>
<ExposeExperimentalFeatures Condition="'$(MinVerPreRelease)' == ''">false</ExposeExperimentalFeatures>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@utpilla I'll need to verify once this is all done and building, but this change should automatically toggle ExposeExperimentalFeatures in the publish workflow.

Copy link
Contributor

@utpilla utpilla Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably also look at updating the publish-packages workflow by making use of the release event activity types:

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release

NuGet.config Outdated Show resolved Hide resolved
@@ -22,12 +22,21 @@
using OpenTelemetry.Internal;
using OpenTelemetry.Trace;

#if EXPOSE_EXPERIMENTAL_FEATURES
namespace OpenTelemetry.Logs.Experimental;
Copy link

@sharwell sharwell Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 I would discourage placing experimental features into a different namespace. This placement means it will be impossible to ship a new experimental feature by simply marking it public (which would be a non-breaking change for both source and binary consumers). By requiring a rename of the namespace, you end up with a source and binary breaking change which tends to produce churn that adds unnecessary ship risk to the process.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you think about this feedback @alanwest?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By requiring a rename of the namespace, you end up with a source and binary breaking change which tends to produce churn that adds unnecessary ship risk to the process.

I definitely see some value in not placing the experimental features into their own namespace. It would make the process of stabilizing the experimental features seamless for customers (as they wouldn't need to update their namespaces).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not feel strongly that an Experimental namespace is the best way to address my underlying concern. It's just one idea and maybe a bad one at that. I'm open to other ideas. Since we talked about this offline, I'll summarize my concern and what I'm interested in brainstorming. Consider the following scenario

  1. User begins using 1.6.0-beta
  2. User starts using the experimental log API and/or exemplar APIs
  3. Then 1.6.0 stable is release
  4. User gets excited and upgrades to the stable release only to find their code does not compile anymore

There's a variety of things we can consider to ameliorate this pain

  1. Include clear release notes
  2. Immediately publish a 1.7.0-alpha.1 release on the heels of the 1.6.0 stable allowing users to stay on the latest code and continue using experimental APIs.

Though, since in my experience many folks do not read release notes, I was trying to consider an option that makes it more abundantly clear that a user is using an experimental feature.

In my opinion, I think the best way I've seen this done is to ship experimental stuff in a separate package altogether much like we did with the OTLP log exporter. This pattern has the additional benefit of aligning with what most other OTel language SDKs do today. Though, I suspect this pattern may be challenging to apply to the log and exemplar APIs, so if this is true, then I am supportive of the pattern this PR poses.

Though, at a minimum, I think we should make sure to do 1 and 2 above.

Copy link

@sharwell sharwell Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted the namespace and added this to the XML comments:

/// <remarks><b>WARNING</b>: This is an experimental API which might change or be removed in the future. Use at your own risk.</remarks>

When we consume the net8 bits we can also add ExperimentalAttribute into the mix.

@CodeBlanch CodeBlanch marked this pull request as ready for review August 9, 2023 18:47
@CodeBlanch CodeBlanch requested a review from a team August 9, 2023 18:47
/// </summary>
/// <remarks>
/// <para><inheritdoc cref="AddInstrumentation{T}(LoggerProviderBuilder, T)" path="/remarks"/></para>
/// Note: The type specified by <typeparamref name="T"/> will be
Copy link
Contributor

@utpilla utpilla Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the warning for this method as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is there on line 41 via the inheritdoc. Easy to miss 😄 I did my best to not copy the warning text everywhere. It should be at most in 1 spot per assembly. In SDK there are 2, one for logs and one for exemplars. Because I figured it was a good idea to detach those two conceptual areas from each other.

@@ -30,13 +30,13 @@
</ItemGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" Condition="'$(ExposeExperimentalFeatures)' == 'true'" />
Copy link
Contributor

@utpilla utpilla Aug 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Create a new ItemGroup with this condition and place these four shared files under it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@@ -19,6 +19,7 @@
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]

#if EXPOSE_EXPERIMENTAL_FEATURES
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being wrapped in the experimental check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When !EXPOSE_EXPERIMENTAL_FEATURES than OpenTelemetry.Extension.Hosting sees the internals of OpenTelemetry.Api and it also sees the internal static class AssemblyInfo from that same file.

It is essentially yet another InternalsVisibleTo problem 🤣

Check out this commit I pushed. I had the idea to use this new C# 11 file-local types feature to prevent these AssemblyInfo helper classes from flowing to other assemblies. Let me know what you think about that!

@@ -27,3 +27,4 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddAspNetCoreInstrum
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddAspNetCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddAspNetCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action<OpenTelemetry.Instrumentation.AspNetCore.AspNetCoreInstrumentationOptions> configureAspNetCoreInstrumentationOptions) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddAspNetCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Instrumentation.AspNetCore.AspNetCoreInstrumentationOptions> configureAspNetCoreInstrumentationOptions) -> OpenTelemetry.Trace.TracerProviderBuilder
virtual OpenTelemetry.Instrumentation.AspNetCore.AspNetCoreMetricsInstrumentationOptions.AspNetCoreMetricEnrichmentFunc.Invoke(string name, Microsoft.AspNetCore.Http.HttpContext context, ref System.Diagnostics.TagList tags) -> void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being added because of the new public API analyzer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya. The new beta seems to have improved delegate checking or something 🤣

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new beta seems to have improved delegate checking or something

Correct. The previous version listed delegates as simple types, without any indication of what the return value or parameter types were. The full delegate signature is captured by the implicitly-created Invoke method, which doesn't exist in source but now is included in the Public API files in order to catch breaking changes to these signatures.

Copy link
Contributor

@utpilla utpilla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Comment on lines 29 to 30
#pragma warning disable SA1400 // Access modifier should be declared
file static class AssemblyInfo
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sharwell I couldn't find an order for the modifiers that would make SA1400/SA1206 and IDE0036 happy. I'm sure you are aware of this but I thought I would mention it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DotNetAnalyzers/StyleCopAnalyzers#3588

Fixed in 1.2.0-beta.507 and newer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sharwell! Fixed it up here: 65637b0

@CodeBlanch CodeBlanch merged commit 3b4db6d into open-telemetry:main Aug 10, 2023
@CodeBlanch CodeBlanch deleted the build-experimental-features branch August 10, 2023 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants