Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f5da22d
Use framework-specific dependency collection for .Net Framework versions
iskiselev Aug 6, 2025
0f69e49
Merge remote-tracking branch 'origin/main'
iskiselev Oct 7, 2025
0045c40
Format fix
iskiselev Oct 7, 2025
8b4d03b
Excluded Assemblies.NetFramework from build on non-windows OS
iskiselev Oct 7, 2025
c347876
Publish .Net Framework project only on windows
iskiselev Oct 7, 2025
8b05f5f
Fixed format for c# files
iskiselev Oct 7, 2025
4ef8534
Excluded .NetFramework assemblies-collecting project from producing N…
iskiselev Oct 7, 2025
ba8784d
Fixed test
iskiselev Oct 8, 2025
db32846
Bootstrap test fix (explicit reference)
iskiselev Oct 8, 2025
ce49362
Test fix (explicit reference)
iskiselev Oct 8, 2025
3c38ccc
Verified file structure fixed
iskiselev Oct 8, 2025
98f034d
Integration test fix (explicit reference)
iskiselev Oct 8, 2025
fad337e
Preserve empty folders with "_._" file
iskiselev Oct 8, 2025
96cfbec
Include _._ in verified structure.
iskiselev Oct 8, 2025
3b2b3fe
Fixed assembly redirection table generation / selection
iskiselev Oct 10, 2025
0829341
Format fix
iskiselev Oct 10, 2025
200839e
Corrected build/test machine GAC install/uninstall
iskiselev Oct 12, 2025
69075e0
Fixed empty lines
iskiselev Oct 12, 2025
ba9f1ce
Moved transitive dependencies pinning to OpenTelemetry.AutoInstrument…
iskiselev Oct 15, 2025
0d8480c
Merge remote-tracking branch 'origin/main'
iskiselev Oct 15, 2025
589f02a
Updated dependencies
iskiselev Oct 15, 2025
f9295d5
Reverted version override for test application
iskiselev Oct 15, 2025
7879ade
Removed unused code
iskiselev Oct 15, 2025
fcd3cfb
Updated image pinning to run tests
iskiselev Oct 16, 2025
24957a5
Merge remote-tracking branch 'origin/main'
iskiselev Oct 16, 2025
44d1c3c
README modified and tests added
iskiselev Oct 16, 2025
d4938a6
Changelog updated. Fixed BOM.
iskiselev Oct 16, 2025
e8330c6
Changelog fixed
iskiselev Oct 16, 2025
22524fb
Generated files updates
iskiselev Oct 16, 2025
7ba8086
Changelog fixed
iskiselev Oct 16, 2025
6cea088
Generated file update
iskiselev Oct 16, 2025
57b2d19
Test with latest .NET SDK
iskiselev Oct 17, 2025
634d4cc
Test with latest .NET SDK
iskiselev Oct 17, 2025
19d1000
Merge remote-tracking branch 'origin/main' into multitargeting-fx
iskiselev Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h
- .NET Framework only, following packages updated
- `OpenTelemetry.Instrumentation.AspNet` from `1.12.0-beta.1` to `1.12.0-beta.2`.

#### Dependencies on .Net Framework

When OpenTelemetry .NET AutoInstrumentation is compiled for .NET Framework,
it uses the net462 Target Framework Moniker (TFM). As a result, the ZIP archive
deployment contained dependency assemblies targeted for .NET Framework 4.6.2.
Some of these assemblies were not designed to be used with later versions of
.NET Framework.

Now, when the OpenTelemetry ZIP archive is built, dependency assemblies are
included for all supported .NET Framework versions. OpenTelemetry .NET
AutoInstrumentation detects the .NET Framework version at install time
and runtime, then loads the correct version of dependency assemblies.

### Deprecated

