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

Strong typed diagnostics #2226

Merged
merged 7 commits into from
Jun 11, 2024
Merged

Conversation

Wraith2
Copy link
Contributor

@Wraith2 Wraith2 commented Nov 17, 2023

fixes #2184

Currently when emitting diagnostic events we use anonymous types. The only way to access the information in those types is using reflection which makes them unusable in reflection-free situations such as trimmed or Native AOT applications.

This PR replaces the anonymous types with dedicated types for each event. The new types are put into a new Microsoft.Data.SqlClient.Diagnostics namespace because no users are ever like to want to deal with those types directly and their names would be confusing it they commonly appears in intellisense listings. Documentation is added for all public members. Ref assembly is updated. Internal references to the names of the events have been updated (please check these carefully).
The names of the events have moved from internal constants to public constants because I feel that the names provide part of the public contract for accessing these diagnostics. If there is pushback on this particular part of the PR I could fairly easily be persuaded to revert them. I'm not sure of it.

The changes I've made are based on the changes contributed to asp.net by @benaadams in dotnet/aspnetcore#11730 . They provide strongly typed properties and optimized access through IReadOnlyList<KeyValuePair<string,object>> so callers do not need to take a direct dependency on our library they can simply try the cast to that interface and cleanly access all the data. I considered also adding IReadOnlyDictionary<string,object> allowing direct access to known named properties without a direct dependency. I can do that if it will be used by callers but wanted to have a discussion about it first.

/cc @kant2002 for trimming, @mbakalov for appinsights/otel oversight

@Wraith2
Copy link
Contributor Author

Wraith2 commented Dec 2, 2023

/me pokes @mbakalov

@kant2002
Copy link
Contributor

kant2002 commented Dec 4, 2023

Honestly I did not see anything related to trimming here. Are you have specific place in mind? Otherwise changes looks good. plain code very friendly to trimming 😄

@Wraith2
Copy link
Contributor Author

Wraith2 commented Dec 4, 2023

If you check the original issue you'll see that this is a suggested method of removing the anonymous types which require the use of reflection. So it doesn't make this library a lot safer but it allows consumer binaries to be safer consuming this one and so propagates trimability up the dependency stack.

@mbakalov
Copy link
Member

mbakalov commented Dec 7, 2023

Confirming we are good with this for otel - thank you! Checking AppInsights next...

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jan 12, 2024

Any appinsights feedback? not expecting it to fail if otel worked but it'd be good to have confirmation.

@JRahnama
Copy link
Member

/azurepipeline run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@JRahnama
Copy link
Member

failures are not related to your changes. I have fixed the pipelines, if you can push something that should pass.

Copy link

codecov bot commented Jan 13, 2024

Codecov Report

Attention: Patch coverage is 30.16591% with 463 lines in your changes missing coverage. Please review.

Project coverage is 72.40%. Comparing base (f7ab115) to head (1424ba7).

Current head 1424ba7 differs from pull request most recent head 8f7f3d5

Please upload reports for the commit 8f7f3d5 to get more accurate results.

Files Patch % Lines
...rc/Microsoft/Data/SqlClient/SqlClientDiagnostic.cs 20.12% 381 Missing ⚠️
...SqlClient/SqlClientDiagnosticListenerExtensions.cs 54.44% 82 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2226      +/-   ##
==========================================
- Coverage   72.81%   72.40%   -0.41%     
==========================================
  Files         311      312       +1     
  Lines       61694    62183     +489     
==========================================
+ Hits        44922    45025     +103     
- Misses      16772    17158     +386     
Flag Coverage Δ
addons 92.88% <ø> (ø)
netcore 76.48% <30.16%> (-0.70%) ⬇️
netfx 70.43% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mbakalov
Copy link
Member

mbakalov commented Jan 22, 2024

@Wraith2 -- sorry for the delay, just did some checking and turns out the change does break AppInsights! 😮

Error is:

