From 74d81fd710a0efb98fcc444e78deaced530dc224 Mon Sep 17 00:00:00 2001 From: Andrew Lock Date: Mon, 29 Mar 2021 10:30:19 +0100 Subject: [PATCH 1/2] Add a consolidated multi-stage pipeline (#1320) * Baby steps for quote-unquote ultimate pipeline. Managed unit tests first * Use an install-dotnet pipeline to simplify dotnet installation. Test usage on the managed pools first before trying to use on arm64 unit test job * Add install-dotnet template to build step * Remove parameter from install-dotnet.yml * Fix indentation in ultimate-pipeline.yml * Add no build argument to the unit test runs * Build the windows profiler after running the managed build * Run the windows native unit tests on the same machine for x86 and x64 * Set buildConfiguration to Release. Remove --no-build argument on unit tests for now * Use one Datadog.Trace.proj per build step. For build_managed, that is BuildCsharp. For unit_tests_managed, that is BuildCsharpTests. * Add --no-build argument to dotnet pack. This means we'll build our binaries once for the BuildCsharp target and then pack the result of that * Update publish command in build_managed job * Add succeededOrFailed condition to native unit tests * Fix native test that only throws after my pipeline changes * Attempt to fix managed unit tests * Try and get Windows build running * Small native unit test fix * Add the alpine and linux profiler * Combine managed and native unit tests into same build stage * Publish linux packages from source build * Modify intermediate artifacts to more clearly identify some artifacts as build-only * Attempt to add benchmarks stage with "condition: true" so that, if it works, we can disable it until it's needed * Modify build and windows build to make it easier to build without passing custom properties everywhere * Modify package.sh to rely on src/bin/tracer-home * Fix benchmarks stage * Turn off benchmark runs because they seem to run just fine * Fix packaging build for linux containers * Rename default tracer home directory to windows-tracer-home * Add S3 upload * Build ARM64 linux profiler * Try to fix flaky unit test build... * Build the macOS profiler in the build phase * Actually do a git checkout in the upload step and add debugging info * Try to make the build-linux-tracer-home-arm64 as fully fleshed out as other linux tracer homes * Try to make the build-macos-tracer-home as fully fleshed out as other linux tracer homes * Try to add runner tool to pipeline * Fix tool build...hopefully * Fix all the dotnet CLI tasks to correctly pass the build configuration * Modify hard-coded release to instead use buildConfiguration variable * Copy over the windows tracer home, including the .NET assemblies, into the dotnet tool * Try windows copy again * Last time I swear * Get linux integration tests up and running in the unified pipeline * Add Alpine Linux now * Revise Linux and Alpine Linux integration tests to not checkout repo * Attempt linux arm64 integration test run * Add initial set of Windows integration-tests. Get rid of duplication later... * Do explicit restore to try and fix framework reproductions * Upload artifacts for integration-test directories to help diagnose the issue with them * Point the managed profiler directory to Windows Tracer Home. This should work! * Fix the TestAllPackageVersions: true to only apply to non-Windows integration test runs * Need to install the earlier .NET Core SDKs in integration test jobs The runtime doesn't install the asp.net crore runtime, whereas the ask does * Extract isMainBranch variable to global * Pass $(tracerHome) variable to MSI builder * Add Crank stage to pipelin * Only run pipeline on master for now * Disable runs on PRs * Undo changes to clr_helper_test.cpp * Restore the publishing of managed profiler assets in the 'docker-compose run Profiler' step to fix the main integration-tests build Co-authored-by: Zach Montoya --- .../steps/install-dotnet-sdks.yml | 25 + .azure-pipelines/steps/install-dotnet.yml | 24 + .azure-pipelines/ultimate-pipeline.yml | 1195 +++++++++++++++++ Datadog.Trace.proj | 12 +- .../Datadog.Trace.ClrProfiler.Native.sh | 2 + build/docker/package.sh | 15 +- 6 files changed, 1267 insertions(+), 6 deletions(-) create mode 100644 .azure-pipelines/steps/install-dotnet-sdks.yml create mode 100644 .azure-pipelines/steps/install-dotnet.yml create mode 100644 .azure-pipelines/ultimate-pipeline.yml diff --git a/.azure-pipelines/steps/install-dotnet-sdks.yml b/.azure-pipelines/steps/install-dotnet-sdks.yml new file mode 100644 index 000000000000..7a966a0771d5 --- /dev/null +++ b/.azure-pipelines/steps/install-dotnet-sdks.yml @@ -0,0 +1,25 @@ +steps: +- task: UseDotNet@2 + displayName: install dotnet core sdk 2.1 + inputs: + packageType: sdk + version: 2.1.x + +- task: UseDotNet@2 + displayName: install dotnet core sdk 3.0 + inputs: + packageType: sdk + version: 3.0.x + +- task: UseDotNet@2 + displayName: install dotnet core sdk 3.1 + inputs: + packageType: sdk + version: 3.1.x + +- task: UseDotNet@2 + displayName: install dotnet core sdk 5 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) + includePreviewVersions: true \ No newline at end of file diff --git a/.azure-pipelines/steps/install-dotnet.yml b/.azure-pipelines/steps/install-dotnet.yml new file mode 100644 index 000000000000..69c4a0f11c03 --- /dev/null +++ b/.azure-pipelines/steps/install-dotnet.yml @@ -0,0 +1,24 @@ +steps: +- task: UseDotNet@2 + displayName: install dotnet core runtime 2.1 + inputs: + packageType: runtime + version: 2.1.x + +- task: UseDotNet@2 + displayName: install dotnet core runtime 3.0 + inputs: + packageType: runtime + version: 3.0.x + +- task: UseDotNet@2 + displayName: install dotnet core runtime 3.1 + inputs: + packageType: runtime + version: 3.1.x + +- task: UseDotNet@2 + displayName: install dotnet core sdk 5.0 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) \ No newline at end of file diff --git a/.azure-pipelines/ultimate-pipeline.yml b/.azure-pipelines/ultimate-pipeline.yml new file mode 100644 index 000000000000..9b8ed1cf8877 --- /dev/null +++ b/.azure-pipelines/ultimate-pipeline.yml @@ -0,0 +1,1195 @@ +trigger: + branches: + include: + - master # Only run on master for now + exclude: + - refs/pull/*/head + paths: + exclude: + - docs/* + - .github/* +pr: + branches: + exclude: # Don't run PR validation for now + - '*' + +# Global variables +variables: + buildConfiguration: Release + dotnetCoreSdk5Version: 5.0.103 + tracerHome: $(System.DefaultWorkingDirectory)/src/bin/windows-tracer-home + ddApiKey: $(DD_API_KEY) + isMainBranch: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')] + DD_DOTNET_TRACER_MSBUILD: + +# Declare the datadog agent as a resource to be used as a pipeline service +resources: + containers: + - container: dd_agent + image: datadog/agent + ports: + - 8126:8126 + env: + DD_API_KEY: $(ddApiKey) + DD_INSIDE_CI: true + +# Stages +stages: +- stage: build + dependsOn: [] + jobs: + - job: build_managed + pool: + vmImage: windows-2019 + steps: + - task: UseDotNet@2 + displayName: Install dotnet core sdk 5.0 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) + + - task: MSBuild@1 + displayName: Build all managed projects + inputs: + solution: Datadog.Trace.proj + configuration: $(buildConfiguration) + msbuildArguments: /t:BuildCsharp + maximumCpuCount: true + + - task: MSBuild@1 + displayName: Publish managed profiler to tracer home for Windows and Linux builds + inputs: + solution: Datadog.Trace.proj + configuration: $(buildConfiguration) + msbuildArguments: /t:PublishManagedProfilerOnDisk + maximumCpuCount: true + + - task: DotNetCoreCLI@2 + displayName: Create NuGet packages + inputs: + command: pack + nobuild: true + packagesToPack: src/Datadog.Trace/Datadog.Trace.csproj;src/Datadog.Trace.OpenTracing/Datadog.Trace.OpenTracing.csproj + packDirectory: $(System.DefaultWorkingDirectory)/nuget-output + + - publish: $(System.DefaultWorkingDirectory)/nuget-output + displayName: Upload NuGet packages + artifact: nuget-packages + + - publish: $(System.DefaultWorkingDirectory) + displayName: Upload working directory after the managed build + artifact: build-managed + + - job: build_native_windows + dependsOn: build_managed # The native build relies on Datadog.Trace.ClrProfiler.Managed.Loader to be built + pool: + vmImage: windows-2019 + variables: + msiHome: $(System.DefaultWorkingDirectory)/src/WindowsInstaller/bin/$(buildConfiguration) + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - task: UseDotNet@2 + displayName: install dotnet core sdk 5.0 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) + + # This is only here because the msi build later causes a restore error...not sure why + - task: DotNetCoreCLI@2 + displayName: dotnet restore + inputs: + command: restore + projects: src/**/*.csproj + + - task: NuGetToolInstaller@1 + displayName: install nuget + + - task: NuGetCommand@2 + displayName: nuget restore + inputs: + restoreSolution: Datadog.Trace.Native.sln + verbosityRestore: Normal + + # this triggers a dependency chain that builds all the managed, x64, and x86 dlls, and the zip and msi files + # Outputs include: + # - Windows Datadog.Trace.ClrProfiler.Native.dll (x86 and x64) + # - Windows MSI (x86 and x64) + # - Windows tracer home directory + - task: MSBuild@1 + displayName: build both msi + inputs: + solution: Datadog.Trace.proj + configuration: $(buildConfiguration) + msbuildArguments: /t:msi /p:Platform=All;ZipHomeDirectory=true;RunWixToolsOutOfProc=true /p:TracerHomeDirectory=$(tracerHome) + maximumCpuCount: true + + - publish: $(System.DefaultWorkingDirectory) + displayName: Upload repo after windows build + artifact: build-repo-managed-native-windows + + - publish: $(msiHome)/x86/en-us + displayName: Upload Windows x86 MSI + artifact: windows-msi-x86 + + - publish: $(msiHome)/x64/en-us + displayName: Upload Windows x64 MSI + artifact: windows-msi-x64 + + - publish: $(tracerHome) + displayName: Upload Windows tracer home directory + artifact: build-windows-tracer-home + + - publish: $(tracerHome).zip + displayName: Upload Windows tracer home zip + artifact: windows-tracer-home + + - job: build_native_linux + dependsOn: build_managed # The native build relies on Datadog.Trace.ClrProfiler.Managed.Loader to be built + pool: + vmImage: ubuntu-20.04 + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.Native.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.Native.sh' + + - task: DockerCompose@0 + displayName: docker-compose run Profiler + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run Profiler + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/package.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/package.sh' + + - task: DockerCompose@0 + displayName: docker-compose run package + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run package + + - publish: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64 + displayName: Uploading linux tracer home artifact + artifact: build-linux-tracer-home + + - publish: $(System.DefaultWorkingDirectory)/deploy/linux + displayName: Publish Linux packages + artifact: linux-packages + + - job: build_native_alpine_linux + dependsOn: build_managed # The native build relies on Datadog.Trace.ClrProfiler.Managed.Loader to be built + pool: + vmImage: ubuntu-20.04 + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.Native.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.Native.sh' + + - task: DockerCompose@0 + displayName: docker-compose run Profiler.Alpine + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run Profiler.Alpine + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/package.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/package.sh' + + - task: DockerCompose@0 + displayName: docker-compose run package.alpine + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run package.alpine + + - publish: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64 + displayName: Uploading alpine linux tracer home artifact + artifact: build-alpine-linux-tracer-home + + - publish: $(System.DefaultWorkingDirectory)/deploy/linux + displayName: Publish Alpine Linux package + artifact: linux-alpine-packages + + - job: build_native_linux_arm64 + dependsOn: build_managed # The native build relies on Datadog.Trace.ClrProfiler.Managed.Loader to be built + pool: Arm64 + workspace: + clean: all + + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.Native.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.Native.sh' + + - task: DockerCompose@0 + displayName: docker-compose run Profiler + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run Profiler + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/package.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/package.sh' + + - task: DockerCompose@0 + displayName: docker-compose run package + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run package + + - publish: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64 + artifact: build-linux-tracer-home-arm64 + + - job: build_native_macos + dependsOn: build_managed # The native build relies on Datadog.Trace.ClrProfiler.Managed.Loader to be built + pool: + vmImage: macOS-10.15 + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - script: | + cd ./src/Datadog.Trace.ClrProfiler.Native + cmake . + make + displayName: build_profiler + + - script: | + mkdir -p src/Datadog.Trace.ClrProfiler.Native/bin/netstandard2.0 + cp src/bin/windows-tracer-home/netstandard2.0/*.dll src/Datadog.Trace.ClrProfiler.Native/bin/netstandard2.0/ + mkdir -p src/Datadog.Trace.ClrProfiler.Native/bin/netcoreapp3.1 + cp src/bin/windows-tracer-home/netcoreapp3.1/*.dll src/Datadog.Trace.ClrProfiler.Native/bin/netcoreapp3.1/ + displayName: Copy files into build-macos-tracer-home + + - publish: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin + displayName: Uploading macos profiler artifact + artifact: build-macos-tracer-home + +- stage: unit_tests + dependsOn: build + jobs: + - job: unit_tests_managed + strategy: + matrix: + windows: + imageName: windows-2019 + linux: + imageName: ubuntu-18.04 + macos: + imageName: macOS-10.15 + pool: + vmImage: $(imageName) + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - template: steps/install-dotnet.yml + + # Ideally we would use the following MSBuild command which can more intelligently parallelize the build + # - task: MSBuild@1 + # displayName: Build all managed unit test projects + # inputs: + # solution: Datadog.Trace.proj + # configuration: $(buildConfiguration) + # msbuildArguments: /t:BuildCsharpTests + # maximumCpuCount: true + + - task: DotNetCoreCLI@2 + displayName: dotnet restore + inputs: + command: restore + projects: test/**/*.Tests.csproj + + - task: DotNetCoreCLI@2 + displayName: dotnet build + inputs: + command: build + arguments: --configuration $(buildConfiguration) /nowarn:netsdk1138 + projects: test/**/*.Tests.csproj + env: + DD_SERVICE: dd-trace-dotnet + + - task: DotNetCoreCLI@2 + displayName: dotnet test + inputs: + command: test + arguments: --configuration $(buildConfiguration) --no-build + projects: test/**/*.Tests.csproj + env: + DD_SERVICE: dd-trace-dotnet + + - job: unit_tests_managed_linux_arm64 + pool: Arm64 + workspace: + clean: all + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - task: DotNetCoreCLI@2 + displayName: dotnet test + inputs: + command: test + arguments: --configuration $(buildConfiguration) + projects: test/**/*.Tests.csproj + env: + DD_SERVICE: dd-trace-dotnet + + - job: native_unit_tests_windows + pool: + vmImage: windows-2019 + + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-repo-managed-native-windows + path: $(System.DefaultWorkingDirectory) + + # Install the .NET SDK so any managed libraries needed for the C++ unit tests can be built + - template: steps/install-dotnet.yml + + # This should already be accounted for but unfortunately it is not + - task: DotNetCoreCLI@2 + displayName: dotnet build + inputs: + command: build + arguments: --configuration $(buildConfiguration) /nowarn:netsdk1138 + projects: | + test/**/Samples.ExampleLibrary*.csproj + + - task: MSBuild@1 + displayName: Build x86 native unit test projects + inputs: + solution: Datadog.Trace.proj + platform: x86 + configuration: $(buildConfiguration) + msbuildArguments: /t:BuildCppTests + maximumCpuCount: true + + - task: MSBuild@1 + displayName: Build x64 native unit test projects + inputs: + solution: Datadog.Trace.proj + platform: x64 + configuration: $(buildConfiguration) + msbuildArguments: /t:BuildCppTests + maximumCpuCount: true + + - script: Datadog.Trace.ClrProfiler.Native.Tests.exe --gtest_output=xml + displayName: run tests + workingDirectory: $(System.DefaultWorkingDirectory)/test/Datadog.Trace.ClrProfiler.Native.Tests/bin/$(buildConfiguration)/x86 + + - script: Datadog.Trace.ClrProfiler.Native.Tests.exe --gtest_output=xml + displayName: run tests + workingDirectory: $(System.DefaultWorkingDirectory)/test/Datadog.Trace.ClrProfiler.Native.Tests/bin/$(buildConfiguration)/x64 + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: publish test results + inputs: + testResultsFiles: test/**/test*.xml + condition: succeededOrFailed() + +- stage: integration_tests + dependsOn: build + jobs: + + - job: Windows + timeoutInMinutes: 100 + strategy: + matrix: + x64: + buildPlatform: x64 + x86: + buildPlatform: x86 + pool: + vmImage: windows-2019 + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-repo-managed-native-windows + path: $(System.DefaultWorkingDirectory) + + - template: steps/install-dotnet-sdks.yml + + - task: NuGetToolInstaller@1 + displayName: install nuget + + - task: NuGetCommand@2 + displayName: nuget restore + inputs: + restoreSolution: Datadog.Trace.sln + verbosityRestore: Normal + + - task: MSBuild@1 + displayName: Build .NET Framework projects (not SDK-based projects) + inputs: + solution: Datadog.Trace.proj + platform: $(buildPlatform) + configuration: $(buildConfiguration) + msbuildArguments: /t:BuildFrameworkReproductions + maximumCpuCount: true + + - task: DotNetCoreCLI@2 + displayName: dotnet build integration tests + inputs: + command: build + projects: | + test/test-applications/regression/**/*.csproj + test/*.IntegrationTests/*.IntegrationTests.csproj + !test/test-applications/regression/**/ExpenseItDemo*.csproj + !test/test-applications/regression/**/EntityFramework6x*.csproj + !test/test-applications/regression/**/StackExchange.Redis.AssemblyConflict.LegacyProject.csproj + arguments: --configuration $(buildConfiguration) -p:Platform=$(buildPlatform) -p:ManagedProfilerOutputDirectory=$(tracerHome) /nowarn:netsdk1138 + + - task: DotNetCoreCLI@2 + displayName: dotnet build samples + inputs: + command: build + projects: | + test/test-applications/integrations/**/*.csproj + !test/test-applications/integrations/dependency-libs/**/*.csproj + arguments: --configuration $(buildConfiguration) -p:Platform=$(buildPlatform) -p:ManagedProfilerOutputDirectory=$(tracerHome) -p:BuildInParallel=false /nowarn:netsdk1138 -p:ExcludeManagedProfiler=true -p:ExcludeNativeProfiler=true -p:LoadManagedProfilerFromProfilerDirectory=false + + - publish: $(System.DefaultWorkingDirectory) + displayName: Upload working directory after the managed build + artifact: build-integration-tests-windows-$(buildPlatform) + + - task: DotNetCoreCLI@2 + displayName: dotnet test + inputs: + command: test + projects: | + test/Datadog.Trace.IntegrationTests/Datadog.Trace.IntegrationTests.csproj + test/Datadog.Trace.OpenTracing.IntegrationTests/Datadog.Trace.OpenTracing.IntegrationTests.csproj + arguments: -c $(buildConfiguration) -p:Platform=$(buildPlatform) + + - task: DotNetCoreCLI@2 + displayName: dotnet test + inputs: + command: test + projects: test/Datadog.Trace.ClrProfiler.IntegrationTests/Datadog.Trace.ClrProfiler.IntegrationTests.csproj + arguments: -c $(buildConfiguration) --filter "(RunOnWindows=True|Category=Smoke)&LoadFromGAC!=True&IIS!=True" -p:Platform=$(buildPlatform) + + - job: Windows_IIS + timeoutInMinutes: 100 + strategy: + matrix: + x64: + buildPlatform: x64 + enable32bit: false + x86: + buildPlatform: x86 + enable32bit: true + pool: + vmImage: windows-2019 + variables: + msiOutputDirectory: src/WindowsInstaller/bin/$(buildConfiguration)/$(buildPlatform)/en-us + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-repo-managed-native-windows + path: $(System.DefaultWorkingDirectory) + + - template: steps/install-dotnet-sdks.yml + + - task: NuGetToolInstaller@1 + displayName: install nuget + + - task: NuGetCommand@2 + displayName: nuget restore + inputs: + restoreSolution: Datadog.Trace.sln + verbosityRestore: Normal + + - task: MSBuild@1 + displayName: Build .NET Framework projects (not SDK-based projects) + inputs: + solution: Datadog.Trace.proj + platform: $(buildPlatform) + configuration: $(buildConfiguration) + msbuildArguments: /t:BuildFrameworkReproductions + maximumCpuCount: true + + - task: DotNetCoreCLI@2 + displayName: dotnet build integration tests + inputs: + command: build + projects: | + test/test-applications/regression/**/*.csproj + test/*.IntegrationTests/*.IntegrationTests.csproj + !test/test-applications/regression/**/ExpenseItDemo*.csproj + !test/test-applications/regression/**/EntityFramework6x*.csproj + !test/test-applications/regression/**/StackExchange.Redis.AssemblyConflict.LegacyProject.csproj + arguments: --configuration $(buildConfiguration) -p:Platform=$(buildPlatform) -p:ManagedProfilerOutputDirectory=$(tracerHome) /nowarn:netsdk1138 + + - task: DotNetCoreCLI@2 + displayName: dotnet build samples + inputs: + command: build + projects: | + test/test-applications/integrations/**/*.csproj + !test/test-applications/integrations/dependency-libs/**/*.csproj + arguments: --configuration $(buildConfiguration) -p:Platform=$(buildPlatform) -p:ManagedProfilerOutputDirectory=$(tracerHome) -p:BuildInParallel=false /nowarn:netsdk1138 -p:ExcludeManagedProfiler=true -p:ExcludeNativeProfiler=true -p:LoadManagedProfilerFromProfilerDirectory=false + + - task: NuGetCommand@2 + displayName: nuget restore IIS samples + inputs: + restoreSolution: test/test-applications/aspnet/samples-iis.sln + verbosityRestore: Normal + + - task: MSBuild@1 + displayName: Publish IIS samples + inputs: + solution: test/test-applications/aspnet/samples-iis.sln + configuration: '$(buildConfiguration)' + msbuildArguments: '/p:DeployOnBuild=true /p:PublishProfile=FolderProfile.pubxml' + maximumCpuCount: true + + - task: DockerCompose@0 + displayName: docker-compose build IIS containers + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: build --build-arg DOTNET_TRACER_MSI=$(msiOutputDirectory)/*.msi --build-arg ENABLE_32_BIT=$(enable32bit) IntegrationTests.IIS.LoaderOptimizationRegKey + + - task: DockerCompose@0 + displayName: docker-compose start IIS containers + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: up -d IntegrationTests.IIS.LoaderOptimizationRegKey + + - publish: $(System.DefaultWorkingDirectory) + displayName: Upload working directory after the managed build + artifact: build-integration-tests-windows-iis-$(buildPlatform) + + - powershell: | + [System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") + $publish = New-Object System.EnterpriseServices.Internal.Publish + Get-ChildItem $(tracerHome)/net45 -Filter *.dll | Foreach-Object { $publish.GacInstall($_.FullName) } + displayName: Add net45 Datadog.Trace.ClrProfiler.Managed assets to the GAC + + - task: DotNetCoreCLI@2 + displayName: dotnet test --filter LoadFromGAC=True + inputs: + command: test + projects: test/Datadog.Trace.ClrProfiler.IntegrationTests/Datadog.Trace.ClrProfiler.IntegrationTests.csproj + arguments: -c $(buildConfiguration) --filter "(RunOnWindows=True|Category=Smoke)&LoadFromGAC=True&IIS!=True" -p:Platform=$(buildPlatform) + + - task: DotNetCoreCLI@2 + displayName: dotnet test IIS + inputs: + command: test + projects: test/Datadog.Trace.ClrProfiler.IntegrationTests/Datadog.Trace.ClrProfiler.IntegrationTests.csproj + arguments: -c $(buildConfiguration) --filter "(IIS=True)" -p:Platform=$(buildPlatform) + + - task: DockerCompose@0 + displayName: docker-compose stop services + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: down + condition: succeededOrFailed() + + - job: Linux + strategy: + matrix: + netcoreapp2_1: + publishTargetFramework: netcoreapp2.1 + netcoreapp3_0: + publishTargetFramework: netcoreapp3.0 + netcoreapp3_1: + publishTargetFramework: netcoreapp3.1 + net5_0: + publishTargetFramework: net5.0 + + variables: + TestAllPackageVersions: true + + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - download: current + artifact: build-linux-tracer-home + + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)/build-linux-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/$(buildConfiguration)/x64 + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/build.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/build.sh' + + - task: DockerCompose@0 + displayName: docker-compose run build + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) -e publishTargetFramework=$(publishTargetFramework) build + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.sh' + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) -e publishTargetFramework=$(publishTargetFramework) IntegrationTests + + - publish: dotnet-tracer-native.log + artifact: $(Agent.JobName)_profiler-logs + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: publish test results + inputs: + testResultsFormat: VSTest + testResultsFiles: test/**/*.trx + condition: succeededOrFailed() + + - job: Alpine_Linux + strategy: + matrix: + netcoreapp2_1: + publishTargetFramework: netcoreapp2.1 + netcoreapp3_0: + publishTargetFramework: netcoreapp3.0 + netcoreapp3_1: + publishTargetFramework: netcoreapp3.1 + net5_0: + publishTargetFramework: net5.0 + + variables: + TestAllPackageVersions: true + + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - download: current + artifact: build-alpine-linux-tracer-home + + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)/build-alpine-linux-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/$(buildConfiguration)/x64 + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/build.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/build.sh' + + - task: DockerCompose@0 + displayName: docker-compose run build + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) -e publishTargetFramework=$(publishTargetFramework) build + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.sh' + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests.Alpine.Core21 + condition: eq(variables['publishTargetFramework'], 'netcoreapp2.1') + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core21 + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests.Alpine.Core30 + condition: eq(variables['publishTargetFramework'], 'netcoreapp3.0') + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core30 + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests.Alpine.Core31 + condition: eq(variables['publishTargetFramework'], 'netcoreapp3.1') + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core31 + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests.Alpine.Core50 + condition: eq(variables['publishTargetFramework'], 'net5.0') + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core50 + + - publish: dotnet-tracer-native.log + artifact: $(Agent.JobName)_profiler-logs + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: publish test results + inputs: + testResultsFormat: VSTest + testResultsFiles: test/**/*.trx + condition: succeededOrFailed() + + - job: Linux_arm64 + pool: Arm64 + workspace: + clean: all + + variables: + TestAllPackageVersions: true + + steps: + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - download: current + artifact: build-linux-tracer-home-arm64 + + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)/build-linux-tracer-home-arm64 + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.ClrProfiler.Native/bin/$(buildConfiguration)/arm64 + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/build.arm64.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/build.arm64.sh' + + - task: DockerCompose@0 + displayName: docker-compose run build.arm64 + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) -e publishTargetFramework=net5.0 build.arm64 + + - script: | + chmod +x $(System.DefaultWorkingDirectory)/build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.arm64.sh + displayName: 'Workaround: Restore wiped executable permission on build/docker/Datadog.Trace.ClrProfiler.IntegrationTests.arm64.sh' + + - task: DockerCompose@0 + displayName: docker-compose run IntegrationTests.ARM64.Core50 + inputs: + containerregistrytype: Container Registry + dockerComposeCommand: run -e TestAllPackageVersions=$(TestAllPackageVersions) -e buildConfiguration=$(buildConfiguration) IntegrationTests.ARM64.Core50 + + - publish: dotnet-tracer-native.log + artifact: $(Agent.JobName)_profiler-logs + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: publish test results + inputs: + testResultsFormat: VSTest + testResultsFiles: test/**/*.trx + condition: succeededOrFailed() + +- stage: benchmarks + dependsOn: build + condition: and(succeeded(), false) + jobs: + + #### Windows + + - job: Windows + pool: Benchmarks + + workspace: + clean: all + + # Enable the Datadog Agent service for this job + services: + dd_agent: dd_agent + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - task: UseDotNet@2 + displayName: Install dotnet core sdk 5.0 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) + + - task: DotNetCoreCLI@2 + displayName: dotnet restore + inputs: + command: restore + projects: src/**/*.csproj + + - task: DotNetCoreCLI@2 + displayName: Benchmarks + inputs: + command: 'run' + projects: '$(System.DefaultWorkingDirectory)/test/benchmarks/Benchmarks.Trace/Benchmarks.Trace.csproj' + arguments: '-c $(buildConfiguration) -f netcoreapp3.1 -- -r net472 netcoreapp3.1 -m -f * --iterationTime 2000' + env: + DD_ENV: CI + DD_SERVICE: dd-trace-dotnet + + - task: PowerShell@2 + inputs: + targetType: 'inline' + script: 'Start-Sleep -s 120' + +- stage: dotnet_tool + dependsOn: build + jobs: + - job: build_runner_tool_and_standalone + + pool: + vmImage: windows-2019 + + # Enable the Datadog Agent service for this job + services: + dd_agent: dd_agent + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - download: current + artifact: build-windows-tracer-home + + - task: CopyFiles@2 + displayName: Copying windows tracer home from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-windows-tracer-home + Contents: | + **/* + !**/*.zip + !**/*.json + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/home + + - download: current + artifact: build-linux-tracer-home + patterns: '**/*.so' + + - task: CopyFiles@2 + displayName: Copying native linux binary from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-linux-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/home/linux-x64 + + - download: current + artifact: build-alpine-linux-tracer-home + patterns: '**/*.so' + + - task: CopyFiles@2 + displayName: Copying native alpine linux binary from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-alpine-linux-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/home/linux-musl-x64 + + - download: current + artifact: build-macos-tracer-home + patterns: '**/*.dylib' + + - task: CopyFiles@2 + displayName: Copying native macos binary from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-macos-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/home/osx-x64 + + # Install the tracer latest stable release to attach the profiler to the build and test steps. + # The script exposes the required environment variables to the following steps + - task: PowerShell@2 + displayName: Install profiler latest release + inputs: + filePath: ./.azure-pipelines/setup_tracer.ps1 + + - task: UseDotNet@2 + displayName: install dotnet core sdk 5.0 + inputs: + packageType: sdk + version: $(dotnetCoreSdk5Version) + + - task: DotNetCoreCLI@2 + displayName: tool build + inputs: + command: build + arguments: --configuration $(buildConfiguration) /nowarn:netsdk1138 + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Tool.csproj + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DotNetCoreCLI@2 + displayName: standalone build win-x86 + inputs: + command: publish + publishWebProjects: false + modifyOutputPath: false + zipAfterPublish: false + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Standalone.csproj + arguments: --configuration $(buildConfiguration) --framework netcoreapp3.1 --runtime win-x86 + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DotNetCoreCLI@2 + displayName: standalone build win-x64 + inputs: + command: publish + publishWebProjects: false + modifyOutputPath: false + zipAfterPublish: false + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Standalone.csproj + arguments: --configuration $(buildConfiguration) --framework netcoreapp3.1 --runtime win-x64 + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DotNetCoreCLI@2 + displayName: standalone build linux-x64 + inputs: + command: publish + publishWebProjects: false + modifyOutputPath: false + zipAfterPublish: false + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Standalone.csproj + arguments: --configuration $(buildConfiguration) --framework netcoreapp3.1 --runtime linux-x64 + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DotNetCoreCLI@2 + displayName: standalone build linux-musl-x64 + inputs: + command: publish + publishWebProjects: false + modifyOutputPath: false + zipAfterPublish: false + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Standalone.csproj + arguments: --configuration $(buildConfiguration) --framework netcoreapp3.1 --runtime linux-musl-x64 + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DotNetCoreCLI@2 + displayName: standalone build linux-osx-x64 + inputs: + command: publish + publishWebProjects: false + modifyOutputPath: false + zipAfterPublish: false + projects: src/Datadog.Trace.Tools.Runner/Datadog.Trace.Tools.Runner.Standalone.csproj + arguments: --configuration $(buildConfiguration) --framework netcoreapp3.1 --runtime osx-x64 + env: + DD_SERVICE: dd-trace-dotnet-runner-tool + + - task: DeleteFiles@1 + displayName: 'Remove unneeded files' + inputs: + Contents: | + $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Tool/!(*.nupkg) + $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Console/publish/win-x64/home* + $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Console/publish/win-x86/home* + $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Console/publish/linux-x64/home* + $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Console/publish/osx-x64/home* + + - publish: $(System.DefaultWorkingDirectory)/src/Datadog.Trace.Tools.Runner/bin/$(buildConfiguration)/Tool + displayName: Uploading runner dotnet tool artifact + artifact: runner-dotnet-tool + +- stage: upload + dependsOn: build + jobs: + - job: s3_upload + + pool: + vmImage: ubuntu-18.04 + + steps: + + - download: current + artifact: windows-msi-x64 + patterns: '**/*x64.msi' + + - download: current + artifact: linux-packages + patterns: '**/*amd64.deb' + + - script: | + mkdir s3_upload + mv $(Pipeline.Workspace)/windows-msi-x64/*.msi s3_upload/ + mv $(Pipeline.Workspace)/linux-packages/*.deb s3_upload/ + displayName: Move deb package and MSI to s3_upload folder + + # for prerelease versions, rename datadog-dotnet-apm-{version}-amd64.deb + # to datadog-dotnet-apm-{version}-{tag}-amd64.deb (i.e. add the prerelease tag) + # by copying most of the filename from datadog-dotnet-apm-{version}-{tag}-x64.msi + - script: | + MSI_NAME=$(ls s3_upload/*.msi) + PACKAGE_NAME=${MSI_NAME::-8} + echo Renaming deb package to $PACKAGE_NAME-amd64.deb + mv s3_upload/*.deb $PACKAGE_NAME-amd64.deb + displayName: Rename deb package name to match MSI name + + # Create index.txt file with the following format: + # BRANCH_NAME + # SHA + # ARTIFACT WILDCARD (datadog-dotnet-apm-vX.X.X-*) + # COMMIT AUTHOR + # Note: For the branch name, normalize 'refs/heads/' to '' and 'refs/tags/' to 'tags/' + - script: | + INDEX_FILE=$(pwd)/s3_upload/index.txt + echo $(Build.SourceBranch) | sed 's/refs\/heads\///g' | sed 's/refs\/tags\//tags\//g' >> $INDEX_FILE + git rev-parse HEAD >> $INDEX_FILE + pushd s3_upload && name=$(ls *.deb) && echo "${name::-9}*" >> $INDEX_FILE && popd + git show -s --format='%ae' HEAD >> $INDEX_FILE + echo Generated index.txt file: + cat $INDEX_FILE + displayName: Write index.txt + + - script: tree s3_upload + displayName: 'tree s3_upload' + + - script: | + sudo apt-get install -y unzip python3-setuptools + curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip" + unzip awscli-bundle.zip + sudo python3 ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws + aws --version + displayName: Install AWS CLI + + - script: aws configure set aws_access_key_id $SECRET + displayName: Authenticate aws_access_key_id + env: + SECRET: $(AWS_ACCESS_KEY_ID) + + - script: aws configure set aws_secret_access_key $SECRET + displayName: Authenticate aws_secret_access_key + env: + SECRET: $(AWS_SECRET_ACCESS_KEY) + + # by default, run this step on master branch only. + # use "push_artifacts_to_s3" to override: + # "true": run this step + # "false": do NOT run this step + # else: run this stage if branch is master + + - script: aws s3 cp s3_upload s3://datadog-reliability-env/dotnet/ --recursive + displayName: Upload deb, MSI, index.txt to s3 + condition: > + and( + succeeded(), + ne(variables['push_artifacts_to_s3'], 'false'), + or( + eq(variables['push_artifacts_to_s3'], 'true'), + eq(variables.isMainBranch, true) + ) + ) + +- stage: throughput + dependsOn: build + condition: and(succeeded(), false) + jobs: + + #### Linux + + - job: Linux + pool: Throughput + + workspace: + clean: all + + steps: + + - checkout: none + + - task: DownloadPipelineArtifact@2 + inputs: + artifact: build-managed + path: $(System.DefaultWorkingDirectory) + + - download: current + artifact: build-windows-tracer-home + patterns: '**/win-x64/*.dll' + + - task: CopyFiles@2 + displayName: Copying windows native bindary from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-windows-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/ + + - download: current + artifact: build-linux-tracer-home + patterns: '**/*.so' + + - task: CopyFiles@2 + displayName: Copying native linux binary from previous job + inputs: + sourceFolder: $(Pipeline.Workspace)/build-linux-tracer-home + targetFolder: $(System.DefaultWorkingDirectory)/ + + - script: | + cd $(System.DefaultWorkingDirectory)/build/crank + chmod +x ./run.sh + ./run.sh + displayName: Crank + env: + DD_SERVICE: dd-trace-dotnet diff --git a/Datadog.Trace.proj b/Datadog.Trace.proj index 34c8692b5df6..3a8d460904d1 100644 --- a/Datadog.Trace.proj +++ b/Datadog.Trace.proj @@ -2,12 +2,12 @@ true Debug - $(MSBuildThisFileDirectory)src\bin\tracer-home + $(MSBuildThisFileDirectory)src\bin\windows-tracer-home - + @@ -45,12 +45,20 @@ + + + + + + + + diff --git a/build/docker/Datadog.Trace.ClrProfiler.Native.sh b/build/docker/Datadog.Trace.ClrProfiler.Native.sh index 007c9d25bc01..5774d54768cf 100755 --- a/build/docker/Datadog.Trace.ClrProfiler.Native.sh +++ b/build/docker/Datadog.Trace.ClrProfiler.Native.sh @@ -5,6 +5,8 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" cd "$DIR/../.." +# TODO Remove this from the native build as it should be logically separate +# This is unnecessary in the unified pipeline as it's already done via the package.sh script PUBLISH_OUTPUT_NET2="$( pwd )/src/bin/managed-publish/netstandard2.0" PUBLISH_OUTPUT_NET31="$( pwd )/src/bin/managed-publish/netcoreapp3.1" diff --git a/build/docker/package.sh b/build/docker/package.sh index 26dcf3957ede..9d7b6d38cf22 100755 --- a/build/docker/package.sh +++ b/build/docker/package.sh @@ -4,11 +4,18 @@ set -euxo pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" VERSION=1.25.0 -mkdir -p $DIR/../../deploy/linux -cp $DIR/../../integrations.json $DIR/../../src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/ -cp $DIR/../../build/artifacts/createLogPath.sh $DIR/../../src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/ +cd "$DIR/../.." +mkdir -p deploy/linux +cp integrations.json src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/ +cp build/artifacts/createLogPath.sh src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/ -cd $DIR/../../deploy/linux +mkdir -p src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/netstandard2.0 +cp src/bin/windows-tracer-home/netstandard2.0/*.dll src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/netstandard2.0/ + +mkdir -p src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/netcoreapp3.1 +cp src/bin/windows-tracer-home/netcoreapp3.1/*.dll src/Datadog.Trace.ClrProfiler.Native/bin/Release/x64/netcoreapp3.1/ + +cd deploy/linux for pkgtype in $PKGTYPES ; do fpm \ -f \ From cf4b751be3676d46093301d7f3204e86668ec187 Mon Sep 17 00:00:00 2001 From: Lucas Pimentel-Ordyna Date: Mon, 29 Mar 2021 10:00:22 -0400 Subject: [PATCH 2/2] enable Service Fabric Service Remoting instrumentation out-of-the-box (#1234) --- Datadog.Trace.sln | 11 - docs/CHANGELOG.md | 4 + .../ServiceFabricRemoting/DatadogInstall.bat | 3 + .../ServiceFabricRemoting/DatadogInstall.ps1 | 50 +++ .../ApplicationManifest.xml | 36 +- .../ApplicationParameters/Cloud.xml | 3 +- .../ApplicationParameters/Local.1Node.xml | 3 +- .../ApplicationParameters/Local.5Node.xml | 3 +- .../ServiceFabricApplication.sfproj | 3 +- .../ServiceFabricRemoting.sln | 38 +- .../WeatherForecast.cs | 2 + .../WeatherService.Abstractions.csproj | 2 +- .../PackageRoot/Config/Settings.xml | 0 .../PackageRoot/ServiceManifest.xml | 46 ++ .../Program.cs | 9 +- .../WeatherService.NetCore31.csproj} | 13 +- .../WeatherService.cs | 46 ++ .../PackageRoot/Config/Settings.xml | 9 + .../PackageRoot/ServiceManifest.xml | 18 +- .../WeatherService.NetFx461/Program.cs | 24 ++ .../WeatherService.NetFx461.csproj | 25 ++ .../WeatherService.cs | 5 +- .../Controllers/WeatherForecastController.cs | 24 +- .../WebApp/PackageRoot/ServiceManifest.xml | 10 + .../ServiceFabricRemoting/WebApp/Program.cs | 3 +- .../ServiceFabricRemoting/WebApp/Startup.cs | 2 - .../WebApp/WebApp.csproj | 12 +- .../Instrumentation.cs | 25 ++ .../Datadog.Trace.ServiceFabric.csproj | 27 -- .../GlobalSuppressions.cs | 8 - src/Datadog.Trace.ServiceFabric/Remoting.cs | 393 ------------------ ...eRemotingRequestMessageHeaderExtensions.cs | 51 --- src/Datadog.Trace.ServiceFabric/nuget.config | 7 - .../PlatformHelpers/ServiceFabric.cs | 20 + .../ServiceFabric}/PropagationContext.cs | 2 + .../ServiceFabric/ServiceRemotingClient.cs | 98 +++++ .../ServiceFabric/ServiceRemotingConstants.cs | 23 + .../ServiceFabric/ServiceRemotingHelpers.cs | 176 ++++++++ ...eRemotingRequestMessageHeaderExtensions.cs | 34 ++ .../ServiceFabric/ServiceRemotingService.cs | 104 +++++ .../ServiceFabric/ServiceRemotingTags.cs | 83 ++++ src/Datadog.Trace/ServiceFabric/Stubs.cs | 103 +++++ 42 files changed, 993 insertions(+), 565 deletions(-) create mode 100644 samples/ServiceFabricRemoting/DatadogInstall.bat create mode 100644 samples/ServiceFabricRemoting/DatadogInstall.ps1 rename samples/ServiceFabricRemoting/{WeatherService => WeatherService.NetCore31}/PackageRoot/Config/Settings.xml (100%) create mode 100644 samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/ServiceManifest.xml rename samples/ServiceFabricRemoting/{WeatherService => WeatherService.NetCore31}/Program.cs (81%) rename samples/ServiceFabricRemoting/{WeatherService/WeatherService.csproj => WeatherService.NetCore31/WeatherService.NetCore31.csproj} (64%) create mode 100644 samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.cs create mode 100644 samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/Config/Settings.xml rename samples/ServiceFabricRemoting/{WeatherService => WeatherService.NetFx461}/PackageRoot/ServiceManifest.xml (67%) create mode 100644 samples/ServiceFabricRemoting/WeatherService.NetFx461/Program.cs create mode 100644 samples/ServiceFabricRemoting/WeatherService.NetFx461/WeatherService.NetFx461.csproj rename samples/ServiceFabricRemoting/{WeatherService => WeatherService.NetFx461}/WeatherService.cs (90%) delete mode 100644 src/Datadog.Trace.ServiceFabric/Datadog.Trace.ServiceFabric.csproj delete mode 100644 src/Datadog.Trace.ServiceFabric/GlobalSuppressions.cs delete mode 100644 src/Datadog.Trace.ServiceFabric/Remoting.cs delete mode 100644 src/Datadog.Trace.ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs delete mode 100644 src/Datadog.Trace.ServiceFabric/nuget.config create mode 100644 src/Datadog.Trace/PlatformHelpers/ServiceFabric.cs rename src/{Datadog.Trace.ServiceFabric => Datadog.Trace/ServiceFabric}/PropagationContext.cs (96%) create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingClient.cs create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingConstants.cs create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingHelpers.cs create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingService.cs create mode 100644 src/Datadog.Trace/ServiceFabric/ServiceRemotingTags.cs create mode 100644 src/Datadog.Trace/ServiceFabric/Stubs.cs diff --git a/Datadog.Trace.sln b/Datadog.Trace.sln index 8d841ec1ed34..536cfdecb65c 100644 --- a/Datadog.Trace.sln +++ b/Datadog.Trace.sln @@ -347,8 +347,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependency-libs", "dependen EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace.DuckTyping.Tests", "test\Datadog.Trace.DuckTyping.Tests\Datadog.Trace.DuckTyping.Tests.csproj", "{91E50134-0E55-4D22-B180-6967174FCE0B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace.ServiceFabric", "src\Datadog.Trace.ServiceFabric\Datadog.Trace.ServiceFabric.csproj", "{5076FEA6-14E7-4094-9351-61FF1FAE4E98}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{A0C5FBBB-CFB2-4FB9-B8F0-55676E9DCF06}" ProjectSection(SolutionItems) = preProject build\PackageVersionsComprehensive.g.props = build\PackageVersionsComprehensive.g.props @@ -1342,14 +1340,6 @@ Global {91E50134-0E55-4D22-B180-6967174FCE0B}.Release|x64.Build.0 = Release|Any CPU {91E50134-0E55-4D22-B180-6967174FCE0B}.Release|x86.ActiveCfg = Release|Any CPU {91E50134-0E55-4D22-B180-6967174FCE0B}.Release|x86.Build.0 = Release|Any CPU - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Debug|Any CPU.ActiveCfg = Debug|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Debug|x64.ActiveCfg = Debug|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Debug|x64.Build.0 = Debug|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Debug|x86.ActiveCfg = Debug|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Release|Any CPU.ActiveCfg = Release|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Release|x64.ActiveCfg = Release|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Release|x64.Build.0 = Release|x64 - {5076FEA6-14E7-4094-9351-61FF1FAE4E98}.Release|x86.ActiveCfg = Release|x64 {1F146D40-8B21-4630-8049-14FA4BBBB217}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F146D40-8B21-4630-8049-14FA4BBBB217}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F146D40-8B21-4630-8049-14FA4BBBB217}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1720,7 +1710,6 @@ Global {AFA0AB23-64F0-4AC1-9050-6CE8FE06F580} = {9518425A-36A5-4B8F-B0B8-6137DB88441D} {8683D82A-2BBE-4199-9C36-C59F48804F90} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A} {91E50134-0E55-4D22-B180-6967174FCE0B} = {8CEC2042-F11C-49F5-A674-2355793B600A} - {5076FEA6-14E7-4094-9351-61FF1FAE4E98} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB} {C70D6696-23F0-4C3D-9C2A-94C4868D5249} = {A0C5FBBB-CFB2-4FB9-B8F0-55676E9DCF06} {CC53E5C5-9D3E-4AD9-A9CA-D2190463EB5B} = {A0C5FBBB-CFB2-4FB9-B8F0-55676E9DCF06} {E5439139-6F94-44FA-9590-C32FCC1C7A93} = {8CEC2042-F11C-49F5-A674-2355793B600A} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a21d5b6c5257..0414e3cc1e4f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,9 @@ # Datadog .NET Tracer (`dd-trace-dotnet`) Release Notes +## [Unreleased] +### Added +- New instrumentation for Service Fabric Service Remoting (#1234) + ## [Release 1.25.0](https://github.com/DataDog/dd-trace-dotnet/releases/tag/v1.25.0) ## Changes diff --git a/samples/ServiceFabricRemoting/DatadogInstall.bat b/samples/ServiceFabricRemoting/DatadogInstall.bat new file mode 100644 index 000000000000..38f091e7dc5f --- /dev/null +++ b/samples/ServiceFabricRemoting/DatadogInstall.bat @@ -0,0 +1,3 @@ + +REM This is a required entry point for PowerShell scripts in Azure Service Fabric +powershell.exe -ExecutionPolicy Bypass -Command ".\DatadogInstall.ps1" > %SvcFabDir%\datadog-powershell-log.txt 2> %SvcFabDir%\datadog-powershell-error.txt diff --git a/samples/ServiceFabricRemoting/DatadogInstall.ps1 b/samples/ServiceFabricRemoting/DatadogInstall.ps1 new file mode 100644 index 000000000000..a636c3223bdd --- /dev/null +++ b/samples/ServiceFabricRemoting/DatadogInstall.ps1 @@ -0,0 +1,50 @@ +# allow overriding defaults using environment variables +if (Test-Path env:SvcFabDir) { $SvcFabDir = $env:SvcFabDir } else { $SvcFabDir = 'D:\SvcFab' } +if (Test-Path env:DD_TRACER_VERSION) { $DD_TRACER_VERSION = $env:DD_TRACER_VERSION } else { $DD_TRACER_VERSION = '1.24.0' } +if (Test-Path env:DD_TRACER_URL) { $DD_TRACER_URL = $env:DD_TRACER_URL } else { $DD_TRACER_URL = "https://github.com/DataDog/dd-trace-dotnet/releases/download/v$DD_TRACER_VERSION/windows-tracer-home.zip" } +if (Test-Path env:DD_DOTNET_TRACER_HOME) { $DD_DOTNET_TRACER_HOME = $env:DD_DOTNET_TRACER_HOME } else { $DD_DOTNET_TRACER_HOME = "$SvcFabDir\datadog-dotnet-tracer\v$DD_TRACER_VERSION" } + +Write-Host "[DatadogInstall.ps1] Installing Datadog .NET Tracer v$DD_TRACER_VERSION" + +# download, extract, and delete the archive +$ArchivePath = "$SvcFabDir\windows-tracer-home.zip" +Write-Host "[DatadogInstall.ps1] Downloading $DD_TRACER_URL to $ArchivePath" +Invoke-WebRequest $DD_TRACER_URL -OutFile $ArchivePath + +Write-Host "[DatadogInstall.ps1] Extracting to $DD_DOTNET_TRACER_HOME" +Expand-Archive -Force -Path "$SvcFabDir\windows-tracer-home.zip" -DestinationPath $DD_DOTNET_TRACER_HOME + +Write-Host "[DatadogInstall.ps1] Deleting $ArchivePath" +Remove-Item $ArchivePath + +# create a folder for log files +$LOGS_PATH = "$SvcFabDir\datadog-dotnet-tracer-logs" + +if (-not (Test-Path -Path $LOGS_PATH -PathType Container)) { + Write-Host "[DatadogInstall.ps1] Creating logs folder $LOGS_PATH" + New-Item -ItemType Directory -Force -Path $LOGS_PATH +} + +function Set-MachineEnvironmentVariable { + param( + [string]$name, + [string]$value + ) + + Write-Host "[DatadogInstall.ps1] Setting environment variable $name=$value" + [System.Environment]::SetEnvironmentVariable($name, $value, [System.EnvironmentVariableTarget]::Machine) +} + +Set-MachineEnvironmentVariable 'DD_DOTNET_TRACER_HOME' $DD_DOTNET_TRACER_HOME +Set-MachineEnvironmentVariable 'DD_INTEGRATIONS' "$DD_DOTNET_TRACER_HOME\integrations.json" +Set-MachineEnvironmentVariable 'DD_TRACE_LOG_PATH' "$LOGS_PATH\dotnet-tracer-native.log" + +# Set-MachineEnvironmentVariable'COR_ENABLE_PROFILING' '0' # Enable per app +Set-MachineEnvironmentVariable 'COR_PROFILER' '{846F5F1C-F9AE-4B07-969E-05C26BC060D8}' +Set-MachineEnvironmentVariable 'COR_PROFILER_PATH_32' "$DD_DOTNET_TRACER_HOME\win-x86\Datadog.Trace.ClrProfiler.Native.dll" +Set-MachineEnvironmentVariable 'COR_PROFILER_PATH_64' "$DD_DOTNET_TRACER_HOME\win-x64\Datadog.Trace.ClrProfiler.Native.dll" + +# Set-MachineEnvironmentVariable 'CORECLR_ENABLE_PROFILING' '0' # Enable per app +Set-MachineEnvironmentVariable 'CORECLR_PROFILER' '{846F5F1C-F9AE-4B07-969E-05C26BC060D8}' +Set-MachineEnvironmentVariable 'CORECLR_PROFILER_PATH_32' "$DD_DOTNET_TRACER_HOME\win-x86\Datadog.Trace.ClrProfiler.Native.dll" +Set-MachineEnvironmentVariable 'CORECLR_PROFILER_PATH_64' "$DD_DOTNET_TRACER_HOME\win-x64\Datadog.Trace.ClrProfiler.Native.dll" diff --git a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationPackageRoot/ApplicationManifest.xml b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationPackageRoot/ApplicationManifest.xml index d69e7d66ca3c..8d07a3d81e6b 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationPackageRoot/ApplicationManifest.xml +++ b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationPackageRoot/ApplicationManifest.xml @@ -1,7 +1,8 @@  - + + @@ -9,15 +10,27 @@ should match the Name and Version attributes of the ServiceManifest element defined in the ServiceManifest.xml file. --> - + + + + + + + + + + + + + - - + + + + + + + @@ -36,4 +54,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Cloud.xml b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Cloud.xml index 381cd5a96cac..d57d6b7bf5f2 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Cloud.xml +++ b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Cloud.xml @@ -1,7 +1,8 @@  - + + \ No newline at end of file diff --git a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.1Node.xml b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.1Node.xml index 2a0c92793ef0..ab5e48a6de1e 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.1Node.xml +++ b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.1Node.xml @@ -1,7 +1,8 @@  - + + diff --git a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.5Node.xml b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.5Node.xml index 2a0c92793ef0..ab5e48a6de1e 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.5Node.xml +++ b/samples/ServiceFabricRemoting/ServiceFabricApplication/ApplicationParameters/Local.5Node.xml @@ -1,7 +1,8 @@  - + + diff --git a/samples/ServiceFabricRemoting/ServiceFabricApplication/ServiceFabricApplication.sfproj b/samples/ServiceFabricRemoting/ServiceFabricApplication/ServiceFabricApplication.sfproj index cbf1ff281368..9584d3b69a5b 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricApplication/ServiceFabricApplication.sfproj +++ b/samples/ServiceFabricRemoting/ServiceFabricApplication/ServiceFabricApplication.sfproj @@ -32,7 +32,8 @@ - + + http://{MachineName}:{ServicePort}/weatherforecast diff --git a/samples/ServiceFabricRemoting/ServiceFabricRemoting.sln b/samples/ServiceFabricRemoting/ServiceFabricRemoting.sln index d282f1482111..65c6fcae7a2d 100644 --- a/samples/ServiceFabricRemoting/ServiceFabricRemoting.sln +++ b/samples/ServiceFabricRemoting/ServiceFabricRemoting.sln @@ -7,62 +7,46 @@ Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "ServiceFabricApplication", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp", "WebApp\WebApp.csproj", "{35D2DD19-F76D-490D-9DF6-0B8CCB97018E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeatherService", "WeatherService\WeatherService.csproj", "{62A2C141-DD29-44BA-88BA-99CE709D1F6C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeatherService.NetCore31", "WeatherService.NetCore31\WeatherService.NetCore31.csproj", "{62A2C141-DD29-44BA-88BA-99CE709D1F6C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeatherService.Abstractions", "WeatherService.Abstractions\WeatherService.Abstractions.csproj", "{5B19C92B-70F3-4944-82E2-778F6DA25D37}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace", "..\..\src\Datadog.Trace\Datadog.Trace.csproj", "{17E1718D-4F1A-43BC-8B4A-CBF5322819A5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{10D3D75A-E5B7-43B4-9937-C7AE7723E34F}" + ProjectSection(SolutionItems) = preProject + DatadogInstall.bat = DatadogInstall.bat + DatadogInstall.ps1 = DatadogInstall.ps1 + EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace.ServiceFabric", "..\..\src\Datadog.Trace.ServiceFabric\Datadog.Trace.ServiceFabric.csproj", "{CDD153A5-243C-4CEB-8E9B-9E1640447EE9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeatherService.NetFx461", "WeatherService.NetFx461\WeatherService.NetFx461.csproj", "{4C032F2D-7A58-44B1-AF96-8EB655E49668}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Debug|Any CPU.ActiveCfg = Debug|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Debug|x64.ActiveCfg = Debug|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Debug|x64.Build.0 = Debug|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Debug|x64.Deploy.0 = Debug|x64 - {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Release|Any CPU.ActiveCfg = Release|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Release|x64.ActiveCfg = Release|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Release|x64.Build.0 = Release|x64 {013DA2CD-0FDA-4747-B3FC-1726BDE4FD00}.Release|x64.Deploy.0 = Release|x64 - {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Debug|Any CPU.ActiveCfg = Debug|x64 {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Debug|x64.ActiveCfg = Debug|x64 {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Debug|x64.Build.0 = Debug|x64 - {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Release|Any CPU.ActiveCfg = Release|x64 {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Release|x64.ActiveCfg = Release|x64 {35D2DD19-F76D-490D-9DF6-0B8CCB97018E}.Release|x64.Build.0 = Release|x64 - {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Debug|Any CPU.ActiveCfg = Debug|x64 {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Debug|x64.ActiveCfg = Debug|x64 {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Debug|x64.Build.0 = Debug|x64 - {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Release|Any CPU.ActiveCfg = Release|x64 {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Release|x64.ActiveCfg = Release|x64 {62A2C141-DD29-44BA-88BA-99CE709D1F6C}.Release|x64.Build.0 = Release|x64 - {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Debug|Any CPU.ActiveCfg = Debug|x64 {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Debug|x64.ActiveCfg = Debug|x64 {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Debug|x64.Build.0 = Debug|x64 - {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Release|Any CPU.ActiveCfg = Release|x64 {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Release|x64.ActiveCfg = Release|x64 {5B19C92B-70F3-4944-82E2-778F6DA25D37}.Release|x64.Build.0 = Release|x64 - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Debug|x64.ActiveCfg = Debug|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Debug|x64.Build.0 = Debug|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Release|Any CPU.Build.0 = Release|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Release|x64.ActiveCfg = Release|Any CPU - {17E1718D-4F1A-43BC-8B4A-CBF5322819A5}.Release|x64.Build.0 = Release|Any CPU - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Debug|Any CPU.ActiveCfg = Debug|x64 - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Debug|x64.ActiveCfg = Debug|x64 - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Debug|x64.Build.0 = Debug|x64 - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Release|Any CPU.ActiveCfg = Release|x64 - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Release|x64.ActiveCfg = Release|x64 - {CDD153A5-243C-4CEB-8E9B-9E1640447EE9}.Release|x64.Build.0 = Release|x64 + {4C032F2D-7A58-44B1-AF96-8EB655E49668}.Debug|x64.ActiveCfg = Debug|x64 + {4C032F2D-7A58-44B1-AF96-8EB655E49668}.Debug|x64.Build.0 = Debug|x64 + {4C032F2D-7A58-44B1-AF96-8EB655E49668}.Release|x64.ActiveCfg = Release|x64 + {4C032F2D-7A58-44B1-AF96-8EB655E49668}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherForecast.cs b/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherForecast.cs index 956a7f2dcd7c..85c491826b93 100644 --- a/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherForecast.cs +++ b/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherForecast.cs @@ -9,5 +9,7 @@ public class WeatherForecast public int Temperature { get; set; } public string Message { get; set; } + + public string Service { get; set; } } } diff --git a/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherService.Abstractions.csproj b/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherService.Abstractions.csproj index d591989e2c0e..71c7bb33c68c 100644 --- a/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherService.Abstractions.csproj +++ b/samples/ServiceFabricRemoting/WeatherService.Abstractions/WeatherService.Abstractions.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + netstandard2.0 x64 diff --git a/samples/ServiceFabricRemoting/WeatherService/PackageRoot/Config/Settings.xml b/samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/Config/Settings.xml similarity index 100% rename from samples/ServiceFabricRemoting/WeatherService/PackageRoot/Config/Settings.xml rename to samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/Config/Settings.xml diff --git a/samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/ServiceManifest.xml b/samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/ServiceManifest.xml new file mode 100644 index 000000000000..8442d5dcd25c --- /dev/null +++ b/samples/ServiceFabricRemoting/WeatherService.NetCore31/PackageRoot/ServiceManifest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + DatadogInstall.bat + CodePackage + + + + + WeatherService.NetFx461.exe + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/ServiceFabricRemoting/WeatherService/Program.cs b/samples/ServiceFabricRemoting/WeatherService.NetCore31/Program.cs similarity index 81% rename from samples/ServiceFabricRemoting/WeatherService/Program.cs rename to samples/ServiceFabricRemoting/WeatherService.NetCore31/Program.cs index 8438ffd7edaa..a0eb90ae4c3a 100644 --- a/samples/ServiceFabricRemoting/WeatherService/Program.cs +++ b/samples/ServiceFabricRemoting/WeatherService.NetCore31/Program.cs @@ -1,7 +1,8 @@ +using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Runtime; -namespace WeatherService +namespace WeatherService.NetCore31 { internal static class Program { @@ -10,16 +11,14 @@ internal static class Program /// private static async Task Main() { - Datadog.Trace.ServiceFabric.Remoting.StartTracing(); - // The ServiceManifest.XML file defines one or more service type names. // Registering a service maps a service type name to a .NET type. // When Service Fabric creates an instance of this service type, // an instance of the class is created in this host process. - await ServiceRuntime.RegisterServiceAsync("WeatherService", context => new WeatherService(context)); + await ServiceRuntime.RegisterServiceAsync("WeatherService_NetCore31", context => new WeatherService(context)); // Prevents this host process from terminating so services keep running. - await Task.Delay(-1); + await Task.Delay(Timeout.Infinite); } } } diff --git a/samples/ServiceFabricRemoting/WeatherService/WeatherService.csproj b/samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.NetCore31.csproj similarity index 64% rename from samples/ServiceFabricRemoting/WeatherService/WeatherService.csproj rename to samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.NetCore31.csproj index 462a9ac7eb10..0716d36a058f 100644 --- a/samples/ServiceFabricRemoting/WeatherService/WeatherService.csproj +++ b/samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.NetCore31.csproj @@ -9,11 +9,16 @@ - - - - + + Always + + + Always + + + + diff --git a/samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.cs b/samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.cs new file mode 100644 index 000000000000..992390a43cfc --- /dev/null +++ b/samples/ServiceFabricRemoting/WeatherService.NetCore31/WeatherService.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Fabric; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using WeatherService.Abstractions; + +namespace WeatherService.NetCore31 +{ + /// + /// An instance of this class is created for each service instance by the Service Fabric runtime. + /// + internal sealed class WeatherService : StatelessService, IWeatherService + { + public WeatherService(StatelessServiceContext context) + : base(context) + { + } + + /// + /// Optional override to create listeners (e.g., TCP, HTTP) for this service replica to handle client or user requests. + /// + /// A collection of listeners. + protected override IEnumerable CreateServiceInstanceListeners() + { + return this.CreateServiceRemotingInstanceListeners(); + } + + public Task GetWeather(string message) + { + var rng = new Random(); + + var forecast = new WeatherForecast + { + Date = DateTime.Now, + Temperature = rng.Next(-100, 100), + Message = message, + Service = typeof(WeatherService).FullName + }; + + return Task.FromResult(forecast); + } + } +} diff --git a/samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/Config/Settings.xml b/samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/Config/Settings.xml new file mode 100644 index 000000000000..902c747afffc --- /dev/null +++ b/samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/Config/Settings.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/samples/ServiceFabricRemoting/WeatherService/PackageRoot/ServiceManifest.xml b/samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/ServiceManifest.xml similarity index 67% rename from samples/ServiceFabricRemoting/WeatherService/PackageRoot/ServiceManifest.xml rename to samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/ServiceManifest.xml index e39a4a8e785d..c09defb3b8d0 100644 --- a/samples/ServiceFabricRemoting/WeatherService/PackageRoot/ServiceManifest.xml +++ b/samples/ServiceFabricRemoting/WeatherService.NetFx461/PackageRoot/ServiceManifest.xml @@ -1,5 +1,5 @@ - - + + + + + DatadogInstall.bat + CodePackage + + - WeatherService.exe + WeatherService.NetFx461.exe + + + + + + + + + DatadogInstall.bat + CodePackage + + WebApp.exe @@ -20,6 +27,9 @@ + + + diff --git a/samples/ServiceFabricRemoting/WebApp/Program.cs b/samples/ServiceFabricRemoting/WebApp/Program.cs index dc9634425960..9dedde22c09d 100644 --- a/samples/ServiceFabricRemoting/WebApp/Program.cs +++ b/samples/ServiceFabricRemoting/WebApp/Program.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; @@ -27,7 +28,7 @@ private static async Task Main(string[] args) await ServiceRuntime.RegisterServiceAsync("WebApp", context => new WebApp(context)); // Prevents this host process from terminating so services keeps running. - await Task.Delay(-1); + await Task.Delay(Timeout.Infinite); } } diff --git a/samples/ServiceFabricRemoting/WebApp/Startup.cs b/samples/ServiceFabricRemoting/WebApp/Startup.cs index c8441c35105e..259b2c7f3078 100644 --- a/samples/ServiceFabricRemoting/WebApp/Startup.cs +++ b/samples/ServiceFabricRemoting/WebApp/Startup.cs @@ -24,8 +24,6 @@ public void ConfigureServices(IServiceCollection services) // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - Datadog.Trace.ServiceFabric.Remoting.StartTracing(); - if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/samples/ServiceFabricRemoting/WebApp/WebApp.csproj b/samples/ServiceFabricRemoting/WebApp/WebApp.csproj index 098a48a1e58a..016cb9e0705e 100644 --- a/samples/ServiceFabricRemoting/WebApp/WebApp.csproj +++ b/samples/ServiceFabricRemoting/WebApp/WebApp.csproj @@ -7,14 +7,20 @@ x64 + + + Always + + + Always + + + - - - diff --git a/src/Datadog.Trace.ClrProfiler.Managed/Instrumentation.cs b/src/Datadog.Trace.ClrProfiler.Managed/Instrumentation.cs index b10068251003..34fd3bf29157 100644 --- a/src/Datadog.Trace.ClrProfiler.Managed/Instrumentation.cs +++ b/src/Datadog.Trace.ClrProfiler.Managed/Instrumentation.cs @@ -4,6 +4,7 @@ using Datadog.Trace.Configuration; using Datadog.Trace.DiagnosticListeners; using Datadog.Trace.Logging; +using Datadog.Trace.ServiceFabric; namespace Datadog.Trace.ClrProfiler { @@ -58,6 +59,7 @@ public static void Initialize() try { + // ensure global instance is created if it's not already _ = Tracer.Instance; } catch @@ -88,6 +90,29 @@ public static void Initialize() { // ignore } + + // we only support Service Fabric Service Remoting instrumentation on .NET Core (including .NET 5+) + if (string.Equals(FrameworkDescription.Instance.Name, ".NET Core", StringComparison.OrdinalIgnoreCase) || + string.Equals(FrameworkDescription.Instance.Name, ".NET", StringComparison.OrdinalIgnoreCase)) + { + try + { + ServiceRemotingClient.StartTracing(); + } + catch + { + // ignore + } + + try + { + ServiceRemotingService.StartTracing(); + } + catch + { + // ignore + } + } #endif } diff --git a/src/Datadog.Trace.ServiceFabric/Datadog.Trace.ServiceFabric.csproj b/src/Datadog.Trace.ServiceFabric/Datadog.Trace.ServiceFabric.csproj deleted file mode 100644 index cd3adf40acd9..000000000000 --- a/src/Datadog.Trace.ServiceFabric/Datadog.Trace.ServiceFabric.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - netstandard2.0;net461 - enable - - - x64 - x64 - - - 1.23.0-alpha1 - Datadog APM - Service Remoting instrumentation for Datadog APM - true - snupkg - - - - - - - - - - - diff --git a/src/Datadog.Trace.ServiceFabric/GlobalSuppressions.cs b/src/Datadog.Trace.ServiceFabric/GlobalSuppressions.cs deleted file mode 100644 index 3d0acc64888c..000000000000 --- a/src/Datadog.Trace.ServiceFabric/GlobalSuppressions.cs +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name must match first type name", Justification = "Auto-generated code", Scope = "type", Target = "~T:System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute")] diff --git a/src/Datadog.Trace.ServiceFabric/Remoting.cs b/src/Datadog.Trace.ServiceFabric/Remoting.cs deleted file mode 100644 index 5e8534b69b99..000000000000 --- a/src/Datadog.Trace.ServiceFabric/Remoting.cs +++ /dev/null @@ -1,393 +0,0 @@ -using System; -using System.Globalization; -using System.Text; -using System.Threading; -using Datadog.Trace.Configuration; -using Microsoft.ServiceFabric.Services.Remoting.V2; -using Microsoft.ServiceFabric.Services.Remoting.V2.Client; -using Microsoft.ServiceFabric.Services.Remoting.V2.Runtime; - -namespace Datadog.Trace.ServiceFabric -{ - /// - /// Provides methods used start and stop tracing Service Remoting requests. - /// - public static class Remoting - { - private const string SpanNamePrefix = "service-remoting"; - - private static readonly IntegrationInfo IntegrationId = IntegrationRegistry.GetIntegrationInfo(nameof(IntegrationIds.ServiceRemoting)); - - private static readonly Datadog.Trace.Logging.IDatadogLogger Log = Datadog.Trace.Logging.DatadogLogging.GetLoggerFor(typeof(Remoting)); - - private static int _firstInitialization = 1; - private static bool _initialized; - private static string? _clientAnalyticsSampleRate; - private static string? _serverAnalyticsSampleRate; - - /// - /// Start tracing Service Remoting requests. - /// - public static void StartTracing() - { - // only run this code once - if (Interlocked.Exchange(ref _firstInitialization, 0) == 1) - { - // cache settings - _clientAnalyticsSampleRate = GetAnalyticsSampleRate(Tracer.Instance, enabledWithGlobalSetting: false)?.ToString(CultureInfo.InvariantCulture); - _serverAnalyticsSampleRate = GetAnalyticsSampleRate(Tracer.Instance, enabledWithGlobalSetting: true)?.ToString(CultureInfo.InvariantCulture); - - // client events - ServiceRemotingClientEvents.SendRequest += ServiceRemotingClientEvents_SendRequest; - ServiceRemotingClientEvents.ReceiveResponse += ServiceRemotingClientEvents_ReceiveResponse; - - // server events - ServiceRemotingServiceEvents.ReceiveRequest += ServiceRemotingServiceEvents_ReceiveRequest; - ServiceRemotingServiceEvents.SendResponse += ServiceRemotingServiceEvents_SendResponse; - - // don't handle any events until we have subscribed to all of them - _initialized = true; - } - } - - /// - /// Event handler called when the Service Remoting client sends a request. - /// - /// The object that raised the event. - /// The event arguments. - private static void ServiceRemotingClientEvents_SendRequest(object? sender, EventArgs? e) - { - if (!_initialized) - { - return; - } - - GetMessageHeaders(e, out var eventArgs, out var messageHeaders); - - try - { - var tracer = Tracer.Instance; - var span = CreateSpan(tracer, context: null, SpanKinds.Client, eventArgs, messageHeaders); - - try - { - // inject propagation context into message headers for distributed tracing - if (messageHeaders != null) - { - SamplingPriority? samplingPriority = span.Context.TraceContext?.SamplingPriority ?? span.Context.SamplingPriority; - string? origin = span.GetTag(Tags.Origin); - var context = new PropagationContext(span.TraceId, span.SpanId, samplingPriority, origin); - - InjectContext(context, messageHeaders); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error injecting message headers."); - } - - tracer.ActivateSpan(span); - } - catch (Exception ex) - { - Log.Error(ex, "Error creating or activating span."); - } - } - - /// - /// Event handler called when the Service Remoting client receives a response - /// from the server after it finishes processing a request. - /// - /// The object that raised the event. - /// The event arguments. Can be of type on success - /// or on failure. - private static void ServiceRemotingClientEvents_ReceiveResponse(object? sender, EventArgs e) - { - if (!_initialized) - { - return; - } - - FinishSpan(e, SpanKinds.Client); - } - - /// - /// Event handler called when the Service Remoting server receives an incoming request. - /// - /// The object that raised the event. - /// The event arguments. - private static void ServiceRemotingServiceEvents_ReceiveRequest(object? sender, EventArgs e) - { - if (!_initialized) - { - return; - } - - GetMessageHeaders(e, out var eventArgs, out var messageHeaders); - PropagationContext? propagationContext = null; - SpanContext? spanContext = null; - - try - { - // extract propagation context from message headers for distributed tracing - if (messageHeaders != null) - { - propagationContext = ExtractContext(messageHeaders); - - if (propagationContext != null) - { - spanContext = new SpanContext(propagationContext.Value.TraceId, propagationContext.Value.ParentSpanId, propagationContext.Value.SamplingPriority); - } - } - } - catch (Exception ex) - { - Log.Error(ex, "Error using propagation context to initialize span context."); - } - - try - { - var tracer = Tracer.Instance; - var span = CreateSpan(tracer, spanContext, SpanKinds.Server, eventArgs, messageHeaders); - - try - { - string? origin = propagationContext?.Origin; - - if (!string.IsNullOrEmpty(origin)) - { - span.SetTag(Tags.Origin, origin); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error setting origin tag on span."); - } - - tracer.ActivateSpan(span); - } - catch (Exception ex) - { - Log.Error(ex, "Error creating or activating new span."); - } - } - - /// - /// Event handler called when the Service Remoting server sends a response - /// after processing an incoming request. - /// - /// The object that raised the event. - /// The event arguments. Can be of type on success - /// or on failure. - private static void ServiceRemotingServiceEvents_SendResponse(object? sender, EventArgs e) - { - if (!_initialized) - { - return; - } - - FinishSpan(e, SpanKinds.Server); - } - - private static void GetMessageHeaders(EventArgs? eventArgs, out ServiceRemotingRequestEventArgs? requestEventArgs, out IServiceRemotingRequestMessageHeader? messageHeaders) - { - requestEventArgs = eventArgs as ServiceRemotingRequestEventArgs; - - try - { - if (requestEventArgs == null) - { - Log.Warning("Unexpected EventArgs type: {0}", eventArgs?.GetType().FullName ?? "null"); - } - - messageHeaders = requestEventArgs?.Request?.GetHeader(); - - if (messageHeaders == null) - { - Log.Warning("Cannot access request headers."); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error accessing request headers."); - messageHeaders = null; - } - } - - private static void InjectContext(PropagationContext context, IServiceRemotingRequestMessageHeader messageHeaders) - { - if (context.TraceId == 0 || context.ParentSpanId == 0) - { - return; - } - - try - { - messageHeaders.TryAddHeader(HttpHeaderNames.TraceId, context, ctx => BitConverter.GetBytes(ctx.TraceId)); - - messageHeaders.TryAddHeader(HttpHeaderNames.ParentId, context, ctx => BitConverter.GetBytes(ctx.ParentSpanId)); - - if (context.SamplingPriority != null) - { - messageHeaders.TryAddHeader(HttpHeaderNames.SamplingPriority, context, ctx => BitConverter.GetBytes((int)ctx.SamplingPriority!)); - } - - if (!string.IsNullOrEmpty(context.Origin)) - { - messageHeaders.TryAddHeader(HttpHeaderNames.Origin, context, ctx => Encoding.UTF8.GetBytes(ctx.Origin!)); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error injecting message headers."); - } - } - - private static PropagationContext? ExtractContext(IServiceRemotingRequestMessageHeader messageHeaders) - { - try - { - ulong traceId = messageHeaders.TryGetHeaderValueUInt64(HttpHeaderNames.TraceId) ?? 0; - - if (traceId > 0) - { - ulong parentSpanId = messageHeaders.TryGetHeaderValueUInt64(HttpHeaderNames.ParentId) ?? 0; - - if (parentSpanId > 0) - { - SamplingPriority? samplingPriority = (SamplingPriority?)messageHeaders.TryGetHeaderValueInt32(HttpHeaderNames.SamplingPriority); - string? origin = messageHeaders.TryGetHeaderValueString(HttpHeaderNames.Origin); - - return new PropagationContext(traceId, parentSpanId, samplingPriority, origin); - } - } - - return null; - } - catch (Exception ex) - { - Log.Error(ex, "Error extracting message headers."); - return default; - } - } - - private static string GetSpanName(string spanKind) - { - return $"{SpanNamePrefix}.{spanKind}"; - } - - private static Span CreateSpan( - Tracer tracer, - SpanContext? context, - string spanKind, - ServiceRemotingRequestEventArgs? eventArgs, - IServiceRemotingRequestMessageHeader? messageHeader) - { - string? methodName = null; - string? resourceName = null; - string? serviceUrl = eventArgs?.ServiceUri?.AbsoluteUri; - - if (eventArgs != null) - { - methodName = eventArgs.MethodName; - - if (string.IsNullOrEmpty(methodName)) - { - // use the numeric id as the method name - methodName = messageHeader == null ? "unknown" : messageHeader.MethodId.ToString(CultureInfo.InvariantCulture); - } - - resourceName = serviceUrl == null ? methodName : $"{serviceUrl}/{methodName}"; - } - - Span span = tracer.StartSpan(GetSpanName(spanKind), context); - span.ResourceName = resourceName ?? "unknown"; - span.SetTag(Tags.SpanKind, spanKind); - - if (serviceUrl != null) - { - span.SetTag(Tags.HttpUrl, serviceUrl); - } - - if (methodName != null) - { - span.SetTag("method-name", methodName); - } - - if (messageHeader != null) - { - span.SetTag("method-id", messageHeader.MethodId.ToString(CultureInfo.InvariantCulture)); - span.SetTag("interface-id", messageHeader.InterfaceId.ToString(CultureInfo.InvariantCulture)); - - if (messageHeader.InvocationId != null) - { - span.SetTag("invocation-id", messageHeader.InvocationId); - } - } - - switch (spanKind) - { - case SpanKinds.Client when _clientAnalyticsSampleRate != null: - span.SetTag(Tags.Analytics, _clientAnalyticsSampleRate); - break; - case SpanKinds.Server when _serverAnalyticsSampleRate != null: - span.SetTag(Tags.Analytics, _serverAnalyticsSampleRate); - break; - } - - return span; - } - - private static void FinishSpan(EventArgs e, string spanKind) - { - if (!_initialized) - { - return; - } - - try - { - var scope = Tracer.Instance.ActiveScope; - - if (scope == null) - { - Log.Warning("Expected an active scope, but there is none."); - return; - } - - string expectedSpanName = GetSpanName(spanKind); - - if (expectedSpanName != scope.Span.OperationName) - { - Log.Warning("Expected span name {0}, but found {1} instead.", expectedSpanName, scope.Span.OperationName); - return; - } - - try - { - if (e is ServiceRemotingFailedResponseEventArgs failedResponseArg && failedResponseArg.Error != null) - { - scope.Span?.SetException(failedResponseArg.Error); - } - } - catch (Exception ex) - { - Log.Error(ex, "Error setting exception tags on span."); - } - - scope.Dispose(); - } - catch (Exception ex) - { - Log.Error(ex, "Error accessing or finishing active span."); - } - } - - private static double? GetAnalyticsSampleRate(Tracer tracer, bool enabledWithGlobalSetting) - { - IntegrationSettings integrationSettings = tracer.Settings.Integrations[IntegrationId]; - bool analyticsEnabled = integrationSettings.AnalyticsEnabled ?? (enabledWithGlobalSetting && tracer.Settings.AnalyticsEnabled); - return analyticsEnabled ? integrationSettings.AnalyticsSampleRate : (double?)null; - } - } -} diff --git a/src/Datadog.Trace.ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs b/src/Datadog.Trace.ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs deleted file mode 100644 index 0e3daa99d797..000000000000 --- a/src/Datadog.Trace.ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Text; -using Microsoft.ServiceFabric.Services.Remoting.V2; - -namespace Datadog.Trace.ServiceFabric -{ - internal static class ServiceRemotingRequestMessageHeaderExtensions - { - public static bool TryAddHeader(this IServiceRemotingRequestMessageHeader headers, string headerName, PropagationContext context, Func headerValue) - { - if (!headers.TryGetHeaderValue(headerName, out _)) - { - byte[] bytes = headerValue(context); - headers.AddHeader(headerName, bytes); - return true; - } - - return false; - } - - public static int? TryGetHeaderValueInt32(this IServiceRemotingRequestMessageHeader headers, string headerName) - { - if (headers.TryGetHeaderValue(headerName, out byte[] bytes) && bytes?.Length == sizeof(int)) - { - return BitConverter.ToInt32(bytes, 0); - } - - return null; - } - - public static ulong? TryGetHeaderValueUInt64(this IServiceRemotingRequestMessageHeader headers, string headerName) - { - if (headers.TryGetHeaderValue(headerName, out byte[] bytes) && bytes?.Length == sizeof(ulong)) - { - return BitConverter.ToUInt64(bytes, 0); - } - - return null; - } - - public static string? TryGetHeaderValueString(this IServiceRemotingRequestMessageHeader headers, string headerName) - { - if (headers.TryGetHeaderValue(headerName, out byte[] bytes) && bytes?.Length > 0) - { - return Encoding.UTF8.GetString(bytes); - } - - return null; - } - } -} diff --git a/src/Datadog.Trace.ServiceFabric/nuget.config b/src/Datadog.Trace.ServiceFabric/nuget.config deleted file mode 100644 index f3ef65bec086..000000000000 --- a/src/Datadog.Trace.ServiceFabric/nuget.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Datadog.Trace/PlatformHelpers/ServiceFabric.cs b/src/Datadog.Trace/PlatformHelpers/ServiceFabric.cs new file mode 100644 index 000000000000..e14d5f7d119d --- /dev/null +++ b/src/Datadog.Trace/PlatformHelpers/ServiceFabric.cs @@ -0,0 +1,20 @@ +using Datadog.Trace.ServiceFabric; +using Datadog.Trace.Util; + +namespace Datadog.Trace.PlatformHelpers +{ + internal static class ServiceFabric + { + public static readonly string ServiceName = EnvironmentHelpers.GetEnvironmentVariable("Fabric_ServiceName"); + + public static readonly string ApplicationId = EnvironmentHelpers.GetEnvironmentVariable("Fabric_ApplicationId"); + + public static readonly string ApplicationName = EnvironmentHelpers.GetEnvironmentVariable("Fabric_ApplicationName"); + + public static readonly string PartitionId = EnvironmentHelpers.GetEnvironmentVariable("Fabric_PartitionId"); + + public static readonly string NodeId = EnvironmentHelpers.GetEnvironmentVariable("Fabric_NodeId"); + + public static readonly string NodeName = EnvironmentHelpers.GetEnvironmentVariable("Fabric_NodeName"); + } +} diff --git a/src/Datadog.Trace.ServiceFabric/PropagationContext.cs b/src/Datadog.Trace/ServiceFabric/PropagationContext.cs similarity index 96% rename from src/Datadog.Trace.ServiceFabric/PropagationContext.cs rename to src/Datadog.Trace/ServiceFabric/PropagationContext.cs index 5047b06ed15d..1cdfae2b8b01 100644 --- a/src/Datadog.Trace.ServiceFabric/PropagationContext.cs +++ b/src/Datadog.Trace/ServiceFabric/PropagationContext.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace Datadog.Trace.ServiceFabric { internal readonly struct PropagationContext diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingClient.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingClient.cs new file mode 100644 index 000000000000..84a7ba77a5b9 --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingClient.cs @@ -0,0 +1,98 @@ +#nullable enable + +using System; +using System.Threading; + +namespace Datadog.Trace.ServiceFabric +{ + /// + /// Provides tracing of ServiceRemotingClientEvents. + /// + internal static class ServiceRemotingClient + { + private static readonly Logging.IDatadogLogger Log = Logging.DatadogLogging.GetLoggerFor(typeof(ServiceRemotingClient)); + + private static int _firstInitialization = 1; + private static bool _initialized; + + /// + /// Start tracing ServiceRemotingClientEvents. + /// + public static void StartTracing() + { + // only run this code once + if (Interlocked.Exchange(ref _firstInitialization, 0) == 1) + { + // try to subscribe to client events + if (ServiceRemotingHelpers.AddEventHandler(ServiceRemotingConstants.ClientEventsTypeName, ServiceRemotingConstants.SendRequestEventName, ServiceRemotingClientEvents_SendRequest) && + ServiceRemotingHelpers.AddEventHandler(ServiceRemotingConstants.ClientEventsTypeName, ServiceRemotingConstants.ReceiveResponseEventName, ServiceRemotingClientEvents_ReceiveResponse)) + { + // don't handle any client events until we have subscribed to both of them + _initialized = true; + Log.Debug($"Subscribed to {ServiceRemotingConstants.ClientEventsTypeName} events."); + } + } + } + + /// + /// Event handler called when the Service Remoting client sends a request. + /// + /// The object that raised the event. + /// The event arguments. + private static void ServiceRemotingClientEvents_SendRequest(object? sender, EventArgs? e) + { + var tracer = Tracer.Instance; + + if (!_initialized || !tracer.Settings.IsIntegrationEnabled(ServiceRemotingConstants.IntegrationId)) + { + return; + } + + ServiceRemotingHelpers.GetMessageHeaders(e, out var eventArgs, out var messageHeaders); + + try + { + var span = ServiceRemotingHelpers.CreateSpan(tracer, context: null, SpanKinds.Client, eventArgs, messageHeaders); + + try + { + // inject propagation context into message headers for distributed tracing + if (messageHeaders != null) + { + SpanContextPropagator.Instance.Inject( + span.Context, + messageHeaders, + (headers, headerName, headerValue) => headers.TryAddHeader(headerName, headerValue)); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error injecting span context into Service Fabric Service Remoting message headers."); + } + + tracer.ActivateSpan(span); + } + catch (Exception ex) + { + Log.Error(ex, "Error creating or activating Service Fabric Service Remoting client span."); + } + } + + /// + /// Event handler called when the Service Remoting client receives a response + /// from the server after it finishes processing a request. + /// + /// The object that raised the event. + /// The event arguments. Can be of type IServiceRemotingResponseEventArgs2 on success + /// or IServiceRemotingFailedResponseEventArgs on failure. + private static void ServiceRemotingClientEvents_ReceiveResponse(object? sender, EventArgs? e) + { + if (!_initialized || !Tracer.Instance.Settings.IsIntegrationEnabled(ServiceRemotingConstants.IntegrationId)) + { + return; + } + + ServiceRemotingHelpers.FinishSpan(e, SpanKinds.Client); + } + } +} diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingConstants.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingConstants.cs new file mode 100644 index 000000000000..04abf889c14c --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingConstants.cs @@ -0,0 +1,23 @@ +using Datadog.Trace.Configuration; + +namespace Datadog.Trace.ServiceFabric +{ + internal static class ServiceRemotingConstants + { + public const string AssemblyName = "Microsoft.ServiceFabric.Services.Remoting"; + + public const string ClientEventsTypeName = "Microsoft.ServiceFabric.Services.Remoting.V2.Client.ServiceRemotingClientEvents"; + + public const string ServiceEventsTypeName = "Microsoft.ServiceFabric.Services.Remoting.V2.Runtime.ServiceRemotingServiceEvents"; + + public const string SendRequestEventName = "SendRequest"; + + public const string ReceiveResponseEventName = "ReceiveResponse"; + + public const string ReceiveRequestEventName = "ReceiveRequest"; + + public const string SendResponseEventName = "SendResponse"; + + public static readonly IntegrationInfo IntegrationId = IntegrationRegistry.GetIntegrationInfo(nameof(IntegrationIds.ServiceRemoting)); + } +} diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingHelpers.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingHelpers.cs new file mode 100644 index 000000000000..f9472862d93a --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingHelpers.cs @@ -0,0 +1,176 @@ +#nullable enable + +using System; +using System.Globalization; +using System.Reflection; +using Datadog.Trace.DuckTyping; + +namespace Datadog.Trace.ServiceFabric +{ + internal static class ServiceRemotingHelpers + { + private const string SpanNamePrefix = "service_remoting"; + + private static readonly Logging.IDatadogLogger Log = Logging.DatadogLogging.GetLoggerFor(typeof(ServiceRemotingHelpers)); + + public static bool AddEventHandler(string typeName, string eventName, EventHandler eventHandler) + { + string fullEventName = $"{typeName}.{eventName}"; + + try + { + Type? type = Type.GetType($"{typeName}, {ServiceRemotingConstants.AssemblyName}", throwOnError: false); + + if (type == null) + { + Log.Warning("Could not get type {typeName}.", typeName); + return false; + } + + EventInfo? eventInfo = type.GetEvent(eventName, BindingFlags.Static | BindingFlags.Public); + + if (eventInfo == null) + { + Log.Warning("Could not get event {eventName}.", fullEventName); + return false; + } + + // use null target because event is static + eventInfo.AddEventHandler(target: null, eventHandler); + Log.Debug("Subscribed to event {eventName}.", fullEventName); + return true; + } + catch (Exception ex) + { + Log.Error(ex, "Error adding event handler to {eventName}.", fullEventName); + return false; + } + } + + public static void GetMessageHeaders(EventArgs? eventArgs, out IServiceRemotingRequestEventArgs? requestEventArgs, out IServiceRemotingRequestMessageHeader? messageHeaders) + { + requestEventArgs = null; + messageHeaders = null; + + if (eventArgs == null) + { + Log.Warning("Unexpected null EventArgs."); + return; + } + + try + { + requestEventArgs = eventArgs.DuckAs(); + messageHeaders = requestEventArgs?.Request?.GetHeader(); + } + catch (Exception ex) + { + Log.Error(ex, "Error accessing request headers."); + return; + } + + if (messageHeaders == null) + { + Log.Warning("Cannot access request headers."); + } + } + + public static string GetSpanName(string spanKind) + { + return $"{SpanNamePrefix}.{spanKind}"; + } + + public static Span CreateSpan( + Tracer tracer, + ISpanContext? context, + string spanKind, + IServiceRemotingRequestEventArgs? eventArgs, + IServiceRemotingRequestMessageHeader? messageHeader) + { + string? methodName = null; + string? resourceName = null; + string? serviceUrl = null; + + string serviceFabricServiceName = PlatformHelpers.ServiceFabric.ServiceName; + + if (eventArgs != null) + { + methodName = eventArgs.MethodName ?? + messageHeader?.MethodName ?? + messageHeader?.MethodId.ToString(CultureInfo.InvariantCulture) ?? + "unknown_method"; + + serviceUrl = eventArgs.ServiceUri?.AbsoluteUri; + resourceName = serviceUrl == null ? methodName : $"{serviceUrl}/{methodName}"; + } + + var tags = new ServiceRemotingTags(spanKind) + { + ApplicationId = PlatformHelpers.ServiceFabric.ApplicationId, + ApplicationName = PlatformHelpers.ServiceFabric.ApplicationName, + PartitionId = PlatformHelpers.ServiceFabric.PartitionId, + NodeId = PlatformHelpers.ServiceFabric.NodeId, + NodeName = PlatformHelpers.ServiceFabric.NodeName, + ServiceName = serviceFabricServiceName, + RemotingUri = serviceUrl, + RemotingMethodName = methodName + }; + + if (messageHeader != null) + { + tags.RemotingMethodId = messageHeader.MethodId.ToString(CultureInfo.InvariantCulture); + tags.RemotingInterfaceId = messageHeader.InterfaceId.ToString(CultureInfo.InvariantCulture); + tags.RemotingInvocationId = messageHeader.InvocationId; + } + + Span span = tracer.StartSpan(GetSpanName(spanKind), tags, context); + span.ResourceName = resourceName; + tags.SetAnalyticsSampleRate(ServiceRemotingConstants.IntegrationId, Tracer.Instance.Settings, enabledWithGlobalSetting: false); + + return span; + } + + public static void FinishSpan(EventArgs? e, string spanKind) + { + try + { + var scope = Tracer.Instance.ActiveScope; + + if (scope == null) + { + Log.Warning("Expected an active scope, but there is none."); + return; + } + + string expectedSpanName = GetSpanName(spanKind); + + if (expectedSpanName != scope.Span.OperationName) + { + Log.Warning("Expected span name {expectedSpanName}, but found {actualSpanName} instead.", expectedSpanName, scope.Span.OperationName); + return; + } + + try + { + var eventArgs = e?.DuckAs(); + var exception = eventArgs?.Error; + + if (exception != null) + { + scope.Span?.SetException(exception); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error setting exception tags on span."); + } + + scope.Dispose(); + } + catch (Exception ex) + { + Log.Error(ex, "Error accessing or finishing active span."); + } + } + } +} diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs new file mode 100644 index 000000000000..b40a67a38d2a --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingRequestMessageHeaderExtensions.cs @@ -0,0 +1,34 @@ +#nullable enable + +using System; +using System.Text; + +namespace Datadog.Trace.ServiceFabric +{ + internal static class ServiceRemotingRequestMessageHeaderExtensions + { + public static bool TryAddHeader(this IServiceRemotingRequestMessageHeader headers, string headerName, string headerValue) + { + if (!headers.TryGetHeaderValue(headerName, out _)) + { + byte[] bytes = Encoding.UTF8.GetBytes(headerValue); + headers.AddHeader(headerName, bytes); + return true; + } + + return false; + } + + public static bool TryGetHeaderValueString(this IServiceRemotingRequestMessageHeader headers, string headerName, out string? headerValue) + { + if (headers.TryGetHeaderValue(headerName, out var bytes) && bytes is not null) + { + headerValue = Encoding.UTF8.GetString(bytes); + return true; + } + + headerValue = default; + return false; + } + } +} diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingService.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingService.cs new file mode 100644 index 000000000000..e7688f374e24 --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingService.cs @@ -0,0 +1,104 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Datadog.Trace.ServiceFabric +{ + /// + /// Provides tracing of ServiceRemotingServiceEvents. + /// + internal static class ServiceRemotingService + { + private static readonly Logging.IDatadogLogger Log = Logging.DatadogLogging.GetLoggerFor(typeof(ServiceRemotingService)); + + private static int _firstInitialization = 1; + private static bool _initialized; + + /// + /// Start tracing ServiceRemotingServiceEvents. + /// + public static void StartTracing() + { + // only run this code once + if (Interlocked.Exchange(ref _firstInitialization, 0) == 1) + { + // try to subscribe to service events + if (ServiceRemotingHelpers.AddEventHandler(ServiceRemotingConstants.ServiceEventsTypeName, ServiceRemotingConstants.ReceiveRequestEventName, ServiceRemotingServiceEvents_ReceiveRequest) && + ServiceRemotingHelpers.AddEventHandler(ServiceRemotingConstants.ServiceEventsTypeName, ServiceRemotingConstants.SendResponseEventName, ServiceRemotingServiceEvents_SendResponse)) + { + // don't handle any service events until we have subscribed to both of them + _initialized = true; + Log.Debug($"Subscribed to {ServiceRemotingConstants.ServiceEventsTypeName} events."); + } + } + } + + /// + /// Event handler called when the Service Remoting server receives an incoming request. + /// + /// The object that raised the event. + /// The event arguments. + private static void ServiceRemotingServiceEvents_ReceiveRequest(object? sender, EventArgs? e) + { + var tracer = Tracer.Instance; + + if (!_initialized || !tracer.Settings.IsIntegrationEnabled(ServiceRemotingConstants.IntegrationId)) + { + return; + } + + ServiceRemotingHelpers.GetMessageHeaders(e, out var eventArgs, out var messageHeaders); + SpanContext? spanContext = null; + + try + { + // extract propagation context from message headers for distributed tracing + if (messageHeaders != null) + { + spanContext = SpanContextPropagator.Instance.Extract(messageHeaders, GetHeaders); + } + } + catch (Exception ex) + { + Log.Error(ex, "Error extracting span context from Service Fabric Service Remoting message headers."); + } + + try + { + var span = ServiceRemotingHelpers.CreateSpan(tracer, spanContext, SpanKinds.Server, eventArgs, messageHeaders); + tracer.ActivateSpan(span); + } + catch (Exception ex) + { + Log.Error(ex, "Error creating or activating new Service Fabric Service Remoting service span."); + } + } + + /// + /// Event handler called when the Service Remoting server sends a response + /// after processing an incoming request. + /// + /// The object that raised the event. + /// The event arguments. Can be of type IServiceRemotingResponseEventArgs2 on success + /// or IServiceRemotingFailedResponseEventArgs2 on failure. + private static void ServiceRemotingServiceEvents_SendResponse(object? sender, EventArgs? e) + { + if (!_initialized || !Tracer.Instance.Settings.IsIntegrationEnabled(ServiceRemotingConstants.IntegrationId)) + { + return; + } + + ServiceRemotingHelpers.FinishSpan(e, SpanKinds.Server); + } + + private static IEnumerable GetHeaders(IServiceRemotingRequestMessageHeader headers, string headerName) + { + if (headers.TryGetHeaderValueString(headerName, out var headerValue)) + { + yield return headerValue; + } + } + } +} diff --git a/src/Datadog.Trace/ServiceFabric/ServiceRemotingTags.cs b/src/Datadog.Trace/ServiceFabric/ServiceRemotingTags.cs new file mode 100644 index 000000000000..37317529a4df --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/ServiceRemotingTags.cs @@ -0,0 +1,83 @@ +#nullable enable + +using Datadog.Trace.ExtensionMethods; +using Datadog.Trace.Tagging; + +namespace Datadog.Trace.ServiceFabric +{ + internal class ServiceRemotingTags : InstrumentationTags + { + protected static readonly IProperty[] ServiceRemotingTagProperties = + InstrumentationTagsProperties.Concat( + new Property(TagNames.ApplicationId, t => t.ApplicationId, (t, v) => t.ApplicationId = v), + new Property(TagNames.ApplicationName, t => t.ApplicationName, (t, v) => t.ApplicationName = v), + new Property(TagNames.PartitionId, t => t.PartitionId, (t, v) => t.PartitionId = v), + new Property(TagNames.NodeId, t => t.NodeId, (t, v) => t.NodeId = v), + new Property(TagNames.NodeName, t => t.NodeName, (t, v) => t.NodeName = v), + new Property(TagNames.ServiceName, t => t.ServiceName, (t, v) => t.ServiceName = v), + new Property(TagNames.RemotingUri, t => t.RemotingUri, (t, v) => t.RemotingUri = v), + new Property(TagNames.RemotingMethodName, t => t.RemotingMethodName, (t, v) => t.RemotingMethodName = v), + new Property(TagNames.RemotingMethodId, t => t.RemotingMethodId, (t, v) => t.RemotingMethodId = v), + new Property(TagNames.RemotingInterfaceId, t => t.RemotingInterfaceId, (t, v) => t.RemotingInterfaceId = v), + new Property(TagNames.RemotingInvocationId, t => t.RemotingInvocationId, (t, v) => t.RemotingInvocationId = v)); + + /// + /// Initializes a new instance of the class. + /// For testing purposes only. Do not use directly. + /// + public ServiceRemotingTags() + { + } + + public ServiceRemotingTags(string spanKind) + { + SpanKind = spanKind; + } + + public override string? SpanKind { get; } + + // general Service Fabric + public string? ApplicationId { get; set; } + + public string? ApplicationName { get; set; } + + public string? PartitionId { get; set; } + + public string? NodeId { get; set; } + + public string? NodeName { get; set; } + + public string? ServiceName { get; set; } + + // Service Remoting + public string? RemotingUri { get; set; } + + public string? RemotingMethodName { get; set; } + + public string? RemotingMethodId { get; set; } + + public string? RemotingInterfaceId { get; set; } + + public string? RemotingInvocationId { get; set; } + + protected override IProperty[] GetAdditionalTags() => ServiceRemotingTagProperties; + + internal static class TagNames + { + // general Service Fabric + public const string ApplicationId = "service-fabric.application-id"; + public const string ApplicationName = "service-fabric.application-name"; + public const string PartitionId = "service-fabric.partition-id"; + public const string NodeId = "service-fabric.node-id"; + public const string NodeName = "service-fabric.node-name"; + public const string ServiceName = "service-fabric.service-name"; + + // Service Remoting + public const string RemotingUri = "service-fabric.service-remoting.uri"; + public const string RemotingMethodName = "service-fabric.service-remoting.method-name"; + public const string RemotingMethodId = "service-fabric.service-remoting.method-id"; + public const string RemotingInterfaceId = "service-fabric.service-remoting.interface-id"; + public const string RemotingInvocationId = "service-fabric.service-remoting.invocation-id"; + } + } +} diff --git a/src/Datadog.Trace/ServiceFabric/Stubs.cs b/src/Datadog.Trace/ServiceFabric/Stubs.cs new file mode 100644 index 000000000000..5dea40f329f7 --- /dev/null +++ b/src/Datadog.Trace/ServiceFabric/Stubs.cs @@ -0,0 +1,103 @@ +#nullable enable + +using System; +using System.ComponentModel; + +#pragma warning disable SA1649 // File name must match first type name +namespace Datadog.Trace.ServiceFabric +{ + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IServiceRemotingRequestMessageHeader + { + /// + /// Gets the method id. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + int MethodId { get; } + + /// + /// Gets the method identifier. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + int InterfaceId { get; } + + /// + /// Gets the invocation identifier. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + string? InvocationId { get; } + + /// + /// Gets the method name. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + string? MethodName { get; } + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + void AddHeader(string headerName, byte[] headerValue); + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + bool TryGetHeaderValue(string headerName, out byte[]? headerValue); + } + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IServiceRemotingRequestMessage + { + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + IServiceRemotingRequestMessageHeader GetHeader(); + } + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IServiceRemotingRequestEventArgs + { + /// + /// Gets the request message. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IServiceRemotingRequestMessage? Request { get; } + + /// + /// Gets the service URI. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Uri? ServiceUri { get; } + + /// + /// Gets the method name. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public string? MethodName { get; } + } + + /// + /// For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IServiceRemotingFailedResponseEventArgs + { + /// + /// Gets the exception. For internal use only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Exception? Error { get; } + } +} +#pragma warning restore SA1649 // File name must match first type name