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

Added instrumentation for netfx SqlClient. #761

Merged
36 changes: 36 additions & 0 deletions OpenTelemetry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,38 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentati
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests", "test\OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests\OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj", "{7C4026CA-6434-4762-8B77-D657EAEE1325}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F1D0972B-38CF-49C2-9F4B-4C5DE02FB71D}"
ProjectSection(SolutionItems) = preProject
.github\CODEOWNERS = .github\CODEOWNERS
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{A533C800-3DC3-4D04-90A7-0CE7A1E6BDB3}"
ProjectSection(SolutionItems) = preProject
.github\ISSUE_TEMPLATE\bug_report.md = .github\ISSUE_TEMPLATE\bug_report.md
.github\ISSUE_TEMPLATE\feature_request.md = .github\ISSUE_TEMPLATE\feature_request.md
.github\ISSUE_TEMPLATE\question.md = .github\ISSUE_TEMPLATE\question.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{E69578EB-B456-4062-A645-877CD964528B}"
ProjectSection(SolutionItems) = preProject
.github\workflows\dotnet-core-linux.yml = .github\workflows\dotnet-core-linux.yml
cijothomas marked this conversation as resolved.
Show resolved Hide resolved
.github\workflows\dotnet-core-win.yml = .github\workflows\dotnet-core-win.yml
.github\workflows\dotnet-core.yml = .github\workflows\dotnet-core.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1542297-8763-4DF4-957C-489ED771C21D}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
src\Directory.Build.targets = src\Directory.Build.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D2E73927-5966-445C-94E9-EFE6F269C8D5}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
test\Directory.Build.targets = test\Directory.Build.targets
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -238,6 +270,10 @@ Global
{47318988-CA8B-4C81-B55D-2FA11D295A49} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E}
{25C06046-C7D0-46B4-AAAC-90C50C43DE7A} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E}
{9A4E3A68-904B-4835-A3C8-F664B73098DB} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E}
{A533C800-3DC3-4D04-90A7-0CE7A1E6BDB3} = {F1D0972B-38CF-49C2-9F4B-4C5DE02FB71D}
{E69578EB-B456-4062-A645-877CD964528B} = {F1D0972B-38CF-49C2-9F4B-4C5DE02FB71D}
{C1542297-8763-4DF4-957C-489ED771C21D} = {7CB2F02E-03FA-4FFF-89A5-C51F107623FD}
{D2E73927-5966-445C-94E9-EFE6F269C8D5} = {7CB2F02E-03FA-4FFF-89A5-C51F107623FD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ public HttpInListener(string name, AspNetInstrumentationOptions options, Activit

public override void OnStartActivity(Activity activity, object payload)
{
const string EventNameSuffix = ".OnStartActivity";

var context = HttpContext.Current;
if (context == null)
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
return;
}

Expand Down Expand Up @@ -114,8 +112,6 @@ public override void OnStartActivity(Activity activity, object payload)

public override void OnStopActivity(Activity activity, object payload)
{
const string EventNameSuffix = ".OnStopActivity";

Activity activityToEnrich = activity;

if (!(this.options.TextFormat is TraceContextFormatActivity))
Expand All @@ -139,7 +135,7 @@ public override void OnStopActivity(Activity activity, object payload)
var context = HttpContext.Current;
if (context == null)
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ public HttpInListener(string name, AspNetCoreInstrumentationOptions options, Act

public override void OnStartActivity(Activity activity, object payload)
{
const string EventNameSuffix = ".OnStartActivity";
var context = this.startContextFetcher.Fetch(payload) as HttpContext;

if (context == null)
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
return;
}

Expand Down Expand Up @@ -120,13 +119,11 @@ public override void OnStartActivity(Activity activity, object payload)

public override void OnStopActivity(Activity activity, object payload)
{
const string EventNameSuffix = ".OnStopActivity";

if (activity.IsAllDataRequested)
{
if (!(this.stopContextFetcher.Fetch(payload) is HttpContext context))
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ public HttpHandlerDiagnosticListener(HttpClientInstrumentationOptions options, A

public override void OnStartActivity(Activity activity, object payload)
{
const string EventNameSuffix = ".OnStartActivity";
if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnStartActivity));
return;
}

Expand Down Expand Up @@ -141,13 +140,11 @@ public override void OnStopActivity(Activity activity, object payload)

public override void OnException(Activity activity, object payload)
{
const string EventNameSuffix = ".OnException";

if (activity.IsAllDataRequested)
{
if (!(this.stopExceptionFetcher.Fetch(payload) is Exception exc))
{
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener) + EventNameSuffix);
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnException));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public override void OnCustom(string name, Activity activity, object payload)

if (command == null)
{
InstrumentationEventSource.Log.NullPayload($"{nameof(SqlClientDiagnosticListener)}-{name}");
InstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
return;
}

Expand Down Expand Up @@ -139,7 +139,7 @@ public override void OnCustom(string name, Activity activity, object payload)
}
else
{
InstrumentationEventSource.Log.NullPayload($"{nameof(SqlClientDiagnosticListener)}-{name}");
InstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ internal class SqlEventSourceListener : EventListener
{
internal const string ActivitySourceName = "System.Data.SqlClient";
internal const string ActivityName = ActivitySourceName + ".Execute";

private const string AdoNetEventSourceName = "Microsoft-AdoNet-SystemData";
private const int BeginExecuteEventId = 1;
private const int EndExecuteEventId = 2;
internal const string AdoNetEventSourceName = "Microsoft-AdoNet-SystemData";
internal const int BeginExecuteEventId = 1;
internal const int EndExecuteEventId = 2;

private static readonly Version Version = typeof(SqlEventSourceListener).Assembly.GetName().Version;
private static readonly ActivitySource SqlClientActivitySource = new ActivitySource(ActivitySourceName, Version.ToString());
Expand All @@ -59,7 +58,7 @@ public override void Dispose()

protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource?.Name == AdoNetEventSourceName)
if (eventSource?.Name.StartsWith(AdoNetEventSourceName) == true)
{
this.eventSource = eventSource;
this.EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)1);
Expand All @@ -70,12 +69,6 @@ protected override void OnEventSourceCreated(EventSource eventSource)

protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
if (eventData?.Payload == null)
{
InstrumentationEventSource.Log.NullPayload(nameof(SqlEventSourceListener) + nameof(this.OnEventWritten));
return;
}

try
{
if (eventData.EventId == BeginExecuteEventId)
Expand Down Expand Up @@ -103,8 +96,9 @@ private void OnBeginExecute(EventWrittenEventArgs eventData)
[3] -> CommandText ([3] = CommandType == CommandType.StoredProcedure ? CommandText : string.Empty)
*/

if (eventData.Payload.Count < 4)
if ((eventData?.Payload?.Count ?? 0) < 4)
{
InstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnBeginExecute));
return;
}

Expand Down Expand Up @@ -151,8 +145,9 @@ private void OnEndExecute(EventWrittenEventArgs eventData)
[2] -> SqlExceptionNumber
*/

if (eventData.Payload.Count < 3)
if ((eventData?.Payload?.Count ?? 0) < 3)
{
InstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnEndExecute));
return;
}

