diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f71577252..c4890f77a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,44 +129,71 @@ jobs: if: (${{ job.status }} != 'cancelled') continue-on-error: true - pack: - needs: build + build-nuget-packages: + needs: [ build, build-container ] - runs-on: ubuntu-20.04 + runs-on: windows-2022 steps: - uses: actions/checkout@v3.3.0 - - uses: nuget/setup-nuget@v1.1.1 - name: Download Windows Artifacts from build job uses: actions/download-artifact@v3.0.2 with: name: bin-windows-2022 - path: nuget/bin-windows + path: bin/ci-artifacts/bin-windows-2022 - name: Download CentOS Artifacts from build job uses: actions/download-artifact@v3.0.2 with: name: bin-centos - path: nuget/bin-linux-glibc + path: bin/ci-artifacts/bin-centos - name: Download Alpine Artifacts from build job uses: actions/download-artifact@v3.0.2 with: name: bin-alpine - path: nuget/bin-linux-musl + path: bin/ci-artifacts/bin-alpine - name: Download Mac-OS Artifacts from build job uses: actions/download-artifact@v3.0.2 with: name: bin-macos-11 - path: nuget/bin-macos + path: bin/ci-artifacts/bin-macos-11 + + - name: Build NuGet Runtime Packages + run: ./build.cmd BuildNuGetPackages - - name: Build NuGet package - run: nuget pack OpenTelemetry.AutoInstrumentation.nuspec -Properties NoWarn=NU5100,NU5123,NU5128 - working-directory: nuget + - name: Test NuGet Packages + run: ./build.cmd TestNuGetPackages - - name: Upload Nuget + - name: Upload Nuget Artifacts uses: actions/upload-artifact@v3.1.2 with: - name: OpenTelemetry.AutoInstrumentation.Nuget - path: nuget/*.nupkg + name: OpenTelemetry.AutoInstrumentation.NuGet.Packages + path: bin/nuget-artifacts/ + + test-nuget-packages: + needs: build-nuget-packages + strategy: + fail-fast: false + matrix: + include: + - machine: ubuntu-20.04 + - machine: macos-11 + runs-on: ${{ matrix.machine }} + steps: + - uses: actions/checkout@v3.3.0 + - uses: actions/setup-dotnet@v3.0.3 + with: + dotnet-version: | + 6.0.x + 7.0.x + + - name: Download NuGet Artifacts from build-nuget-packages job + uses: actions/download-artifact@v3.0.2 + with: + name: OpenTelemetry.AutoInstrumentation.NuGet.Packages + path: bin/nuget-artifacts/ + + - name: Test NuGet Packages + run: ./build.cmd TestNuGetPackages diff --git a/.gitignore b/.gitignore index 4447fe1ac1..0631675169 100644 --- a/.gitignore +++ b/.gitignore @@ -287,6 +287,9 @@ blog/ # exception to the ignore rule !/**/.gitkeep +# ignore artifacts downloaded to build OpenTelemetry.AutoInstrumentation.Runtime package +nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native/runtimes/ + # profiler build files src/OpenTelemetry.AutoInstrumentation.Native/build/ src/OpenTelemetry.AutoInstrumentation.Native/deps/ diff --git a/OpenTelemetry.AutoInstrumentation.sln b/OpenTelemetry.AutoInstrumentation.sln index 538c1a509f..627d53931f 100644 --- a/OpenTelemetry.AutoInstrumentation.sln +++ b/OpenTelemetry.AutoInstrumentation.sln @@ -170,6 +170,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GacInstallTool", "tools\Gac EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryVersionsGenerator", "tools\LibraryVersionsGenerator\LibraryVersionsGenerator.csproj", "{119F5BAD-6A58-40EA-8E0A-666CADE3CAF8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{98868FAF-0854-4E66-8306-3EFA7F2E9A45}" + ProjectSection(SolutionItems) = preProject + nuget\OpenTelemetry.AutoInstrumentation.Dependencies\OpenTelemetry.AutoInstrumentation.Dependencies.nuspec = nuget\OpenTelemetry.AutoInstrumentation.Dependencies\OpenTelemetry.AutoInstrumentation.Dependencies.nuspec + nuget\OpenTelemetry.AutoInstrumentation\OpenTelemetry.AutoInstrumentation.nuspec = nuget\OpenTelemetry.AutoInstrumentation\OpenTelemetry.AutoInstrumentation.nuspec + nuget\OpenTelemetry.AutoInstrumentation.Runtime.Native\OpenTelemetry.AutoInstrumentation.Runtime.Native.nuspec = nuget\OpenTelemetry.AutoInstrumentation.Runtime.Native\OpenTelemetry.AutoInstrumentation.Runtime.Native.nuspec + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGetPackagesTests", "test\NuGetPackagesTests\NuGetPackagesTests.csproj", "{AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget-packages", "nuget-packages", "{2EF2F7CE-E56F-4B81-A5A5-277693529D43}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.SelfContained", "test\test-applications\nuget-packages\TestApplication.SelfContained\TestApplication.SelfContained.csproj", "{25ED93D0-A70C-4A07-84D9-EF94115259C9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -798,6 +811,30 @@ Global {119F5BAD-6A58-40EA-8E0A-666CADE3CAF8}.Release|x64.Build.0 = Release|Any CPU {119F5BAD-6A58-40EA-8E0A-666CADE3CAF8}.Release|x86.ActiveCfg = Release|Any CPU {119F5BAD-6A58-40EA-8E0A-666CADE3CAF8}.Release|x86.Build.0 = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|x64.ActiveCfg = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|x64.Build.0 = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Debug|x86.Build.0 = Debug|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|Any CPU.Build.0 = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|x64.ActiveCfg = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|x64.Build.0 = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|x86.ActiveCfg = Release|Any CPU + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0}.Release|x86.Build.0 = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|x64.ActiveCfg = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|x64.Build.0 = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|x86.ActiveCfg = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Debug|x86.Build.0 = Debug|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|Any CPU.Build.0 = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|x64.ActiveCfg = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|x64.Build.0 = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|x86.ActiveCfg = Release|Any CPU + {25ED93D0-A70C-4A07-84D9-EF94115259C9}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -859,6 +896,9 @@ Global {D6181786-C7F1-400D-A678-8DC300485429} = {00F4C92D-6652-4BD8-A334-B35D3E711BE6} {6A63DAA1-463A-4F7E-B3FF-3B444F161DBD} = {00F4C92D-6652-4BD8-A334-B35D3E711BE6} {119F5BAD-6A58-40EA-8E0A-666CADE3CAF8} = {00F4C92D-6652-4BD8-A334-B35D3E711BE6} + {AFD7582B-E9CD-4DF4-93B4-D5BBD7F539D0} = {5C915382-C886-457D-8641-9E766D8E5A17} + {2EF2F7CE-E56F-4B81-A5A5-277693529D43} = {91A299AD-6C09-4B7F-BD8B-A705D9BFC672} + {25ED93D0-A70C-4A07-84D9-EF94115259C9} = {2EF2F7CE-E56F-4B81-A5A5-277693529D43} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F} diff --git a/build/Build.NuGet.Steps.cs b/build/Build.NuGet.Steps.cs new file mode 100644 index 0000000000..bc55fd02d0 --- /dev/null +++ b/build/Build.NuGet.Steps.cs @@ -0,0 +1,163 @@ +using System.Runtime.InteropServices; +using Extensions; +using Nuke.Common; +using Nuke.Common.IO; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.Tools.NuGet; +using static Nuke.Common.IO.FileSystemTasks; +using static Nuke.Common.Tools.DotNet.DotNetTasks; + +partial class Build +{ + AbsolutePath NuGetArtifactsDirectory => NuGetArtifacts ?? (OutputDirectory / "nuget-artifacts"); + + Target BuildNuGetPackages => _ => _ + .Description( + "Builds the NuGet packages of the project assuming that any necessary build artifacts were already downloaded.") + .DependsOn(BuildManagedSrcNuGetPackages) + .DependsOn(CopyIntegrationsJsonForNuGetPackage) + .DependsOn(SetupRuntimeNativeFolderForNuGetPackage) + .DependsOn(BuildNuSpecNuGetPackages); + + Target TestNuGetPackages => _ => _ + .Description( + "Test the NuGet packages of the project assuming that the packages are available at bin/nuget-artifacts.") + .DependsOn(BuildNuGetPackagesTests) + .DependsOn(BuildNuGetPackagesTestApplications) + .DependsOn(RunNuGetPackagesTests); + + Target BuildManagedSrcNuGetPackages => _ => _ + .Description("Build the NuGet packages that are generated directly from src/**/*.csproj files") + .Executes(() => + { + foreach (var project in Solution.GetManagedSrcProjects().Where(p => !p.Name.EndsWith("AdditionalDeps"))) + { + DotNetPack(x => x + .SetProject(project) + .SetConfiguration(BuildConfiguration) + .SetVersionSuffix(NuGetVersionSuffix) + .SetOutputDirectory(NuGetArtifactsDirectory)); + } + }); + + Target CopyIntegrationsJsonForNuGetPackage => _ => _ + .Unlisted() + .Executes(() => + { + var source = RootDirectory / "integrations.json"; + var dest = RootDirectory / "nuget" / "OpenTelemetry.AutoInstrumentation" / + "contentFiles" / "any" / "any"; + CopyFileToDirectory(source, dest, FileExistsPolicy.Overwrite); + }); + + Target SetupRuntimeNativeFolderForNuGetPackage => _ => _ + .Unlisted() + .Description("Setup the \"runtimes/{platform}-{architecture}/native\" folders under \"nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native\".") + .Executes(() => + { + const string ciArtifactsDirectory = "bin/ci-artifacts"; + const string baseRuntimeNativePath = "./nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native/"; + + var requiredArtifacts = new string[] + { + "bin-alpine/linux-musl-x64", + "bin-centos/linux-x64", + "bin-macos-11/osx-x64", + "bin-windows-2022/win-x64", + "bin-windows-2022/win-x86" + }; + + foreach (var artifactFolder in requiredArtifacts) + { + var sourcePath = Path.Combine(ciArtifactsDirectory, artifactFolder); + + var platformAndArchitecture = Path.GetFileName(artifactFolder); + var destinationPath = + Path.Combine(baseRuntimeNativePath, "runtimes", platformAndArchitecture, "native"); + DeleteDirectory(destinationPath); + + CopyDirectoryRecursively(sourcePath, destinationPath); + } + }); + + Target BuildNuSpecNuGetPackages => _ => _ + .Description("Build the NuGet packages specified by nuget/**/*.nuspec projects.") + .After(CopyIntegrationsJsonForNuGetPackage) + .After(SetupRuntimeNativeFolderForNuGetPackage) + .Executes(() => + { + // .nuspec files don't support .props or another way to share properties. + // To avoid repeating these values on all .nuspec files they are going to + // be passed as properties. + // Keeping common values here and using them as properties + var nuspecCommonProperties = new Dictionary + { + { "NoWarn", "NU5128" }, + { "NuGetLicense", "Apache-2.0" }, + { "NuGetPackageVersion", $"{NuGetBaseVersionNumber}{NuGetVersionSuffix}" }, + { "NuGetRequiredLicenseAcceptance", "true" }, + { "OpenTelemetryAuthors", "OpenTelemetry Authors" } + }; + + var nuspecSolutionFolder = Solution.GetSolutionFolder("nuget") + ?? throw new InvalidOperationException("Couldn't find the expected \"nuget\" solution folder."); + + var nuspecProjects = nuspecSolutionFolder.Items.Keys.ToArray(); + foreach (var nuspecProject in nuspecProjects) + { + NuGetTasks.NuGetPack(s => s + .SetTargetPath(nuspecProject) + .SetConfiguration(BuildConfiguration) + .SetProperties(nuspecCommonProperties) + .SetOutputDirectory(NuGetArtifactsDirectory)); + } + }); + + Target BuildNuGetPackagesTests => _ => _ + .Description("Builds the NuGetPackagesTests project") + .Executes(() => + { + var nugetPackagesTestProject = Solution.GetProject("NuGetPackagesTests"); + DotNetBuild(s => s + .SetProjectFile(nugetPackagesTestProject) + .SetConfiguration(BuildConfiguration)); + }); + + Target BuildNuGetPackagesTestApplications => _ => _ + .Description("Builds the TestApplications.* used by the NuGetPackagesTests") + .Executes(() => + { + foreach (var packagesTestApplicationProject in Solution.GetNuGetPackagesTestApplications()) + { + // Unlike the integration apps these require a restore step. + DotNetBuild(s => s + .SetProjectFile(packagesTestApplicationProject) + .SetProperty("NuGetPackageVersion", $"{NuGetBaseVersionNumber}{NuGetVersionSuffix}") + .SetRuntime(RuntimeInformation.RuntimeIdentifier) + .SetConfiguration(BuildConfiguration) + .SetPlatform(Platform)); + } + }); + + Target RunNuGetPackagesTests => _ => _ + .Description("Run the NuGetPackagesTests.") + .After(BuildNuGetPackagesTests) + .After(BuildNuGetPackagesTestApplications) + .Executes(() => + { + var nugetPackagesTestProject = Solution.GetProject("NuGetPackagesTests"); + + for (var i = 0; i < TestCount; i++) + { + DotNetMSBuild(config => config + .SetConfiguration(BuildConfiguration) + .SetFilter(AndFilter(TestNameFilter(), ContainersFilter())) + .SetBlameHangTimeout("5m") + .EnableTrxLogOutput(GetResultsDirectory(nugetPackagesTestProject)) + .SetTargetPath(nugetPackagesTestProject) + .DisableRestore() + .RunTests() + ); + } + }); +} diff --git a/build/Build.Steps.cs b/build/Build.Steps.cs index ba4a43b387..c6c27af5aa 100644 --- a/build/Build.Steps.cs +++ b/build/Build.Steps.cs @@ -22,7 +22,6 @@ partial class Build AbsolutePath TestsDirectory => RootDirectory / "test"; AbsolutePath TracerHomeDirectory => TracerHome ?? (OutputDirectory / "tracer-home"); - AbsolutePath ArtifactsDirectory => Artifacts ?? (OutputDirectory / "artifacts"); AbsolutePath BuildDataDirectory => RootDirectory / "build_data"; AbsolutePath ProfilerTestLogs => BuildDataDirectory / "profiler-logs"; AbsolutePath AdditionalDepsDirectory => TracerHomeDirectory / "AdditionalDeps"; @@ -55,7 +54,7 @@ partial class Build .Executes(() => { EnsureExistingDirectory(TracerHomeDirectory); - EnsureExistingDirectory(ArtifactsDirectory); + EnsureExistingDirectory(NuGetArtifactsDirectory); EnsureExistingDirectory(BuildDataDirectory); EnsureExistingDirectory(ProfilerTestLogs); }); @@ -79,7 +78,7 @@ DotNetRestoreSettings Restore(DotNetRestoreSettings s) => .SetVerbosity(DotNetVerbosity.Normal) .SetProperty("configuration", BuildConfiguration.ToString()) .SetPlatform(Platform) - .When(!string.IsNullOrEmpty(NugetPackageDirectory), o => o.SetPackageDirectory(NugetPackageDirectory)); + .When(!string.IsNullOrEmpty(NuGetPackagesDirectory), o => o.SetPackageDirectory(NuGetPackagesDirectory)); if (LibraryVersion.Versions.TryGetValue(project.Name, out var libraryVersions)) { @@ -107,8 +106,8 @@ DotNetRestoreSettings Restore(DotNetRestoreSettings s) => .SetTargetPath(project) .SetSolutionDirectory(Solution.Directory) .SetVerbosity(NuGetVerbosity.Normal) - .When(!string.IsNullOrEmpty(NugetPackageDirectory), o => - o.SetPackagesDirectory(NugetPackageDirectory))); + .When(!string.IsNullOrEmpty(NuGetPackagesDirectory), o => + o.SetPackagesDirectory(NuGetPackagesDirectory))); } } })); diff --git a/build/Build.cs b/build/Build.cs index 46252379a0..08f1e400cb 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -36,11 +36,18 @@ partial class Build : NukeBuild [Parameter("The location to create the tracer home directory. Default is './bin/tracer-home'")] readonly AbsolutePath TracerHome; - [Parameter("The location to place NuGet packages and other packages. Default is './bin/artifacts'")] - readonly AbsolutePath Artifacts; - [Parameter("The location to restore Nuget packages. Optional")] - readonly AbsolutePath NugetPackageDirectory; + [Parameter("The location to place the NuGet packages built from the project. Default is './bin/nuget-artifacts'")] + readonly AbsolutePath NuGetArtifacts; + + [Parameter("The location to restore NuGet packages. Optional")] + readonly AbsolutePath NuGetPackagesDirectory; + + [Parameter("Version number of the NuGet packages built from the project. Default is '0.6.0'")] + string NuGetBaseVersionNumber = "0.6.0"; + + [Parameter("Version suffix added to the NuGet packages built from the project. Default is '-local.1'")] + string NuGetVersionSuffix = "-local.1"; Target Clean => _ => _ .Description("Cleans all build output") @@ -57,7 +64,7 @@ partial class Build : NukeBuild TestsDirectory.GlobDirectories("**/bin", "**/obj").ForEach(x => DeleteDirectory(x)); EnsureCleanDirectory(OutputDirectory); EnsureCleanDirectory(TracerHomeDirectory); - EnsureCleanDirectory(ArtifactsDirectory); + EnsureCleanDirectory(NuGetArtifactsDirectory); EnsureCleanDirectory(NativeProfilerProject.Directory / "build"); EnsureCleanDirectory(NativeProfilerProject.Directory / "deps"); EnsureCleanDirectory(BuildDataDirectory); diff --git a/build/ProjectsHelper.cs b/build/ProjectsHelper.cs index c33dc8c1d9..64a824de5d 100644 --- a/build/ProjectsHelper.cs +++ b/build/ProjectsHelper.cs @@ -14,6 +14,8 @@ public static class ProjectsHelper private readonly static AbsolutePath SrcDirectory = NukeBuild.RootDirectory / "src"; private readonly static AbsolutePath TestDirectory = NukeBuild.RootDirectory / "test"; + private readonly static AbsolutePath TestIntegrationApps = TestDirectory / "test-applications" / "integrations"; + private readonly static AbsolutePath TestNuGetPackagesApps = TestDirectory / "test-applications" / "nuget-packages"; public static IEnumerable GetManagedSrcProjects(this Solution solution) { @@ -61,14 +63,23 @@ public static Project GetManagedIntegrationTestProject(this Solution solution) return solution.GetProject(Projects.Tests.IntegrationTests); } - public static IEnumerable GetTestApplications(this Solution solution) + public static IEnumerable GetIntegrationTestApplications(this Solution solution) { - var testApplications = solution.GetProjects(TestApplicationSelector); + var testApplications = solution + .GetProjects(TestApplicationSelector) + .Where(p => TestIntegrationApps.Contains(p.Directory)); var testLibraries = solution.GetProjects(TestLibrarySelector); return testApplications.Concat(testLibraries); } + public static IEnumerable GetNuGetPackagesTestApplications(this Solution solution) + { + return solution + .GetProjects(TestApplicationSelector) + .Where(p => TestNuGetPackagesApps.Contains(p.Directory)); + } + public static Project GetTestMock(this Solution solution) { return solution.GetProject(Projects.Mocks.AutoInstrumentationMock); @@ -77,14 +88,14 @@ public static Project GetTestMock(this Solution solution) public static IEnumerable GetWindowsOnlyTestApplications(this Solution solution) { return solution - .GetTestApplications() + .GetIntegrationTestApplications() .Where(x => x.Name.EndsWith(NetFrameworkMarker)); } public static IEnumerable GetCrossPlatformTestApplications(this Solution solution) { return solution - .GetTestApplications() + .GetIntegrationTestApplications() .Where(x => !x.Name.EndsWith(NetFrameworkMarker)); } diff --git a/docs/README.md b/docs/README.md index bbc50abcaf..fb1728c8ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -74,15 +74,16 @@ See [config.md#instrumented-libraries-and-frameworks](config.md#instrumented-lib ### Considerations on scope -Currently, instrumenting [`self-contained`](https://learn.microsoft.com/en-us/dotnet/core/deploying/#publish-self-contained) -applications is not supported. Note that a `self-contained` applications is +Instrumenting [`self-contained`](https://learn.microsoft.com/en-us/dotnet/core/deploying/#publish-self-contained) +applications is going to be supported through [NuGet packages](./internal/using-the-nuget-packages.md). +Note that a `self-contained` application is automatically generated in .NET 7.0 whenever the `dotnet publish` or `dotnet build` command is used with a Runtime Identifier (RID) parameter, for example when `-r` or `--runtime` is used when running the command. Until version `v0.6.0-beta.1` (inclusive) there were issues instrumenting the `dotnet` CLI. To build and launch an instrumented application, take the -following into account if you are using one of the affected versions: +following into account if you are using one of the *affected versions*: - Don't set the automatic instrumentation environment variables in the same session used to run the `dotnet` tool. diff --git a/docs/developing.md b/docs/developing.md index f70e90601d..fdf8e775fa 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -78,6 +78,28 @@ Clean your repository by running: git clean -fXd ``` +### Building NuGet packages locally + +To build the NuGet package with the native components (`OpenTelemetry.AutoInstrumentation.Runtime.Native`) +locally it is necessary to download CI artifacts. + +Download the `bin-*` artifacts from a successful CI job and expand each one into +a folder with the same name as the artifact under `./bin/ci-artifacts/`. The +PowerShell snippet below shows how to properly copy and expand the artifacts, +it assumes that the code is run from the root of the repository and the CI +artifacts we added to `~/Downloads/`: + +```PowerShell +$artifacts = @("bin-alpine", "bin-centos", "bin-macos-11", "bin-windows-2022") +$destFolder = "./bin/ci-artifacts/" +$zipFilesFolder = "~/Downloads/" + +rm -r -force $destFolder +mkdir $destFolder + +$artifacts | % { $dest = $(Join-Path $destFolder $_); $zip = $(Join-Path $zipFilesFolder $_) + ".zip"; Expand-Archive $zip $dest } +``` + ### Documentation lint If you made changes to the Markdown documents (`*.md` files), ensure that lint diff --git a/docs/internal/using-the-nuget-packages.md b/docs/internal/using-the-nuget-packages.md new file mode 100644 index 0000000000..2f8662e911 --- /dev/null +++ b/docs/internal/using-the-nuget-packages.md @@ -0,0 +1,62 @@ +# Using the OpenTelemetry.AutoInstrumentation NuGet packages + +> **Warning** +> Currently, NuGet packages are only available as CI artifacts. +When following these instructions, ensure that the packages are downloaded +and that the target project is either using a `nuget.config` file configured to use +the downloaded packages, for example the +[`nuget.config` used by the NuGet packages test applications](../../test/test-applications/nuget-packages/nuget.config), +or the packages are added to the project by specifying the `--source` parameter +when running [`dotnet add package` command](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package). + +## When to use the NuGet packages + +Use the NuGet packages in the following scenarios: + +1. Simplify deployment. For example, a container running a single application. +1. Support instrumentation of [`self-contained`](https://learn.microsoft.com/en-us/dotnet/core/deploying/#publish-self-contained) + applications. +1. Facilitate developer experimentation with automatic instrumentation through + NuGet packages. + +## Limitations + +While NuGet packages are a convenient way to deploy automatic +instrumentation, they can't be used in all cases. The most common +reasons for not using NuGet packages include the following: + +1. You can't add the package to the application project. For example, +the application is from a third party that can't add the package. +1. Reduce disk usage, or the size of a virtual machine, when multiple applications +to be instrumented are installed in a single machine. In this case you can use +a single deployment for all .NET applications running on the machine. +1. A legacy application that can't be migrated to the [SDK-style project](https://learn.microsoft.com/en-us/nuget/resources/check-project-format#check-the-project-format). + +## Using the NuGet packages + +To automatically instrument your application with OpenTelemetry .NET add +the `OpenTelemetry.AutoInstrumentation` package to your project: + +```terminal +dotnet add [] package OpenTelemetry.AutoInstrumentation --source --prerelease +``` + +To distribute the appropriate native runtime components with your .NET application, +specify a [Runtime Identifier (RID)](https://learn.microsoft.com/en-us/dotnet/core/rid-catalog) +to build the application using `dotnet build` or `dotnet publish`. This might +require choosing between distributing a +[_self-contained_ or a _framework-dependent_](https://learn.microsoft.com/en-us/dotnet/core/deploying/) +application. Both types are compatible with automatic instrumentation. + +Use the script in the output folder of the build to launch the +application with automatic instrumentation activated. + +- On Windows, use `instrument.cmd ` +- On Linux or Unix, use `instrument.sh ` + +If you launch the application using the `dotnet` CLI, add `dotnet` after the script. + +- On Windows, use `instrument.cmd dotnet ` +- On Linux and Unix, use `instrument.sh dotnet ` + +The script passes to the application all the command-line parameters you provide. diff --git a/docs/releasing.md b/docs/releasing.md index 45b7889d4a..dd378ed062 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -5,10 +5,9 @@ - [`OpenTelemetry.DotNet.Auto.psm1`](../OpenTelemetry.DotNet.Auto.psm1) - [`otel-dotnet-auto-install.sh`](../otel-dotnet-auto-install.sh) - [`docs/README.md`](./README.md) - - [`nuget/OpenTelemetry.AutoInstrumentation.nuspec`](../nuget/OpenTelemetry.AutoInstrumentation.nuspec) + - [`build/Build.cs`](../build/Build.cs) + - [`src/Directory.Build.props`](../src/Directory.Build.props) - [`src/OpenTelemetry.AutoInstrumentation/Constants.cs`](../src/OpenTelemetry.AutoInstrumentation/Constants.cs) - - [`src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj`](../src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj) - - [`src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj`](../src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj) - [`src/OpenTelemetry.AutoInstrumentation.Native/CMakeLists.txt`](../src/OpenTelemetry.AutoInstrumentation.Native/CMakeLists.txt) - [`src/OpenTelemetry.AutoInstrumentation.Native/Resource.rc`](../src/OpenTelemetry.AutoInstrumentation.Native/Resource.rc) - [`src/OpenTelemetry.AutoInstrumentation.Native/otel_profiler_constants.h`](../src/OpenTelemetry.AutoInstrumentation.Native/otel_profiler_constants.h) diff --git a/nuget/OpenTelemetry.AutoInstrumentation.nuspec b/nuget/OpenTelemetry.AutoInstrumentation.Dependencies/OpenTelemetry.AutoInstrumentation.Dependencies.nuspec similarity index 75% rename from nuget/OpenTelemetry.AutoInstrumentation.nuspec rename to nuget/OpenTelemetry.AutoInstrumentation.Dependencies/OpenTelemetry.AutoInstrumentation.Dependencies.nuspec index 7eaec49f6f..7048e3d9fb 100644 --- a/nuget/OpenTelemetry.AutoInstrumentation.nuspec +++ b/nuget/OpenTelemetry.AutoInstrumentation.Dependencies/OpenTelemetry.AutoInstrumentation.Dependencies.nuspec @@ -1,17 +1,22 @@  - OpenTelemetry.AutoInstrumentation - 0.6.0 - OpenTelemetry Auto-Instrumentation - OpenTelemetry Authors - OpenTelemetry Authors - true - Apache-2.0 + OpenTelemetry.AutoInstrumentation.Dependencies + OpenTelemetry Auto-Instrumentation package with all managed dependencies. + + + $NuGetPackageVersion$ + $OpenTelemetryAuthors$ + $NuGetRequiredLicenseAcceptance$ + $NuGetLicense$ + + https://opentelemetry.io/ - Observability OpenTelemetry Monitoring Telemetry Tracing Auto Automatic Instrumentation + O11y Observability OpenTelemetry OTel Logs Metrics Monitoring Telemetry Tracing Auto Automatic Instrumentation + + @@ -59,17 +64,4 @@ - - - - - - - - - - - - - diff --git a/nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native/OpenTelemetry.AutoInstrumentation.Runtime.Native.nuspec b/nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native/OpenTelemetry.AutoInstrumentation.Runtime.Native.nuspec new file mode 100644 index 0000000000..08931d4c15 --- /dev/null +++ b/nuget/OpenTelemetry.AutoInstrumentation.Runtime.Native/OpenTelemetry.AutoInstrumentation.Runtime.Native.nuspec @@ -0,0 +1,21 @@ + + + + OpenTelemetry.AutoInstrumentation.Runtime.Native + Native runtime components used by the OpenTelmetry.AutoInstrumentation project. + + + $NuGetPackageVersion$ + $OpenTelemetryAuthors$ + $NuGetRequiredLicenseAcceptance$ + $NuGetLicense$ + + + https://opentelemetry.io/ + O11y Observability OpenTelemetry OTel Logs Metrics Monitoring Telemetry Tracing Auto Automatic Instrumentation + + + + + + diff --git a/nuget/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.nuspec b/nuget/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.nuspec new file mode 100644 index 0000000000..2f3c05d4ce --- /dev/null +++ b/nuget/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.nuspec @@ -0,0 +1,38 @@ + + + + OpenTelemetry.AutoInstrumentation + OpenTelemetry Auto-Instrumentation package with all required components to enable automatic instrumentation. + + + $NuGetPackageVersion$ + $OpenTelemetryAuthors$ + $NuGetRequiredLicenseAcceptance$ + $NuGetLicense$ + + + https://opentelemetry.io/ + O11y Observability OpenTelemetry OTel Logs Metrics Monitoring Telemetry Tracing Auto Automatic Instrumentation + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.cmd b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.cmd new file mode 100644 index 0000000000..aa64d99e58 --- /dev/null +++ b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.cmd @@ -0,0 +1,24 @@ +@echo off +setlocal + +:: This script is expected to be used in a build that specified a RuntimeIdentifier (RID) +set BASE_PATH=%~dp0 + +:: Settings for .NET Framework +set COR_ENABLE_PROFILING=1 +set COR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318} +set COR_PROFILER_PATH=%BASE_PATH%OpenTelemetry.AutoInstrumentation.Native.dll + +:: Settings for .NET +set ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper +set CORECLR_ENABLE_PROFILING=1 +set CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318} +set CORECLR_PROFILER_PATH=%BASE_PATH%OpenTelemetry.AutoInstrumentation.Native.dll +set DOTNET_STARTUP_HOOKS=%BASE_PATH%OpenTelemetry.AutoInstrumentation.StartupHook.dll + +:: Settings for OpenTelemetry +set OTEL_DOTNET_AUTO_HOME=%BASE_PATH% +set OTEL_DOTNET_AUTO_INTEGRATIONS_FILE=%BASE_PATH%integrations.json + +@echo on +%* diff --git a/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.sh b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.sh new file mode 100755 index 0000000000..6e1e3d9fba --- /dev/null +++ b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/instrument.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +BASE_PATH="$(cd $(dirname "$0") && pwd)" + +# Settings for .NET +export ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper +export CORECLR_ENABLE_PROFILING=1 +export CORECLR_PROFILER="{918728DD-259F-4A6A-AC2B-B85E1B658318}" +export CORECLR_PROFILER_PATH=$(ls ${BASE_PATH}/OpenTelemetry.AutoInstrumentation.Native.*) +export DOTNET_STARTUP_HOOKS=${BASE_PATH}/OpenTelemetry.AutoInstrumentation.StartupHook.dll + +# Settings for OpenTelemetry +export OTEL_DOTNET_AUTO_HOME=${BASE_PATH} +export OTEL_DOTNET_AUTO_INTEGRATIONS_FILE=${BASE_PATH}/integrations.json + +$@ diff --git a/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/integrations.json b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/integrations.json new file mode 100644 index 0000000000..1b176b58e1 --- /dev/null +++ b/nuget/OpenTelemetry.AutoInstrumentation/contentFiles/any/any/integrations.json @@ -0,0 +1,362 @@ +[ + { + "name": "GraphQL", + "type": "Trace", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "GraphQL", + "type": "GraphQL.Execution.ExecutionStrategy", + "method": "ExecuteAsync", + "signature_types": [ + "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", + "GraphQL.Execution.ExecutionContext" + ], + "minimum_major": 2, + "minimum_minor": 3, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration" + } + }, + { + "caller": {}, + "target": { + "assembly": "GraphQL", + "type": "GraphQL.Execution.SubscriptionExecutionStrategy", + "method": "ExecuteAsync", + "signature_types": [ + "System.Threading.Tasks.Task`1[GraphQL.ExecutionResult]", + "GraphQL.Execution.ExecutionContext" + ], + "minimum_major": 2, + "minimum_minor": 3, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration" + } + } + ] + }, + { + "name": "ILogger", + "type": "Log", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "Microsoft.Extensions.Logging", + "type": "Microsoft.Extensions.Logging.LoggingBuilder", + "method": ".ctor", + "signature_types": [ + "System.Void", + "Microsoft.Extensions.DependencyInjection.IServiceCollection" + ], + "minimum_major": 3, + "minimum_minor": 1, + "minimum_patch": 0, + "maximum_major": 7, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.Logger.LoggingBuilderIntegration" + } + } + ] + }, + { + "name": "MongoDB", + "type": "Trace", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "MongoDB.Driver", + "type": "MongoDB.Driver.MongoClient", + "method": ".ctor", + "signature_types": [ + "System.Void", + "MongoDB.Driver.MongoClientSettings" + ], + "minimum_major": 2, + "minimum_minor": 13, + "minimum_patch": 3, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.MongoDB.MongoClientIntegration" + } + } + ] + }, + { + "name": "MySqlData", + "type": "Trace", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "MySql.Data", + "type": "MySql.Data.MySqlClient.MySqlConnectionStringBuilder", + "method": "get_Logging", + "signature_types": [ + "System.Boolean" + ], + "minimum_major": 8, + "minimum_minor": 0, + "minimum_patch": 31, + "maximum_major": 8, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.MySqlData.MySqlConnectionStringBuilderIntegration" + } + } + ] + }, + { + "name": "NServiceBus", + "type": "Trace", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "NServiceBus.Core", + "type": "NServiceBus.EndpointConfiguration", + "method": ".ctor", + "signature_types": [ + "System.Void", + "System.String" + ], + "minimum_major": 8, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 8, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration" + } + } + ] + }, + { + "name": "NServiceBus", + "type": "Metric", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "NServiceBus.Core", + "type": "NServiceBus.EndpointConfiguration", + "method": ".ctor", + "signature_types": [ + "System.Void", + "System.String" + ], + "minimum_major": 8, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 8, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.NServiceBus.EndpointConfigurationIntegration" + } + } + ] + }, + { + "name": "StackExchangeRedis", + "type": "Trace", + "method_replacements": [ + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImpl", + "signature_types": [ + "StackExchange.Redis.ConnectionMultiplexer", + "System.Object", + "System.IO.TextWriter" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImpl", + "signature_types": [ + "StackExchange.Redis.ConnectionMultiplexer", + "StackExchange.Redis.ConfigurationOptions", + "System.IO.TextWriter" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImpl", + "signature_types": [ + "StackExchange.Redis.ConnectionMultiplexer", + "StackExchange.Redis.ConfigurationOptions", + "System.IO.TextWriter", + "System.Nullable`1[StackExchange.Redis.ServerType]" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImpl", + "signature_types": [ + "StackExchange.Redis.ConnectionMultiplexer", + "StackExchange.Redis.ConfigurationOptions", + "System.IO.TextWriter", + "System.Nullable`1[StackExchange.Redis.ServerType]", + "StackExchange.Redis.EndPointCollection" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegration" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImplAsync", + "signature_types": [ + "System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", + "System.Object", + "System.IO.TextWriter" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImplAsync", + "signature_types": [ + "System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", + "StackExchange.Redis.ConfigurationOptions", + "System.IO.TextWriter" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync" + } + }, + { + "caller": {}, + "target": { + "assembly": "StackExchange.Redis", + "type": "StackExchange.Redis.ConnectionMultiplexer", + "method": "ConnectImplAsync", + "signature_types": [ + "System.Threading.Tasks.Task`1[StackExchange.Redis.ConnectionMultiplexer]", + "StackExchange.Redis.ConfigurationOptions", + "System.IO.TextWriter", + "System.Nullable`1[StackExchange.Redis.ServerType]" + ], + "minimum_major": 2, + "minimum_minor": 0, + "minimum_patch": 0, + "maximum_major": 2, + "maximum_minor": 65535, + "maximum_patch": 65535 + }, + "wrapper": { + "assembly": "OpenTelemetry.AutoInstrumentation", + "type": "OpenTelemetry.AutoInstrumentation.Instrumentations.StackExchangeRedis.StackExchangeRedisIntegrationAsync" + } + } + ] + } +] \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d72a79f8e0..2d8fcc605a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -8,19 +8,20 @@ true + 0.6.0$(VersionSuffix) true https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/raw/main/opentelemetry-logo-64x64.png packageIcon.png https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/ Apache-2.0 - false + true See release notes at https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases - OpenTelemetry;OTEL;APM;tracing;profiling;instrumentation + APM;AutoInstrumentation;Automatic Instrumentation;Instrumentation;Logs;Metrics;Monitoring;O11y;Observability;OpenTelemetry;OTel;Telemetry;Tracing git https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation.git Copyright 2021 OpenTelemetry, originated from Datadog, Inc. OpenTelemetry - OpenTelemetry + OpenTelemetry Authors diff --git a/src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj b/src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj index 5f626c03d9..603067a3fb 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj +++ b/src/OpenTelemetry.AutoInstrumentation.Loader/OpenTelemetry.AutoInstrumentation.Loader.csproj @@ -5,9 +5,6 @@ $(TargetFrameworks);net462 ..\bin\ProfilerResources\ - - 0.6.0 - false diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/startup_hook.h b/src/OpenTelemetry.AutoInstrumentation.Native/startup_hook.h index a08c3d185b..7c2593d43c 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/startup_hook.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/startup_hook.h @@ -19,10 +19,13 @@ inline bool IsStartupHookValid(const std::vector& startup_hooks, const return false; } - const auto expected_startuphook_path = + const auto expected_deployment_startuphook_path = std::filesystem::path(home_path) / "net" / "OpenTelemetry.AutoInstrumentation.StartupHook.dll"; - if (!std::filesystem::exists(expected_startuphook_path)) + const auto expected_nuget_startuphook_path = + std::filesystem::path(home_path) + / "OpenTelemetry.AutoInstrumentation.StartupHook.dll"; + if (!std::filesystem::exists(expected_deployment_startuphook_path) && !std::filesystem::exists(expected_nuget_startuphook_path)) { return false; } @@ -31,7 +34,7 @@ inline bool IsStartupHookValid(const std::vector& startup_hooks, const { const auto start_hook_path = std::filesystem::path(*i); std::error_code ec; - if (std::filesystem::equivalent(expected_startuphook_path, start_hook_path, ec)) + if (std::filesystem::equivalent(expected_deployment_startuphook_path, start_hook_path, ec) || std::filesystem::equivalent(expected_nuget_startuphook_path, start_hook_path, ec)) { return true; } diff --git a/src/OpenTelemetry.AutoInstrumentation.StartupHook/StartupHook.cs b/src/OpenTelemetry.AutoInstrumentation.StartupHook/StartupHook.cs index b54aeb26be..887be51573 100644 --- a/src/OpenTelemetry.AutoInstrumentation.StartupHook/StartupHook.cs +++ b/src/OpenTelemetry.AutoInstrumentation.StartupHook/StartupHook.cs @@ -69,28 +69,25 @@ public static void Initialize() if (profilerType != null) { - Logger.Error( - $"OpenTelemetry.AutoInstrumentation assembly was already loaded from: {profilerType.Assembly?.Location}. " + - "Check the DOTNET_STARTUP_HOOK environment variable."); + Logger.Information( + $"OpenTelemetry.AutoInstrumentation assembly loaded from: {profilerType.Assembly?.Location}."); + } + + ThrowIfReferenceIncorrectOpenTelemetryVersion(loaderAssemblyLocation); + + // Instrumentation is not initialized. + // Creating an instance of OpenTelemetry.AutoInstrumentation.Loader.Startup + // will initialize Instrumentation through its static constructor. + string loaderFilePath = Path.Combine(loaderAssemblyLocation, "OpenTelemetry.AutoInstrumentation.Loader.dll"); + Assembly loaderAssembly = Assembly.LoadFrom(loaderFilePath); + var loaderInstance = loaderAssembly.CreateInstance("OpenTelemetry.AutoInstrumentation.Loader.Loader"); + if (loaderInstance is null) + { + Logger.Error("StartupHook failed to create an instance of the Loader"); } else { - ThrowIfReferenceIncorrectOpenTelemetryVersion(loaderAssemblyLocation); - - // Instrumentation is not initialized. - // Creating an instance of OpenTelemetry.AutoInstrumentation.Loader.Startup - // will initialize Instrumentation through its static constructor. - string loaderFilePath = Path.Combine(loaderAssemblyLocation, "OpenTelemetry.AutoInstrumentation.Loader.dll"); - Assembly loaderAssembly = Assembly.LoadFrom(loaderFilePath); - var loaderInstance = loaderAssembly.CreateInstance("OpenTelemetry.AutoInstrumentation.Loader.Loader"); - if (loaderInstance is null) - { - Logger.Error("StartupHook failed to create an instance of the Loader"); - } - else - { - Logger.Information("StartupHook initialized successfully!"); - } + Logger.Information("StartupHook initialized successfully!"); } } catch (Exception ex) diff --git a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj index fffaf69ca2..16546f282b 100644 --- a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj +++ b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj @@ -3,7 +3,7 @@ - 0.6.0 + OpenTelemetry.AutoInstrumentation.Runtime.Managed diff --git a/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.NetFramework.cs b/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.NetFramework.cs index 9778313e46..9b3684344a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.NetFramework.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.NetFramework.cs @@ -24,5 +24,6 @@ [assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Bootstrapping.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008db7c66f4ebdc6aac4196be5ce1ff4b59b020028e6dbd6e46f15aa40b3215975b92d0a8e45aba5f36114a8cb56241fbfa49f4c017e6c62197857e4e9f62451bc23d3a660e20861f95a57f23e20c77d413ad216ff1bb55f94104d4c501e32b03219d8603fb6fa73401c6ae6808c8daa61b9eaee5d2377d3c23c9ca6016c6582d8")] [assembly: InternalsVisibleTo("IntegrationTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008db7c66f4ebdc6aac4196be5ce1ff4b59b020028e6dbd6e46f15aa40b3215975b92d0a8e45aba5f36114a8cb56241fbfa49f4c017e6c62197857e4e9f62451bc23d3a660e20861f95a57f23e20c77d413ad216ff1bb55f94104d4c501e32b03219d8603fb6fa73401c6ae6808c8daa61b9eaee5d2377d3c23c9ca6016c6582d8")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: InternalsVisibleTo("NuGetPackagesTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001008db7c66f4ebdc6aac4196be5ce1ff4b59b020028e6dbd6e46f15aa40b3215975b92d0a8e45aba5f36114a8cb56241fbfa49f4c017e6c62197857e4e9f62451bc23d3a660e20861f95a57f23e20c77d413ad216ff1bb55f94104d4c501e32b03219d8603fb6fa73401c6ae6808c8daa61b9eaee5d2377d3c23c9ca6016c6582d8")] #endif diff --git a/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.cs b/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.cs index 72ac1a9b2f..a40d6850bc 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Properties/AssemblyInfo.cs @@ -22,4 +22,5 @@ [assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Tests")] [assembly: InternalsVisibleTo("IntegrationTests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] +[assembly: InternalsVisibleTo("NuGetPackagesTests")] #endif diff --git a/test/IntegrationTests/DotNetCliTests.cs b/test/IntegrationTests/DotNetCliTests.cs index e5c8acb73a..3a5e2d26a5 100644 --- a/test/IntegrationTests/DotNetCliTests.cs +++ b/test/IntegrationTests/DotNetCliTests.cs @@ -79,6 +79,7 @@ private static void ChangeDefaultProgramToHttpClient() { const string ProgramContent = @" using var httpClient = new HttpClient(); +httpClient.Timeout = TimeSpan.FromSeconds(5); using var response = await httpClient.GetAsync(""http://example.com""); Console.WriteLine(response.StatusCode); "; diff --git a/test/IntegrationTests/Helpers/EnvironmentHelper.cs b/test/IntegrationTests/Helpers/EnvironmentHelper.cs index 1122526a1d..3a17f69b0e 100644 --- a/test/IntegrationTests/Helpers/EnvironmentHelper.cs +++ b/test/IntegrationTests/Helpers/EnvironmentHelper.cs @@ -45,10 +45,11 @@ public EnvironmentHelper( Type anchorType, ITestOutputHelper output, string? testApplicationDirectory = null, + string testApplicationType = "integrations", bool prependTestApplicationToAppName = true) { TestApplicationName = testApplicationName; - _testApplicationDirectory = testApplicationDirectory ?? Path.Combine("test", "test-applications", "integrations"); + _testApplicationDirectory = testApplicationDirectory ?? Path.Combine("test", "test-applications", testApplicationType); _targetFramework = Assembly.GetAssembly(anchorType)?.GetCustomAttribute()!; _output = output; @@ -69,7 +70,11 @@ public EnvironmentHelper( ? "TestApplication." : string.Empty; - SetDefaultEnvironmentVariables(); + if (testApplicationType == "integrations") + { + // Only integration tests assume the default environment variable settings. + SetDefaultEnvironmentVariables(); + } } public bool DebugModeEnabled { get; set; } = true; diff --git a/test/IntegrationTests/Helpers/TestHelper.cs b/test/IntegrationTests/Helpers/TestHelper.cs index 9372d4f5ed..f3d0cb51ec 100644 --- a/test/IntegrationTests/Helpers/TestHelper.cs +++ b/test/IntegrationTests/Helpers/TestHelper.cs @@ -23,16 +23,19 @@ namespace IntegrationTests.Helpers; public abstract class TestHelper { - protected TestHelper(string testApplicationName, ITestOutputHelper output) + protected TestHelper(string testApplicationName, ITestOutputHelper output, string testApplicationType = "integrations") { Output = output; - EnvironmentHelper = new EnvironmentHelper(testApplicationName, typeof(TestHelper), output); + EnvironmentHelper = new EnvironmentHelper(testApplicationName, typeof(TestHelper), output, testApplicationType: testApplicationType); output.WriteLine($"Platform: {EnvironmentTools.GetPlatform()}"); output.WriteLine($"Configuration: {EnvironmentTools.GetBuildConfiguration()}"); output.WriteLine($"TargetFramework: {EnvironmentHelper.GetTargetFramework()}"); output.WriteLine($".NET Core: {EnvironmentHelper.IsCoreClr()}"); - output.WriteLine($"Profiler DLL: {EnvironmentHelper.GetProfilerPath()}"); + if (testApplicationType == "integrations") + { + output.WriteLine($"Profiler DLL: {EnvironmentHelper.GetProfilerPath()}"); + } } protected EnvironmentHelper EnvironmentHelper { get; } diff --git a/test/NuGetPackagesTests/NuGetPackagesTests.csproj b/test/NuGetPackagesTests/NuGetPackagesTests.csproj new file mode 100644 index 0000000000..cd7cf4c1e3 --- /dev/null +++ b/test/NuGetPackagesTests/NuGetPackagesTests.csproj @@ -0,0 +1,41 @@ + + + + $(DefineConstants);_WINDOWS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/NuGetPackagesTests/SelfContainedTests.cs b/test/NuGetPackagesTests/SelfContainedTests.cs new file mode 100644 index 0000000000..e18cd2a996 --- /dev/null +++ b/test/NuGetPackagesTests/SelfContainedTests.cs @@ -0,0 +1,112 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using FluentAssertions; +using IntegrationTests.Helpers; +using Xunit.Abstractions; + +namespace IntegrationTests; + +[Trait("Category", "EndToEnd")] +public sealed class SelfContainedTests : TestHelper +{ + private readonly string _selfContainedAppDir; + + public SelfContainedTests(ITestOutputHelper output) + : base("SelfContained", output, "nuget-packages") + { + var nonSelfContainedOutputDir = EnvironmentHelper + .GetTestApplicationApplicationOutputDirectory(); + + // The self-contained app is going to have an extra folder before it: the one + // with a RID like "win-x64", "linux-x64", etc. + var childrenDirs = Directory.GetDirectories(nonSelfContainedOutputDir); + childrenDirs.Should().ContainSingle(); + + _selfContainedAppDir = childrenDirs[0]; + } + + [Fact] + public void InstrumentExecutable() + { + RunAndAssertHttpSpans(() => + { + var instrumentationTarget = Path.Combine(_selfContainedAppDir, EnvironmentHelper.FullTestApplicationName); + instrumentationTarget = EnvironmentTools.IsWindows() ? instrumentationTarget + ".exe" : instrumentationTarget; + RunInstrumentationTarget(instrumentationTarget); + }); + } + +#if !NETFRAMEWORK + [Fact] + public void InstrumentDll() + { + RunAndAssertHttpSpans(() => + { + var dllName = EnvironmentHelper.FullTestApplicationName.EndsWith(".exe") + ? EnvironmentHelper.FullTestApplicationName.Replace(".exe", ".dll") + : EnvironmentHelper.FullTestApplicationName + ".dll"; + var dllPath = Path.Combine(_selfContainedAppDir, dllName); + RunInstrumentationTarget($"dotnet {dllPath}"); + }); + } +#endif + + private void RunInstrumentationTarget(string instrumentationTarget) + { + var instrumentationScriptExtension = EnvironmentTools.IsWindows() ? ".cmd" : ".sh"; + var instrumentationScriptPath = + Path.Combine(_selfContainedAppDir, "instrument") + instrumentationScriptExtension; + + Output.WriteLine($"Running: {instrumentationScriptPath} {instrumentationTarget}"); + + using var process = InstrumentedProcessHelper.Start(instrumentationScriptPath, instrumentationTarget, EnvironmentHelper); + using var helper = new ProcessHelper(process); + + process.Should().NotBeNull(); + + bool processTimeout = !process!.WaitForExit((int)TestTimeout.ProcessExit.TotalMilliseconds); + if (processTimeout) + { + process.Kill(); + } + + Output.WriteLine("ProcessId: " + process.Id); + Output.WriteLine("Exit Code: " + process.ExitCode); + Output.WriteResult(helper); + + processTimeout.Should().BeFalse("Test application timed out"); + process.ExitCode.Should().Be(0, "Test application exited with non-zero exit code"); + } + + private void RunAndAssertHttpSpans(Action appLauncherAction) + { + var collector = new MockSpansCollector(Output); + SetExporter(collector); + +#if NETFRAMEWORK + collector.Expect("OpenTelemetry.Instrumentation.Http.HttpWebRequest"); +#elif NET7_0_OR_GREATER + collector.Expect("System.Net.Http"); +#else + collector.Expect("OpenTelemetry.Instrumentation.Http.HttpClient"); +#endif + + appLauncherAction(); + + collector.AssertExpectations(); + } +} diff --git a/test/NuGetPackagesTests/xunit.runner.json b/test/NuGetPackagesTests/xunit.runner.json new file mode 100644 index 0000000000..c46c5d61ef --- /dev/null +++ b/test/NuGetPackagesTests/xunit.runner.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "diagnosticMessages": true, + "longRunningTestSeconds": 60, + "parallelizeTestCollections": false +} diff --git a/test/test-applications/integrations/TestApplication.CustomSdk/Program.cs b/test/test-applications/integrations/TestApplication.CustomSdk/Program.cs index 04b8f52b9e..2788cdd2bb 100644 --- a/test/test-applications/integrations/TestApplication.CustomSdk/Program.cs +++ b/test/test-applications/integrations/TestApplication.CustomSdk/Program.cs @@ -85,6 +85,7 @@ public static async Task Main(string[] args) await PingRedis(args); using var client = new HttpClient(); + client.Timeout = TimeSpan.FromSeconds(5); await client.GetStringAsync("https://www.bing.com", cancellation.Token); } diff --git a/test/test-applications/nuget-packages/Directory.Build.props b/test/test-applications/nuget-packages/Directory.Build.props new file mode 100644 index 0000000000..68109858aa --- /dev/null +++ b/test/test-applications/nuget-packages/Directory.Build.props @@ -0,0 +1,22 @@ + + + + + + + + net7.0;net6.0 + $(TargetFrameworks);net462 + + enable + enable + + false + false + 11.0 + + + ..\bin\$(MSBuildProjectName)\ + + + diff --git a/test/test-applications/nuget-packages/Directory.Build.targets b/test/test-applications/nuget-packages/Directory.Build.targets new file mode 100644 index 0000000000..3cccfb916d --- /dev/null +++ b/test/test-applications/nuget-packages/Directory.Build.targets @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/test-applications/nuget-packages/Directory.Packages.props b/test/test-applications/nuget-packages/Directory.Packages.props new file mode 100644 index 0000000000..3cccfb916d --- /dev/null +++ b/test/test-applications/nuget-packages/Directory.Packages.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/test-applications/nuget-packages/TestApplication.SelfContained/Program.cs b/test/test-applications/nuget-packages/TestApplication.SelfContained/Program.cs new file mode 100644 index 0000000000..c847920af7 --- /dev/null +++ b/test/test-applications/nuget-packages/TestApplication.SelfContained/Program.cs @@ -0,0 +1,20 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +var httpClient = new HttpClient(); +httpClient.Timeout = TimeSpan.FromSeconds(5); +var response = await httpClient.GetAsync("http://example.com"); +Console.WriteLine(response.StatusCode); diff --git a/test/test-applications/nuget-packages/TestApplication.SelfContained/TestApplication.SelfContained.csproj b/test/test-applications/nuget-packages/TestApplication.SelfContained/TestApplication.SelfContained.csproj new file mode 100644 index 0000000000..ac544a1e5a --- /dev/null +++ b/test/test-applications/nuget-packages/TestApplication.SelfContained/TestApplication.SelfContained.csproj @@ -0,0 +1,11 @@ + + + + Exe + true + + + + + + diff --git a/test/test-applications/nuget-packages/nuget.config b/test/test-applications/nuget-packages/nuget.config new file mode 100644 index 0000000000..e66f9ac3d0 --- /dev/null +++ b/test/test-applications/nuget-packages/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + +