From e534a751dc0f7ca66cb98c71a8a8f1749470aa95 Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Tue, 27 Jul 2021 16:27:09 -0500 Subject: [PATCH 1/7] Add SetCommandKey and Enrich options to the Redis instrumentation --- .../.publicApi/net461/PublicAPI.Unshipped.txt | 6 +- .../netstandard2.0/PublicAPI.Unshipped.txt | 6 +- .../RedisProfilerEntryToActivityConverter.cs | 59 ++++++++++++++-- ....Instrumentation.StackExchangeRedis.csproj | 3 +- .../StackExchangeRedisCallsInstrumentation.cs | 4 +- ...xchangeRedisCallsInstrumentationOptions.cs | 13 ++++ ...isProfilerEntryToActivityConverterTests.cs | 16 ++--- ...kExchangeRedisCallsInstrumentationTests.cs | 68 +++++++++++++++++-- 8 files changed, 151 insertions(+), 24 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt index f3c586af488..f6438371d02 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt @@ -1,6 +1,10 @@ OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.get -> System.Action +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.get -> System.TimeSpan OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.set -> void +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.get -> bool +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.StackExchangeRedisCallsInstrumentationOptions() -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index f3c586af488..f6438371d02 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,6 +1,10 @@ OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.get -> System.Action +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.get -> System.TimeSpan OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.set -> void +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.get -> bool +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.StackExchangeRedisCallsInstrumentationOptions() -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions -static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder \ No newline at end of file +static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs index b5df1db85a6..54ae958f9e1 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs @@ -13,9 +13,11 @@ // See the License for the specific language governing permissions and // limitations under the License. // +using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; +using Fasterflect; using OpenTelemetry.Trace; using StackExchange.Redis.Profiling; @@ -23,7 +25,38 @@ namespace OpenTelemetry.Instrumentation.StackExchangeRedis.Implementation { internal static class RedisProfilerEntryToActivityConverter { - public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfiledCommand command) + private static readonly Lazy> CommandAndKeyGetter = new Lazy>(() => + { + var redisAssembly = typeof(IProfiledCommand).Assembly; + Type profiledCommandType = redisAssembly.GetType("StackExchange.Redis.Profiling.ProfiledCommand"); + Type messageType = redisAssembly.GetType("StackExchange.Redis.Message"); + + var messageDelegate = profiledCommandType.DelegateForGetFieldValue("Message", Flags.NonPublic | Flags.Instance); + var commandAndKeyDelegate = messageType.DelegateForGetPropertyValue("CommandAndKey"); + + if (messageDelegate == null || commandAndKeyDelegate == null) + { + return new Func(source => null); + } + + return new Func(source => + { + if (source == null) + { + return null; + } + + var message = messageDelegate(source); + if (message == null) + { + return null; + } + + return commandAndKeyDelegate(message) as string; + }); + }); + + public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfiledCommand command, StackExchangeRedisCallsInstrumentationOptions options) { var name = command.Command; // Example: SET; if (string.IsNullOrEmpty(name)) @@ -43,6 +76,8 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi return null; } + activity.SetEndTime(command.CommandCreated + command.ElapsedTime); + if (activity.IsAllDataRequested == true) { // see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/database.md @@ -62,7 +97,21 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi activity.SetTag(StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName, command.Flags.ToString()); - if (command.Command != null) + if (options.SetCommandKey) + { + var commandAndKey = CommandAndKeyGetter.Value.Invoke(command); + + if (!string.IsNullOrEmpty(commandAndKey)) + { + activity.SetTag(SemanticConventions.AttributeDbStatement, commandAndKey); + } + else if (command.Command != null) + { + // Example: "db.statement": SET; + activity.SetTag(SemanticConventions.AttributeDbStatement, command.Command); + } + } + else if (command.Command != null) { // Example: "db.statement": SET; activity.SetTag(SemanticConventions.AttributeDbStatement, command.Command); @@ -100,7 +149,7 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi activity.AddEvent(new ActivityEvent("Sent", send)); activity.AddEvent(new ActivityEvent("ResponseReceived", response)); - activity.SetEndTime(command.CommandCreated + command.ElapsedTime); + options.Enrich?.Invoke(activity, command); } activity.Stop(); @@ -108,11 +157,11 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi return activity; } - public static void DrainSession(Activity parentActivity, IEnumerable sessionCommands) + public static void DrainSession(Activity parentActivity, IEnumerable sessionCommands, StackExchangeRedisCallsInstrumentationOptions options) { foreach (var command in sessionCommands) { - ProfilerCommandToActivity(parentActivity, command); + ProfilerCommandToActivity(parentActivity, command, options); } } } diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj index b447cbc7eba..78b6bb62f4f 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;net461 StackExchange.Redis instrumentation for OpenTelemetry .NET @@ -12,6 +12,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentation.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentation.cs index b54cac1988a..5a85e3d416a 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentation.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentation.cs @@ -120,7 +120,7 @@ public void Dispose() internal void Flush() { - RedisProfilerEntryToActivityConverter.DrainSession(null, this.defaultSession.FinishProfiling()); + RedisProfilerEntryToActivityConverter.DrainSession(null, this.defaultSession.FinishProfiling(), this.options); foreach (var entry in this.Cache) { @@ -132,7 +132,7 @@ internal void Flush() } ProfilingSession session = entry.Value.Session; - RedisProfilerEntryToActivityConverter.DrainSession(parent, session.FinishProfiling()); + RedisProfilerEntryToActivityConverter.DrainSession(parent, session.FinishProfiling(), this.options); this.Cache.TryRemove((entry.Key.TraceId, entry.Key.SpanId), out _); } } diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs index d414d838ccb..eba57beaa8a 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs @@ -15,7 +15,10 @@ // using System; +using System.Data; using System.Diagnostics; +using OpenTelemetry.Trace; +using StackExchange.Redis.Profiling; namespace OpenTelemetry.Instrumentation.StackExchangeRedis { @@ -28,5 +31,15 @@ public class StackExchangeRedisCallsInstrumentationOptions /// Gets or sets the maximum time that should elapse between flushing the internal buffer of Redis profiling sessions and creating objects. Default value: 00:00:10. /// public TimeSpan FlushInterval { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// Gets or sets a value indicating whether or not the should add the command key to the tag. Default value: False. + /// + public bool SetCommandKey { get; set; } + + /// + /// Gets or sets. + /// + public Action Enrich { get; set; } } } diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToActivityConverterTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToActivityConverterTests.cs index 9a67dcb6da0..a385124addb 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToActivityConverterTests.cs +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/Implementation/RedisProfilerEntryToActivityConverterTests.cs @@ -61,7 +61,7 @@ public void ProfilerCommandToActivity_UsesCommandAsName() profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); profiledCommand.Setup(m => m.Command).Returns("SET"); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.Equal("SET", result.DisplayName); } @@ -74,7 +74,7 @@ public void ProfilerCommandToActivity_UsesTimestampAsStartTime() var profiledCommand = new Mock(); profiledCommand.Setup(m => m.CommandCreated).Returns(now.DateTime); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.Equal(now, result.StartTimeUtc); } @@ -86,7 +86,7 @@ public void ProfilerCommandToActivity_SetsDbTypeAttributeAsRedis() var profiledCommand = new Mock(); profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(SemanticConventions.AttributeDbSystem)); Assert.Equal("redis", result.GetTagValue(SemanticConventions.AttributeDbSystem)); @@ -100,7 +100,7 @@ public void ProfilerCommandToActivity_UsesCommandAsDbStatementAttribute() profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); profiledCommand.Setup(m => m.Command).Returns("SET"); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(SemanticConventions.AttributeDbStatement)); Assert.Equal("SET", result.GetTagValue(SemanticConventions.AttributeDbStatement)); @@ -116,7 +116,7 @@ public void ProfilerCommandToActivity_UsesFlagsForFlagsAttribute() CommandFlags.NoRedirect; profiledCommand.Setup(m => m.Flags).Returns(expectedFlags); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName)); Assert.Equal("PreferMaster, FireAndForget, NoRedirect", result.GetTagValue(StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName)); @@ -134,7 +134,7 @@ public void ProfilerCommandToActivity_UsesIpEndPointAsEndPoint() profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); profiledCommand.Setup(m => m.EndPoint).Returns(ipLocalEndPoint); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(SemanticConventions.AttributeNetPeerIp)); Assert.Equal($"{address}.0.0.0", result.GetTagValue(SemanticConventions.AttributeNetPeerIp)); @@ -152,7 +152,7 @@ public void ProfilerCommandToActivity_UsesDnsEndPointAsEndPoint() profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); profiledCommand.Setup(m => m.EndPoint).Returns(dnsEndPoint); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(SemanticConventions.AttributeNetPeerName)); Assert.Equal(dnsEndPoint.Host, result.GetTagValue(SemanticConventions.AttributeNetPeerName)); @@ -170,7 +170,7 @@ public void ProfilerCommandToActivity_UsesOtherEndPointAsEndPoint() profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow); profiledCommand.Setup(m => m.EndPoint).Returns(unixEndPoint); - var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object); + var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object, new StackExchangeRedisCallsInstrumentationOptions()); Assert.NotNull(result.GetTagValue(SemanticConventions.AttributePeerService)); Assert.Equal(unixEndPoint.ToString(), result.GetTagValue(SemanticConventions.AttributePeerService)); diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs index c99a7091144..177ea73ea1c 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs @@ -41,6 +41,48 @@ To use Docker... private const string RedisEndPointEnvVarName = "OTEL_REDISENDPOINT"; private static readonly string RedisEndPoint = SkipUnlessEnvVarFoundTheoryAttribute.GetEnvironmentVariable(RedisEndPointEnvVarName); + [Trait("CategoryName", "RedisIntegrationTests")] + [SkipUnlessEnvVarFoundTheory(RedisEndPointEnvVarName)] + [InlineData("value1")] + public void SuccessfulCommandTestWithKey(string value) + { + var connectionOptions = new ConfigurationOptions + { + AbortOnConnectFail = true, + }; + connectionOptions.EndPoints.Add(RedisEndPoint); + + using var connection = ConnectionMultiplexer.Connect(connectionOptions); + + var activityProcessor = new Mock>(); + var sampler = new TestSampler(); + using (Sdk.CreateTracerProviderBuilder() + .AddProcessor(activityProcessor.Object) + .SetSampler(sampler) + .AddRedisInstrumentation(connection, c => c.SetCommandKey = true) + .Build()) + { + var db = connection.GetDatabase(); + + bool set = db.StringSet("key1", value, TimeSpan.FromSeconds(60)); + + Assert.True(set); + + var redisValue = db.StringGet("key1"); + + Assert.True(redisValue.HasValue); + Assert.Equal(value, redisValue.ToString()); + } + + // Disposing SDK should flush the Redis profiling session immediately. + + Assert.Equal(7, activityProcessor.Invocations.Count); + + VerifyActivityData((Activity)activityProcessor.Invocations[1].Arguments[0], true, connection.GetEndPoints()[0], true); + VerifyActivityData((Activity)activityProcessor.Invocations[3].Arguments[0], false, connection.GetEndPoints()[0], true); + VerifySamplingParameters(sampler.LatestSamplingParameters); + } + [Trait("CategoryName", "RedisIntegrationTests")] [SkipUnlessEnvVarFoundTheory(RedisEndPointEnvVarName)] [InlineData("value1")] @@ -59,7 +101,7 @@ public void SuccessfulCommandTest(string value) using (Sdk.CreateTracerProviderBuilder() .AddProcessor(activityProcessor.Object) .SetSampler(sampler) - .AddRedisInstrumentation(connection) + .AddRedisInstrumentation(connection, c => c.SetCommandKey = false) .Build()) { var db = connection.GetDatabase(); @@ -78,8 +120,8 @@ public void SuccessfulCommandTest(string value) Assert.Equal(7, activityProcessor.Invocations.Count); - VerifyActivityData((Activity)activityProcessor.Invocations[1].Arguments[0], true, connection.GetEndPoints()[0]); - VerifyActivityData((Activity)activityProcessor.Invocations[3].Arguments[0], false, connection.GetEndPoints()[0]); + VerifyActivityData((Activity)activityProcessor.Invocations[1].Arguments[0], true, connection.GetEndPoints()[0], false); + VerifyActivityData((Activity)activityProcessor.Invocations[3].Arguments[0], false, connection.GetEndPoints()[0], false); VerifySamplingParameters(sampler.LatestSamplingParameters); } @@ -255,17 +297,31 @@ public void StackExchangeRedis_DependencyInjection_Failure() Assert.Throws(() => serviceProvider.GetRequiredService()); } - private static void VerifyActivityData(Activity activity, bool isSet, EndPoint endPoint) + private static void VerifyActivityData(Activity activity, bool isSet, EndPoint endPoint, bool setCommandKey = false) { if (isSet) { Assert.Equal("SETEX", activity.DisplayName); - Assert.Equal("SETEX", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + if (setCommandKey) + { + Assert.Equal("SETEX key1", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + } + else + { + Assert.Equal("SETEX", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + } } else { Assert.Equal("GET", activity.DisplayName); - Assert.Equal("GET", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + if (setCommandKey) + { + Assert.Equal("GET key1", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + } + else + { + Assert.Equal("GET", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); + } } Assert.Equal(Status.Unset, activity.GetStatus()); From 2f9bb74ef887ef2040bef74994395138e15756f2 Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Thu, 5 Aug 2021 22:07:03 -0500 Subject: [PATCH 2/7] Change option to SetVerboseDatabaseStatements add script to DbStatement tag value --- .../RedisProfilerEntryToActivityConverter.cs | 67 +++++++++++++++---- ....Instrumentation.StackExchangeRedis.csproj | 4 +- ...xchangeRedisCallsInstrumentationOptions.cs | 4 +- ...kExchangeRedisCallsInstrumentationTests.cs | 24 +++++-- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs index 54ae958f9e1..4c7cf250c1e 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs @@ -17,7 +17,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net; -using Fasterflect; +using System.Reflection; +using System.Reflection.Emit; using OpenTelemetry.Trace; using StackExchange.Redis.Profiling; @@ -25,34 +26,47 @@ namespace OpenTelemetry.Instrumentation.StackExchangeRedis.Implementation { internal static class RedisProfilerEntryToActivityConverter { - private static readonly Lazy> CommandAndKeyGetter = new Lazy>(() => + private static readonly Lazy> MessageDataGetter = new Lazy>(() => { var redisAssembly = typeof(IProfiledCommand).Assembly; Type profiledCommandType = redisAssembly.GetType("StackExchange.Redis.Profiling.ProfiledCommand"); Type messageType = redisAssembly.GetType("StackExchange.Redis.Message"); + Type scriptMessageType = redisAssembly.GetType("StackExchange.Redis.RedisDatabase+ScriptEvalMessage"); - var messageDelegate = profiledCommandType.DelegateForGetFieldValue("Message", Flags.NonPublic | Flags.Instance); - var commandAndKeyDelegate = messageType.DelegateForGetPropertyValue("CommandAndKey"); + var messageDelegate = CreateFieldGetter(profiledCommandType, "Message", BindingFlags.NonPublic | BindingFlags.Instance); + var scriptDelegate = CreateFieldGetter(scriptMessageType, "script", BindingFlags.NonPublic | BindingFlags.Instance); + var commandAndKeyFetcher = new PropertyFetcher("CommandAndKey"); - if (messageDelegate == null || commandAndKeyDelegate == null) + if (messageDelegate == null) { - return new Func(source => null); + return new Func(source => (null, null)); } - return new Func(source => + return new Func(source => { if (source == null) { - return null; + return (null, null); } var message = messageDelegate(source); if (message == null) { - return null; + return (null, null); } - return commandAndKeyDelegate(message) as string; + string script = null; + if (message.GetType() == scriptMessageType) + { + script = scriptDelegate.Invoke(message); + } + + if (commandAndKeyFetcher.TryFetch(message, out var value)) + { + return (value, script); + } + + return (null, script); }); }); @@ -97,11 +111,15 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi activity.SetTag(StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName, command.Flags.ToString()); - if (options.SetCommandKey) + if (options.SetVerboseDatabaseStatements) { - var commandAndKey = CommandAndKeyGetter.Value.Invoke(command); + var (commandAndKey, script) = MessageDataGetter.Value.Invoke(command); - if (!string.IsNullOrEmpty(commandAndKey)) + if (!string.IsNullOrEmpty(commandAndKey) && !string.IsNullOrEmpty(script)) + { + activity.SetTag(SemanticConventions.AttributeDbStatement, commandAndKey + " " + script); + } + else if (!string.IsNullOrEmpty(commandAndKey)) { activity.SetTag(SemanticConventions.AttributeDbStatement, commandAndKey); } @@ -164,5 +182,28 @@ public static void DrainSession(Activity parentActivity, IEnumerable + /// Creates getter for a field defined in private or internal type + /// repesented with classType variable. + /// + private static Func CreateFieldGetter(Type classType, string fieldName, BindingFlags flags) + { + FieldInfo field = classType.GetField(fieldName, flags); + if (field != null) + { + string methodName = classType.FullName + ".get_" + field.Name; + DynamicMethod getterMethod = new DynamicMethod(methodName, typeof(TField), new[] { typeof(object) }, true); + ILGenerator generator = getterMethod.GetILGenerator(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Castclass, classType); + generator.Emit(OpCodes.Ldfld, field); + generator.Emit(OpCodes.Ret); + + return (Func)getterMethod.CreateDelegate(typeof(Func)); + } + + return null; + } } } diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj index 78b6bb62f4f..9890827d021 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/OpenTelemetry.Instrumentation.StackExchangeRedis.csproj @@ -1,8 +1,9 @@ - + netstandard2.0;net461 StackExchange.Redis instrumentation for OpenTelemetry .NET $(PackageTags);distributed-tracing;Redis;StackExchange.Redis + true true @@ -12,7 +13,6 @@ - diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs index eba57beaa8a..265d56036a3 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs @@ -33,9 +33,9 @@ public class StackExchangeRedisCallsInstrumentationOptions public TimeSpan FlushInterval { get; set; } = TimeSpan.FromSeconds(10); /// - /// Gets or sets a value indicating whether or not the should add the command key to the tag. Default value: False. + /// Gets or sets a value indicating whether or not the should use reflection to get more detailed tag values. Default value: False. /// - public bool SetCommandKey { get; set; } + public bool SetVerboseDatabaseStatements { get; set; } /// /// Gets or sets. diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs index 177ea73ea1c..585678dab21 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs @@ -53,22 +53,29 @@ public void SuccessfulCommandTestWithKey(string value) connectionOptions.EndPoints.Add(RedisEndPoint); using var connection = ConnectionMultiplexer.Connect(connectionOptions); + var db = connection.GetDatabase(); + db.KeyDelete("key1"); var activityProcessor = new Mock>(); var sampler = new TestSampler(); using (Sdk.CreateTracerProviderBuilder() .AddProcessor(activityProcessor.Object) .SetSampler(sampler) - .AddRedisInstrumentation(connection, c => c.SetCommandKey = true) + .AddRedisInstrumentation(connection, c => c.SetVerboseDatabaseStatements = true) .Build()) { - var db = connection.GetDatabase(); + var prepared = LuaScript.Prepare("redis.call('set', @key, @value)"); + db.ScriptEvaluate(prepared, new { key = (RedisKey)"mykey", value = 123 }); + + var redisValue = db.StringGet("key1"); + + Assert.False(redisValue.HasValue); bool set = db.StringSet("key1", value, TimeSpan.FromSeconds(60)); Assert.True(set); - var redisValue = db.StringGet("key1"); + redisValue = db.StringGet("key1"); Assert.True(redisValue.HasValue); Assert.Equal(value, redisValue.ToString()); @@ -76,10 +83,15 @@ public void SuccessfulCommandTestWithKey(string value) // Disposing SDK should flush the Redis profiling session immediately. - Assert.Equal(7, activityProcessor.Invocations.Count); + Assert.Equal(11, activityProcessor.Invocations.Count); + + var scriptActivity = (Activity)activityProcessor.Invocations[1].Arguments[0]; + Assert.Equal("EVAL", scriptActivity.DisplayName); + Assert.Equal("EVAL redis.call('set', ARGV[1], ARGV[2])", scriptActivity.GetTagValue(SemanticConventions.AttributeDbStatement)); - VerifyActivityData((Activity)activityProcessor.Invocations[1].Arguments[0], true, connection.GetEndPoints()[0], true); VerifyActivityData((Activity)activityProcessor.Invocations[3].Arguments[0], false, connection.GetEndPoints()[0], true); + VerifyActivityData((Activity)activityProcessor.Invocations[5].Arguments[0], true, connection.GetEndPoints()[0], true); + VerifyActivityData((Activity)activityProcessor.Invocations[7].Arguments[0], false, connection.GetEndPoints()[0], true); VerifySamplingParameters(sampler.LatestSamplingParameters); } @@ -101,7 +113,7 @@ public void SuccessfulCommandTest(string value) using (Sdk.CreateTracerProviderBuilder() .AddProcessor(activityProcessor.Object) .SetSampler(sampler) - .AddRedisInstrumentation(connection, c => c.SetCommandKey = false) + .AddRedisInstrumentation(connection, c => c.SetVerboseDatabaseStatements = false) .Build()) { var db = connection.GetDatabase(); From 837f4a5db6c2125fbe41bd24ba9fcab958008045 Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Fri, 6 Aug 2021 13:37:00 -0500 Subject: [PATCH 3/7] Fix public API --- .../.publicApi/net461/PublicAPI.Unshipped.txt | 4 ++-- .../.publicApi/netstandard2.0/PublicAPI.Unshipped.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt index f6438371d02..ebca0c81e02 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/net461/PublicAPI.Unshipped.txt @@ -3,8 +3,8 @@ OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrume OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.get -> System.TimeSpan OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.set -> void -OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.get -> bool -OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.set -> void +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetVerboseDatabaseStatements.get -> bool +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetVerboseDatabaseStatements.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.StackExchangeRedisCallsInstrumentationOptions() -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index f6438371d02..ebca0c81e02 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -3,8 +3,8 @@ OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrume OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.Enrich.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.get -> System.TimeSpan OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.FlushInterval.set -> void -OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.get -> bool -OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetCommandKey.set -> void +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetVerboseDatabaseStatements.get -> bool +OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.SetVerboseDatabaseStatements.set -> void OpenTelemetry.Instrumentation.StackExchangeRedis.StackExchangeRedisCallsInstrumentationOptions.StackExchangeRedisCallsInstrumentationOptions() -> void OpenTelemetry.Trace.TracerProviderBuilderExtensions static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddRedisInstrumentation(this OpenTelemetry.Trace.TracerProviderBuilder builder, StackExchange.Redis.IConnectionMultiplexer connection = null, System.Action configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder From df89893764b72707fa52bcbce623701dcefe213e Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Mon, 9 Aug 2021 21:17:25 -0500 Subject: [PATCH 4/7] Updating README and CHANGELOG for Redis instrumentation changes --- .../CHANGELOG.md | 2 + .../README.md | 39 ++++++++++++++- ...xchangeRedisCallsInstrumentationOptions.cs | 6 ++- ...kExchangeRedisCallsInstrumentationTests.cs | 49 +++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md index bbced768f45..b44222903cd 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Adds SetVerboseDatabaseStatements option to allow setting more detailed database statement tag values. +* Adds Enrich option to allow enriching activities from the source profiled command objects. * Removes upper constraint for Microsoft.Extensions.Options dependency. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md index cdf212b32a9..9e5788796ac 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md @@ -67,7 +67,7 @@ This instrumentation can be configured to change the default behavior by using ### FlushInterval -StackExchange.Redis has its own internal profiler. OpenTelmetry converts each +StackExchange.Redis has its own internal profiler. OpenTelemetry converts each profiled command from the internal profiler to an Activity for collection. By default, this conversion process flushes profiled commands on a 10 second interval. The `FlushInterval` option can be used to adjust this internval. @@ -83,6 +83,43 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() .Build(); ``` +### SetVerboseDatabaseStatements + +StackExchange.Redis by default does not give detailed database statements like +what key or script was used during an operation. The `SetVerboseDatabaseStatements` +option can be used to enable gathering this more detailed information. + +The following example shows how to use `SetVerboseDatabaseStatements`. + +```csharp +using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddRedisInstrumentation( + connection, + options => options.SetVerboseDatabaseStatements = true) + .AddConsoleExporter() + .Build(); +``` + +## Enrich + +This option allows one to enrich the activity with additional information from the +raw `IProfiledCommand` object. The `Enrich` action is called only when +`activity.IsAllDataRequested` is `true`. It contains the activity itself (which can +be enriched), and the source profiled command object. + +The following code snippet shows how to add additional tags using `Enrich`. + +```csharp +using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddRedisInstrumentation(opt => opt.Enrich = (activity, command) => + { + if (command.ElapsedTime < TimeSpan.FromMilliseconds(100)) + { + activity.AddTag("is_fast", true); + } + }) + .Build(); +``` ## References * [OpenTelemetry Project](https://opentelemetry.io/) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs index 265d56036a3..735bc172984 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/StackExchangeRedisCallsInstrumentationOptions.cs @@ -38,8 +38,12 @@ public class StackExchangeRedisCallsInstrumentationOptions public bool SetVerboseDatabaseStatements { get; set; } /// - /// Gets or sets. + /// Gets or sets an action to enrich an Activity. /// + /// + /// : the activity being enriched. + /// : the profiled redis command from which additional information can be extracted to enrich the activity. + /// public Action Enrich { get; set; } } } diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs index 585678dab21..46a29aa7b67 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs @@ -158,6 +158,55 @@ public async void ProfilerSessionUsesTheSameDefault() Assert.Equal(second, third); } + [Trait("CategoryName", "RedisIntegrationTests")] + [SkipUnlessEnvVarFoundTheory(RedisEndPointEnvVarName)] + [InlineData("value1")] + public void CanEnrichActivityFromCommand(string value) + { + var connectionOptions = new ConfigurationOptions + { + AbortOnConnectFail = true, + }; + connectionOptions.EndPoints.Add(RedisEndPoint); + + using var connection = ConnectionMultiplexer.Connect(connectionOptions); + + var activityProcessor = new Mock>(); + var sampler = new TestSampler(); + using (Sdk.CreateTracerProviderBuilder() + .AddProcessor(activityProcessor.Object) + .SetSampler(sampler) + .AddRedisInstrumentation(connection, c => c.Enrich = (activity, command) => + { + if (command.ElapsedTime < TimeSpan.FromMilliseconds(100)) + { + activity.AddTag("is_fast", true); + } + }) + .Build()) + { + var db = connection.GetDatabase(); + + bool set = db.StringSet("key1", value, TimeSpan.FromSeconds(60)); + + Assert.True(set); + + var redisValue = db.StringGet("key1"); + + Assert.True(redisValue.HasValue); + Assert.Equal(value, redisValue.ToString()); + } + + // Disposing SDK should flush the Redis profiling session immediately. + + Assert.Equal(7, activityProcessor.Invocations.Count); + + var setActivity = (Activity)activityProcessor.Invocations[1].Arguments[0]; + Assert.Equal(true, setActivity.GetTagValue("is_fast")); + var getActivity = (Activity)activityProcessor.Invocations[3].Arguments[0]; + Assert.Equal(true, getActivity.GetTagValue("is_fast")); + } + [Fact] public void CheckCacheIsFlushedProperly() { From 961bb6ba6d2b4c4ab499838d1e452a9d20d810ba Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Mon, 9 Aug 2021 21:23:49 -0500 Subject: [PATCH 5/7] Fix markdown lint issues --- .../CHANGELOG.md | 6 ++++-- .../README.md | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md index b44222903cd..fb149110925 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md @@ -2,8 +2,10 @@ ## Unreleased -* Adds SetVerboseDatabaseStatements option to allow setting more detailed database statement tag values. -* Adds Enrich option to allow enriching activities from the source profiled command objects. +* Adds SetVerboseDatabaseStatements option to allow setting more detailed database + statement tag values. +* Adds Enrich option to allow enriching activities from the source profiled command + objects. * Removes upper constraint for Microsoft.Extensions.Options dependency. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179)) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md index 9e5788796ac..3b595c40c85 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md @@ -70,7 +70,7 @@ This instrumentation can be configured to change the default behavior by using StackExchange.Redis has its own internal profiler. OpenTelemetry converts each profiled command from the internal profiler to an Activity for collection. By default, this conversion process flushes profiled commands on a 10 second -interval. The `FlushInterval` option can be used to adjust this internval. +interval. The `FlushInterval` option can be used to adjust this internal. The following example shows how to use `FlushInterval`. @@ -120,6 +120,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() }) .Build(); ``` + ## References * [OpenTelemetry Project](https://opentelemetry.io/) From e5c1f45181f346066e039b385382fddc3abec5e9 Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Mon, 9 Aug 2021 21:38:53 -0500 Subject: [PATCH 6/7] Update src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md Co-authored-by: Cijo Thomas --- src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md index 3b595c40c85..cc79a704ed4 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md @@ -70,7 +70,7 @@ This instrumentation can be configured to change the default behavior by using StackExchange.Redis has its own internal profiler. OpenTelemetry converts each profiled command from the internal profiler to an Activity for collection. By default, this conversion process flushes profiled commands on a 10 second -interval. The `FlushInterval` option can be used to adjust this internal. +interval. The `FlushInterval` option can be used to adjust this interval. The following example shows how to use `FlushInterval`. From 852f0b859ebdd542eaa23b3e765e30a9167ab63c Mon Sep 17 00:00:00 2001 From: "Eric J. Smith" Date: Mon, 9 Aug 2021 21:39:05 -0500 Subject: [PATCH 7/7] Update src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md Co-authored-by: Cijo Thomas --- src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md index cc79a704ed4..5c0dd925211 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/README.md @@ -115,7 +115,7 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder() { if (command.ElapsedTime < TimeSpan.FromMilliseconds(100)) { - activity.AddTag("is_fast", true); + activity.SetTag("is_fast", true); } }) .Build();