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

StackExchange.Redis integration #130

Merged
merged 6 commits into from
Sep 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions Datadog.Trace.sln
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace.ClrProfiler.I
{BC7B3216-9C37-4570-8A4A-5D716AB98E9C} = {BC7B3216-9C37-4570-8A4A-5D716AB98E9C}
{C0C8D381-D6B9-4C76-9428-F40F2FA93A9A} = {C0C8D381-D6B9-4C76-9428-F40F2FA93A9A}
{086FF8A0-9CEE-470A-9751-78B0F1340649} = {086FF8A0-9CEE-470A-9751-78B0F1340649}
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A} = {F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.SqlServer", "samples\Samples.SqlServer\Samples.SqlServer.csproj", "{086FF8A0-9CEE-470A-9751-78B0F1340649}"
ProjectSection(ProjectDependencies) = postProject
{C0C8D381-D6B9-4C76-9428-F40F2FA93A9A} = {C0C8D381-D6B9-4C76-9428-F40F2FA93A9A}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.RedisCore", "samples\Samples.RedisCore\Samples.RedisCore.csproj", "{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -364,6 +367,18 @@ Global
{086FF8A0-9CEE-470A-9751-78B0F1340649}.Release|x64.Build.0 = Release|x64
{086FF8A0-9CEE-470A-9751-78B0F1340649}.Release|x86.ActiveCfg = Release|x86
{086FF8A0-9CEE-470A-9751-78B0F1340649}.Release|x86.Build.0 = Release|x86
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|x64.ActiveCfg = Debug|x64
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|x64.Build.0 = Debug|x64
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|x86.ActiveCfg = Debug|x86
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Debug|x86.Build.0 = Debug|x86
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|Any CPU.Build.0 = Release|Any CPU
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|x64.ActiveCfg = Release|x64
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|x64.Build.0 = Release|x64
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|x86.ActiveCfg = Release|x86
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -390,6 +405,7 @@ Global
{BC7B3216-9C37-4570-8A4A-5D716AB98E9C} = {AA6F5582-3B71-49AC-AA39-8F7815AC46BE}
{0D546118-B70A-44D0-B675-39EDB99FCEEE} = {8CEC2042-F11C-49F5-A674-2355793B600A}
{086FF8A0-9CEE-470A-9751-78B0F1340649} = {AA6F5582-3B71-49AC-AA39-8F7815AC46BE}
{F5B27CC4-1DF6-4ECD-A4FD-8200152F9A5A} = {AA6F5582-3B71-49AC-AA39-8F7815AC46BE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
Expand Down
20 changes: 20 additions & 0 deletions ci/install-redis.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"

$tmp = [System.IO.Path]::GetTempPath()
$installerUrl = "https://github.com/MicrosoftArchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.msi"
$installerPath = Join-Path $tmp "install-redis.msi"
$installerLog = Join-Path $tmp 'install-redis.log'

if (Test-Path "C:\Program Files\Redis\redis-server.exe") {
Write-Output "redis is already installed"
Exit 0;
}

if (-not (Test-Path $installerPath)) {
Write-Output "downloading redis to $installerPath"
(New-Object Net.WebClient).DownloadFile($installerUrl, $installerPath)
}

Write-Output "installing redis"
Start-Process "msiexec.exe" -ArgumentList "/i",$installerPath,"/qn","/norestart","/L",$installerLog -Wait -NoNewWindow
Get-Content $installerLog
2 changes: 1 addition & 1 deletion devenv.bat
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ SET CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
SET CORECLR_PROFILER_PATH=%~dp0\src\Datadog.Trace.ClrProfiler.Native\bin\%profiler_configuration%\%profiler_platform%\Datadog.Trace.ClrProfiler.Native.dll

rem Limit profiling to these processes only
SET DD_PROFILER_PROCESSES=w3wp.exe;iisexpress.exe;Samples.AspNetCoreMvc2.exe;dotnet.exe;Samples.ConsoleFramework.exe;Samples.ConsoleCore.exe;Samples.SqlServer.exe
SET DD_PROFILER_PROCESSES=w3wp.exe;iisexpress.exe;Samples.AspNetCoreMvc2.exe;dotnet.exe;Samples.ConsoleFramework.exe;Samples.ConsoleCore.exe;Samples.SqlServer.exe;Samples.RedisCore.exe

rem Set location of integration definitions
SET DD_INTEGRATIONS=%~dp0\integrations.json;%~dp0\test-integrations.json
Expand Down
39 changes: 38 additions & 1 deletion integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
{
"name": "SqlServer",
"method_replacements": [
{
{
"caller": {
"assembly": "System.Data",
"type": "System.Data.SqlClient.SqlCommand"
Expand Down Expand Up @@ -131,5 +131,42 @@
}
}
]
},
{
"name": "StackExchangeRedis",
"method_replacements": [
{
"caller": {
"assembly": "StackExchange.Redis"
},
"target": {
"assembly": "StackExchange.Redis",
"type": "StackExchange.Redis.ConnectionMultiplexer",
"method": "ExecuteSyncImpl"
},
"wrapper": {
"assembly": "Datadog.Trace.ClrProfiler.Managed, Version=0.2.2.0, Culture=neutral, PublicKeyToken=def86d061d0d2eeb",
"type": "Datadog.Trace.ClrProfiler.Integrations.StackExchangeRedis",
"method": "ExecuteSyncImpl",
"signature": "00 04 1C 1C 1C 1C 1C"
Copy link
Member

@lucaspimentel lucaspimentel Sep 14, 2018

Choose a reason for hiding this comment

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

don't you need an array of ints here?
never mind, saw the changes loading the json

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added support for a hex string. Made it easier to understand since ildasm shows everything in hex and the header defines them that way too.

}
},
{
"caller": {
"assembly": "StackExchange.Redis"
},
"target": {
"assembly": "StackExchange.Redis",
"type": "StackExchange.Redis.ConnectionMultiplexer",
"method": "ExecuteAsyncImpl"
},
"wrapper": {
"assembly": "Datadog.Trace.ClrProfiler.Managed, Version=0.2.2.0, Culture=neutral, PublicKeyToken=def86d061d0d2eeb",
"type": "Datadog.Trace.ClrProfiler.Integrations.StackExchangeRedis",
"method": "ExecuteAsyncImpl",
"signature": "00 05 1C 1C 1C 1C 1C 1C"
}
}
]
}
]
19 changes: 19 additions & 0 deletions samples/Samples.RedisCore/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using StackExchange.Redis;

namespace Samples.RedisCore
{
class Program
{
static void Main(string[] args)
{
var redis = ConnectionMultiplexer.Connect("localhost");
for (var i = 0; i < 100; i++)
{
redis.GetDatabase().StringSet($"KEY-{i}", $"VALUE {i}");
var value = redis.GetDatabase().StringGetAsync($"KEY-{i}").Result;
Console.WriteLine(value.ToString());
}
}
}
}
7 changes: 7 additions & 0 deletions samples/Samples.RedisCore/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"profiles": {
"Samples.RedisCore": {
"commandName": "Project"
}
}
}
26 changes: 26 additions & 0 deletions samples/Samples.RedisCore/Samples.RedisCore.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net461;net47;netcoreapp2.0</TargetFrameworks>
<Platforms>AnyCPU;x64;x86</Platforms>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64</RuntimeIdentifiers>
</PropertyGroup>

<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' != 'netcoreapp2.0'">
<RuntimeIdentifier>win-$(Platform)</RuntimeIdentifier>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.0.505" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Datadog.Trace.ClrProfiler.Managed\Datadog.Trace.ClrProfiler.Managed.csproj" />
</ItemGroup>

</Project>
46 changes: 38 additions & 8 deletions src/Datadog.Trace.ClrProfiler.Managed/DynamicMethodBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ public static class DynamicMethodBuilder
/// <typeparam name="TDelegate">A <see cref="Delegate"/> type with the signature of the method to call.</typeparam>
/// <param name="type">The <see cref="Type"/> that contains the method.</param>
/// <param name="methodName">The name of the method.</param>
/// <param name="isStatic"><c>true</c> if the method is static, <c>false</c> otherwise.</param>
/// <param name="methodParameterTypes">optional types for the method parameters</param>
/// <param name="methodGenericArguments">optional generic type arguments for a generic method</param>
/// <returns>A <see cref="Delegate"/> that can be used to execute the dynamic method.</returns>
public static TDelegate CreateMethodCallDelegate<TDelegate>(
Type type,
string methodName,
bool isStatic)
Type[] methodParameterTypes = null,
Type[] methodGenericArguments = null)
where TDelegate : Delegate
{
Type delegateType = typeof(TDelegate);
Expand All @@ -48,20 +50,48 @@ public static class DynamicMethodBuilder
}

// find any method that matches by name and parameter types
MethodInfo methodInfo = type.GetMethod(
methodName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
null,
isStatic ? parameterTypes : parameterTypes.Skip(1).ToArray(),
null);
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
methods = methods.Where(m => m.Name == methodName).ToArray();
if (methodParameterTypes != null)
{
methods = methods.Where(m =>
{
var ps = m.GetParameters();
if (ps.Length != methodParameterTypes.Length)
{
return false;
}

for (var i = 0; i < ps.Length; i++)
{
var t1 = ps[i].ParameterType;
var t2 = methodParameterTypes[i];

// generics can be tricky to compare for type equality
// so we will just check the namespace and name
if (t1.Namespace != t2.Namespace || t1.Name != t2.Name)
{
return false;
}
}

return true;
}).ToArray();
}

MethodInfo methodInfo = methods.FirstOrDefault();
if (methodInfo == null)
{
// method not found
// TODO: logging
return null;
}

if (methodGenericArguments != null)
{
methodInfo = methodInfo.MakeGenericMethod(methodGenericArguments);
}

var dynamicMethod = new DynamicMethod(methodName, returnType, parameterTypes, type);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ public AspNetCoreMvc2Integration(object actionDescriptorObj, object httpContextO

_beforeAction = DynamicMethodBuilder.CreateMethodCallDelegate<Action<object, object, object, object>>(
type,
"BeforeAction",
isStatic: true);
"BeforeAction");
}
}
catch
Expand Down Expand Up @@ -141,8 +140,7 @@ public AspNetCoreMvc2Integration(object actionDescriptorObj, object httpContextO

_afterAction = DynamicMethodBuilder.CreateMethodCallDelegate<Action<object, object, object, object>>(
type,
"AfterAction",
isStatic: true);
"AfterAction");
}
}
catch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static object ExecuteReaderWithMethod(dynamic @this, int behavior, string
_executeReaderWithMethod = DynamicMethodBuilder.CreateMethodCallDelegate<Func<object, CommandBehavior, string, object>>(
command.GetType(),
"ExecuteReader",
isStatic: false);
new Type[] { typeof(CommandBehavior), typeof(string) });
}

using (var scope = CreateScope(command))
Expand Down Expand Up @@ -61,7 +61,7 @@ public static object ExecuteReader(dynamic @this, int behavior)
_executeReader = DynamicMethodBuilder.CreateMethodCallDelegate<Func<object, CommandBehavior, object>>(
command.GetType(),
"ExecuteReader",
isStatic: false);
new Type[] { typeof(CommandBehavior) });
}

using (var scope = CreateScope(command))
Expand Down
Loading