Expand Down
14 changes: 10 additions & 4 deletions src/OpenTelemetry/Instrumentation/InstrumentationEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ public void UnknownErrorProcessingEvent(string handlerName, string eventName, Ex
this.UnknownErrorProcessingEvent(handlerName, eventName, ToInvariantString(ex));
}

[Event(4, Message = "Unknown error processing event '{0}' from handler '{1}', Exception: {2}", Level = EventLevel.Error)]
[Event(4, Message = "Unknown error processing event '{1}' from handler '{0}', Exception: {2}", Level = EventLevel.Error)]
public void UnknownErrorProcessingEvent(string handlerName, string eventName, string ex)
{
this.WriteEvent(4, handlerName, eventName, ex);
}

[Event(5, Message = "Payload is NULL in '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullPayload(string eventName)
[Event(5, Message = "Payload is NULL in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
public void NullPayload(string handlerName, string eventName)
{
this.WriteEvent(5, eventName);
this.WriteEvent(5, handlerName, eventName);
}

[Event(6, Message = "Request is filtered out.", Level = EventLevel.Verbose)]
Expand All @@ -100,6 +100,12 @@ public void ExceptionInitializingInstrumentation(string instrumentationType, str
this.WriteEvent(7, instrumentationType, ex);
}

[Event(8, Message = "Payload is invalid in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
public void InvalidPayload(string handlerName, string eventName)
{
this.WriteEvent(8, handlerName, eventName);
}

/// <summary>
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
/// appropriate for diagnostics tracing.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// <copyright file="SkipUnlessEnvVarFoundTheoryAttribute.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using Xunit;

namespace OpenTelemetry.Instrumentation.Dependencies.Tests
{
public class SkipUnlessEnvVarFoundTheoryAttribute : TheoryAttribute
{
public SkipUnlessEnvVarFoundTheoryAttribute(string environmentVariable)
{
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(environmentVariable, EnvironmentVariableTarget.Machine)))
{
this.Skip = $"Skipped because {environmentVariable} environment variable was not configured.";
}
}
}
}
Loading