Skip to content

Commit

Permalink
update HttpSemanticConventions for Instrumentation.SqlClient (#4644)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyMothra authored Jul 13, 2023
1 parent b5e8361 commit 5b725de
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/OpenTelemetry.Api/Internal/SemanticConventions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ internal static class SemanticConventions
public const string AttributeHttpRequestMethod = "http.request.method"; // replaces: "http.method" (AttributeHttpMethod)
public const string AttributeHttpResponseStatusCode = "http.response.status_code"; // replaces: "http.status_code" (AttributeHttpStatusCode)
public const string AttributeNetworkProtocolVersion = "network.protocol.version"; // replaces: "http.flavor" (AttributeHttpFlavor)
public const string AttributeServerAddress = "server.address"; // replaces: "net.host.name" (AttributeNetHostName)
public const string AttributeServerAddress = "server.address"; // replaces: "net.host.name" (AttributeNetHostName) and "net.peer.name" (AttributeNetPeerName)
public const string AttributeServerPort = "server.port"; // replaces: "net.host.port" (AttributeNetHostPort) and "net.peer.port" (AttributeNetPeerPort)
public const string AttributeServerSocketAddress = "server.socket.address"; // replaces: "net.peer.ip" (AttributeNetPeerIp)
public const string AttributeUrlFull = "url.full"; // replaces: "http.url" (AttributeHttpUrl)
public const string AttributeUrlPath = "url.path"; // replaces: "http.target" (AttributeHttpTarget)
public const string AttributeUrlScheme = "url.scheme"; // replaces: "http.scheme" (AttributeHttpScheme)
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

* Updated [Semantic Conventions](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md).
This library can emit either old, new, or both attributes. Users can control
which attributes are emitted by setting the environment variable
`OTEL_SEMCONV_STABILITY_OPT_IN`.
([#4644](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4644))

## 1.5.0-beta.1

Released 2023-Jun-05
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ namespace OpenTelemetry.Instrumentation.SqlClient
/// </remarks>
public class SqlClientInstrumentationOptions
{
internal readonly HttpSemanticConvention HttpSemanticConvention;

/*
* Match...
* protocol[ ]:[ ]serverName
Expand Down Expand Up @@ -67,6 +65,9 @@ public class SqlClientInstrumentationOptions

private static readonly ConcurrentDictionary<string, SqlConnectionDetails> ConnectionDetailCache = new(StringComparer.OrdinalIgnoreCase);

private readonly bool emitOldAttributes;
private readonly bool emitNewAttributes;

/// <summary>
/// Initializes a new instance of the <see cref="SqlClientInstrumentationOptions"/> class.
/// </summary>
Expand All @@ -79,7 +80,9 @@ internal SqlClientInstrumentationOptions(IConfiguration configuration)
{
Debug.Assert(configuration != null, "configuration was null");

this.HttpSemanticConvention = GetSemanticConventionOptIn(configuration);
var httpSemanticConvention = GetSemanticConventionOptIn(configuration);
this.emitOldAttributes = httpSemanticConvention.HasFlag(HttpSemanticConvention.Old);
this.emitNewAttributes = httpSemanticConvention.HasFlag(HttpSemanticConvention.New);
}

/// <summary>
Expand Down Expand Up @@ -134,19 +137,23 @@ internal SqlClientInstrumentationOptions(IConfiguration configuration)
/// langword="false"/>.
/// </summary>
/// <remarks>
/// <para><b>EnableConnectionLevelAttributes is supported on all
/// runtimes.</b></para>
/// <para>The default behavior is to set the SqlConnection DataSource as
/// the <see cref="SemanticConventions.AttributePeerService"/> tag. If
/// enabled, SqlConnection DataSource will be parsed and the server name
/// will be sent as the <see
/// cref="SemanticConventions.AttributeNetPeerName"/> or <see
/// cref="SemanticConventions.AttributeNetPeerIp"/> tag, the instance
/// name will be sent as the <see
/// cref="SemanticConventions.AttributeDbMsSqlInstanceName"/> tag, and
/// the port will be sent as the <see
/// cref="SemanticConventions.AttributeNetPeerPort"/> tag if it is not
/// 1433 (the default port).</para>
/// <para>
/// <b>EnableConnectionLevelAttributes is supported on all runtimes.</b>
/// </para>
/// <para>
/// The default behavior is to set the SqlConnection DataSource as the <see cref="SemanticConventions.AttributePeerService"/> tag.
/// If enabled, SqlConnection DataSource will be parsed and the server name will be sent as the
/// <see cref="SemanticConventions.AttributeNetPeerName"/> or <see cref="SemanticConventions.AttributeNetPeerIp"/> tag,
/// the instance name will be sent as the <see cref="SemanticConventions.AttributeDbMsSqlInstanceName"/> tag,
/// and the port will be sent as the <see cref="SemanticConventions.AttributeNetPeerPort"/> tag if it is not 1433 (the default port).
/// </para>
/// <para>
/// If the environment variable OTEL_SEMCONV_STABILITY_OPT_IN is set to "http", the newer Semantic Convention v1.21.0 Attributes will be emitted.
/// SqlConnection DataSource will be parsed and the server name will be sent as the
/// <see cref="SemanticConventions.AttributeServerAddress"/> or <see cref="SemanticConventions.AttributeServerSocketAddress"/> tag,
/// the instance name will be sent as the <see cref="SemanticConventions.AttributeDbMsSqlInstanceName"/> tag,
/// and the port will be sent as the <see cref="SemanticConventions.AttributeServerPort"/> tag if it is not 1433 (the default port).
/// </para>
/// </remarks>
public bool EnableConnectionLevelAttributes { get; set; }

Expand Down Expand Up @@ -302,23 +309,45 @@ internal void AddConnectionLevelDetailsToActivity(string dataSource, Activity sq
ConnectionDetailCache.TryAdd(dataSource, connectionDetails);
}

if (!string.IsNullOrEmpty(connectionDetails.ServerHostName))
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerName, connectionDetails.ServerHostName);
}
else
if (!string.IsNullOrEmpty(connectionDetails.InstanceName))
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerIp, connectionDetails.ServerIpAddress);
sqlActivity.SetTag(SemanticConventions.AttributeDbMsSqlInstanceName, connectionDetails.InstanceName);
}

if (!string.IsNullOrEmpty(connectionDetails.InstanceName))
if (this.emitOldAttributes)
{
sqlActivity.SetTag(SemanticConventions.AttributeDbMsSqlInstanceName, connectionDetails.InstanceName);
if (!string.IsNullOrEmpty(connectionDetails.ServerHostName))
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerName, connectionDetails.ServerHostName);
}
else
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerIp, connectionDetails.ServerIpAddress);
}

if (!string.IsNullOrEmpty(connectionDetails.Port))
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerPort, connectionDetails.Port);
}
}

if (!string.IsNullOrEmpty(connectionDetails.Port))
// see the spec https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md
if (this.emitNewAttributes)
{
sqlActivity.SetTag(SemanticConventions.AttributeNetPeerPort, connectionDetails.Port);
if (!string.IsNullOrEmpty(connectionDetails.ServerHostName))
{
sqlActivity.SetTag(SemanticConventions.AttributeServerAddress, connectionDetails.ServerHostName);
}
else
{
sqlActivity.SetTag(SemanticConventions.AttributeServerSocketAddress, connectionDetails.ServerIpAddress);
}

if (!string.IsNullOrEmpty(connectionDetails.Port))
{
// TODO: Should we continue to emit this if the default port (1433) is being used?
sqlActivity.SetTag(SemanticConventions.AttributeServerPort, connectionDetails.Port);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
// </copyright>

using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using OpenTelemetry.Trace;
using Xunit;
using static OpenTelemetry.Internal.HttpSemanticConventionHelper;

namespace OpenTelemetry.Instrumentation.SqlClient.Tests
{
Expand Down Expand Up @@ -102,5 +104,110 @@ public void SqlClientInstrumentationOptions_EnableConnectionLevelAttributes(
Assert.Equal(expectedInstanceName, activity.GetTagValue(SemanticConventions.AttributeDbMsSqlInstanceName));
Assert.Equal(expectedPort, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort));
}

// Tests for v1.21.0 Semantic Conventions for database client calls.
// see the spec https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md
// This test emits the new attributes.
// This test method can replace the other (old) test method when this library is GA.
[Theory]
[InlineData(true, "localhost", "localhost", null, null, null)]
[InlineData(true, "127.0.0.1,1433", null, "127.0.0.1", null, null)]
[InlineData(true, "127.0.0.1,1434", null, "127.0.0.1", null, "1434")]
[InlineData(true, "127.0.0.1\\instanceName, 1818", null, "127.0.0.1", "instanceName", "1818")]
[InlineData(false, "localhost", "localhost", null, null, null)]
public void SqlClientInstrumentationOptions_EnableConnectionLevelAttributes_New(
bool enableConnectionLevelAttributes,
string dataSource,
string expectedServerHostName,
string expectedServerIpAddress,
string expectedInstanceName,
string expectedPort)
{
var source = new ActivitySource("sql-client-instrumentation");
var activity = source.StartActivity("Test Sql Activity");

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> { [SemanticConventionOptInKeyName] = "http" })
.Build();

var options = new SqlClientInstrumentationOptions(configuration)
{
EnableConnectionLevelAttributes = enableConnectionLevelAttributes,
};
options.AddConnectionLevelDetailsToActivity(dataSource, activity);

if (!enableConnectionLevelAttributes)
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributePeerService));
}
else
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributeServerAddress));
}

Assert.Equal(expectedServerIpAddress, activity.GetTagValue(SemanticConventions.AttributeServerSocketAddress));
Assert.Equal(expectedInstanceName, activity.GetTagValue(SemanticConventions.AttributeDbMsSqlInstanceName));
Assert.Equal(expectedPort, activity.GetTagValue(SemanticConventions.AttributeServerPort));
}

// Tests for v1.21.0 Semantic Conventions for database client calls.
// see the spec https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md
// This test emits both the new and older attributes.
// This test method can be deleted when this library is GA.
[Theory]
[InlineData(true, "localhost", "localhost", null, null, null)]
[InlineData(true, "127.0.0.1,1433", null, "127.0.0.1", null, null)]
[InlineData(true, "127.0.0.1,1434", null, "127.0.0.1", null, "1434")]
[InlineData(true, "127.0.0.1\\instanceName, 1818", null, "127.0.0.1", "instanceName", "1818")]
[InlineData(false, "localhost", "localhost", null, null, null)]
public void SqlClientInstrumentationOptions_EnableConnectionLevelAttributes_Dupe(
bool enableConnectionLevelAttributes,
string dataSource,
string expectedServerHostName,
string expectedServerIpAddress,
string expectedInstanceName,
string expectedPort)
{
var source = new ActivitySource("sql-client-instrumentation");
var activity = source.StartActivity("Test Sql Activity");

var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string> { [SemanticConventionOptInKeyName] = "http/dup" })
.Build();

var options = new SqlClientInstrumentationOptions(configuration)
{
EnableConnectionLevelAttributes = enableConnectionLevelAttributes,
};
options.AddConnectionLevelDetailsToActivity(dataSource, activity);

// New
if (!enableConnectionLevelAttributes)
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributePeerService));
}
else
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributeServerAddress));
}

Assert.Equal(expectedServerIpAddress, activity.GetTagValue(SemanticConventions.AttributeServerSocketAddress));
Assert.Equal(expectedInstanceName, activity.GetTagValue(SemanticConventions.AttributeDbMsSqlInstanceName));
Assert.Equal(expectedPort, activity.GetTagValue(SemanticConventions.AttributeServerPort));

// Old
if (!enableConnectionLevelAttributes)
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributePeerService));
}
else
{
Assert.Equal(expectedServerHostName, activity.GetTagValue(SemanticConventions.AttributeNetPeerName));
}

Assert.Equal(expectedServerIpAddress, activity.GetTagValue(SemanticConventions.AttributeNetPeerIp));
Assert.Equal(expectedInstanceName, activity.GetTagValue(SemanticConventions.AttributeDbMsSqlInstanceName));
Assert.Equal(expectedPort, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort));
}
}
}

0 comments on commit 5b725de

Please sign in to comment.