diff --git a/Elastic.OpenTelemetry.sln b/Elastic.OpenTelemetry.sln index 688c3f2..58b5a84 100644 --- a/Elastic.OpenTelemetry.sln +++ b/Elastic.OpenTelemetry.sln @@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.AutoInstrumentation EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoInstrumentation.IntegrationTests", "tests\AutoInstrumentation.IntegrationTests\AutoInstrumentation.IntegrationTests.csproj", "{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.OpenTelemetry.AutoInstrumentation", "src\Elastic.OpenTelemetry.AutoInstrumentation\Elastic.OpenTelemetry.AutoInstrumentation.csproj", "{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -107,6 +109,10 @@ Global {782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Debug|Any CPU.Build.0 = Debug|Any CPU {782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Release|Any CPU.Build.0 = Release|Any CPU + {B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -123,6 +129,7 @@ Global {A3D1ED4D-863B-45D7-9829-305DD33B4CE5} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9} {F3AA76EC-C7D8-42DA-947D-4376B6562772} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9} {782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD} = {AAD39891-0B70-47FA-A212-43E1AAE5DF56} + {B1CA9165-89D9-4D6E-AFEF-5434A8D8A672} = {E622CFF2-C6C4-40FB-BE42-7C4F2B38B75A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {573B2B5F-8CBB-4D52-A55A-4E65E282AAFB} diff --git a/Elastic.OpenTelemetry.sln.DotSettings b/Elastic.OpenTelemetry.sln.DotSettings index 5a02848..1a8f956 100644 --- a/Elastic.OpenTelemetry.sln.DotSettings +++ b/Elastic.OpenTelemetry.sln.DotSettings @@ -585,6 +585,7 @@ See the LICENSE file in the project root for more information True True True + True True True True diff --git a/build/build.fsproj b/build/build.fsproj index c4d18d0..40a5dc5 100644 --- a/build/build.fsproj +++ b/build/build.fsproj @@ -8,6 +8,7 @@ + @@ -21,6 +22,7 @@ + diff --git a/build/scripts/BuildInformation.fs b/build/scripts/BuildInformation.fs index 6103337..e12988d 100644 --- a/build/scripts/BuildInformation.fs +++ b/build/scripts/BuildInformation.fs @@ -14,6 +14,7 @@ open Fake.Tools.Git type BuildConfiguration = static member ValidateAssemblyName = false static member GenerateApiChanges = false + static member OpenTelemetryAutoInstrumentationVersion = SemVer.parse("1.7.0") type Software = static member Organization = "elastic" diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 21fa4ce..e150787 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -34,6 +34,7 @@ type Build = | [] ValidatePackages | [] GenerateReleaseNotes | [] GenerateApiChanges + | [] Redistribute | [] Release | [] Single_Target @@ -63,6 +64,7 @@ with | ValidateLicenses | ValidatePackages | GenerateReleaseNotes + | Redistribute | GenerateApiChanges -> "Undocumented, dependent target" // flags diff --git a/build/scripts/Packaging.fs b/build/scripts/Packaging.fs new file mode 100644 index 0000000..c76c662 --- /dev/null +++ b/build/scripts/Packaging.fs @@ -0,0 +1,111 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + + +module Packaging + +open System +open System.IO +open System.IO.Compression +open System.Net.Http +open Argu +open BuildInformation +open CommandLine +open Octokit + +let private otelAutoVersion = BuildConfiguration.OpenTelemetryAutoInstrumentationVersion; + +let private downloadFolder = Path.Combine(".artifacts", "otel-distribution", otelAutoVersion.AsString) |> Directory.CreateDirectory +let private distroFolder = Path.Combine(".artifacts", "elastic-distribution", otelAutoVersion.AsString) |> Directory.CreateDirectory + +let private fileInfo (directory: DirectoryInfo) file = Path.Combine(directory.FullName, file) |> FileInfo +let private downloadFile (asset: ReleaseAsset) = fileInfo downloadFolder asset.Name +let private stageFile (asset: ReleaseAsset) = fileInfo downloadFolder (asset.Name.Replace("opentelemetry", "stage")) +let private distroFile (asset: ReleaseAsset) = fileInfo distroFolder (asset.Name.Replace("opentelemetry", "elastic")) + +let pluginFiles tfm = + ["dll"; "pdb"; "xml"] + |> List.map(fun e -> $"Elastic.OpenTelemetry.%s{e}") + |> List.map(fun f -> Path.Combine(".artifacts", "bin", "Elastic.OpenTelemetry", $"release_%s{tfm}", "", f)) + |> List.map(fun f -> FileInfo(f)) + + +/// downloads the artifacts if they don't already exist locally +let downloadArtifacts (_:ParseResults) = + let client = GitHubClient(ProductHeaderValue("Elastic.OpenTelemetry")) + let token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") + if not(String.IsNullOrWhiteSpace(token)) then + Console.WriteLine($"using GITHUB_TOKEN"); + let tokenAuth = Credentials(token); + client.Credentials <- tokenAuth + + let assets = + async { + let! release = client.Repository.Release.Get("open-telemetry", "opentelemetry-dotnet-instrumentation", $"v{otelAutoVersion.AsString}") |> Async.AwaitTask; + Console.WriteLine($"Release %s{release.Name} has %i{release.Assets.Count} assets"); + return release.Assets + |> Seq.map (fun asset -> (asset, downloadFile asset)) + |> Seq.toList + } |> Async.RunSynchronously + + async { + use httpClient = new HttpClient() + assets + |> Seq.filter (fun (_, f) -> not f.Exists) + |> Seq.iter (fun (asset, f) -> + async { + Console.WriteLine($"Retrieving {asset.Name}"); + let! fileData = httpClient.GetByteArrayAsync(asset.BrowserDownloadUrl) |> Async.AwaitTask + Console.WriteLine($"Saveing %i{fileData.Length} bytes to {f.FullName}") + File.WriteAllBytes(f.FullName, fileData) + f.Refresh() + } |> Async.RunSynchronously + ) + } |> Async.RunSynchronously + assets + +let injectPluginFiles (asset: ReleaseAsset) (stagedZip: FileInfo) tfm target = + use zipArchive = ZipFile.Open(stagedZip.FullName, ZipArchiveMode.Update) + pluginFiles tfm |> List.iter(fun f -> + printfn $"Staging zip: %s{asset.Name}, Adding: %s{f.Name} (%s{tfm}_ to %s{target}" + zipArchive.CreateEntryFromFile(f.FullName, Path.Combine(target, f.Name)) |> ignore + ) + +/// moves artifacts from open-distribution to elastic-distribution and renames them to `staged-dotnet-instrumentation*`. +/// staged meaning we haven't injected our opentelemetry dll into the zip yet, +let stageArtifacts (assets:List) = + let stagedZips = + assets + |> List.filter(fun (a, _) -> a.Name.EndsWith(".zip")) + |> List.map(fun (z, f) -> + let stage = stageFile z + z, f.CopyTo(stage.FullName, true) + ) + + stagedZips |> List.iter (fun (asset, path) -> + + injectPluginFiles asset path "netstandard2.1" "net" + if asset.Name.EndsWith("-windows.zip") then + injectPluginFiles asset path "net462" "netfx" + + let distro = distroFile asset + path.MoveTo(distro.FullName, true) + distro.Refresh() + + printfn $"Created: %s{distro.FullName}" + ) + stagedZips + + + +let redistribute (arguments:ParseResults) = + let assets = downloadArtifacts arguments + let staged = stageArtifacts assets + + printfn "" + assets |> List.iter (fun (asset, path) -> + printfn "Asset: %s" asset.Name + ) + + diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index 4f543f8..b70bba4 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -185,6 +185,7 @@ let Setup (parsed:ParseResults) = | ValidatePackages -> Build.Step validatePackages | GenerateReleaseNotes -> Build.Step generateReleaseNotes | GenerateApiChanges -> Build.Step generateApiChanges + | Redistribute -> Build.Step Packaging.redistribute // flags | Single_Target diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj b/src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj new file mode 100644 index 0000000..db96356 --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/Elastic.OpenTelemetry.AutoInstrumentation.csproj @@ -0,0 +1,52 @@ + + + + net6.0;net8.0;net462 + enable + enable + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.cmd b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.cmd new file mode 100755 index 0000000..9cf290b --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.cmd @@ -0,0 +1,31 @@ +@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 + +:: On .NET Framework automatic assembly redirection MUST be disabled. This setting +:: is ignored on .NET. This is necessary because the NuGet package doesn't bring +:: the pre-defined versions of the transitive dependencies used in the automatic +:: redirection. Instead the transitive dependencies versions are determined by +:: the NuGet version resolution algorithm when building the application. +set OTEL_DOTNET_AUTO_NETFX_REDIRECT_ENABLED=false + +:: 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_RULE_ENGINE_ENABLED=false + +@echo on +%* diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh new file mode 100755 index 0000000..1a8d131 --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/_instrument.sh @@ -0,0 +1,17 @@ +#!/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}" +CORECLR_PROFILER_PATH="$(ls ${BASE_PATH}/OpenTelemetry.AutoInstrumentation.Native.*)" +export CORECLR_PROFILER_PATH +export DOTNET_STARTUP_HOOKS=${BASE_PATH}/OpenTelemetry.AutoInstrumentation.StartupHook.dll + +# Settings for OpenTelemetry +export OTEL_DOTNET_AUTO_HOME=${BASE_PATH} +export OTEL_DOTNET_AUTO_RULE_ENGINE_ENABLED=false + +exec "$@" diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.cmd b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.cmd new file mode 100644 index 0000000..4fbf084 --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.cmd @@ -0,0 +1,9 @@ +@echo off +setlocal + +:: This script is expected to be used in a build that specified a RuntimeIdentifier (RID) +set BASE_PATH=%~dp0 + +set OTEL_DOTNET_AUTO_PLUGINS=Elastic.OpenTelemetry.AutoInstrumentationPlugin, Elastic.OpenTelemetry + +call %BASE_PATH%_instrument.cmd %* \ No newline at end of file diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.props b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.props new file mode 100644 index 0000000..c2e528f --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.props @@ -0,0 +1,12 @@ + + + + + + False + Always + Always + + + \ No newline at end of file diff --git a/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.sh b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.sh new file mode 100644 index 0000000..720478e --- /dev/null +++ b/src/Elastic.OpenTelemetry.AutoInstrumentation/instrument.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# This script is expected to be used in a build that specified a RuntimeIdentifier (RID) +BASE_PATH="$(cd "$(dirname "$0")" && pwd)" + +export OTEL_DOTNET_AUTO_PLUGINS="Elastic.OpenTelemetry.AutoInstrumentationPlugin, Elastic.OpenTelemetry" + +. $BASE_PATH/_instrument.sh + +exec "$@"