diff --git a/.github/ISSUE_TEMPLATE/comp_extensions_enrichment.md b/.github/ISSUE_TEMPLATE/comp_extensions_enrichment.md new file mode 100644 index 0000000000..4e10dc3c77 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/comp_extensions_enrichment.md @@ -0,0 +1,54 @@ +--- +name: OpenTelemetry.Extensions.Enrichment +about: Issue with OpenTelemetry.Extensions.Enrichment +labels: comp:extensions.enrichment +--- + +# Issue with OpenTelemetry.Extensions.Enrichment + +**What type of request is this?** + +* [ ] Feature Request +* [ ] Bug +* [ ] Question + +## Request Details + +**What are the OpenTelemetry packages and versions you are using?** + +_List [all OpenTelemetry NuGet +packages](https://www.nuget.org/profiles/OpenTelemetry) and version that you are +using (e.g. `OpenTelemetry 1.4.0`)._ + +**What environment are you using?** + +_Please include the runtime versions (e.g. `net462`, `net48`, `net6.0`, `net7.0` +etc.), OS details (e.g.Windows, Linux, etc.), architecture (e.g. 32bit, 64bit, +etc.), and anything else important (e.g. IIS, container, etc.)._ + +**What is the expected behavior?** + +_Describe what you expected to see._ + +**What is the actual behavior?** + +_Describe what you saw instead._ + +**What are the steps to reproduce the issue?** + +_Describe how to reproduce the issue._ + +If you are reporting a non-obvious bug, please create a self-contained project +and apply the minimum required code to result in the issue you're observing. + +We will close this issue if: + +* The repro project you share with us is too complex. We can't investigate + custom projects please try to keep it to just what is needed to demonstrate + the issue. + +* We can't reproduce the behavior you're reporting. + +## Additional Context + +_Include any other context about the bug or feature request here._ diff --git a/.github/component_owners.yml b/.github/component_owners.yml index e6eb61f68b..37ee61990c 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -29,6 +29,8 @@ components: - vishweshbankwar src/OpenTelemetry.Extensions.Docker/: - iskiselev + src/OpenTelemetry.Extensions.Enrichment/: + - xakep139 src/OpenTelemetry.Extensions.PersistentStorage.Abstractions/: - vishweshbankwar src/OpenTelemetry.Extensions.PersistentStorage/: @@ -98,6 +100,8 @@ components: - codeblanch test/OpenTelemetry.Extensions.Docker.Tests/: - iskiselev + test/OpenTelemetry.Extensions.Enrichment.Tests/: + - xakep139 test/OpenTelemetry.Extensions.PersistentStorage.Tests/: - vishweshbankwar test/OpenTelemetry.Instrumentation.AWSLambda.Tests/: diff --git a/.github/workflows/package-Extensions.Enrichment.yml b/.github/workflows/package-Extensions.Enrichment.yml new file mode 100644 index 0000000000..7d6fc0629c --- /dev/null +++ b/.github/workflows/package-Extensions.Enrichment.yml @@ -0,0 +1,67 @@ +name: Pack OpenTelemetry.Extensions.Enrichment + +on: + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: true + default: 'warning' + push: + tags: + - 'Extensions.Enrichment-*' # trigger when we create a tag with prefix "Extensions.Enrichment-" + +jobs: + build-test-pack: + runs-on: ${{ matrix.os }} + permissions: + contents: write + env: + PROJECT: OpenTelemetry.Extensions.Enrichment + + strategy: + matrix: + os: [windows-latest] + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # fetching all + + - uses: actions/setup-dotnet@v3.0.3 + with: + dotnet-version: '7.0.x' + + - name: Install dependencies + run: dotnet restore src/${{env.PROJECT}} + + - name: dotnet build ${{env.PROJECT}} + run: dotnet build src/${{env.PROJECT}} --configuration Release --no-restore -p:Deterministic=true + + - name: dotnet test ${{env.PROJECT}} + run: dotnet test test/${{env.PROJECT}}.Tests + + - name: dotnet pack ${{env.PROJECT}} + run: dotnet pack src/${{env.PROJECT}} --configuration Release --no-build + + - name: Publish Artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{env.PROJECT}}-packages + path: '**/${{env.PROJECT}}/bin/**/*.*nupkg' + + - name: Publish Nuget + run: | + nuget push **/${{env.PROJECT}}/bin/**/*.nupkg -Source https://api.nuget.org/v3/index.json -ApiKey ${{ secrets.NUGET_TOKEN }} -SymbolApiKey ${{ secrets.NUGET_TOKEN }} + + - name: Create GitHub Prerelease + if: ${{ (contains(github.ref_name, '-alpha.') || contains(github.ref_name, '-beta.') || contains(github.ref_name, '-rc.')) }} + run: gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --verify-tag --notes "See [CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/${{ github.ref_name }}/src/${{env.PROJECT}}/CHANGELOG.md) for details." --prerelease + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create GitHub Release + if: ${{ !(contains(github.ref_name, '-alpha.') || contains(github.ref_name, '-beta.') || contains(github.ref_name, '-rc.')) }} + run: gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --verify-tag --notes "See [CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/blob/${{ github.ref_name }}/src/${{env.PROJECT}}/CHANGELOG.md) for details." --latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/build/Common.props b/build/Common.props index c322c24bcd..3420b287d8 100644 --- a/build/Common.props +++ b/build/Common.props @@ -7,6 +7,8 @@ $(DefineConstants);SIGNED true net462 + net6.0 + netstandard2.0 diff --git a/opentelemetry-dotnet-contrib.sln b/opentelemetry-dotnet-contrib.sln index 820b0db25e..a2ad722e26 100644 --- a/opentelemetry-dotnet-contrib.sln +++ b/opentelemetry-dotnet-contrib.sln @@ -249,6 +249,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OneC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OneCollector.Tests", "test\OpenTelemetry.Exporter.OneCollector.Tests\OpenTelemetry.Exporter.OneCollector.Tests.csproj", "{61520801-1CAA-4041-A3EF-CFFB9D4A180B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Enrichment", "src\OpenTelemetry.Extensions.Enrichment\OpenTelemetry.Extensions.Enrichment.csproj", "{5BA85306-64B8-4E04-90EB-7069C187E250}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Enrichment.Tests", "test\OpenTelemetry.Extensions.Enrichment.Tests\OpenTelemetry.Extensions.Enrichment.Tests.csproj", "{5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -527,6 +531,14 @@ Global {61520801-1CAA-4041-A3EF-CFFB9D4A180B}.Debug|Any CPU.Build.0 = Debug|Any CPU {61520801-1CAA-4041-A3EF-CFFB9D4A180B}.Release|Any CPU.ActiveCfg = Release|Any CPU {61520801-1CAA-4041-A3EF-CFFB9D4A180B}.Release|Any CPU.Build.0 = Release|Any CPU + {5BA85306-64B8-4E04-90EB-7069C187E250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BA85306-64B8-4E04-90EB-7069C187E250}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BA85306-64B8-4E04-90EB-7069C187E250}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BA85306-64B8-4E04-90EB-7069C187E250}.Release|Any CPU.Build.0 = Release|Any CPU + {5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -608,6 +620,8 @@ Global {DFC6A4A9-5262-4507-B747-CC6B814205E6} = {2097345F-4DD3-477D-BC54-A922F9B2B402} {73C10993-03AC-42F4-85BB-96EAAA8212D9} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} {61520801-1CAA-4041-A3EF-CFFB9D4A180B} = {2097345F-4DD3-477D-BC54-A922F9B2B402} + {5BA85306-64B8-4E04-90EB-7069C187E250} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} + {5A7BE9DA-3582-49D8-A8E7-164C1E3CDB38} = {2097345F-4DD3-477D-BC54-A922F9B2B402} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B0816796-CDB3-47D7-8C3C-946434DE3B66} diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/AWSXRayIdGenerator.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/AWSXRayIdGenerator.cs index 32380686f6..7741963524 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/AWSXRayIdGenerator.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/AWSXRayIdGenerator.cs @@ -41,6 +41,7 @@ public static class AWSXRayIdGenerator internal static void ReplaceTraceId(Sampler? sampler = null) { +#pragma warning disable CA2000 // Dispose objects before losing scope var awsXRayActivityListener = new ActivityListener { ActivityStarted = (activity) => @@ -63,6 +64,7 @@ internal static void ReplaceTraceId(Sampler? sampler = null) ShouldListenTo = (_) => true, }; +#pragma warning restore CA2000 // Dispose objects before losing scope ActivitySource.AddActivityListener(awsXRayActivityListener); } @@ -141,7 +143,9 @@ private static string GenerateHexNumber(int digits) /// An array of bytes to contain random numbers. private static void NextBytes(byte[] buffer) { +#pragma warning disable CA5394 // Do not use insecure randomness Global.NextBytes(buffer); +#pragma warning restore CA5394 // Do not use insecure randomness } /// @@ -151,7 +155,9 @@ private static void NextBytes(byte[] buffer) /// A 32-bit signed integer that is greater than or equal to 0, and less than maxValue. private static int Next(int maxValue) { +#pragma warning disable CA5394 // Do not use insecure randomness return Global.Next(maxValue); +#pragma warning restore CA5394 // Do not use insecure randomness } private static ActivitySamplingResult ComputeRootActivitySamplingResult( diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEBSResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEBSResourceDetector.cs index 141464c14e..7e30090643 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEBSResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEBSResourceDetector.cs @@ -29,7 +29,9 @@ namespace OpenTelemetry.Contrib.Extensions.AWSXRay.Resources; public class AWSEBSResourceDetector : IResourceDetector { private const string AWSEBSMetadataWindowsFilePath = "C:\\Program Files\\Amazon\\XRay\\environment.conf"; +#if NETSTANDARD private const string AWSEBSMetadataLinuxFilePath = "/var/elasticbeanstalk/xray/environment.conf"; +#endif /// /// Detector the required and optional resource attributes from AWS ElasticBeanstalk. @@ -55,9 +57,9 @@ public class AWSEBSResourceDetector : IResourceDetector filePath = AWSEBSMetadataWindowsFilePath; #endif - var metadata = this.GetEBSMetadata(filePath); + var metadata = GetEBSMetadata(filePath); - resourceAttributes = this.ExtractResourceAttributes(metadata); + resourceAttributes = ExtractResourceAttributes(metadata); } catch (Exception ex) { @@ -67,7 +69,7 @@ public class AWSEBSResourceDetector : IResourceDetector return resourceAttributes; } - internal List>? ExtractResourceAttributes(AWSEBSMetadataModel? metadata) + internal static List>? ExtractResourceAttributes(AWSEBSMetadataModel? metadata) { var resourceAttributes = new List>() { @@ -82,7 +84,7 @@ public class AWSEBSResourceDetector : IResourceDetector return resourceAttributes; } - internal AWSEBSMetadataModel? GetEBSMetadata(string filePath) + internal static AWSEBSMetadataModel? GetEBSMetadata(string filePath) { return ResourceDetectorUtils.DeserializeFromFile(filePath); } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEC2ResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEC2ResourceDetector.cs index b6c5908929..9b613bd2b2 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEC2ResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEC2ResourceDetector.cs @@ -41,11 +41,11 @@ public class AWSEC2ResourceDetector : IResourceDetector try { - var token = this.GetAWSEC2Token(); - var identity = this.GetAWSEC2Identity(token); - var hostName = this.GetAWSEC2HostName(token); + var token = GetAWSEC2Token(); + var identity = GetAWSEC2Identity(token); + var hostName = GetAWSEC2HostName(token); - resourceAttributes = this.ExtractResourceAttributes(identity, hostName); + resourceAttributes = ExtractResourceAttributes(identity, hostName); } catch (Exception ex) { @@ -55,7 +55,7 @@ public class AWSEC2ResourceDetector : IResourceDetector return resourceAttributes; } - internal List> ExtractResourceAttributes(AWSEC2IdentityDocumentModel? identity, string hostName) + internal static List> ExtractResourceAttributes(AWSEC2IdentityDocumentModel? identity, string hostName) { var resourceAttributes = new List>() { @@ -72,30 +72,30 @@ public class AWSEC2ResourceDetector : IResourceDetector return resourceAttributes; } - internal AWSEC2IdentityDocumentModel? DeserializeResponse(string response) + internal static AWSEC2IdentityDocumentModel? DeserializeResponse(string response) { return ResourceDetectorUtils.DeserializeFromString(response); } - private string GetAWSEC2Token() + private static string GetAWSEC2Token() { return ResourceDetectorUtils.SendOutRequest(AWSEC2MetadataTokenUrl, "PUT", new KeyValuePair(AWSEC2MetadataTokenTTLHeader, "60")).Result; } - private AWSEC2IdentityDocumentModel? GetAWSEC2Identity(string token) + private static AWSEC2IdentityDocumentModel? GetAWSEC2Identity(string token) { - var identity = this.GetIdentityResponse(token); - var identityDocument = this.DeserializeResponse(identity); + var identity = GetIdentityResponse(token); + var identityDocument = DeserializeResponse(identity); return identityDocument; } - private string GetIdentityResponse(string token) + private static string GetIdentityResponse(string token) { return ResourceDetectorUtils.SendOutRequest(AWSEC2IdentityDocumentUrl, "GET", new KeyValuePair(AWSEC2MetadataTokenHeader, token)).Result; } - private string GetAWSEC2HostName(string token) + private static string GetAWSEC2HostName(string token) { return ResourceDetectorUtils.SendOutRequest(AWSEC2HostNameUrl, "GET", new KeyValuePair(AWSEC2MetadataTokenHeader, token)).Result; } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSECSResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSECSResourceDetector.cs index 9331685a8e..b33b37568a 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSECSResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSECSResourceDetector.cs @@ -36,16 +36,16 @@ public class AWSECSResourceDetector : IResourceDetector { List>? resourceAttributes = null; - if (!this.IsECSProcess()) + if (!IsECSProcess()) { return resourceAttributes; } try { - var containerId = this.GetECSContainerId(AWSECSMetadataPath); + var containerId = GetECSContainerId(AWSECSMetadataPath); - resourceAttributes = this.ExtractResourceAttributes(containerId); + resourceAttributes = ExtractResourceAttributes(containerId); } catch (Exception ex) { @@ -55,7 +55,7 @@ public class AWSECSResourceDetector : IResourceDetector return resourceAttributes; } - internal List> ExtractResourceAttributes(string? containerId) + internal static List> ExtractResourceAttributes(string? containerId) { var resourceAttributes = new List>() { @@ -67,7 +67,7 @@ public class AWSECSResourceDetector : IResourceDetector return resourceAttributes; } - internal string? GetECSContainerId(string path) + internal static string? GetECSContainerId(string path) { string? containerId = null; @@ -87,7 +87,7 @@ public class AWSECSResourceDetector : IResourceDetector return containerId; } - internal bool IsECSProcess() + internal static bool IsECSProcess() { return Environment.GetEnvironmentVariable(AWSECSMetadataURLKey) != null || Environment.GetEnvironmentVariable(AWSECSMetadataURLV4Key) != null; } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs index 51c83c24be..7587506300 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSEKSResourceDetector.cs @@ -40,20 +40,20 @@ public class AWSEKSResourceDetector : IResourceDetector /// List of key-value pairs of resource attributes. public IEnumerable>? Detect() { - var credentials = this.GetEKSCredentials(AWSEKSCredentialPath); - var httpClientHandler = Handler.Create(AWSEKSCertificatePath); + var credentials = GetEKSCredentials(AWSEKSCredentialPath); + using var httpClientHandler = Handler.Create(AWSEKSCertificatePath); - if (credentials == null || !this.IsEKSProcess(credentials, httpClientHandler)) + if (credentials == null || !IsEKSProcess(credentials, httpClientHandler)) { return null; } - return this.ExtractResourceAttributes( - this.GetEKSClusterName(credentials, httpClientHandler), - this.GetEKSContainerId(AWSEKSMetadataFilePath)); + return ExtractResourceAttributes( + GetEKSClusterName(credentials, httpClientHandler), + GetEKSContainerId(AWSEKSMetadataFilePath)); } - internal List> ExtractResourceAttributes(string? clusterName, string? containerId) + internal static List> ExtractResourceAttributes(string? clusterName, string? containerId) { var resourceAttributes = new List>() { @@ -74,11 +74,11 @@ public class AWSEKSResourceDetector : IResourceDetector return resourceAttributes; } - internal string? GetEKSCredentials(string path) + internal static string? GetEKSCredentials(string path) { try { - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); using (var streamReader = ResourceDetectorUtils.GetStreamReader(path)) { @@ -88,7 +88,9 @@ public class AWSEKSResourceDetector : IResourceDetector } } - return "Bearer " + stringBuilder.ToString(); + stringBuilder.Insert(0, "Bearer "); + + return stringBuilder.ToString(); } catch (Exception ex) { @@ -98,7 +100,7 @@ public class AWSEKSResourceDetector : IResourceDetector return null; } - internal string? GetEKSContainerId(string path) + internal static string? GetEKSContainerId(string path) { try { @@ -122,17 +124,17 @@ public class AWSEKSResourceDetector : IResourceDetector return null; } - internal AWSEKSClusterInformationModel? DeserializeResponse(string response) + internal static AWSEKSClusterInformationModel? DeserializeResponse(string response) { return ResourceDetectorUtils.DeserializeFromString(response); } - private string? GetEKSClusterName(string credentials, HttpClientHandler? httpClientHandler) + private static string? GetEKSClusterName(string credentials, HttpClientHandler? httpClientHandler) { try { - var clusterInfo = this.GetEKSClusterInfo(credentials, httpClientHandler); - return this.DeserializeResponse(clusterInfo)?.Data?.ClusterName; + var clusterInfo = GetEKSClusterInfo(credentials, httpClientHandler); + return DeserializeResponse(clusterInfo)?.Data?.ClusterName; } catch (Exception ex) { @@ -142,7 +144,7 @@ public class AWSEKSResourceDetector : IResourceDetector return null; } - private bool IsEKSProcess(string credentials, HttpClientHandler? httpClientHandler) + private static bool IsEKSProcess(string credentials, HttpClientHandler? httpClientHandler) { string? awsAuth = null; try @@ -157,7 +159,7 @@ private bool IsEKSProcess(string credentials, HttpClientHandler? httpClientHandl return !string.IsNullOrEmpty(awsAuth); } - private string GetEKSClusterInfo(string credentials, HttpClientHandler? httpClientHandler) + private static string GetEKSClusterInfo(string credentials, HttpClientHandler? httpClientHandler) { return ResourceDetectorUtils.SendOutRequest(AWSClusterInfoUrl, "GET", new KeyValuePair("Authorization", credentials), httpClientHandler).Result; } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSLambdaResourceDetector.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSLambdaResourceDetector.cs index ec163976b7..7da1884ff0 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSLambdaResourceDetector.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/AWSLambdaResourceDetector.cs @@ -38,7 +38,7 @@ public class AWSLambdaResourceDetector : IResourceDetector try { - resourceAttributes = this.ExtractResourceAttributes(); + resourceAttributes = ExtractResourceAttributes(); } catch (Exception ex) { @@ -48,7 +48,7 @@ public class AWSLambdaResourceDetector : IResourceDetector return resourceAttributes; } - internal List> ExtractResourceAttributes() + internal static List> ExtractResourceAttributes() { var resourceAttributes = new List>() { diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/Http/ServerCertificateValidationProvider.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/Http/ServerCertificateValidationProvider.cs index 03d725dbd2..fc48b71aac 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/Http/ServerCertificateValidationProvider.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/Http/ServerCertificateValidationProvider.cs @@ -80,6 +80,27 @@ private static bool LoadCertificateToTrustedCollection(X509Certificate2Collectio } } + private static bool HasCommonCertificate(X509Chain chain, X509Certificate2Collection? collection) + { + if (collection == null) + { + return false; + } + + foreach (var chainElement in chain.ChainElements) + { + foreach (var certificate in collection) + { + if (Enumerable.SequenceEqual(chainElement.Certificate.GetPublicKey(), certificate.GetPublicKey())) + { + return true; + } + } + } + + return false; + } + private bool ValidateCertificate(X509Certificate2 cert, X509Chain chain, SslPolicyErrors errors) { var isSslPolicyPassed = errors == SslPolicyErrors.None || @@ -119,7 +140,7 @@ private bool ValidateCertificate(X509Certificate2 cert, X509Chain chain, SslPoli } // check if at least one certificate in the chain is in our trust list - var isTrusted = this.HasCommonCertificate(chain, this.trustedCertificates); + var isTrusted = HasCommonCertificate(chain, this.trustedCertificates); if (!isTrusted) { var serverCertificates = string.Empty; @@ -144,25 +165,4 @@ private bool ValidateCertificate(X509Certificate2 cert, X509Chain chain, SslPoli return isSslPolicyPassed && isValidChain && isTrusted; } - - private bool HasCommonCertificate(X509Chain chain, X509Certificate2Collection? collection) - { - if (collection == null) - { - return false; - } - - foreach (var chainElement in chain.ChainElements) - { - foreach (var certificate in collection) - { - if (Enumerable.SequenceEqual(chainElement.Certificate.GetPublicKey(), certificate.GetPublicKey())) - { - return true; - } - } - } - - return false; - } } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/ResourceDetectorUtils.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/ResourceDetectorUtils.cs index 74509c9cad..2c774d340b 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/ResourceDetectorUtils.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Resources/ResourceDetectorUtils.cs @@ -27,7 +27,9 @@ namespace OpenTelemetry.Contrib.Extensions.AWSXRay.Resources; /// /// Class for resource detector utils. /// +#pragma warning disable CA1052 public class ResourceDetectorUtils +#pragma warning restore CA1052 { internal static async Task SendOutRequest(string url, string method, KeyValuePair header, HttpClientHandler? handler = null) { @@ -37,11 +39,13 @@ internal static async Task SendOutRequest(string url, string method, Key httpRequestMessage.Method = new HttpMethod(method); httpRequestMessage.Headers.Add(header.Key, header.Value); +#pragma warning disable CA2000 // Dispose objects before losing scope var httpClient = handler == null ? new HttpClient() : new HttpClient(handler); - using (var response = await httpClient.SendAsync(httpRequestMessage)) +#pragma warning restore CA2000 // Dispose objects before losing scope + using (var response = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false)) { response.EnsureSuccessStatusCode(); - return await response.Content.ReadAsStringAsync(); + return await response.Content.ReadAsStringAsync().ConfigureAwait(false); } } } diff --git a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Trace/AWSXRayPropagator.cs b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Trace/AWSXRayPropagator.cs index 5e899960cd..73ae58c161 100644 --- a/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Trace/AWSXRayPropagator.cs +++ b/src/OpenTelemetry.Contrib.Extensions.AWSXRay/Trace/AWSXRayPropagator.cs @@ -35,7 +35,7 @@ public class AWSXRayPropagator : TextMapPropagator private const char TraceHeaderDelimiter = ';'; private const string RootKey = "Root"; - private const string Version = "1"; + private const char Version = '1'; private const int RandomNumberHexDigits = 24; private const int EpochHexDigits = 8; private const int TotalLength = 35; @@ -232,7 +232,7 @@ internal static bool TryParseOTFormatTraceId(ReadOnlySpan traceId, out Rea return false; } - if (!traceId.StartsWith(Version.AsSpan())) + if (traceId.Length < 1 || traceId[0] != Version) { return false; } @@ -303,6 +303,7 @@ internal static bool TryParseSampleDecision(ReadOnlySpan sampleDecision, o internal static string ToXRayTraceIdFormat(string traceId) { var sb = new StringBuilder(); + sb.Append(Version); sb.Append(TraceIdDelimiter); sb.Append(traceId.Substring(0, EpochHexDigits)); diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs index c10ca0bd7f..78879e2459 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/AWSTracingPipelineHandler.cs @@ -57,7 +57,7 @@ public override void InvokeSync(IExecutionContext executionContext) { if (activity != null) { - this.ProcessException(activity, ex); + ProcessException(activity, ex); } throw; @@ -66,7 +66,7 @@ public override void InvokeSync(IExecutionContext executionContext) { if (activity != null) { - this.ProcessEndRequest(executionContext, activity); + ProcessEndRequest(executionContext, activity); } } } @@ -84,7 +84,7 @@ public override async Task InvokeAsync(IExecutionContext executionContext) { if (activity != null) { - this.ProcessException(activity, ex); + ProcessException(activity, ex); } throw; @@ -93,53 +93,14 @@ public override async Task InvokeAsync(IExecutionContext executionContext) { if (activity != null) { - this.ProcessEndRequest(executionContext, activity); + ProcessEndRequest(executionContext, activity); } } return ret; } - private Activity? ProcessBeginRequest(IExecutionContext executionContext) - { - Activity? activity = null; - - var requestContext = executionContext.RequestContext; - var service = AWSServiceHelper.GetAWSServiceName(requestContext); - var operation = AWSServiceHelper.GetAWSOperationName(requestContext); - - activity = AWSSDKActivitySource.StartActivity(service + "." + operation, ActivityKind.Client); - - if (activity == null) - { - return null; - } - - if (this.options.SuppressDownstreamInstrumentation) - { - SuppressInstrumentationScope.Enter(); - } - - if (activity.IsAllDataRequested) - { - activity.SetTag(AWSSemanticConventions.AttributeAWSServiceName, service); - activity.SetTag(AWSSemanticConventions.AttributeAWSOperationName, operation); - var client = executionContext.RequestContext.ClientConfig; - if (client != null) - { - var region = client.RegionEndpoint?.SystemName; - activity.SetTag(AWSSemanticConventions.AttributeAWSRegion, region ?? AWSSDKUtils.DetermineRegion(client.ServiceURL)); - } - - this.AddRequestSpecificInformation(activity, requestContext, service); - } - - AwsPropagator.Inject(new PropagationContext(activity.Context, Baggage.Current), requestContext.Request.Headers, Setter); - - return activity; - } - - private void ProcessEndRequest(IExecutionContext executionContext, Activity activity) + private static void ProcessEndRequest(IExecutionContext executionContext, Activity activity) { var responseContext = executionContext.ResponseContext; var requestContext = executionContext.RequestContext; @@ -148,7 +109,7 @@ private void ProcessEndRequest(IExecutionContext executionContext, Activity acti { if (Utils.GetTagValue(activity, AWSSemanticConventions.AttributeAWSRequestId) == null) { - activity.SetTag(AWSSemanticConventions.AttributeAWSRequestId, this.FetchRequestId(requestContext, responseContext)); + activity.SetTag(AWSSemanticConventions.AttributeAWSRequestId, FetchRequestId(requestContext, responseContext)); } var httpResponse = responseContext.HttpResponse; @@ -156,7 +117,7 @@ private void ProcessEndRequest(IExecutionContext executionContext, Activity acti { int statusCode = (int)httpResponse.StatusCode; - this.AddStatusCodeToActivity(activity, statusCode); + AddStatusCodeToActivity(activity, statusCode); activity.SetTag(AWSSemanticConventions.AttributeHttpResponseContentLength, httpResponse.ContentLength); } } @@ -164,7 +125,7 @@ private void ProcessEndRequest(IExecutionContext executionContext, Activity acti activity.Stop(); } - private void ProcessException(Activity activity, Exception ex) + private static void ProcessException(Activity activity, Exception ex) { if (activity.IsAllDataRequested) { @@ -174,13 +135,13 @@ private void ProcessException(Activity activity, Exception ex) if (ex is AmazonServiceException amazonServiceException) { - this.AddStatusCodeToActivity(activity, (int)amazonServiceException.StatusCode); + AddStatusCodeToActivity(activity, (int)amazonServiceException.StatusCode); activity.SetTag(AWSSemanticConventions.AttributeAWSRequestId, amazonServiceException.RequestId); } } } - private void AddRequestSpecificInformation(Activity activity, IRequestContext requestContext, string service) + private static void AddRequestSpecificInformation(Activity activity, IRequestContext requestContext, string service) { if (AWSServiceHelper.ServiceParameterMap.TryGetValue(service, out string parameter)) { @@ -202,12 +163,12 @@ private void AddRequestSpecificInformation(Activity activity, IRequestContext re } } - private void AddStatusCodeToActivity(Activity activity, int status_code) + private static void AddStatusCodeToActivity(Activity activity, int status_code) { activity.SetTag(AWSSemanticConventions.AttributeHttpStatusCode, status_code); } - private string FetchRequestId(IRequestContext requestContext, IResponseContext responseContext) + private static string FetchRequestId(IRequestContext requestContext, IResponseContext responseContext) { string request_id = string.Empty; var response = responseContext.Response; @@ -236,4 +197,41 @@ private string FetchRequestId(IRequestContext requestContext, IResponseContext r return request_id; } + + private Activity? ProcessBeginRequest(IExecutionContext executionContext) + { + var requestContext = executionContext.RequestContext; + var service = AWSServiceHelper.GetAWSServiceName(requestContext); + var operation = AWSServiceHelper.GetAWSOperationName(requestContext); + + Activity? activity = AWSSDKActivitySource.StartActivity(service + "." + operation, ActivityKind.Client); + + if (activity == null) + { + return null; + } + + if (this.options.SuppressDownstreamInstrumentation) + { + SuppressInstrumentationScope.Enter(); + } + + if (activity.IsAllDataRequested) + { + activity.SetTag(AWSSemanticConventions.AttributeAWSServiceName, service); + activity.SetTag(AWSSemanticConventions.AttributeAWSOperationName, operation); + var client = executionContext.RequestContext.ClientConfig; + if (client != null) + { + var region = client.RegionEndpoint?.SystemName; + activity.SetTag(AWSSemanticConventions.AttributeAWSRegion, region ?? AWSSDKUtils.DetermineRegion(client.ServiceURL)); + } + + AddRequestSpecificInformation(activity, requestContext, service); + } + + AwsPropagator.Inject(new PropagationContext(activity.Context, Baggage.Current), requestContext.Request.Headers, Setter); + + return activity; + } } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/Utils.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/Utils.cs index ff51298620..45f44990fa 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/Utils.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWS/Implementation/Utils.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -25,7 +26,7 @@ internal class Utils { foreach (KeyValuePair tag in activity.TagObjects) { - if (tag.Key.Equals(tagName)) + if (tag.Key.Equals(tagName, StringComparison.Ordinal)) { return tag.Value; } @@ -41,7 +42,7 @@ internal static string RemoveSuffix(string originalString, string suffix) return string.Empty; } - if (originalString.EndsWith(suffix)) + if (originalString.EndsWith(suffix, StringComparison.Ordinal)) { return originalString.Substring(0, originalString.Length - suffix.Length); } @@ -69,7 +70,7 @@ private static string RemovePrefix(string originalString, string prefix) return string.Empty; } - if (originalString.StartsWith(prefix)) + if (originalString.StartsWith(prefix, StringComparison.Ordinal)) { return originalString.Substring(prefix.Length); } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.AWS/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.AWS/TracerProviderBuilderExtensions.cs index 526d152eec..47063958d0 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.AWS/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.AWS/TracerProviderBuilderExtensions.cs @@ -41,7 +41,7 @@ public static TracerProviderBuilder AddAWSInstrumentation( var awsClientOptions = new AWSClientInstrumentationOptions(); configure?.Invoke(awsClientOptions); - new AWSClientsInstrumentation(awsClientOptions); + _ = new AWSClientsInstrumentation(awsClientOptions); builder.AddSource("Amazon.AWS.AWSClientInstrumentation"); return builder; } diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..7dc5c58110 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..bc0e2eeb73 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net462/PublicAPI.Unshipped.txt @@ -0,0 +1,20 @@ +abstract OpenTelemetry.Extensions.Enrichment.BaseEnricher.Enrich(T enrichmentBag) -> void +Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions +OpenTelemetry.Extensions.Enrichment.BaseEnricher +OpenTelemetry.Extensions.Enrichment.BaseEnricher.BaseEnricher() -> void +OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions +OpenTelemetry.Extensions.Enrichment.TraceEnricher +OpenTelemetry.Extensions.Enrichment.TraceEnricher.TraceEnricher() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.Add(string! key, object? value) -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag(System.Diagnostics.Activity! activity) -> void +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! enrichmentAction) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Func! enricherImplementationFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action! enrichmentAction) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Func! enricherImplementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder! +virtual OpenTelemetry.Extensions.Enrichment.TraceEnricher.Enrich(ref OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag traceEnrichmentBag) -> void diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..7dc5c58110 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..bc0e2eeb73 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/net6.0/PublicAPI.Unshipped.txt @@ -0,0 +1,20 @@ +abstract OpenTelemetry.Extensions.Enrichment.BaseEnricher.Enrich(T enrichmentBag) -> void +Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions +OpenTelemetry.Extensions.Enrichment.BaseEnricher +OpenTelemetry.Extensions.Enrichment.BaseEnricher.BaseEnricher() -> void +OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions +OpenTelemetry.Extensions.Enrichment.TraceEnricher +OpenTelemetry.Extensions.Enrichment.TraceEnricher.TraceEnricher() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.Add(string! key, object? value) -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag(System.Diagnostics.Activity! activity) -> void +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! enrichmentAction) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Func! enricherImplementationFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action! enrichmentAction) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Func! enricherImplementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder! +virtual OpenTelemetry.Extensions.Enrichment.TraceEnricher.Enrich(ref OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag traceEnrichmentBag) -> void diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..7dc5c58110 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..bc0e2eeb73 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -0,0 +1,20 @@ +abstract OpenTelemetry.Extensions.Enrichment.BaseEnricher.Enrich(T enrichmentBag) -> void +Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions +OpenTelemetry.Extensions.Enrichment.BaseEnricher +OpenTelemetry.Extensions.Enrichment.BaseEnricher.BaseEnricher() -> void +OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions +OpenTelemetry.Extensions.Enrichment.TraceEnricher +OpenTelemetry.Extensions.Enrichment.TraceEnricher.TraceEnricher() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.Add(string! key, object? value) -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag() -> void +OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag.TraceEnrichmentBag(System.Diagnostics.Activity! activity) -> void +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! enrichmentAction) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Func! enricherImplementationFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.OpenTelemetryEnrichmentServiceCollectionExtensions.AddTraceEnricher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, OpenTelemetry.Extensions.Enrichment.TraceEnricher! enricher) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Action! enrichmentAction) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder, System.Func! enricherImplementationFactory) -> OpenTelemetry.Trace.TracerProviderBuilder! +static OpenTelemetry.Extensions.Enrichment.OpenTelemetryEnrichmentProviderBuilderExtensions.AddTraceEnricher(this OpenTelemetry.Trace.TracerProviderBuilder! builder) -> OpenTelemetry.Trace.TracerProviderBuilder! +virtual OpenTelemetry.Extensions.Enrichment.TraceEnricher.Enrich(ref OpenTelemetry.Extensions.Enrichment.TraceEnrichmentBag traceEnrichmentBag) -> void diff --git a/src/OpenTelemetry.Extensions.Enrichment/BaseEnricher.cs b/src/OpenTelemetry.Extensions.Enrichment/BaseEnricher.cs new file mode 100644 index 0000000000..c1efec51a9 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/BaseEnricher.cs @@ -0,0 +1,26 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Extensions.Enrichment; + +public abstract class BaseEnricher +{ + protected BaseEnricher() + { + } + + public abstract void Enrich(T enrichmentBag); +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/CHANGELOG.md b/src/OpenTelemetry.Extensions.Enrichment/CHANGELOG.md new file mode 100644 index 0000000000..825c32f0d0 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/src/OpenTelemetry.Extensions.Enrichment/EnrichmentActions.cs b/src/OpenTelemetry.Extensions.Enrichment/EnrichmentActions.cs new file mode 100644 index 0000000000..c615155cd5 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/EnrichmentActions.cs @@ -0,0 +1,41 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenTelemetry.Extensions.Enrichment; + +#pragma warning disable CA1812 // Class is instantiated through dependency injection +internal sealed class EnrichmentActions : TraceEnricher +#pragma warning restore CA1812 // Class is instantiated through dependency injection +{ + private readonly Action[] actions; + + public EnrichmentActions(IEnumerable> actions) + { + this.actions = actions.ToArray(); + } + + public override void Enrich(TraceEnrichmentBag enrichmentBag) + { + for (int i = 0; i < this.actions.Length; i++) + { + this.actions[i].Invoke(enrichmentBag); + } + } +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetry.Extensions.Enrichment.csproj b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetry.Extensions.Enrichment.csproj new file mode 100644 index 0000000000..3b41bba5e1 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetry.Extensions.Enrichment.csproj @@ -0,0 +1,21 @@ + + + + $(NetFrameworkMinimumSupportedVersion);$(NetStandardMinimumSupportedVersion) + OpenTelemetry .NET SDK telemetry enrichment. + $(NoWarn),CS1591 + Extensions.Enrichment- + enable + latest-all + + + + + + + + + + + + diff --git a/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentProviderBuilderExtensions.cs b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentProviderBuilderExtensions.cs new file mode 100644 index 0000000000..e4c05b4ece --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentProviderBuilderExtensions.cs @@ -0,0 +1,105 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using Microsoft.Extensions.DependencyInjection; +using OpenTelemetry.Internal; +using OpenTelemetry.Trace; + +namespace OpenTelemetry.Extensions.Enrichment; + +/// +/// Extension methods to register telemery enrichers. +/// +public static class OpenTelemetryEnrichmentProviderBuilderExtensions +{ + /// + /// Adds trace enricher. + /// + /// being configured. + /// Enricher object type. + /// Thrown when the is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static TracerProviderBuilder AddTraceEnricher(this TracerProviderBuilder builder) + where T : TraceEnricher + { + Guard.ThrowIfNull(builder); + + return builder + .ConfigureServices(services => services.AddTraceEnricher()); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The object being added. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static TracerProviderBuilder AddTraceEnricher(this TracerProviderBuilder builder, TraceEnricher enricher) + { + Guard.ThrowIfNull(builder); + Guard.ThrowIfNull(enricher); + + return builder + .ConfigureServices(services => services.AddTraceEnricher(enricher)); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The delegate to enrich traces. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static TracerProviderBuilder AddTraceEnricher(this TracerProviderBuilder builder, Action enrichmentAction) + { + Guard.ThrowIfNull(builder); + Guard.ThrowIfNull(enrichmentAction); + + return builder + .ConfigureServices(services => services.AddTraceEnricher(enrichmentAction)); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The object being added using implementation factory. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static TracerProviderBuilder AddTraceEnricher(this TracerProviderBuilder builder, Func enricherImplementationFactory) + { + Guard.ThrowIfNull(builder); + Guard.ThrowIfNull(enricherImplementationFactory); + + return builder + .ConfigureServices(services => services + .AddTraceEnricher(enricherImplementationFactory)); + } +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentServiceCollectionExtensions.cs b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentServiceCollectionExtensions.cs new file mode 100644 index 0000000000..4738a2940e --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/OpenTelemetryEnrichmentServiceCollectionExtensions.cs @@ -0,0 +1,128 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Linq; +using Microsoft.Extensions.DependencyInjection.Extensions; +using OpenTelemetry.Extensions.Enrichment; +using OpenTelemetry.Internal; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extension methods to register telemery enrichers. +/// +public static class OpenTelemetryEnrichmentServiceCollectionExtensions +{ + /// + /// Adds trace enricher. + /// + /// being configured. + /// Enricher object type. + /// Thrown when the is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static IServiceCollection AddTraceEnricher(this IServiceCollection services) + where T : TraceEnricher + { + Guard.ThrowIfNull(services); + + return services + .TryAddEnrichment() + .AddSingleton(); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The object being added. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static IServiceCollection AddTraceEnricher(this IServiceCollection services, TraceEnricher enricher) + { + Guard.ThrowIfNull(services); + Guard.ThrowIfNull(enricher); + + return services + .TryAddEnrichment() + .AddSingleton(enricher); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The delegate to enrich traces. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static IServiceCollection AddTraceEnricher(this IServiceCollection services, Action enrichmentAction) + { + Guard.ThrowIfNull(services); + Guard.ThrowIfNull(enrichmentAction); + + services.TryAddSingleton(); + + return services + .TryAddEnrichment() + .AddSingleton(enrichmentAction); + } + + /// + /// Adds trace enricher. + /// + /// being configured. + /// The object being added using implementation factory. + /// Thrown when the or is . + /// The instance of to chain the calls. + /// + /// Add this enricher *before* exporter related Activity processors. + /// + public static IServiceCollection AddTraceEnricher(this IServiceCollection services, Func enricherImplementationFactory) + { + Guard.ThrowIfNull(services); + Guard.ThrowIfNull(enricherImplementationFactory); + + return services + .TryAddEnrichment() + .AddSingleton((serviceProvider) => enricherImplementationFactory(serviceProvider)); + } + + private static IServiceCollection TryAddEnrichment(this IServiceCollection services) + { + if (!services.Any(x => x.ServiceType == typeof(TraceEnrichmentProcessor))) + { + services + .AddSingleton() + .ConfigureOpenTelemetryTracerProvider((sp, builder) => + { + var proc = sp.GetRequiredService(); + builder.AddProcessor(proc); + }); + } + + return services; + } +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/README.md b/src/OpenTelemetry.Extensions.Enrichment/README.md new file mode 100644 index 0000000000..6a8ed5095c --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/README.md @@ -0,0 +1,11 @@ +# OpenTelemetry .NET SDK telemetry enrichment framework + +[![nuget](https://img.shields.io/nuget/v/OpenTelemetry.Extensions.Enrichment.svg)](https://www.nuget.org/packages/OpenTelemetry.Extensions.Enrichment) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Extensions.Enrichment.svg)](https://www.nuget.org/packages/OpenTelemetry.Extensions.Enrichment) + +Contains OpenTelemetry .NET SDK telemetry enrichment framework +which is used for enrichment of traces. + +## Traces + +TBD diff --git a/src/OpenTelemetry.Extensions.Enrichment/TraceEnricher.cs b/src/OpenTelemetry.Extensions.Enrichment/TraceEnricher.cs new file mode 100644 index 0000000000..bbd6b2445b --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/TraceEnricher.cs @@ -0,0 +1,31 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; + +namespace OpenTelemetry.Extensions.Enrichment; + +public abstract class TraceEnricher : BaseEnricher +{ + protected TraceEnricher() + { + } + + public virtual void Enrich(ref TraceEnrichmentBag traceEnrichmentBag) + { + throw new NotImplementedException(); + } +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentBag.cs b/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentBag.cs new file mode 100644 index 0000000000..2b01eaadd9 --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentBag.cs @@ -0,0 +1,36 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Diagnostics; + +namespace OpenTelemetry.Extensions.Enrichment; + +#pragma warning disable CA1815 // Override equals and operator equals on value types +public readonly struct TraceEnrichmentBag +#pragma warning restore CA1815 // Override equals and operator equals on value types +{ + private readonly Activity activity; + + public TraceEnrichmentBag(Activity activity) + { + this.activity = activity; + } + + public void Add(string key, object? value) + { + this.activity.SetTag(key, value); + } +} diff --git a/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentProcessor.cs b/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentProcessor.cs new file mode 100644 index 0000000000..5dc9628baa --- /dev/null +++ b/src/OpenTelemetry.Extensions.Enrichment/TraceEnrichmentProcessor.cs @@ -0,0 +1,43 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace OpenTelemetry.Extensions.Enrichment; + +#pragma warning disable CA1812 // Class is instantiated through dependency injection +internal sealed class TraceEnrichmentProcessor : BaseProcessor +#pragma warning restore CA1812 // Class is instantiated through dependency injection +{ + private readonly TraceEnricher[] traceEnrichers; + + public TraceEnrichmentProcessor(IEnumerable traceEnrichers) + { + this.traceEnrichers = traceEnrichers.ToArray(); + } + + public override void OnEnd(Activity activity) + { + var propertyBag = new TraceEnrichmentBag(activity); + + foreach (var enricher in this.traceEnrichers) + { + enricher.Enrich(propertyBag); + } + } +} diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 0288dcace5..e1de3a6e74 100644 --- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -8,4 +8,5 @@ OpenTelemetry.Instrumentation.EntityFrameworkCore.EntityFrameworkInstrumentation OpenTelemetry.Instrumentation.EntityFrameworkCore.EntityFrameworkInstrumentationOptions.EnrichWithIDbCommand.set -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddEntityFrameworkCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddEntityFrameworkCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddEntityFrameworkCoreInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action configure) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/CHANGELOG.md index 0932c9f920..a10413b0cd 100644 --- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +* Added overloads which accept a name to the `TracerProviderBuilder` + `EntityFrameworkInstrumentationOptions` extension to allow for more fine-grained + options management + ([#1020](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1020)) + ## 1.0.0-beta.5 Released 2023-Feb-27 diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/OpenTelemetry.Instrumentation.EntityFrameworkCore.csproj b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/OpenTelemetry.Instrumentation.EntityFrameworkCore.csproj index b5ac491519..7cb47060c4 100644 --- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/OpenTelemetry.Instrumentation.EntityFrameworkCore.csproj +++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/OpenTelemetry.Instrumentation.EntityFrameworkCore.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 Microsoft.EntityFrameworkCore instrumentation for OpenTelemetry .NET @@ -8,7 +8,8 @@ - + + diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/README.md b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/README.md index 00a9ef753b..48a3cd970b 100644 --- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/README.md +++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/README.md @@ -3,13 +3,113 @@ [![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Instrumentation.EntityFrameworkCore.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EntityFrameworkCore) [![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Instrumentation.EntityFrameworkCore.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EntityFrameworkCore) -Automatically instruments the outgoing database requests from -[Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore). +This is an [Instrumentation +Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), +which instruments +[Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) +and collects traces about outgoing requests. -## Installation +**Note: This component is based on the OpenTelemetry semantic conventions for +[metrics](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/metrics/semantic_conventions) +and +[traces](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/trace/semantic_conventions). +These conventions are +[Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/document-status.md), +and hence, this package is a +[pre-release](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/VERSIONING.md#pre-releases). +Until a [stable +version](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/telemetry-stability.md) +is released, there can be [breaking changes](./CHANGELOG.md). You can track the +progress from +[milestones](https://github.com/open-telemetry/opentelemetry-dotnet/milestone/23).** + +## Steps to enable OpenTelemetry.Instrumentation.EntityFrameworkCore + +### Step 1: Install Package + +Add a reference to the +[`OpenTelemetry.Instrumentation.EntityFrameworkCore`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EntityFrameworkCore) +package. Also, add any other instrumentations & exporters you will need. ```shell -dotnet add package OpenTelemetry.Instrumentation.EntityFrameworkCore +dotnet add package --prerelease OpenTelemetry.Instrumentation.EntityFrameworkCore +``` + +### Step 2: Enable EntityFrameworkCore Instrumentation at application startup + +`EntityFrameworkCore` instrumentation must be enabled at application startup. + +The following example demonstrates adding `EntityFrameworkCore` +instrumentation to a console application. This example also sets up the +OpenTelemetry Console exporter, which requires adding the package +[`OpenTelemetry.Exporter.Console`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Console/README.md) +to the application. + +```csharp +using OpenTelemetry; +using OpenTelemetry.Trace; +public class Program +{ + public static void Main(string[] args) + { + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddEntityFrameworkCoreInstrumentation() + .AddConsoleExporter() + .Build(); + } +} +``` + +For an ASP.NET Core application, adding instrumentation is typically done in +the `ConfigureServices` of your `Startup` class. Refer to documentation for +[OpenTelemetry.Instrumentation.AspNetCore](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Instrumentation.AspNetCore/README.md). + +For an ASP.NET application, adding instrumentation is typically done in the +`Global.asax.cs`. Refer to the documentation for +[OpenTelemetry.Instrumentation.AspNet](../OpenTelemetry.Instrumentation.AspNet/README.md). + +## Advanced configuration + +This instrumentation can be configured to change the default behavior by using +`EntityFrameworkInstrumentationOptions`. + +```csharp +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddEntityFrameworkCoreInstrumentation(options => + { + options.EnrichWithIDbCommand = (activity, command) => + { + var stateDisplayName = $"{command.CommandType} main"; + activity.DisplayName = stateDisplayName; + activity.SetTag("db.name", stateDisplayName); + }; + }) + .AddConsoleExporter()); +``` + +When used with +[`OpenTelemetry.Extensions.Hosting`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Extensions.Hosting/README.md), +all configurations to `EntityFrameworkInstrumentationOptions` +can be done in the `ConfigureServices` method of you applications `Startup` +class as shown below. + +```csharp +// Configure +services.Configure(options => +{ + options.EnrichWithIDbCommand = (activity, command) => + { + var stateDisplayName = $"{command.CommandType} main"; + activity.DisplayName = stateDisplayName; + activity.SetTag("db.name", stateDisplayName); + }; +}); + +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddEntityFrameworkCoreInstrumentation() + .AddConsoleExporter()); ``` ## References diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/TracerProviderBuilderExtensions.cs index 8aa9e3d6c1..2240cb090c 100644 --- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/TracerProviderBuilderExtensions.cs @@ -15,6 +15,8 @@ // using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenTelemetry.Instrumentation.EntityFrameworkCore; using OpenTelemetry.Instrumentation.EntityFrameworkCore.Implementation; using OpenTelemetry.Internal; @@ -32,7 +34,8 @@ public static class TracerProviderBuilderExtensions /// being configured. /// The instance of to chain the calls. public static TracerProviderBuilder AddEntityFrameworkCoreInstrumentation( - this TracerProviderBuilder builder) => AddEntityFrameworkCoreInstrumentation(builder, configure: null); + this TracerProviderBuilder builder) => + AddEntityFrameworkCoreInstrumentation(builder, name: null, configure: null); /// /// Enables Microsoft.EntityFrameworkCore instrumentation. @@ -42,14 +45,35 @@ public static TracerProviderBuilder AddEntityFrameworkCoreInstrumentation( /// The instance of to chain the calls. public static TracerProviderBuilder AddEntityFrameworkCoreInstrumentation( this TracerProviderBuilder builder, + Action configure) => + AddEntityFrameworkCoreInstrumentation(builder, name: null, configure); + + /// + /// Enables Microsoft.EntityFrameworkCore instrumentation. + /// + /// being configured. + /// Name which is used when retrieving options. + /// EntityFrameworkCore configuration options. + /// The instance of to chain the calls. + public static TracerProviderBuilder AddEntityFrameworkCoreInstrumentation( + this TracerProviderBuilder builder, + string name, Action configure) { Guard.ThrowIfNull(builder); - var options = new EntityFrameworkInstrumentationOptions(); - configure?.Invoke(options); + name ??= Options.DefaultName; + + if (configure != null) + { + builder.ConfigureServices(services => services.Configure(name, configure)); + } - builder.AddInstrumentation(() => new EntityFrameworkInstrumentation(options)); + builder.AddInstrumentation(sp => + { + var options = sp.GetRequiredService>().Get(name); + return new EntityFrameworkInstrumentation(options); + }); builder.AddSource(EntityFrameworkDiagnosticListener.ActivitySourceName); diff --git a/src/OpenTelemetry.Internal/IsExternalInit.cs b/src/OpenTelemetry.Internal/IsExternalInit.cs index de19a976dd..c0809ffb0e 100644 --- a/src/OpenTelemetry.Internal/IsExternalInit.cs +++ b/src/OpenTelemetry.Internal/IsExternalInit.cs @@ -15,11 +15,10 @@ // #if NETFRAMEWORK || NETSTANDARD2_0_OR_GREATER -namespace System.Runtime.CompilerServices +namespace System.Runtime.CompilerServices; + +// This enabled "init" keyword in net462 + netstandard2.0 targets. +internal static class IsExternalInit { - // This enabled "init" keyword in net462 + netstandard2.0 targets. - internal sealed class IsExternalInit - { - } } #endif diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEBSResourceDetector.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEBSResourceDetector.cs index 1b3df6c3e8..47d2587ecc 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEBSResourceDetector.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEBSResourceDetector.cs @@ -37,10 +37,9 @@ public void TestDetect() [Fact] public void TestExtractResourceAttributes() { - var ebsResourceDetector = new AWSEBSResourceDetector(); var sampleModel = new SampleAWSEBSMetadataModel(); - var resourceAttributes = ebsResourceDetector.ExtractResourceAttributes(sampleModel).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSEBSResourceDetector.ExtractResourceAttributes(sampleModel).ToDictionary(x => x.Key, x => x.Value); Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); Assert.Equal("aws_elastic_beanstalk", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); @@ -53,8 +52,7 @@ public void TestExtractResourceAttributes() [Fact] public void TestGetEBSMetadata() { - var ebsResourceDetector = new AWSEBSResourceDetector(); - var ebsMetadata = ebsResourceDetector.GetEBSMetadata(AWSEBSMetadataFilePath); + var ebsMetadata = AWSEBSResourceDetector.GetEBSMetadata(AWSEBSMetadataFilePath); Assert.NotNull(ebsMetadata); Assert.Equal("1234567890", ebsMetadata.DeploymentId); diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEC2ResourceDetector.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEC2ResourceDetector.cs index 8fff5c438c..23a7ebea8b 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEC2ResourceDetector.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEC2ResourceDetector.cs @@ -35,10 +35,9 @@ public void TestDetect() [Fact] public void TestExtractResourceAttributes() { - var ec2ResourceDetector = new AWSEC2ResourceDetector(); var sampleEC2IdentityDocumentModel = new SampleAWSEC2IdentityDocumentModel(); var hostName = "Test host name"; - var resourceAttributes = ec2ResourceDetector.ExtractResourceAttributes(sampleEC2IdentityDocumentModel, hostName).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSEC2ResourceDetector.ExtractResourceAttributes(sampleEC2IdentityDocumentModel, hostName).ToDictionary(x => x.Key, x => x.Value); Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); Assert.Equal("aws_ec2", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); @@ -55,9 +54,7 @@ public void TestDeserializeResponse() { var ec2IdentityDocument = "{\"accountId\": \"123456789012\", \"architecture\": \"x86_64\", \"availabilityZone\": \"us-east-1a\", \"billingProducts\": null, \"devpayProductCodes\": null, \"marketplaceProductCodes\": null, \"imageId\": \"ami-12345678901234567\", \"instanceId\": \"i-12345678901234567\", \"instanceType\": \"t2.micro\", \"kernelId\": null, \"pendingTime\": \"2021-08-11T22:41:54Z\", \"privateIp\": \"123.456.789.123\", \"ramdiskId\": null, \"region\": \"us-east-1\", \"version\": \"2021-08-11\"}"; - var ec2ResourceDetector = new AWSEC2ResourceDetector(); - - var ec2IdentityDocumentModel = ec2ResourceDetector.DeserializeResponse(ec2IdentityDocument); + var ec2IdentityDocumentModel = AWSEC2ResourceDetector.DeserializeResponse(ec2IdentityDocument); Assert.NotNull(ec2IdentityDocumentModel); Assert.Equal("123456789012", ec2IdentityDocumentModel.AccountId); diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSECSResourceDetector.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSECSResourceDetector.cs index 73223bb2a7..daf37dabda 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSECSResourceDetector.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSECSResourceDetector.cs @@ -40,10 +40,9 @@ public void TestDetect() [Fact] public void TestExtractResourceAttributes() { - var ecsResourceDetector = new AWSECSResourceDetector(); var containerId = "Test container id"; - var resourceAttributes = ecsResourceDetector.ExtractResourceAttributes(containerId).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSECSResourceDetector.ExtractResourceAttributes(containerId).ToDictionary(x => x.Key, x => x.Value); Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); Assert.Equal("aws_ecs", resourceAttributes[AWSSemanticConventions.AttributeCloudPlatform]); @@ -53,8 +52,7 @@ public void TestExtractResourceAttributes() [Fact] public void TestGetECSContainerId() { - var ecsResourceDetector = new AWSECSResourceDetector(); - var ecsContainerId = ecsResourceDetector.GetECSContainerId(AWSECSMetadataFilePath); + var ecsContainerId = AWSECSResourceDetector.GetECSContainerId(AWSECSMetadataFilePath); Assert.Equal("a4d00c9dd675d67f866c786181419e1b44832d4696780152e61afd44a3e02856", ecsContainerId); } @@ -65,8 +63,7 @@ public void TestIsECSProcess() Environment.SetEnvironmentVariable(AWSECSMetadataURLKey, "TestECSURIKey"); Environment.SetEnvironmentVariable(AWSECSMetadataURLV4Key, "TestECSURIV4Key"); - var ecsResourceDetector = new AWSECSResourceDetector(); - var isEcsProcess = ecsResourceDetector.IsECSProcess(); + var isEcsProcess = AWSECSResourceDetector.IsECSProcess(); Assert.True(isEcsProcess); } @@ -74,8 +71,7 @@ public void TestIsECSProcess() [Fact] public void TestIsNotECSProcess() { - var ecsResourceDetector = new AWSECSResourceDetector(); - var isEcsProcess = ecsResourceDetector.IsECSProcess(); + var isEcsProcess = AWSECSResourceDetector.IsECSProcess(); Assert.False(isEcsProcess); } diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs index d7689835be..bae0540d8f 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Resources/TestAWSEKSResourceDetector.cs @@ -38,11 +38,10 @@ public void TestDetect() [Fact] public void TestExtractResourceAttributes() { - var eksResourceDetector = new AWSEKSResourceDetector(); var clusterName = "Test cluster name"; var containerId = "Test container id"; - var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(clusterName, containerId).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSEKSResourceDetector.ExtractResourceAttributes(clusterName, containerId).ToDictionary(x => x.Key, x => x.Value); Assert.Equal(4, resourceAttributes.Count); Assert.Equal("aws", resourceAttributes[AWSSemanticConventions.AttributeCloudProvider]); @@ -54,10 +53,9 @@ public void TestExtractResourceAttributes() [Fact] public void TestExtractResourceAttributesWithEmptyClusterName() { - var eksResourceDetector = new AWSEKSResourceDetector(); var containerId = "Test container id"; - var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(string.Empty, containerId).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSEKSResourceDetector.ExtractResourceAttributes(string.Empty, containerId).ToDictionary(x => x.Key, x => x.Value); // Validate the count of resourceAttributes -> Excluding cluster name, there will be only three resourceAttributes Assert.Equal(3, resourceAttributes.Count); @@ -69,10 +67,9 @@ public void TestExtractResourceAttributesWithEmptyClusterName() [Fact] public void TestExtractResourceAttributesWithEmptyContainerId() { - var eksResourceDetector = new AWSEKSResourceDetector(); var clusterName = "Test cluster name"; - var resourceAttributes = eksResourceDetector.ExtractResourceAttributes(clusterName, string.Empty).ToDictionary(x => x.Key, x => x.Value); + var resourceAttributes = AWSEKSResourceDetector.ExtractResourceAttributes(clusterName, string.Empty).ToDictionary(x => x.Key, x => x.Value); // Validate the count of resourceAttributes -> Excluding container id, there will be only three resourceAttributes Assert.Equal(3, resourceAttributes.Count); @@ -84,8 +81,7 @@ public void TestExtractResourceAttributesWithEmptyContainerId() [Fact] public void TestGetEKSCredentials() { - var eksResourceDetector = new AWSEKSResourceDetector(); - var eksCredentials = eksResourceDetector.GetEKSCredentials(AWSEKSCredentialsPath); + var eksCredentials = AWSEKSResourceDetector.GetEKSCredentials(AWSEKSCredentialsPath); Assert.Equal("Bearer Test AWS EKS Token", eksCredentials); } @@ -93,8 +89,7 @@ public void TestGetEKSCredentials() [Fact] public void TestGetEKSContainerId() { - var eksResourceDetector = new AWSEKSResourceDetector(); - var eksContainerId = eksResourceDetector.GetEKSContainerId(AWSEKSMetadataFilePath); + var eksContainerId = AWSEKSResourceDetector.GetEKSContainerId(AWSEKSMetadataFilePath); Assert.Equal("a4d00c9dd675d67f866c786181419e1b44832d4696780152e61afd44a3e02856", eksContainerId); } @@ -104,8 +99,7 @@ public void TestDeserializeResponse() { var awsEKSClusterInformation = "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": {\"name\": \"cluster-info\", \"namespace\": \"amazon-cloudwatch\", \"selfLink\": \"/api/v1/namespaces/amazon-cloudwatch/configmaps/cluster-info\", \"uid\": \"0734438c-48f4-45c3-b06d-b6f16f7f0e1e\", \"resourceVersion\": \"25911\", \"creationTimestamp\": \"2021-07-23T18:41:56Z\", \"annotations\": {\"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"data\\\":{\\\"cluster.name\\\":\\\"Test\\\",\\\"logs.region\\\":\\\"us-west-2\\\"},\\\"kind\\\":\\\"ConfigMap\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"name\\\":\\\"cluster-info\\\",\\\"namespace\\\":\\\"amazon-cloudwatch\\\"}}\\n\"}}, \"data\": {\"cluster.name\": \"Test\", \"logs.region\": \"us-west-2\"}}"; - var eksResourceDetector = new AWSEKSResourceDetector(); - var eksClusterInformation = eksResourceDetector.DeserializeResponse(awsEKSClusterInformation); + var eksClusterInformation = AWSEKSResourceDetector.DeserializeResponse(awsEKSClusterInformation); Assert.NotNull(eksClusterInformation); Assert.NotNull(eksClusterInformation.Data); diff --git a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Trace/TestAWSXRayPropagator.cs b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Trace/TestAWSXRayPropagator.cs index a3d4f8f80e..a314b89850 100644 --- a/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Trace/TestAWSXRayPropagator.cs +++ b/test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/Trace/TestAWSXRayPropagator.cs @@ -29,7 +29,12 @@ public class TestAWSXRayPropagator private const string TraceId = "5759e988bd862e3fe1be46a994272793"; private const string ParentId = "53995c3f42cd8ad8"; +#if NETFRAMEWORK private static readonly string[] Empty = new string[0]; +#else + private static readonly string[] Empty = Array.Empty(); +#endif + private static readonly Func, string, IEnumerable> Getter = (headers, name) => { if (headers.TryGetValue(name, out var value)) diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/HttpResponseMessageBody.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/HttpResponseMessageBody.cs index 65edbf905b..80f6d26bfa 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/HttpResponseMessageBody.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/HttpResponseMessageBody.cs @@ -26,8 +26,8 @@ internal class HttpResponseMessageBody : IHttpResponseBody { private HttpClient? httpClient; private HttpResponseMessage response; - private bool disposeClient = false; - private bool disposed = false; + private bool disposeClient; + private bool disposed; public HttpResponseMessageBody(HttpResponseMessage response, HttpClient? httpClient, bool disposeClient) { diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockHttpRequest.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockHttpRequest.cs index d253897b8b..a6229f8d29 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockHttpRequest.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockHttpRequest.cs @@ -32,7 +32,7 @@ namespace OpenTelemetry.Contrib.Instrumentation.AWS.Tests; #if NET452 internal class MockHttpRequest : IHttpRequest { - private Stream? requestStream = null; + private Stream? requestStream; public MockHttpRequest(Uri requestUri, Action? action, Func? responseCreator = null) { diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockWebResponse.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockWebResponse.cs index cad99085df..326bdfa0f8 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockWebResponse.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/MockWebResponse.cs @@ -19,7 +19,6 @@ #if NET452 using System.IO; #endif -using System.Linq; using System.Net; #if !NET452 using System.Net.Http; @@ -130,30 +129,30 @@ public static HttpResponse ParseRawReponse(string rawResponse) var responseLines = rawResponse.Split('\n'); - if (responseLines.Count() == 0) + if (responseLines.Length == 0) { throw new ArgumentException( "The resource does not contain a valid HTTP response.", - "resourceName"); + nameof(rawResponse)); } response.StatusLine = responseLines[0]; var currentLine = responseLines[0]; - var statusCode = ParseStatusCode(currentLine); + _ = ParseStatusCode(currentLine); - var lineIndex = 0; - if (responseLines.Count() > 1) + int lineIndex; + if (responseLines.Length > 1) { - for (lineIndex = 1; lineIndex < responseLines.Count(); lineIndex++) + for (lineIndex = 1; lineIndex < responseLines.Length; lineIndex++) { currentLine = responseLines[lineIndex]; - if (currentLine.Trim() == string.Empty) + if (string.IsNullOrEmpty(currentLine.Trim())) { currentLine = responseLines[lineIndex - 1]; break; } - var index = currentLine.IndexOf(":"); + var index = currentLine.IndexOf(":", StringComparison.Ordinal); if (index != -1) { var headerKey = currentLine.Substring(0, index); @@ -163,17 +162,16 @@ public static HttpResponse ParseRawReponse(string rawResponse) } } - var startOfBody = rawResponse.IndexOf(currentLine) + currentLine.Length; + var startOfBody = rawResponse.IndexOf(currentLine, StringComparison.Ordinal) + currentLine.Length; response.Body = rawResponse.Substring(startOfBody).Trim(); return response; } private static HttpStatusCode ParseStatusCode(string? statusLine) { - var statusCode = string.Empty; try { - statusCode = (statusLine ?? string.Empty).Split(' ')[1]; + string statusCode = statusLine?.Split(' ')[1] ?? string.Empty; return (HttpStatusCode)Enum.Parse(typeof(HttpStatusCode), statusCode); } catch (Exception exception) diff --git a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/Utils.cs b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/Utils.cs index 211e7242fa..6f060b217d 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/Utils.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.AWS.Tests/Tools/Utils.cs @@ -59,7 +59,9 @@ public static string GetResourceText(string resourceName) public static string FindResourceName(string partialName) { +#pragma warning disable CA2249 // Consider using 'string.Contains' instead of 'string.IndexOf' return FindResourceName(s => s.IndexOf(partialName, StringComparison.OrdinalIgnoreCase) >= 0).SingleOrDefault(); +#pragma warning restore CA2249 // Consider using 'string.Contains' instead of 'string.IndexOf' } public static IEnumerable FindResourceName(Predicate match) diff --git a/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher.cs b/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher.cs new file mode 100644 index 0000000000..c225b38b9d --- /dev/null +++ b/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher.cs @@ -0,0 +1,29 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Extensions.Enrichment.Tests; + +internal class MyTraceEnricher : TraceEnricher +{ + public const string Key = nameof(MyTraceEnricher); + + public int TimesCalled { get; private set; } + + public override void Enrich(TraceEnrichmentBag enrichmentBag) + { + enrichmentBag.Add(Key, ++this.TimesCalled); + } +} diff --git a/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher2.cs b/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher2.cs new file mode 100644 index 0000000000..8631f2f6bf --- /dev/null +++ b/test/OpenTelemetry.Extensions.Enrichment.Tests/MyTraceEnricher2.cs @@ -0,0 +1,29 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Extensions.Enrichment.Tests; + +internal class MyTraceEnricher2 : TraceEnricher +{ + public const string Key = nameof(MyTraceEnricher2); + + public int TimesCalled { get; private set; } + + public override void Enrich(TraceEnrichmentBag enrichmentBag) + { + enrichmentBag.Add(Key, ++this.TimesCalled); + } +} diff --git a/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetry.Extensions.Enrichment.Tests.csproj b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetry.Extensions.Enrichment.Tests.csproj new file mode 100644 index 0000000000..48538d1d58 --- /dev/null +++ b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetry.Extensions.Enrichment.Tests.csproj @@ -0,0 +1,29 @@ + + + + Unit test project for OpenTelemetry .NET SDK telemetry enrichment. + + $(NetFrameworkMinimumSupportedVersion) + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + + + + + + diff --git a/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentProviderBuilderExtensions.cs b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentProviderBuilderExtensions.cs new file mode 100644 index 0000000000..032105b732 --- /dev/null +++ b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentProviderBuilderExtensions.cs @@ -0,0 +1,148 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Extensions.Enrichment.Tests; + +public sealed class OpenTelemetryEnrichmentProviderBuilderExtensions +{ + private const string SourceName = nameof(OpenTelemetryEnrichmentProviderBuilderExtensions); + + [Fact] + public void AddTraceEnricherOfTRegistersEnricher() + { + var exportedItems = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource(SourceName) + .AddTraceEnricher() + .AddTraceEnricher() + .AddInMemoryExporter(exportedItems) + .Build(); + + using var source = new ActivitySource(SourceName); + using (var activity = source.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + } + + [Fact] + public void AddTraceEnricherRegistersEnricher() + { + var exportedItems = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource(SourceName) + .AddTraceEnricher(new MyTraceEnricher()) + .AddTraceEnricher(new MyTraceEnricher2()) + .AddInMemoryExporter(exportedItems) + .Build(); + + using var source1 = new ActivitySource(SourceName); + + using (var activity = source1.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + } + + [Fact] + public void AddTraceEnricherActionRegistersEnricher() + { + var exportedItems = new List(); + + const string testKey1 = "key1"; + const string testValue1 = "value1"; + const string testKey2 = "key2"; + const string testValue2 = "value2"; + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource(SourceName) + .AddTraceEnricher(bag => bag.Add(testKey1, testValue1)) + .AddTraceEnricher(bag => bag.Add(testKey2, testValue2)) + .AddInMemoryExporter(exportedItems) + .Build(); + + using var source1 = new ActivitySource(SourceName); + + using (var activity = source1.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == testKey1); + Assert.Equal(testValue1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == testKey2); + Assert.Equal(testValue2, tagObject2.Single().Value); + } + } + + [Fact] + public void AddTraceEnricherFactoryRegistersEnricher() + { + var exportedItems = new List(); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource(SourceName) + .AddTraceEnricher(sp => new MyTraceEnricher()) + .AddTraceEnricher(sp => new MyTraceEnricher2()) + .AddInMemoryExporter(exportedItems) + .Build(); + + using var source1 = new ActivitySource(SourceName); + + using (var activity = source1.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + } +} diff --git a/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentServiceCollectionExtensionsTests.cs b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentServiceCollectionExtensionsTests.cs new file mode 100644 index 0000000000..96b4ac80d5 --- /dev/null +++ b/test/OpenTelemetry.Extensions.Enrichment.Tests/OpenTelemetryEnrichmentServiceCollectionExtensionsTests.cs @@ -0,0 +1,194 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Extensions.Enrichment.Tests; + +public sealed class OpenTelemetryEnrichmentServiceCollectionExtensionsTests +{ + private const string SourceName = nameof(OpenTelemetryEnrichmentServiceCollectionExtensionsTests); + + [Fact] + public async Task AddTraceEnricherOfTRegistersEnricher() + { + var exportedItems = new List(); + + using var host = Host.CreateDefaultBuilder() + .ConfigureServices(services => services + .AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource(SourceName) + .AddInMemoryExporter(exportedItems)) + .Services + .AddTraceEnricher() + .AddTraceEnricher()) + .Build(); + + await host.StartAsync().ConfigureAwait(false); + + var enrichers = host.Services.GetServices().ToArray(); + Assert.NotNull(enrichers); + Assert.Equal(2, enrichers.Length); + + using var source = new ActivitySource(SourceName); + using (var activity = source.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Equal(1, (enrichers[0] as MyTraceEnricher).TimesCalled); + Assert.Equal(1, (enrichers[1] as MyTraceEnricher2).TimesCalled); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + + await host.StopAsync().ConfigureAwait(false); + } + + [Fact] + public async Task AddTraceEnricherRegistersEnricher() + { + var exportedItems = new List(); + + using var host = Host.CreateDefaultBuilder() + .ConfigureServices(services => services + .AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource(SourceName) + .AddInMemoryExporter(exportedItems)) + .Services + .AddTraceEnricher(new MyTraceEnricher()) + .AddTraceEnricher(new MyTraceEnricher2())) + .Build(); + + await host.StartAsync().ConfigureAwait(false); + + var enrichers = host.Services.GetServices().ToArray(); + Assert.NotNull(enrichers); + Assert.Equal(2, enrichers.Length); + + using var source = new ActivitySource(SourceName); + using (var activity = source.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + + await host.StopAsync().ConfigureAwait(false); + } + + [Fact] + public async Task AddTraceEnricherActionRegistersEnricher() + { + var exportedItems = new List(); + + const string testKey1 = "key1"; + const string testValue1 = "value1"; + const string testKey2 = "key2"; + const string testValue2 = "value2"; + + using var host = Host.CreateDefaultBuilder() + .ConfigureServices(services => services + .AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource(SourceName) + .AddInMemoryExporter(exportedItems)) + .Services + .AddTraceEnricher(bag => bag.Add(testKey1, testValue1)) + .AddTraceEnricher(bag => bag.Add(testKey2, testValue2))) + .Build(); + + await host.StartAsync().ConfigureAwait(false); + + using var source1 = new ActivitySource(SourceName); + + using (var activity = source1.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == testKey1); + Assert.Equal(testValue1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == testKey2); + Assert.Equal(testValue2, tagObject2.Single().Value); + } + } + + [Fact] + public async Task AddTraceEnricherFactoryRegistersEnricher() + { + var exportedItems = new List(); + + using var host = Host.CreateDefaultBuilder() + .ConfigureServices(services => services + .AddOpenTelemetry() + .WithTracing(builder => builder + .AddSource(SourceName) + .AddInMemoryExporter(exportedItems)) + .Services + .AddTraceEnricher(sp => new MyTraceEnricher()) + .AddTraceEnricher(sp => new MyTraceEnricher2())) + .Build(); + + await host.StartAsync().ConfigureAwait(false); + + var enrichers = host.Services.GetServices().ToArray(); + Assert.NotNull(enrichers); + Assert.Equal(2, enrichers.Length); + + using var source = new ActivitySource(SourceName); + using (var activity = source.StartActivity(SourceName)) + { + activity.Stop(); + + Assert.Single(exportedItems); + + var tagObjects = exportedItems[0].TagObjects; + var tagObject1 = tagObjects.Where(tag => tag.Key == MyTraceEnricher.Key); + Assert.Equal(1, tagObject1.Single().Value); + + var tagObject2 = tagObjects.Where(tag => tag.Key == MyTraceEnricher2.Key); + Assert.Equal(1, tagObject2.Single().Value); + } + + await host.StopAsync().ConfigureAwait(false); + } +} diff --git a/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/DependencyInjectionConfigTests.cs b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/DependencyInjectionConfigTests.cs new file mode 100644 index 0000000000..2832d20da8 --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/DependencyInjectionConfigTests.cs @@ -0,0 +1,65 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests; + +public class DependencyInjectionConfigTests +{ + [Theory] + [InlineData(null)] + [InlineData("CustomName")] + public async Task TestTracingOptionsDiConfig(string name) + { + bool optionsPickedFromDi = false; + + var services = new ServiceCollection(); + + services + .Configure(name, _ => optionsPickedFromDi = true) + .AddOpenTelemetry() + .WithTracing(builder => + builder.AddEntityFrameworkCoreInstrumentation(name, configure: null)); + + var sp = services.BuildServiceProvider(); + + try + { + foreach (var hostedService in sp.GetServices()) + { + await hostedService.StartAsync(CancellationToken.None); + } + + Assert.True(optionsPickedFromDi); + } + finally + { + foreach (var hostedService in sp.GetServices().Reverse()) + { + await hostedService.StopAsync(CancellationToken.None); + } + + await sp.DisposeAsync(); + } + } +} diff --git a/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests.csproj b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests.csproj index f7d381ba8e..d98e5a9248 100644 --- a/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests.csproj @@ -29,7 +29,7 @@ - +