### Removed
Expand Down
19 changes: 19 additions & 0 deletions OpenTelemetry.AutoInstrumentation.sln
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.ProfilerSpa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.NoCode", "test\test-applications\integrations\TestApplication.NoCode\TestApplication.NoCode.csproj", "{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.AutoInstrumentation.Assemblies.NetFramework", "src\OpenTelemetry.AutoInstrumentation.Assemblies.NetFramework\OpenTelemetry.AutoInstrumentation.Assemblies.NetFramework.csproj", "{B69564D4-7D5B-7147-6CBA-233BB8A33C50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1585,6 +1587,22 @@ Global
{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE}.Release|x64.Build.0 = Release|x64
{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE}.Release|x86.ActiveCfg = Release|x86
{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE}.Release|x86.Build.0 = Release|x86
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|ARM64.Build.0 = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|x64.ActiveCfg = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|x64.Build.0 = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|x86.ActiveCfg = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Debug|x86.Build.0 = Debug|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|Any CPU.Build.0 = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|ARM64.ActiveCfg = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|ARM64.Build.0 = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|x64.ActiveCfg = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|x64.Build.0 = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|x86.ActiveCfg = Release|Any CPU
{B69564D4-7D5B-7147-6CBA-233BB8A33C50}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1678,6 +1696,7 @@ Global
{FD1A1ABD-6A48-4E94-B5F7-2081AFCD1BBB} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{665280EB-F428-4C04-A293-33228C73BF8A} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{B69564D4-7D5B-7147-6CBA-233BB8A33C50} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
Expand Down
92 changes: 75 additions & 17 deletions build/AssemblyRedirectionSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Text.RegularExpressions;
using Mono.Cecil;
using Serilog;

Expand All @@ -7,8 +8,36 @@ public static class AssemblyRedirectionSourceGenerator
public static void Generate(string assembliesFolderPath, string generatedFilePath)
{
Log.Debug("Generating assembly redirection file {0}", generatedFilePath);
var assemblies = new SortedDictionary<string, AssemblyNameDefinition>();
foreach (var fileName in Directory.EnumerateFiles(assembliesFolderPath))
var assemblies = new SortedDictionary<int, SortedDictionary<string, AssemblyNameDefinition>>();

var folders = new Dictionary<int, string>();

var frameworkVersionRegEx = new Regex(@"^net(?<version>\d{2,3})$");
foreach (var directory in Directory.EnumerateDirectories(assembliesFolderPath))
{
var folderName = Path.GetFileName(directory);
var framework = frameworkVersionRegEx.Match(folderName).Groups["version"].Value;
if (framework == string.Empty)
{
Log.Error("Unexpected folder name: {0}, will not be processed", framework);
continue;
}
var frameworkVersion = int.Parse(framework);
if (frameworkVersion < 100)
{
frameworkVersion *= 10;
}

if (folders.TryGetValue(frameworkVersion, out var folder))
{
Log.Error("For {0}: already registered folder {1}, {2} will be skipped", frameworkVersion, folder, directory);
continue;
}
folders[frameworkVersion] = directory;
assemblies[frameworkVersion] = new SortedDictionary<string, AssemblyNameDefinition>();
}

void Process(string fileName, int? framework)
{
try
{
Expand All @@ -17,25 +46,50 @@ public static void Generate(string assembliesFolderPath, string generatedFilePat
if (assemblyDef.Name == "netstandard")
{
// Skip netstandard, since it doesn't need redirection.
continue;
return;
}

assemblies[assemblyDef.Name] = assemblyDef;
Log.Debug("Adding {0} assembly to the redirection map. Targeted version {1}", assemblyDef.Name, assemblyDef.Version);

foreach (var keys in framework != null ? (IEnumerable<int>)[framework.Value] : assemblies.Keys)
{
assemblies[keys][assemblyDef.Name] = assemblyDef;
Log.Debug("Adding {0} assembly to the redirection map {1}. Targeted version {2}", assemblyDef.Name,
keys, assemblyDef.Version);
}
}
catch (BadImageFormatException)
{
Log.Debug("Skipping \"{0}\" couldn't open it as a managed assembly", fileName);
}
}

foreach (var fileName in Directory.EnumerateFiles(assembliesFolderPath))
{
Process(fileName, null);
}

foreach (var fx in folders)
{
foreach (var fileName in Directory.EnumerateFiles(fx.Value))
{
var filenameToProcess = fileName;
if (Path.GetExtension(fileName) == ".link")
{
filenameToProcess = Path.Combine(assembliesFolderPath, File.ReadAllText(fileName),
Path.GetFileNameWithoutExtension(fileName));
}

Process(filenameToProcess, fx.Key);
}
}

var sourceContents = GenerateSourceContents(assemblies);

File.WriteAllText(generatedFilePath, sourceContents);
Log.Information("Assembly redirection source generated {0}", generatedFilePath);
}

private static string GenerateSourceContents(SortedDictionary<string, AssemblyNameDefinition> assemblies)
private static string GenerateSourceContents(SortedDictionary<int, SortedDictionary<string, AssemblyNameDefinition>> assemblies)
{
#pragma warning disable format
return
Expand Down Expand Up @@ -70,22 +124,26 @@ namespace trace
#pragma warning restore format
}

private static string GenerateEntries(SortedDictionary<string, AssemblyNameDefinition> assemblies)
private static string GenerateEntries(SortedDictionary<int, SortedDictionary<string, AssemblyNameDefinition>> frameworks)
{
var longLineLength = 80;
var sb = new StringBuilder(assemblies.Count * longLineLength);
var sb = new StringBuilder();

foreach (var kvp in assemblies)
foreach (var fx in frameworks)
{
var v = kvp.Value.Version!;
if (kvp.Key != "OpenTelemetry.AutoInstrumentation")
{
sb.AppendLine($" {{ L\"{kvp.Key}\", {{{v.Major}, {v.Minor}, {v.Build}, {v.Revision}}} }},");
}
else
sb.AppendLine($" {{ {fx.Key}, {{");
foreach (var kvp in fx.Value)
{
sb.AppendLine($" {{ L\"{kvp.Key}\", {{auto_major, 0, 0, 0}} }},");
var v = kvp.Value.Version!;
if (kvp.Key != "OpenTelemetry.AutoInstrumentation")
{
sb.AppendLine($" {{ L\"{kvp.Key}\", {{{v.Major}, {v.Minor}, {v.Build}, {v.Revision}}} }},");
}
else
{
sb.AppendLine($" {{ L\"{kvp.Key}\", {{auto_major, 0, 0, 0}} }},");
}
}
sb.AppendLine(" }},");
}

return sb.ToString()
Expand Down
2 changes: 1 addition & 1 deletion build/Build.NuGet.Steps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ partial class Build
.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")))
foreach (var project in Solution.GetManagedSrcProjects().Where(p => !p.Name.EndsWith("AdditionalDeps") && !p.Name.Contains("Assemblies")))
{
DotNetPack(x => x
.SetProject(project)
Expand Down
58 changes: 31 additions & 27 deletions build/Build.Steps.Windows.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using DependencyListGenerator;
using Extensions;
using NuGet.Versioning;
using Nuke.Common;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
Expand Down Expand Up @@ -208,46 +210,41 @@ void BuildDockerImage(Project project, params string[] targets)
.Executes(() =>
{
// The target project needs to have its NuGet packages restored prior to running the tool.
var targetProject = Solution.GetProjectByName(Projects.AutoInstrumentation);
var targetProject = Solution.GetProjectByName(Projects.AutoInstrumentationNetFxAssemblies);
DotNetRestore(s => s.SetProjectFile(targetProject));

var project = targetProject.GetMSBuildProject();
var packages = Solution.Directory / "src" / "Directory.Packages.props";

const string label = $"Transient dependencies auto-generated by {nameof(GenerateNetFxTransientDependencies)}";
var deps = Generator.EnumerateDependencies(project.FullPath);
var packages = Solution.Directory / "src" / Projects.AutoInstrumentationNetFxAssemblies / "Directory.Packages.props";
var packagesProject = ProjectModelTasks.ParseProject(packages);

var packagesGroup = project.Xml.ItemGroups.FirstOrDefault(x => x.Label == label);
if (packagesGroup == null)
foreach (var framework in targetProject.GetTargetFrameworks() ?? [])
{
packagesGroup = project.Xml.AddItemGroup();
packagesGroup.Label = label;
packagesGroup.Condition = " '$(TargetFramework)' == 'net462' AND $(_IsPacking) != true ";
}
var label =
$"Transient dependencies auto-generated by {nameof(GenerateNetFxTransientDependencies)} for {framework}";

var packagesProject = ProjectModelTasks.ParseProject(packages);
var versionGroup = packagesProject.Xml.ItemGroups.FirstOrDefault(x => x.Label == label);
if (versionGroup == null)
{
versionGroup = packagesProject.Xml.AddItemGroup();
versionGroup.Label = label;
}
var projectForTfm = targetProject.GetMSBuildProject(targetFramework: framework);
var definedVersions = projectForTfm
.Items.Where(it => it.ItemType == "PackageVersion").ToDictionary(item => item.EvaluatedInclude, item => item.GetMetadata("Version"));

var deps = Generator.EnumerateDependencies(project.FullPath);
foreach (var item in deps)
{
if (!packagesGroup.Items.Any(x => x.Include == item.Name))
var versionGroup = packagesProject.Xml.ItemGroups.FirstOrDefault(x => x.Label == label);
if (versionGroup == null)
{
packagesGroup.AddItem("PackageReference", item.Name);
versionGroup = packagesProject.Xml.AddItemGroup();
versionGroup.Label = label;
versionGroup.Condition = $" '$(TargetFramework)' == '{framework}' ";
}

if (!versionGroup.Items.Any(x => x.Include == item.Name))
foreach (var item in deps[framework])
{
var reference = versionGroup.AddItem("PackageVersion", item.Name);
reference.AddMetadata("Version", item.Version, expressAsAttribute: true);
if (!definedVersions.ContainsKey(item.Name))
{
var reference = versionGroup.AddItem("PackageVersion", item.Name);
reference.AddMetadata("Version", item.Version, expressAsAttribute: true);
}
}
}

project.Save();
packagesProject.Save();
});

Expand Down Expand Up @@ -288,9 +285,16 @@ private void RunNetFxGacOperation(string operation)
throw new InvalidOperationException("This target must be run on Windows as Administrator.");
}

var netFxAssembliesFolder = TracerHomeDirectory / MapToFolderOutput(TargetFramework.NET462);
// We assume that dev machine running test has .Net Framework not older than TargetFrameworksNetFx.Last()
var netFxCommonAssembliesFolder = TracerHomeDirectory / MapToFolderOutput(TargetFrameworksNetFx.Last());
var netFxAssembliesFolder = TracerHomeDirectory / MapToFolderOutputNetFx(TargetFrameworksNetFx.Last());
var installTool = Solution.GetProjectByName(Projects.Tools.GacInstallTool);

DotNetRun(s => s
.SetProjectFile(installTool)
.SetConfiguration(BuildConfiguration)
.SetApplicationArguments(operation, netFxCommonAssembliesFolder));

DotNetRun(s => s
.SetProjectFile(installTool)
.SetConfiguration(BuildConfiguration)
Expand Down
Loading