Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions OpenTelemetry.AutoInstrumentation.sln
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.AutoInstrumen
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Wcf.Core", "test\test-applications\integrations\TestApplication.Wcf.Core\TestApplication.Wcf.Core.csproj", "{0F864722-CE44-4D99-9B67-CF0ED1893FF1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.EntityFrameworkCore.Npgsql", "test\test-applications\integrations\TestApplication.EntityFrameworkCore.Npgsql\TestApplication.EntityFrameworkCore.Npgsql.csproj", "{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1638,6 +1640,22 @@ Global
{0F864722-CE44-4D99-9B67-CF0ED1893FF1}.Release|x64.Build.0 = Release|Any CPU
{0F864722-CE44-4D99-9B67-CF0ED1893FF1}.Release|x86.ActiveCfg = Release|Any CPU
{0F864722-CE44-4D99-9B67-CF0ED1893FF1}.Release|x86.Build.0 = Release|Any CPU
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|Any CPU.ActiveCfg = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|Any CPU.Build.0 = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|ARM64.ActiveCfg = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|ARM64.Build.0 = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|x64.ActiveCfg = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|x64.Build.0 = Debug|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|x86.ActiveCfg = Debug|x86
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Debug|x86.Build.0 = Debug|x86
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|Any CPU.ActiveCfg = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|Any CPU.Build.0 = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|ARM64.ActiveCfg = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|ARM64.Build.0 = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|x64.ActiveCfg = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|x64.Build.0 = Release|x64
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|x86.ActiveCfg = Release|x86
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1734,6 +1752,7 @@ Global
{500BF40F-EECB-4F6A-377B-EDBDFFDE09BE} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{B69564D4-7D5B-7147-6CBA-233BB8A33C50} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
{0F864722-CE44-4D99-9B67-CF0ED1893FF1} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{0E2E77E0-E2FF-4E0E-A132-46E0E187F53C} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

#if NET
using OpenTelemetry.AutoInstrumentation.Configurations;
using OpenTelemetry.AutoInstrumentation.Logging;
using OpenTelemetry.AutoInstrumentation.Plugins;

namespace OpenTelemetry.AutoInstrumentation.Loading.Initializers;

internal class EntityFrameworkCoreInitializer : InstrumentationInitializer
{
private const string NpgsqlEfCoreProviderName = "Npgsql.EntityFrameworkCore.PostgreSQL";
private static readonly IOtelLogger Logger = OtelLogging.GetLogger();

private readonly PluginManager _pluginManager;
private readonly TracerSettings _tracerSettings;

Expand All @@ -26,10 +30,26 @@ public override void Initialize(ILifespanManager lifespanManager)
var options = new OpenTelemetry.Instrumentation.EntityFrameworkCore.EntityFrameworkInstrumentationOptions();

_pluginManager.ConfigureTracesOptions(options);
ConfigureNpgsqlSuppressionIfNeeded(options);

var instrumentation = Activator.CreateInstance(instrumentationType, options)!;

lifespanManager.Track(instrumentation);
}

private void ConfigureNpgsqlSuppressionIfNeeded(OpenTelemetry.Instrumentation.EntityFrameworkCore.EntityFrameworkInstrumentationOptions options)
{
if (!_tracerSettings.EnabledInstrumentations.Contains(TracerInstrumentation.Npgsql))
{
return;
}

var currentFilter = options.Filter;
options.Filter = (providerName, command) =>
!string.Equals(providerName, NpgsqlEfCoreProviderName, StringComparison.Ordinal) &&
(currentFilter?.Invoke(providerName, command) ?? true);

Logger.Information("Configured EntityFrameworkCore instrumentation to skip Npgsql provider because Npgsql instrumentation is enabled.");
}
}
#endif
48 changes: 48 additions & 0 deletions test/IntegrationTests/EntityFrameworkCoreNpgsqlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#if NET

using IntegrationTests.Helpers;
using Xunit.Abstractions;

namespace IntegrationTests;

[Collection(PostgresCollectionFixture.Name)]
public class EntityFrameworkCoreNpgsqlTests : TestHelper
{
private readonly PostgresFixture _postgres;

public EntityFrameworkCoreNpgsqlTests(ITestOutputHelper output, PostgresFixture postgres)
: base("EntityFrameworkCore.Npgsql", output)
{
_postgres = postgres;
}

[Fact]
[Trait("Category", "EndToEnd")]
[Trait("Containers", "Linux")]
public void SubmitTraces_NpgsqlSpanHasApplicationSpanAsParent()
{
using var collector = new MockSpansCollector(Output);
SetExporter(collector);

collector.Expect("TestApplication.EntityFrameworkCore.Npgsql");
collector.Expect("Npgsql");
collector.ExpectCollected(collected =>
{
var applicationSpan = collected.First(span => span.Scope.Name == "TestApplication.EntityFrameworkCore.Npgsql");
var npgsqlSpan = collected.First(span => span.Scope.Name == "Npgsql");

return npgsqlSpan.Span.ParentSpanId.Equals(applicationSpan.Span.SpanId);
});

RunTestApplication(new()
{
Arguments = $"--postgres {_postgres.Port}"
});

collector.AssertExpectations();
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,21 @@ internal void TracerSettings_Instrumentations_SupportedValues(string tracerInstr
Assert.Equal([expectedTracerInstrumentation], settings.EnabledInstrumentations);
}

#if NET
[Fact]
internal void TracerSettings_Instrumentations_EntityFrameworkCoreAndNpgsqlCanBeEnabledTogether()
{
Environment.SetEnvironmentVariable(ConfigurationKeys.Traces.TracesInstrumentationEnabled, "false");
Environment.SetEnvironmentVariable(string.Format(CultureInfo.InvariantCulture, ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, "ENTITYFRAMEWORKCORE"), "true");
Environment.SetEnvironmentVariable(string.Format(CultureInfo.InvariantCulture, ConfigurationKeys.Traces.EnabledTracesInstrumentationTemplate, "NPGSQL"), "true");

var settings = Settings.FromDefaultSources<TracerSettings>(false);

Assert.Contains(TracerInstrumentation.EntityFrameworkCore, settings.EnabledInstrumentations);
Assert.Contains(TracerInstrumentation.Npgsql, settings.EnabledInstrumentations);
}
#endif

[Theory]
#if NETFRAMEWORK
[InlineData("ASPNET", MetricInstrumentation.AspNet)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics;
using Microsoft.EntityFrameworkCore;
using TestApplication.Shared;

namespace TestApplication.EntityFrameworkCore.Npgsql;

internal static class Program
{
private static readonly ActivitySource ActivitySource = new("TestApplication.EntityFrameworkCore.Npgsql");

public static async Task Main(string[] args)
{
ConsoleHelper.WriteSplashScreen(args);

var postgresPort = GetPostgresPort(args);
var connectionString = $"Server=127.0.0.1;Port={postgresPort};User ID=postgres;Database=postgres";

var contextOptions = new DbContextOptionsBuilder<TestDbContext>()
.UseNpgsql(connectionString)
.Options;

using var activity = ActivitySource.StartActivity("parent");
using var context = new TestDbContext(contextOptions);

await context.Database.ExecuteSqlRawAsync("SELECT 123;").ConfigureAwait(false);
}

private static string GetPostgresPort(string[] args)
{
if (args.Length > 1)
{
return args[1];
}

return "5432";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net10.0;net9.0;net8.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Npgsql" VersionOverride="9.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" VersionOverride="9.0.4" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using Microsoft.EntityFrameworkCore;

namespace TestApplication.EntityFrameworkCore.Npgsql;

#pragma warning disable CA1812 // Avoid uninstantiated internal classes. This class is instantiated by EF Core.
internal sealed class TestDbContext : DbContext
#pragma warning restore CA1812 // Avoid uninstantiated internal classes. This class is instantiated by EF Core.
{
public TestDbContext(DbContextOptions options)
: base(options)
{
}
}
Loading