Skip to content

Commit f842bb7

Browse files
authored
Packaging initial infrastructure (#133)
Not complete but enough to review as part 1 😄 * Introduces our own version of `OpenTelemetry.AutoInstrumentation` named `Elastic.OpenTelemetry.AutoInstrumentation`. Through a bit of msbuild magic we redistribute `instrument.{sh|cmd}` as `_instrument.{sh|cmd}` and introduce our own `instrument.{sh|cmd}` that sets the appropiate plugin environment variable before calling the opentelemetry instrument script. This allows the invocation to be exactly the same no matter if our distribution or the vanilla opentelemetry package is installed. A user can move from or away from Elastic without having to touch orchestration work. Simply installing the package is enough to move to or away from us. * This PR includes the start of a `./build.sh redistribute` build command that redistributes the opentelemetry autoinstrumentation zip files that include our AutoInstrumentation plugin. A follow up of this PR will focus on creating Elastic versions of the global auto instrumentation installation scripts and ensuring these get staged as part of the release.
1 parent 3f2d2fb commit f842bb7

13 files changed

+256
-0
lines changed

Elastic.OpenTelemetry.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.AutoInstrumentation
4545
EndProject
4646
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoInstrumentation.IntegrationTests", "tests\AutoInstrumentation.IntegrationTests\AutoInstrumentation.IntegrationTests.csproj", "{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}"
4747
EndProject
48+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.OpenTelemetry.AutoInstrumentation", "src\Elastic.OpenTelemetry.AutoInstrumentation\Elastic.OpenTelemetry.AutoInstrumentation.csproj", "{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}"
49+
EndProject
4850
Global
4951
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5052
Debug|Any CPU = Debug|Any CPU
@@ -107,6 +109,10 @@ Global
107109
{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
108110
{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
109111
{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD}.Release|Any CPU.Build.0 = Release|Any CPU
112+
{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
113+
{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Debug|Any CPU.Build.0 = Debug|Any CPU
114+
{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Release|Any CPU.ActiveCfg = Release|Any CPU
115+
{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672}.Release|Any CPU.Build.0 = Release|Any CPU
110116
EndGlobalSection
111117
GlobalSection(SolutionProperties) = preSolution
112118
HideSolutionNode = FALSE
@@ -123,6 +129,7 @@ Global
123129
{A3D1ED4D-863B-45D7-9829-305DD33B4CE5} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9}
124130
{F3AA76EC-C7D8-42DA-947D-4376B6562772} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9}
125131
{782E4DC1-8186-4BAC-B2F4-89E6DF22A4DD} = {AAD39891-0B70-47FA-A212-43E1AAE5DF56}
132+
{B1CA9165-89D9-4D6E-AFEF-5434A8D8A672} = {E622CFF2-C6C4-40FB-BE42-7C4F2B38B75A}
126133
EndGlobalSection
127134
GlobalSection(ExtensibilityGlobals) = postSolution
128135
SolutionGuid = {573B2B5F-8CBB-4D52-A55A-4E65E282AAFB}

Elastic.OpenTelemetry.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ See the LICENSE file in the project root for more information</s:String>
585585
<s:Boolean x:Key="/Default/UserDictionary/Words/=Faas/@EntryIndexedValue">True</s:Boolean>
586586
<s:Boolean x:Key="/Default/UserDictionary/Words/=Instrumentations/@EntryIndexedValue">True</s:Boolean>
587587
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mountinfo/@EntryIndexedValue">True</s:Boolean>
588+
<s:Boolean x:Key="/Default/UserDictionary/Words/=netfx/@EntryIndexedValue">True</s:Boolean>
588589
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nonsampled/@EntryIndexedValue">True</s:Boolean>
589590
<s:Boolean x:Key="/Default/UserDictionary/Words/=otel/@EntryIndexedValue">True</s:Boolean>
590591
<s:Boolean x:Key="/Default/UserDictionary/Words/=Otlp/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

build/build.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<ItemGroup>
99
<PackageReference Include="Argu" Version="6.1.4"/>
1010
<PackageReference Include="Bullseye" Version="4.2.1"/>
11+
<PackageReference Include="Octokit" Version="13.0.1" />
1112
<PackageReference Include="Proc.Fs" Version="0.8.1"/>
1213
<PackageReference Include="Fake.Tools.Git" Version="5.20.3"/>
1314
<PackageReference Remove="FSharp.Core"/>
@@ -21,6 +22,7 @@
2122
<ItemGroup>
2223
<Compile Include="scripts\BuildInformation.fs"/>
2324
<Compile Include="scripts\CommandLine.fs"/>
25+
<Compile Include="scripts\Packaging.fs" />
2426
<Compile Include="scripts\Targets.fs"/>
2527
<Compile Include="scripts\Program.fs"/>
2628
<None Include="**\*"/>

build/scripts/BuildInformation.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ open Fake.Tools.Git
1414
type BuildConfiguration =
1515
static member ValidateAssemblyName = false
1616
static member GenerateApiChanges = false
17+
static member OpenTelemetryAutoInstrumentationVersion = SemVer.parse("1.7.0")
1718

1819
type Software =
1920
static member Organization = "elastic"

build/scripts/CommandLine.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Build =
3434
| [<CliPrefix(CliPrefix.None);Hidden;SubCommand>] ValidatePackages
3535
| [<CliPrefix(CliPrefix.None);Hidden;SubCommand>] GenerateReleaseNotes
3636
| [<CliPrefix(CliPrefix.None);Hidden;SubCommand>] GenerateApiChanges
37+
| [<CliPrefix(CliPrefix.None);Hidden;SubCommand>] Redistribute
3738
| [<CliPrefix(CliPrefix.None);SubCommand>] Release
3839

3940
| [<Inherit;AltCommandLine("-s")>] Single_Target
@@ -63,6 +64,7 @@ with
6364
| ValidateLicenses
6465
| ValidatePackages
6566
| GenerateReleaseNotes
67+
| Redistribute
6668
| GenerateApiChanges -> "Undocumented, dependent target"
6769

6870
// flags

build/scripts/Packaging.fs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
6+
module Packaging
7+
8+
open System
9+
open System.IO
10+
open System.IO.Compression
11+
open System.Net.Http
12+
open Argu
13+
open BuildInformation
14+
open CommandLine
15+
open Octokit
16+
17+
let private otelAutoVersion = BuildConfiguration.OpenTelemetryAutoInstrumentationVersion;
18+
19+
let private downloadFolder = Path.Combine(".artifacts", "otel-distribution", otelAutoVersion.AsString) |> Directory.CreateDirectory
20+
let private distroFolder = Path.Combine(".artifacts", "elastic-distribution", otelAutoVersion.AsString) |> Directory.CreateDirectory
21+
22+
let private fileInfo (directory: DirectoryInfo) file = Path.Combine(directory.FullName, file) |> FileInfo
23+
let private downloadFile (asset: ReleaseAsset) = fileInfo downloadFolder asset.Name
24+
let private stageFile (asset: ReleaseAsset) = fileInfo downloadFolder (asset.Name.Replace("opentelemetry", "stage"))
25+
let private distroFile (asset: ReleaseAsset) = fileInfo distroFolder (asset.Name.Replace("opentelemetry", "elastic"))
26+
27+
let pluginFiles tfm =
28+
["dll"; "pdb"; "xml"]
29+
|> List.map(fun e -> $"Elastic.OpenTelemetry.%s{e}")
30+
|> List.map(fun f -> Path.Combine(".artifacts", "bin", "Elastic.OpenTelemetry", $"release_%s{tfm}", "", f))
31+
|> List.map(fun f -> FileInfo(f))
32+
33+
34+
/// downloads the artifacts if they don't already exist locally
35+
let downloadArtifacts (_:ParseResults<Build>) =
36+
let client = GitHubClient(ProductHeaderValue("Elastic.OpenTelemetry"))
37+
let token = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
38+
if not(String.IsNullOrWhiteSpace(token)) then
39+
Console.WriteLine($"using GITHUB_TOKEN");
40+
let tokenAuth = Credentials(token);
41+
client.Credentials <- tokenAuth
42+
43+
let assets =
44+
async {
45+
let! release = client.Repository.Release.Get("open-telemetry", "opentelemetry-dotnet-instrumentation", $"v{otelAutoVersion.AsString}") |> Async.AwaitTask;
46+
Console.WriteLine($"Release %s{release.Name} has %i{release.Assets.Count} assets");
47+
return release.Assets
48+
|> Seq.map (fun asset -> (asset, downloadFile asset))
49+
|> Seq.toList
50+
} |> Async.RunSynchronously
51+
52+
async {
53+
use httpClient = new HttpClient()
54+
assets
55+
|> Seq.filter (fun (_, f) -> not f.Exists)
56+
|> Seq.iter (fun (asset, f) ->
57+
async {
58+
Console.WriteLine($"Retrieving {asset.Name}");
59+
let! fileData = httpClient.GetByteArrayAsync(asset.BrowserDownloadUrl) |> Async.AwaitTask
60+
Console.WriteLine($"Saveing %i{fileData.Length} bytes to {f.FullName}")
61+
File.WriteAllBytes(f.FullName, fileData)
62+
f.Refresh()
63+
} |> Async.RunSynchronously
64+
)
65+
} |> Async.RunSynchronously
66+
assets
67+
68+
let injectPluginFiles (asset: ReleaseAsset) (stagedZip: FileInfo) tfm target =
69+
use zipArchive = ZipFile.Open(stagedZip.FullName, ZipArchiveMode.Update)
70+
pluginFiles tfm |> List.iter(fun f ->
71+
printfn $"Staging zip: %s{asset.Name}, Adding: %s{f.Name} (%s{tfm}_ to %s{target}"
72+
zipArchive.CreateEntryFromFile(f.FullName, Path.Combine(target, f.Name)) |> ignore
73+
)
74+
75+
/// moves artifacts from open-distribution to elastic-distribution and renames them to `staged-dotnet-instrumentation*`.
76+
/// staged meaning we haven't injected our opentelemetry dll into the zip yet,
77+
let stageArtifacts (assets:List<ReleaseAsset * FileInfo>) =
78+
let stagedZips =
79+
assets
80+
|> List.filter(fun (a, _) -> a.Name.EndsWith(".zip"))
81+
|> List.map(fun (z, f) ->
82+
let stage = stageFile z
83+
z, f.CopyTo(stage.FullName, true)
84+
)
85+
86+
stagedZips |> List.iter (fun (asset, path) ->
87+
88+
injectPluginFiles asset path "netstandard2.1" "net"
89+
if asset.Name.EndsWith("-windows.zip") then
90+
injectPluginFiles asset path "net462" "netfx"
91+
92+
let distro = distroFile asset
93+
path.MoveTo(distro.FullName, true)
94+
distro.Refresh()
95+
96+
printfn $"Created: %s{distro.FullName}"
97+
)
98+
stagedZips
99+
100+
101+
102+
let redistribute (arguments:ParseResults<Build>) =
103+
let assets = downloadArtifacts arguments
104+
let staged = stageArtifacts assets
105+
106+
printfn ""
107+
assets |> List.iter (fun (asset, path) ->
108+
printfn "Asset: %s" asset.Name
109+
)
110+
111+

build/scripts/Targets.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ let Setup (parsed:ParseResults<Build>) =
185185
| ValidatePackages -> Build.Step validatePackages
186186
| GenerateReleaseNotes -> Build.Step generateReleaseNotes
187187
| GenerateApiChanges -> Build.Step generateApiChanges
188+
| Redistribute -> Build.Step Packaging.redistribute
188189

189190
// flags
190191
| Single_Target
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net6.0;net8.0;net462</TargetFrameworks>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>True</IsPackable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="OpenTelemetry.AutoInstrumentation" Version="1.7.0" GeneratePathProperty="true" PrivateAssets="contentfiles" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<Content Remove="README.md" />
16+
17+
<!-- ensure we remove the linked instrument.cmd from base OpenTelemetry.AutoInstrumentation
18+
and link it as _instrument.cmd since we manually copy it over in the prebuild event -->
19+
<Content Update="instrument.cmd" CopyToPublishDirectory="Never" CopyToOutputDirectory="Never" />
20+
<Content Remove="instrument.cmd" />
21+
<Content Include="_instrument.cmd" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always"
22+
Pack="True" PackagePath="contentFiles/any/any/_instrument.cmd"/>
23+
<Content Include="instrument.cmd" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always"
24+
Pack="True" PackagePath="contentFiles/any/any/instrument.cmd"/>
25+
26+
<!-- ensure we remove the linked instrument.sh from base OpenTelemetry.AutoInstrumentation
27+
and link it as _instrument.sh since we manually copy it over in the prebuild event -->
28+
29+
<Content Update="instrument.sh" CopyToPublishDirectory="Never" CopyToOutputDirectory="Never" />
30+
<Content Remove="instrument.sh" />
31+
<Content Include="_instrument.sh" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always"
32+
Pack="True" PackagePath="contentFiles/any/any/_instrument.sh"/>
33+
<Content Include="instrument.sh" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always"
34+
Pack="True" PackagePath="contentFiles/any/any/instrument.sh"/>
35+
36+
<Content Include="instrument.props" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always"
37+
Pack="True" PackagePath="build/elastic.opentelemetry.autoinstrumentation.props"/>
38+
39+
</ItemGroup>
40+
41+
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
42+
<!-- Copies the content files manually as physical files in the source repository -->
43+
<!-- we manually repackage these as contentfiles (albeit renamed) -->
44+
<Copy SourceFiles="$(PkgOpenTelemetry_AutoInstrumentation)/contentFiles/any/any/instrument.cmd" DestinationFiles="$(MSBuildThisFileDirectory)/_instrument.cmd"/>
45+
<Copy SourceFiles="$(PkgOpenTelemetry_AutoInstrumentation)/contentFiles/any/any/instrument.sh" DestinationFiles="$(MSBuildThisFileDirectory)/_instrument.sh"/>
46+
</Target>
47+
48+
<ItemGroup>
49+
<ProjectReference Include="..\Elastic.OpenTelemetry\Elastic.OpenTelemetry.csproj" />
50+
</ItemGroup>
51+
52+
</Project>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
@echo off
2+
setlocal
3+
4+
:: This script is expected to be used in a build that specified a RuntimeIdentifier (RID)
5+
set BASE_PATH=%~dp0
6+
7+
:: Settings for .NET Framework
8+
set COR_ENABLE_PROFILING=1
9+
set COR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318}
10+
set COR_PROFILER_PATH=%BASE_PATH%OpenTelemetry.AutoInstrumentation.Native.dll
11+
12+
:: On .NET Framework automatic assembly redirection MUST be disabled. This setting
13+
:: is ignored on .NET. This is necessary because the NuGet package doesn't bring
14+
:: the pre-defined versions of the transitive dependencies used in the automatic
15+
:: redirection. Instead the transitive dependencies versions are determined by
16+
:: the NuGet version resolution algorithm when building the application.
17+
set OTEL_DOTNET_AUTO_NETFX_REDIRECT_ENABLED=false
18+
19+
:: Settings for .NET
20+
set ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper
21+
set CORECLR_ENABLE_PROFILING=1
22+
set CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318}
23+
set CORECLR_PROFILER_PATH=%BASE_PATH%OpenTelemetry.AutoInstrumentation.Native.dll
24+
set DOTNET_STARTUP_HOOKS=%BASE_PATH%OpenTelemetry.AutoInstrumentation.StartupHook.dll
25+
26+
:: Settings for OpenTelemetry
27+
set OTEL_DOTNET_AUTO_HOME=%BASE_PATH%
28+
set OTEL_DOTNET_AUTO_RULE_ENGINE_ENABLED=false
29+
30+
@echo on
31+
%*
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
3+
BASE_PATH="$(cd "$(dirname "$0")" && pwd)"
4+
5+
# Settings for .NET
6+
export ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper
7+
export CORECLR_ENABLE_PROFILING=1
8+
export CORECLR_PROFILER="{918728DD-259F-4A6A-AC2B-B85E1B658318}"
9+
CORECLR_PROFILER_PATH="$(ls ${BASE_PATH}/OpenTelemetry.AutoInstrumentation.Native.*)"
10+
export CORECLR_PROFILER_PATH
11+
export DOTNET_STARTUP_HOOKS=${BASE_PATH}/OpenTelemetry.AutoInstrumentation.StartupHook.dll
12+
13+
# Settings for OpenTelemetry
14+
export OTEL_DOTNET_AUTO_HOME=${BASE_PATH}
15+
export OTEL_DOTNET_AUTO_RULE_ENGINE_ENABLED=false
16+
17+
exec "$@"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@echo off
2+
setlocal
3+
4+
:: This script is expected to be used in a build that specified a RuntimeIdentifier (RID)
5+
set BASE_PATH=%~dp0
6+
7+
set OTEL_DOTNET_AUTO_PLUGINS=Elastic.OpenTelemetry.AutoInstrumentationPlugin, Elastic.OpenTelemetry
8+
9+
call %BASE_PATH%_instrument.cmd %*
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<!-- Hide the shipped content files VS project tree.
4+
Can be removed once https://github.com/NuGet/Home/issues/4856 is resolved -->
5+
<ItemGroup>
6+
<Content Update="@(Content)">
7+
<Visible Condition="'%(NuGetItemType)' == 'Content' and '%(NuGetPackageId)' == 'elastic.opentelemetry.autoinstrumentation'">False</Visible>
8+
<CopyToOutputDirectory Condition="'%(NuGetItemType)' == 'Content' and '%(NuGetPackageId)' == 'elastic.opentelemetry.autoinstrumentation'">Always</CopyToOutputDirectory>
9+
<CopyToPublishDirectory Condition="'%(NuGetItemType)' == 'Content' and '%(NuGetPackageId)' == 'elastic.opentelemetry.autoinstrumentation'">Always</CopyToPublishDirectory>
10+
</Content>
11+
</ItemGroup>
12+
</Project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
# This script is expected to be used in a build that specified a RuntimeIdentifier (RID)
4+
BASE_PATH="$(cd "$(dirname "$0")" && pwd)"
5+
6+
export OTEL_DOTNET_AUTO_PLUGINS="Elastic.OpenTelemetry.AutoInstrumentationPlugin, Elastic.OpenTelemetry"
7+
8+
. $BASE_PATH/_instrument.sh
9+
10+
exec "$@"

0 commit comments

Comments
 (0)