-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Instrumentation.EntityFrameworkCore] Fix db.statement tag for Devart Oracle #2466
base: main
Are you sure you want to change the base?
[Instrumentation.EntityFrameworkCore] Fix db.statement tag for Devart Oracle #2466
Conversation
if (command.GetType().FullName?.Contains("Devart.Data.Oracle") == true) | ||
{ | ||
string payloadString = payload?.ToString() ?? string.Empty; | ||
if ((payloadString.Contains("CommandType='Text'") && this.options.SetDbStatementForText) || | ||
(payloadString.Contains("CommandType='StoredProcedure'") && this.options.SetDbStatementForStoredProcedure)) | ||
{ | ||
string[] result = payloadString.Split(['\n'], 2); | ||
if (result.Length > 1) | ||
{ | ||
activity.AddTag(AttributeDbStatement, result[1]); | ||
} | ||
} | ||
} | ||
else if (this.commandTypeFetcher.Fetch(command) is CommandType commandType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is couple things you should consider here:
- Support both for emitting old and new attributes. See lese if statement for details:
if (this.options.SetDbStatementForStoredProcedure)
{
if (this.options.EmitOldAttributes)
{
activity.AddTag(AttributeDbStatement, commandText);
}
if (this.options.EmitNewAttributes)
{
activity.AddTag(AttributeDbQueryText, commandText);
}
}
- payloadString split, is it always '\n' or it can be vary based on the environment settings?
- Consider adding stub/mocked tests for this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
I was writing this code based on an older version (1.0.0-beta.10) that didn't have
this.options.EmitOldAttributes
andthis.options.EmitNewAttributes
. So, I will update the code structure to follow the convention of the switch statement. -
Updated the line as follows:
string[] result = payloadString.Split([Environment.NewLine], 2, StringSplitOptions.None);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I am unable to write mock tests because Devart requires a license in order to connect to Oracle database. 😞
src/OpenTelemetry.Instrumentation.EntityFrameworkCore/CHANGELOG.md
Outdated
Show resolved
Hide resolved
Co-authored-by: Piotr Kiełkowicz <[email protected]>
Hi @Kielek, can you chack on these changes I made? |
@@ -200,7 +200,50 @@ public override void OnEventWritten(string name, object? payload) | |||
return; | |||
} | |||
|
|||
if (this.commandTypeFetcher.Fetch(command) is CommandType commandType) | |||
if (command.GetType().FullName?.Contains("Devart.Data.Oracle") == true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider code below. It is doing couple of things
- It is always trying to fetch method in the standard way (probably most common)
- If it fails it goes to fallback mechanism for Devart.
- Changes some Linq comparison to standard way.
- Optimize
payloadString.Contains(
usages in new code, it is better to check bools first (cheaper).
From a06207733b5917f57328bd281d6d586948719e79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= <[email protected]>
Date: Wed, 22 Jan 2025 09:31:15 +0100
Subject: [PATCH] proposal
---
.../EntityFrameworkDiagnosticListener.cs | 116 ++++++++----------
1 file changed, 53 insertions(+), 63 deletions(-)
diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Implementation/EntityFrameworkDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Implementation/EntityFrameworkDiagnosticListener.cs
index 26eb87b9..0cdb07fe 100644
--- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Implementation/EntityFrameworkDiagnosticListener.cs
+++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Implementation/EntityFrameworkDiagnosticListener.cs
@@ -200,90 +200,80 @@ internal sealed class EntityFrameworkDiagnosticListener : ListenerHandler
return;
}
- if (command.GetType().FullName?.Contains("Devart.Data.Oracle") == true)
+ if (this.commandTypeFetcher.Fetch(command) is CommandType commandType)
{
- string payloadString = payload?.ToString() ?? string.Empty;
- string[] result = payloadString.Split([Environment.NewLine], 2, StringSplitOptions.None);
- string commandText = result.Length > 1 ? result[1] : payloadString;
-
- if (payloadString.Contains("CommandType='Text'"))
+ if (this.commandTextFetcher.TryFetch(command, out var commandText)) // consider adding here && !string.IsNullOrEmpty(commandText)
{
- if (this.options.SetDbStatementForText)
+ switch (commandType)
{
- if (this.options.EmitOldAttributes)
- {
- activity.AddTag(AttributeDbStatement, commandText);
- }
+ case CommandType.StoredProcedure:
+ if (this.options.SetDbStatementForStoredProcedure)
+ {
+ if (this.options.EmitOldAttributes)
+ {
+ activity.AddTag(AttributeDbStatement, commandText);
+ }
+
+ if (this.options.EmitNewAttributes)
+ {
+ activity.AddTag(AttributeDbQueryText, commandText);
+ }
+ }
- if (this.options.EmitNewAttributes)
- {
- activity.AddTag(AttributeDbQueryText, commandText);
- }
+ break;
+
+ case CommandType.Text:
+ if (this.options.SetDbStatementForText)
+ {
+ if (this.options.EmitOldAttributes)
+ {
+ activity.AddTag(AttributeDbStatement, commandText);
+ }
+
+ if (this.options.EmitNewAttributes)
+ {
+ activity.AddTag(AttributeDbQueryText, commandText);
+ }
+ }
+
+ break;
+
+ case CommandType.TableDirect:
+ break;
+ default:
+ break;
}
}
- else if (payloadString.Contains("CommandType='StoredProcedure'"))
+ else if (command.GetType().FullName?.StartsWith("Devart.Data.Oracle", StringComparison.Ordinal) == true)
{
- if (this.options.SetDbStatementForText)
+ string payloadString = payload?.ToString() ?? string.Empty;
+ string[] result = payloadString.Split([Environment.NewLine], 2, StringSplitOptions.None);
+ string devartCommandText = result.Length > 1 ? result[1] : payloadString;
+
+ if (this.options.SetDbStatementForText && payloadString.Contains("CommandType='Text'"))
{
if (this.options.EmitOldAttributes)
{
- activity.AddTag(AttributeDbStatement, commandText);
+ activity.AddTag(AttributeDbStatement, devartCommandText);
}
if (this.options.EmitNewAttributes)
{
- activity.AddTag(AttributeDbQueryText, commandText);
+ activity.AddTag(AttributeDbQueryText, devartCommandText);
}
}
- }
- else if (payloadString.Contains("CommandType='TableDirect'"))
- {
- }
- else
- {
- }
- }
- else if (this.commandTypeFetcher.Fetch(command) is CommandType commandType)
- {
- var commandText = this.commandTextFetcher.Fetch(command);
- switch (commandType)
- {
- case CommandType.StoredProcedure:
- if (this.options.SetDbStatementForStoredProcedure)
+ else if (this.options.SetDbStatementForText && payloadString.Contains("CommandType='StoredProcedure'"))
+ {
+ if (this.options.EmitOldAttributes)
{
- if (this.options.EmitOldAttributes)
- {
- activity.AddTag(AttributeDbStatement, commandText);
- }
-
- if (this.options.EmitNewAttributes)
- {
- activity.AddTag(AttributeDbQueryText, commandText);
- }
+ activity.AddTag(AttributeDbStatement, devartCommandText);
}
- break;
-
- case CommandType.Text:
- if (this.options.SetDbStatementForText)
+ if (this.options.EmitNewAttributes)
{
- if (this.options.EmitOldAttributes)
- {
- activity.AddTag(AttributeDbStatement, commandText);
- }
-
- if (this.options.EmitNewAttributes)
- {
- activity.AddTag(AttributeDbQueryText, commandText);
- }
+ activity.AddTag(AttributeDbQueryText, devartCommandText);
}
-
- break;
-
- case CommandType.TableDirect:
- break;
- default:
- break;
+ }
}
}
--
5.45.2.windows.1
Sorry for waiting long for a feedback, it is not trivial change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kielek Thank you for the response and suggestions.
When this code is executed this.commandTypeFetcher.Fetch(command)
in the IF statement, the exception will leave the EntityFrameworkCoreCommandExecuting
case (It will not step into the ELSE IF statement to check if it's Devart). This can be fixed with a try-catch statement, where the TRY part contains the original code, and the CATCH statement handles fallback:
try
{
if (this.commandTypeFetcher.Fetch(command) is CommandType commandType)
{
if (this.commandTextFetcher.TryFetch(command, out var commandText) && !string.IsNullOrEmpty(commandText))
{
switch (commandType)
{
case CommandType.StoredProcedure:
if (this.options.SetDbStatementForStoredProcedure)
{
if (this.options.EmitOldAttributes)
{
activity.AddTag(AttributeDbStatement, commandText);
}
if (this.options.EmitNewAttributes)
{
activity.AddTag(AttributeDbQueryText, commandText);
}
}
break;
case CommandType.Text:
if (this.options.SetDbStatementForText)
{
if (this.options.EmitOldAttributes)
{
activity.AddTag(AttributeDbStatement, commandText);
}
if (this.options.EmitNewAttributes)
{
activity.AddTag(AttributeDbQueryText, commandText);
}
}
break;
case CommandType.TableDirect:
break;
default:
break;
}
}
}
}
catch (Exception)
{
string payloadString = payload?.ToString() ?? string.Empty;
string[] result = payloadString.Split([Environment.NewLine], 2, StringSplitOptions.None);
string commandText = result.Length > 1 ? result[1] : payloadString;
if (payloadString.Contains("CommandType='Text'"))
{
if (this.options.SetDbStatementForText)
{
if (this.options.EmitOldAttributes)
{
activity.AddTag(AttributeDbStatement, commandText);
}
if (this.options.EmitNewAttributes)
{
activity.AddTag(AttributeDbQueryText, commandText);
}
}
}
else if (payloadString.Contains("CommandType='StoredProcedure'"))
{
if (this.options.SetDbStatementForText)
{
if (this.options.EmitOldAttributes)
{
activity.AddTag(AttributeDbStatement, commandText);
}
if (this.options.EmitNewAttributes)
{
activity.AddTag(AttributeDbQueryText, commandText);
}
}
}
}
With this change we don't need to check if Devart is causing this problem or another provider for database connection.
Is this change acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's about converting it to if (this.commandTypeFetcher.TryFetch(command, out var commandType)
, without try/catch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried it but still throws exception unfortunately 😞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is what I've dug up while analyzing this exception. Firstly, the Fetch function calls the TryFetch function in its implementation. The TryFetch function is implemented as:
public bool TryFetch(object obj, out T value)
{
if (obj == null)
{
value = default;
return false;
}
if (this.innerFetcher == null)
{
var type = obj.GetType().GetTypeInfo();
var property = type.DeclaredProperties.FirstOrDefault(p => string.Equals(p.Name, this.propertyName, StringComparison.OrdinalIgnoreCase)) ?? type.GetProperty(this.propertyName);
this.innerFetcher = PropertyFetch.FetcherForProperty(property);
}
return this.innerFetcher.TryFetch(obj, out value);
}
Now if we follow the code execution, PropertyFetch.FetcherForProperty(property);
is called with the following implementation:
public static PropertyFetch FetcherForProperty(PropertyInfo propertyInfo)
{
if (propertyInfo == null || !typeof(T).IsAssignableFrom(propertyInfo.PropertyType))
{
// returns null on any fetch.
return new PropertyFetch();
}
var typedPropertyFetcher = typeof(TypedPropertyFetch<,>);
var instantiatedTypedPropertyFetcher = typedPropertyFetcher.MakeGenericType(
typeof(T), propertyInfo.DeclaringType, propertyInfo.PropertyType);
return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo);
}
The return statement calls (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, propertyInfo);
which calls the constructor of the TypedPropertyFetch
:
#pragma warning disable CA1812
private sealed class TypedPropertyFetch<TDeclaredObject, TDeclaredProperty> : PropertyFetch
#pragma warning restore CA1812
where TDeclaredProperty : T
{
private readonly Func<TDeclaredObject, TDeclaredProperty> propertyFetch;
public TypedPropertyFetch(PropertyInfo property)
{
#if NET
this.propertyFetch = property.GetMethod.CreateDelegate<Func<TDeclaredObject, TDeclaredProperty>>();
#else
this.propertyFetch = (Func<TDeclaredObject, TDeclaredProperty>)property.GetMethod.CreateDelegate(typeof(Func<TDeclaredObject, TDeclaredProperty>));
#endif
}
When CreateDelegate()
is called, the exception is thrown System.ArgumentException: 'Cannot bind to the target method because its signature is not compatible with that of the delegate type.'
.
This is the part I can't solve, which is why I made this workaround.
This PR was marked stale due to lack of activity. It will be closed in 7 days. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2466 +/- ##
==========================================
- Coverage 73.91% 0 -73.92%
==========================================
Files 267 0 -267
Lines 9615 0 -9615
==========================================
- Hits 7107 0 -7107
+ Misses 2508 0 -2508 |
This PR was marked stale due to lack of activity. It will be closed in 7 days. |
This PR was marked stale due to lack of activity. It will be closed in 7 days. |
@vladajankovic , again, sorry for long response. I have more other non-maintainer related activities currently, but finally I have find some time to check this problem once more time. And the results looks good to me. Could you please provide some testing code which is failing? If it is still failing, please provide code snipped which could help with debugging. Tested on: Docker: From 817ac1e0828273a9b8ec51d10656efadf3390a4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= <[email protected]>
Date: Tue, 18 Feb 2025 11:43:38 +0100
Subject: [PATCH] test
---
opentelemetry-dotnet-contrib.sln | 7 ++
.../Properties/AssemblyInfo.cs | 2 +
.../EntityFrameworkDevartPostgreSqlTests.cs | 114 ++++++++++++++++++
...ameworkCore.Devart.PostgreSql.Tests.csproj | 23 ++++
4 files changed, 146 insertions(+)
create mode 100644 test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/EntityFrameworkDevartPostgreSqlTests.cs
create mode 100644 test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests.csproj
diff --git a/opentelemetry-dotnet-contrib.sln b/opentelemetry-dotnet-contrib.sln
index 03d61a66..8fad7807 100644
--- a/opentelemetry-dotnet-contrib.sln
+++ b/opentelemetry-dotnet-contrib.sln
@@ -403,6 +403,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentati
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.ServiceFabricRemoting.Tests", "test\OpenTelemetry.Instrumentation.ServiceFabricRemoting.Tests\OpenTelemetry.Instrumentation.ServiceFabricRemoting.Tests.csproj", "{00C9F0B8-3D51-483C-821A-5889B38A144C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests", "test\OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests\OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests.csproj", "{900B96E1-4298-944D-3444-F33E17BDC508}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -833,6 +835,10 @@ Global
{00C9F0B8-3D51-483C-821A-5889B38A144C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00C9F0B8-3D51-483C-821A-5889B38A144C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00C9F0B8-3D51-483C-821A-5889B38A144C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {900B96E1-4298-944D-3444-F33E17BDC508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {900B96E1-4298-944D-3444-F33E17BDC508}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {900B96E1-4298-944D-3444-F33E17BDC508}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {900B96E1-4298-944D-3444-F33E17BDC508}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -961,6 +967,7 @@ Global
{9B994669-E839-4C42-A0F1-DF9DD058C1DC} = {3A464E7A-42F3-44B0-B8D7-80521A7704A6}
{91BA4FF0-50BC-49D0-976B-CBC9E5FE8337} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
{00C9F0B8-3D51-483C-821A-5889B38A144C} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
+ {900B96E1-4298-944D-3444-F33E17BDC508} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B0816796-CDB3-47D7-8C3C-946434DE3B66}
diff --git a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Properties/AssemblyInfo.cs b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Properties/AssemblyInfo.cs
index 7e447d9e..e4aa97c1 100644
--- a/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Properties/AssemblyInfo.cs
+++ b/src/OpenTelemetry.Instrumentation.EntityFrameworkCore/Properties/AssemblyInfo.cs
@@ -5,6 +5,8 @@ using System.Runtime.CompilerServices;
#if SIGNED
[assembly: InternalsVisibleTo("OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")]
+[assembly: InternalsVisibleTo("OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")]
#else
[assembly: InternalsVisibleTo("OpenTelemetry.Instrumentation.EntityFrameworkCore.Tests")]
+[assembly: InternalsVisibleTo("OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests")]
#endif
diff --git a/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/EntityFrameworkDevartPostgreSqlTests.cs b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/EntityFrameworkDevartPostgreSqlTests.cs
new file mode 100644
index 00000000..1ac0a143
--- /dev/null
+++ b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/EntityFrameworkDevartPostgreSqlTests.cs
@@ -0,0 +1,114 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Data.Common;
+using System.Diagnostics;
+using Devart.Data.PostgreSql;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using OpenTelemetry.Instrumentation.EntityFrameworkCore.Implementation;
+using OpenTelemetry.Trace;
+using Xunit;
+
+namespace OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests;
+
+public class EntityFrameworkDevartPostgreSqlTests : IDisposable
+{
+ private readonly DbContextOptions<ItemsContext> contextOptions;
+ private readonly DbConnection connection;
+
+ public EntityFrameworkDevartPostgreSqlTests()
+ {
+ var dbContextOptionsBuilder = new DbContextOptionsBuilder<ItemsContext>();
+ var connection2 = CreatePgSqlConnection();
+ dbContextOptionsBuilder.UsePostgreSql(connection2);
+ this.contextOptions = dbContextOptionsBuilder
+ .Options;
+
+ this.connection = RelationalOptionsExtension.Extract(this.contextOptions).Connection!;
+
+ this.Seed();
+ }
+
+ [Fact]
+ public void EntityFrameworkContextEventsInstrumentedTest()
+ {
+ var exportedItems = new List<Activity>();
+ using var shutdownSignal = Sdk.CreateTracerProviderBuilder()
+ .AddInMemoryExporter(exportedItems)
+ .AddEntityFrameworkCoreInstrumentation(x => x.SetDbStatementForText = true).Build();
+
+ using (var context = new ItemsContext(this.contextOptions))
+ {
+ var items = context.Set<Item>().OrderBy(e => e.Name).ToList();
+
+ Assert.Equal(3, items.Count);
+ Assert.Equal("ItemOne", items[0].Name);
+ Assert.Equal("ItemThree", items[1].Name);
+ Assert.Equal("ItemTwo", items[2].Name);
+ }
+
+ var activity = Assert.Single(exportedItems);
+ Assert.Equal(ActivityKind.Client, activity.Kind);
+ Assert.Equal("postgresql", activity.Tags.FirstOrDefault(t => t.Key == EntityFrameworkDiagnosticListener.AttributeDbSystem).Value);
+
+ Assert.Equal("SELECT i.\"Name\"\r\nFROM \"Item\" AS i\r\nORDER BY i.\"Name\"", activity.Tags.FirstOrDefault(t => t.Key == EntityFrameworkDiagnosticListener.AttributeDbStatement).Value);
+ }
+
+ public void Dispose() => this.connection.Dispose();
+
+ private static PgSqlConnection CreatePgSqlConnection()
+ {
+ var connection = new PgSqlConnection("Server=127.0.0.1;Port=5432;User ID=postgres;");
+
+ connection.Open();
+
+ return connection;
+ }
+
+ private void Seed()
+ {
+ using var context = new ItemsContext(this.contextOptions);
+
+ context.Database.EnsureDeleted();
+ context.Database.EnsureCreated();
+
+ var one = new Item("ItemOne");
+
+ var two = new Item("ItemTwo");
+
+ var three = new Item("ItemThree");
+
+ context.AddRange(one, two, three);
+
+ context.SaveChanges();
+ }
+
+ private class Item
+ {
+ public Item(string name)
+ {
+ this.Name = name;
+ }
+
+ public string Name { get; }
+ }
+
+ private class ItemsContext : DbContext
+ {
+ public ItemsContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity<Item>(
+ b =>
+ {
+ b.Property(e => e.Name);
+ b.HasKey("Name");
+ });
+ }
+ }
+}
diff --git a/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests.csproj b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests.csproj
new file mode 100644
index 00000000..402b4314
--- /dev/null
+++ b/test/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests/OpenTelemetry.Instrumentation.EntityFrameworkCore.Devart.PostgreSql.Tests.csproj
@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
+ <TargetFrameworks>$(SupportedNetTargets)</TargetFrameworks>
+ <Description>Unit test project for OpenTelemetry Microsoft.EntityFrameworkCore instrumentation.</Description>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Devart.Data.PostgreSQL.EFCore" Version="8.4.193.9" />
+ <PackageReference Include="OpenTelemetry.Exporter.InMemory" Version="$(OpenTelemetryExporterInMemoryPkgVer)" />
+ <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="$(OpenTelemetryCoreLatestVersion)" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.EntityFrameworkCore\OpenTelemetry.Instrumentation.EntityFrameworkCore.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="$(RepoRoot)\src\Shared\SpanAttributeConstants.cs" Link="Includes\SpanAttributeConstants.cs" />
+ </ItemGroup>
+
+</Project>
--
2.47.1.windows.2
|
Fixes #2462
Changes
Added code to fix exception thrown when Devart Oracle is used (
this.commandTypeFetcher.Fetch(command)
).If Devart Oracle is used, the SQL statement will be extracted from the payload.
Merge requirement checklist
CHANGELOG.md
files updated for non-trivial changes