AI (Internal): [Microsoft-ApplicationInsights-Extensibility-DependencyCollector] SqlClientDiagnosticSourceListener OnNext failed to call event handler. Error details 'System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.ApplicationInsights.DependencyCollector.Implementation.SqlClientDiagnostics.SqlClientDiagnosticSourceListener.BeforeOpenConnectionHelper(KeyValuePair`2 evnt, PropertyFetcher operationIdFetcher, PropertyFetcher connectionFetcher, PropertyFetcher operationFetcher, PropertyFetcher timestampFetcher, PropertyFetcher dataSourceFetcher, PropertyFetcher databaseFetcher)
   at Microsoft.ApplicationInsights.DependencyCollector.Implementation.SqlClientDiagnostics.SqlClientDiagnosticSourceListener.System.IObserver<System.Collections.Generic.KeyValuePair<System.String,System.Object>>.OnNext(KeyValuePair`2 evnt)'

Reason is the way AppInsights instrumentation reflects on the payload properties does not support inheritance. E.g. this code tries to get OperationId property:

private void BeforeOpenConnectionHelper(KeyValuePair<string, object> evnt,
    PropertyFetcher operationIdFetcher,
    PropertyFetcher connectionFetcher,
    PropertyFetcher operationFetcher,
    PropertyFetcher timestampFetcher,
    PropertyFetcher dataSourceFetcher,
    PropertyFetcher databaseFetcher)
{
    var operationId = (Guid)operationIdFetcher.Fetch(evnt.Value);

    DependencyCollectorEventSource.Log.SqlClientDiagnosticSubscriberCallbackCalled(operationId, evnt.Key);

    var connection = connectionFetcher.Fetch(evnt.Value);

    // ...

The PropertyFetcher does this:

if (fetch == null || fetch.Type != objType)
{
    this.innerFetcher = fetch = PropertyFetch.FetcherForProperty(objType, objType?.GetTypeInfo()?.GetDeclaredProperty(this.propertyName));
}

And GetDeclaredProperty does not see the OperationId defined on the SqlClientDiagnostic base class.

The reason Otel works is because it is lucky. The Otel instrumentation has the same issue, but it just happens to only access Command and Exception properties.

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jan 22, 2024

Interesting. I think that the "right" way to fix this is to fix app insights but I don't think that's realistic. It's something worth raising with appinsights and otel because in future if people aren't using anonymous objects then inheritance is something that could be used to avoid a lot of code duplication.

I'll need to rewrite without the base class and put in some notes that inheritance cannot be used.

@mbakalov
Copy link
Member

Thanks! I agree on the right way. Will check with AppInsights and Otel if it is something that can be changed in the future.

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jan 23, 2024

Base class removed and everything implemented directly on the new classes. Once the CI finishes can you retest on appinsights please.

@mbakalov
Copy link
Member

@Wraith2: confirm it works ok now for both Otel and AppInsights, thanks!

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jun 3, 2024

@David-Engel any particular blocker on this?

@kf-gonzalez2 kf-gonzalez2 added this to the 6.0-preview1 milestone Jun 4, 2024
@David-Engel
Copy link
Contributor

David-Engel commented Jun 4, 2024

any particular blocker on this?

No, sorry. Just time and priorities. If you address the inheritDoc issue, we'll try to get this merged for 6.0 preview 1.

@JRahnama
Copy link
Member

@Wraith2 and of course a conflict had to happen here right on this PR when we are ready to merge.

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jun 11, 2024

rebasing now. give me a minute to resolve things and check it.

@Wraith2
Copy link
Contributor Author

Wraith2 commented Jun 11, 2024

Done, we're in the hands of the CI now.

@David-Engel David-Engel merged commit ffd8771 into dotnet:main Jun 11, 2024
148 checks passed
@Wraith2 Wraith2 deleted the strong-typed-diagnostics branch June 12, 2024 20:57
mdaigle pushed a commit that referenced this pull request Jun 20, 2024
deepaksa1 added a commit to deepaksa1/SqlClient that referenced this pull request Jul 22, 2024
* Updating Azure.Identity version to 1.11.3 (dotnet#2526)

* Fix | Clone of SqlConnection should include AccessTokenCallback (dotnet#2525)

* Enhancement | Add trace logs for packet size (dotnet#2522)

* Merged PR 4583: eng | Fix policheck errors.

Fix policheck errors.

Sample pipeline run which did not have policheck errors:

https://sqlclientdrivers.visualstudio.com/ADO.Net/_build/results?buildId=88114&view=sariftools.scans.build-tab

Related work items: #30279

* Doc | Fix SNI dependencies of 5.1 and 5.2 release notes (dotnet#2537)

* Change | Separate tests for NetFx and NetCore - NetFx-Only Connection String Properties (dotnet#2466)

* Adding TransparentNetworkIpResolution to list of unsupported on platform connection string error messages
Splitting unit test for netfx-only connection string properties such that test does not fail on netcore

* Remove DeprecatedSynonymCount since referencing the unsupported array is not possible

* Fix | Enhance certificate validation (dotnet#2487)

* Hotfix v5.2.1 Release notes (dotnet#2534)

* Improve AccessTokenCallback sample code (dotnet#2543)

* Merged PR 4621: eng | Fix policheck

* Fix | Adjust path for .AssemblyAttributes in obj folder (dotnet#2550)

* Fix | Fixed GenerateSspiClientContext to retry negotiation with default port (dotnet#2559)

* Strong typed diagnostics (dotnet#2226)

* Fix | Replaced System.Runtime.Caching with Microsoft.Extensions.Caching.Memory (dotnet#2493)

* Add | Add SourceLink translation (dotnet#2552)

* Add | Cache TokenCredential objects to take advantage of token caching (dotnet#2380)

* Merged common code base for SqlUtil.cs (dotnet#2533)

* Add scope trace for GenerateSspiClientContext (dotnet#2497)

* Address conflicts (dotnet#2562)

* Addressing conflict (dotnet#2560)

* Merge SqlColumnEncryptionCertificateStoreProvider (dotnet#2521)

* Add | No-op if engineedition is 6 or 11 due to lack of support for ASSEMBLYPROPERTY function (dotnet#2593)

* Change | Remove some unneeded references and update Azure.Identity (dotnet#2577)

* Add test for issue 2456 (dotnet#2457)

* Merged common code base for AlwaysEncryptedKeyConverter (dotnet#2538)

* Merged AlwaysEncryptedKeyConverter.CrossPlatform and AlwaysEncryptedKeyConverter.Cng.

* 3 Small Changes (dotnet#2594)

* * Port sqlclientx datasource changes
* Remove link to missing nuget.config file
* Remove root namespaces from sqlclient csproj files

* Test to see if namespace changes are breaking the pr build

* Reinstate removing the root namespace and fix resource filename generation

* Test fixes to accommodate recent infra changes (dotnet#2646)

* Test fixes to accomodate recent infra changes

* Fix - Don't error when using infinte connect timeout and Entra auth (dotnet#2651)

* eng | Add delay signed to official builds (dotnet#2653)

* eng | Initial YAML CI pipeline (dotnet#2575)

* Fix | Fix decrypt failure to drain data (dotnet#2618)

* [Scheduled Run] Localized resource files from OneLocBuild

* eng | Add Delay sign to ref csprojs (dotnet#2684)

* [Scheduled Run] Localized resource files from OneLocBuild

* [Scheduled Run] Localized resource files from OneLocBuild

---------

Co-authored-by: Javad Rahnama <v-jarahn@microsoft.com>
Co-authored-by: David Engel <v-davidengel@microsoft.com>
Co-authored-by: Aris Rellegue <v-arellegue@microsoft.com>
Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com>
Co-authored-by: Benjamin Russell <russellben@microsoft.com>
Co-authored-by: Aris Rellegue <134557572+arellegue@users.noreply.github.com>
Co-authored-by: dauinsight <145612907+dauinsight@users.noreply.github.com>
Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com>
Co-authored-by: Daniel Au <v-audaniel@microsoft.com>
Co-authored-by: Wraith <wraith2@gmail.com>
Co-authored-by: SqlClient Azure DevOps <sqlclient@microsoft.com>
Co-authored-by: Edward Neal <55035479+edwardneal@users.noreply.github.com>
Co-authored-by: Erik Ejlskov Jensen <ErikEJ@users.noreply.github.com>
Co-authored-by: David Engel <davidengel@microsoft.com>
@David-Engel David-Engel added the 💡 Enhancement New feature request label Aug 8, 2024
@DavoudEshtehari DavoudEshtehari added the 🆕 Public API Use this label for new API additions to the driver. label Aug 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💡 Enhancement New feature request 🆕 Public API Use this label for new API additions to the driver.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consider changing diagnostic events to use public declared types as their payload
7 participants