Skip to content
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

update HttpSemanticConventions for Instrumentation.SqlClient #4644

Merged
merged 23 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
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/opentelemetry-specification/blob/v1.21.0/specification/trace/semantic_conventions/database.md).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're lacking clarity here, https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/CHANGELOG.md#v1210-2023-05-09 clearly called out that semconv got moved to a new repo so it doesn't seem to be part of v1.21.0 release, yet we're referring to 1.21.0 database link, what does that mean and what exactly are we trying to follow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was already discussed. #4538 (comment)

The semantic-conventions repo doesn't have any versioned releases for me to link to.
@utpilla asked me to link to the former repo which does have versioned tags to link to.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me change the question, which exact semantic convention version do we want to implement in this PR? (I don't think the goal to implement the link that you put here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to implement the breaking changes to the HTTP Semantic Conventions.
These changes are described in the v1.21.0 of the opentelemetry-specification.
https://github.com/open-telemetry/opentelemetry-specification/tree/v1.21.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI for all persons here.

Semantic-Conventions repo is readying their first release. The version will be v1.21.0. No ETA because they're building out the processes.
https://github.com/open-telemetry/semantic-conventions/blob/df8e53054147acf49918582bd446d0f524170071/CHANGELOG.md

Trask advised that we should link to "main" for now.

I need some time to update all the comments and links. Will need to create a new PR to correct everything that merged already.

Copy link
Member

@reyang reyang Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No ETA because they're building out the processes.

FYI - open-telemetry/semantic-conventions#190

This library can emit either old, new, or both attributes. Users can control
vishweshbankwar marked this conversation as resolved.
Show resolved Hide resolved
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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR, but why is this method in the options class instead of the listener?

We should probably move this code to the listener. That would also make us consistent with other instrumentation libraries for how we read the environment variable.

{
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/opentelemetry-specification/blob/v1.21.0/specification/trace/semantic_conventions/database.md
if (this.emitNewAttributes)
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
{
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))
vishweshbankwar marked this conversation as resolved.
Show resolved Hide resolved
{
// 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,48 @@ public void SqlClientInstrumentationOptions_EnableConnectionLevelAttributes(
Assert.Equal(expectedInstanceName, activity.GetTagValue(SemanticConventions.AttributeDbMsSqlInstanceName));
Assert.Equal(expectedPort, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort));
}

// Tests for newer HTTP v1.21.0 Semantic Conventions.
// This test method can replace the other 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" })
utpilla marked this conversation as resolved.
Show resolved Hide resolved
.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));
}
}
}