Skip to content

Commit 7ef0c82

Browse files
authored
feat: Add Couchbase 3.x instrumentation (#3048)
1 parent f8bf4fd commit 7ef0c82

File tree

19 files changed

+970
-128
lines changed

19 files changed

+970
-128
lines changed

.github/workflows/all_solutions.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ jobs:
427427
namespace:
428428
[
429429
CosmosDB,
430-
# Couchbase, TEMPORARILY DISABLED
430+
Couchbase3,
431431
Elasticsearch,
432432
MongoDB,
433433
Msmq,
@@ -483,7 +483,7 @@ jobs:
483483

484484
- name: Install HostableWebCore Feature
485485
if: | # only install for the required namespaces
486-
matrix.namespace == 'Couchbase' || matrix.namespace == 'MongoDB' || matrix.namespace == 'MsSql' || matrix.namespace == 'Oracle'
486+
matrix.namespace == 'MongoDB' || matrix.namespace == 'MsSql' || matrix.namespace == 'Oracle'
487487
run: |
488488
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HostableWebCore
489489
shell: powershell

FullAgent.sln

+8
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Home", "src\Agent\NewRelic\
167167
{8D2B52DD-D45C-481D-92F0-28990F168820} = {8D2B52DD-D45C-481D-92F0-28990F168820}
168168
{9C20BC4E-7A9F-4518-B3E7-C1FFD6C0EC8A} = {9C20BC4E-7A9F-4518-B3E7-C1FFD6C0EC8A}
169169
{9E9E1367-E09E-45F9-9A01-7D4489FBCB23} = {9E9E1367-E09E-45F9-9A01-7D4489FBCB23}
170+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C} = {A0F784BB-D66D-47E0-80F4-66CF8DAF697C}
170171
{A4B357E3-9CEF-492C-A0E2-2397D15F1CD6} = {A4B357E3-9CEF-492C-A0E2-2397D15F1CD6}
171172
{AA683341-1FF5-4D45-A831-1BAF3C100A5C} = {AA683341-1FF5-4D45-A831-1BAF3C100A5C}
172173
{B65A0C00-100D-4F27-BAC7-6B8A9FC7619D} = {B65A0C00-100D-4F27-BAC7-6B8A9FC7619D}
@@ -228,6 +229,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI", "src\Agent\NewReli
228229
EndProject
229230
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSearch", "src\Agent\NewRelic\Agent\Extensions\Providers\Wrapper\OpenSearch\OpenSearch.csproj", "{EC27FFD7-FAE4-4882-95C4-D3FA60F738BD}"
230231
EndProject
232+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Couchbase3", "src\Agent\NewRelic\Agent\Extensions\Providers\Wrapper\Couchbase3\Couchbase3.csproj", "{A0F784BB-D66D-47E0-80F4-66CF8DAF697C}"
233+
EndProject
231234
Global
232235
GlobalSection(SolutionConfigurationPlatforms) = preSolution
233236
Debug|Any CPU = Debug|Any CPU
@@ -482,6 +485,10 @@ Global
482485
{EC27FFD7-FAE4-4882-95C4-D3FA60F738BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
483486
{EC27FFD7-FAE4-4882-95C4-D3FA60F738BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
484487
{EC27FFD7-FAE4-4882-95C4-D3FA60F738BD}.Release|Any CPU.Build.0 = Release|Any CPU
488+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
489+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C}.Debug|Any CPU.Build.0 = Debug|Any CPU
490+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C}.Release|Any CPU.ActiveCfg = Release|Any CPU
491+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C}.Release|Any CPU.Build.0 = Release|Any CPU
485492
EndGlobalSection
486493
GlobalSection(SolutionProperties) = preSolution
487494
HideSolutionNode = FALSE
@@ -555,6 +562,7 @@ Global
555562
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
556563
{1B7804AF-5D4D-4049-96EF-A4786B6B9432} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
557564
{EC27FFD7-FAE4-4882-95C4-D3FA60F738BD} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
565+
{A0F784BB-D66D-47E0-80F4-66CF8DAF697C} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
558566
EndGlobalSection
559567
GlobalSection(ExtensibilityGlobals) = postSolution
560568
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35

build/ArtifactBuilder/CoreAgentComponents.cs

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ protected override void CreateAgentComponents()
3939
{
4040
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNetCore.dll",
4141
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.CosmosDb.dll",
42+
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase3.dll",
4243
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Elasticsearch.dll",
4344
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpClient.dll",
4445
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Log4NetLogging.dll",
@@ -68,6 +69,7 @@ protected override void CreateAgentComponents()
6869
{
6970
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNetCore.Instrumentation.xml",
7071
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml",
72+
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml",
7173
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Elasticsearch.Instrumentation.xml",
7274
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpClient.Instrumentation.xml",
7375
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Log4NetLogging.Instrumentation.xml",

build/ArtifactBuilder/FrameworkAgentComponents.cs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ protected override void CreateAgentComponents()
3333
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNet.dll",
3434
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.CosmosDb.dll",
3535
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase.dll",
36+
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase3.dll",
3637
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Elasticsearch.dll",
3738
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpClient.dll",
3839
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpWebRequest.dll",
@@ -77,6 +78,7 @@ protected override void CreateAgentComponents()
7778
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.AspNetCore.Instrumentation.xml",
7879
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml",
7980
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase.Instrumentation.xml",
81+
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml",
8082
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.Elasticsearch.Instrumentation.xml",
8183
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpClient.Instrumentation.xml",
8284
$@"{SourceHomeBuilderPath}\extensions\NewRelic.Providers.Wrapper.HttpWebRequest.Instrumentation.xml",

src/Agent/MsiInstaller/Installer/Product.wxs

+12
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ SPDX-License-Identifier: Apache-2.0
360360
<Component Id="CouchbaseWrapperComponent" Guid="{21A0A03D-4799-4D8B-B6DB-553DD66C7020}">
361361
<File Id="CouchbaseWrapperFile" Name="NewRelic.Providers.Wrapper.Couchbase.dll" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Couchbase.dll" />
362362
</Component>
363+
<Component Id="Couchbase3WrapperComponent" Guid="{5C26ECDA-11E8-46FE-93BA-006694940A78}">
364+
<File Id="Couchbase3WrapperFile" Name="NewRelic.Providers.Wrapper.Couchbase3.dll" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Couchbase3.dll" />
365+
</Component>
363366
<Component Id="CosmosDbWrapperComponent" Guid="{C72D656C-B55D-4690-9BD7-9343096D4553}">
364367
<File Id="CosmosDbWrapperFile" Name="NewRelic.Providers.Wrapper.CosmosDb.dll" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.CosmosDb.dll" />
365368
</Component>
@@ -445,6 +448,9 @@ SPDX-License-Identifier: Apache-2.0
445448
<Component Id="CoreCosmosDbWrapperComponent" Guid="{3855755F-2A69-43EC-AE31-8D778E4B41E2}">
446449
<File Id="CoreCosmosDbWrapperFile" Name="NewRelic.Providers.Wrapper.CosmosDb.dll" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.CosmosDb.dll" />
447450
</Component>
451+
<Component Id="CoreCouchbase3WrapperComponent" Guid="{B16DD3A3-49C2-4DCE-888E-EA6957145EA0}">
452+
<File Id="CoreCouchbase3WrapperFile" Name="NewRelic.Providers.Wrapper.Couchbase3.dll" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.Couchbase3.dll" />
453+
</Component>
448454
<Component Id="CoreLog4NetLoggingWrapperComponent" Guid="{882392E9-9403-41EC-9321-9C6E53781744}">
449455
<File Id="CoreLog4NetLoggingWrapperFile" Name="NewRelic.Providers.Wrapper.Log4NetLogging.dll" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.Log4NetLogging.dll" />
450456
</Component>
@@ -572,6 +578,9 @@ SPDX-License-Identifier: Apache-2.0
572578
<Component Id="CouchbaseInstrumentationComponent" Guid="{03FA7D3A-3368-45B1-92B8-19DA97A659B8}">
573579
<File Id="CouchbaseInstrumentationFile" Name="NewRelic.Providers.Wrapper.Couchbase.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Couchbase.Instrumentation.xml" />
574580
</Component>
581+
<Component Id="Couchbase3InstrumentationComponent" Guid="{3D23BC6A-9FB2-4192-ADAF-886B3A8EBD4C}">
582+
<File Id="Couchbase3InstrumentationFile" Name="NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml" />
583+
</Component>
575584
<Component Id="CosmosDbInstrumentationComponent" Guid="{56DEAF3E-5F51-4C47-82E5-1C2D0FF4E7DD}">
576585
<File Id="CosmosDbInstrumentationFile" Name="NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)\extensions\NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml" />
577586
</Component>
@@ -650,6 +659,9 @@ SPDX-License-Identifier: Apache-2.0
650659
<Component Id="CoreCosmosDbInstrumentationComponent" Guid="{1B6D4139-9217-4A03-94D0-D6E3AFFE0A8E}">
651660
<File Id="CoreCosmosDbInstrumentationFile" Name="NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.CosmosDb.Instrumentation.xml" />
652661
</Component>
662+
<Component Id="CoreCouchbase3InstrumentationComponent" Guid="{B4200037-3CB1-444C-B3D7-D4D06542E22C}">
663+
<File Id="CoreCouchbase3InstrumentationFile" Name="NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.Couchbase3.Instrumentation.xml" />
664+
</Component>
653665
<Component Id="CoreLog4NetLoggingInstrumentationComponent" Guid="{A40554DF-870C-477C-8910-1113A221820C}">
654666
<File Id="CoreLog4NetLoggingInstrumentationFile" Name="NewRelic.Providers.Wrapper.Log4NetLogging.Instrumentation.xml" KeyPath="yes" Source="$(var.HomeFolderPath)_coreclr\extensions\NewRelic.Providers.Wrapper.Log4NetLogging.Instrumentation.xml" />
655667
</Component>

src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/Couchbase/Instrumentation.xml

+1-14
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,7 @@ SPDX-License-Identifier: Apache-2.0
77
<instrumentation>
88

99
<tracerFactory>
10-
<match assemblyName="Couchbase" className="Couchbase.CouchbaseClient">
11-
<exactMethodMatcher methodName="ExecuteRemove" parameters="System.String,Couchbase.Operations.PersistTo,Couchbase.Operations.ReplicateTo" />
12-
<exactMethodMatcher methodName="Get" parameters="Couchbase.IView" />
13-
<exactMethodMatcher methodName="PerformConcatenate"/>
14-
<exactMethodMatcher methodName="PerformMutate"/>
15-
<exactMethodMatcher methodName="PerformRemove"/>
16-
<exactMethodMatcher methodName="PerformStore" />
17-
<exactMethodMatcher methodName="PerformTryGet" />
18-
<exactMethodMatcher methodName="PerformTryGetAndTouch"/>
19-
<exactMethodMatcher methodName="PerformTryGetWithLock"/>
20-
<exactMethodMatcher methodName="Touch" />
21-
<exactMethodMatcher methodName="Unlock"/>
22-
</match>
23-
<match assemblyName="Couchbase.NetClient" className="Couchbase.CouchbaseBucket">
10+
<match assemblyName="Couchbase.NetClient" className="Couchbase.CouchbaseBucket" maxVersion="3.0.0.0">
2411
<exactMethodMatcher methodName="Append"/>
2512
<exactMethodMatcher methodName="AppendAsync"/>
2613
<exactMethodMatcher methodName="Decrement" parameters="System.String,System.UInt64,System.UInt64,System.UInt32" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net462;netstandard2.0</TargetFrameworks>
5+
<AssemblyName>NewRelic.Providers.Wrapper.Couchbase3</AssemblyName>
6+
<RootNamespace>NewRelic.Providers.Wrapper.Couchbase3</RootNamespace>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Content Include="Instrumentation.xml">
11+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
12+
</Content>
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\..\NewRelic.Agent.Extensions\NewRelic.Agent.Extensions.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using System;
5+
using System.Collections;
6+
using System.Linq;
7+
using NewRelic.Agent.Extensions.Providers.Wrapper;
8+
using NewRelic.Reflection;
9+
using NewRelic.Agent.Extensions.Parsing;
10+
using NewRelic.Agent.Api;
11+
using System.Threading.Tasks;
12+
13+
namespace NewRelic.Providers.Wrapper.Couchbase3;
14+
15+
public class Couchbase3CollectionWrapper: IWrapper
16+
{
17+
private Func<object, string> _getMethodInfo;
18+
public Func<object, string> GetMethodInfo => _getMethodInfo ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("Couchbase.NetClient", "Couchbase.KeyValue.CouchbaseCollection", "Name");
19+
20+
public bool IsTransactionRequired => true;
21+
22+
public CanWrapResponse CanWrap(InstrumentedMethodInfo methodInfo)
23+
{
24+
return new CanWrapResponse(methodInfo.RequestedWrapperName.Equals(nameof(Couchbase3CollectionWrapper)));
25+
}
26+
27+
public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction)
28+
{
29+
var isAsync = instrumentedMethodCall.InstrumentedMethodInfo.Method.MethodName != "GetAllReplicasAsync"; // this is the only non-async method in ICouchbaseCollection
30+
if (isAsync)
31+
transaction.AttachToAsync(); // all methods are async
32+
33+
var operation = instrumentedMethodCall.MethodCall.Method.MethodName;
34+
35+
var model = GetMethodInfo.Invoke(instrumentedMethodCall.MethodCall.InvocationTarget);
36+
37+
var segment = transaction.StartDatastoreSegment(
38+
instrumentedMethodCall.MethodCall,
39+
new ParsedSqlStatement(DatastoreVendor.Couchbase, model, operation));
40+
41+
return isAsync ? Delegates.GetAsyncDelegateFor<Task>(agent, segment) : Delegates.GetDelegateFor(segment);
42+
}
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using System;
5+
using System.Collections;
6+
using NewRelic.Agent.Extensions.Providers.Wrapper;
7+
using NewRelic.Reflection;
8+
using NewRelic.Agent.Extensions.Parsing;
9+
using NewRelic.Agent.Api;
10+
using System.Threading.Tasks;
11+
12+
namespace NewRelic.Providers.Wrapper.Couchbase3;
13+
14+
public class Couchbase3QueryWrapper : IWrapper
15+
{
16+
private static Func<object, string> _getMethodInfo;
17+
private static Func<object, string> GetMethodInfo => _getMethodInfo ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("Couchbase.NetClient", "Couchbase.KeyValue.Scope", "Name");
18+
19+
private static Func<object, object> _getBucket;
20+
private static Func<object, object> GetBucket => _getBucket ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("Couchbase.NetClient", "Couchbase.KeyValue.Scope", "Bucket");
21+
22+
private static Func<object, string> _getName;
23+
private static Func<object, string> GetName => _getName ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("Couchbase.NetClient", "Couchbase.Core.BucketBase", "Name");
24+
25+
public bool IsTransactionRequired => true;
26+
27+
public CanWrapResponse CanWrap(InstrumentedMethodInfo methodInfo)
28+
{
29+
return new CanWrapResponse(methodInfo.RequestedWrapperName.Equals(nameof(Couchbase3QueryWrapper)));
30+
}
31+
32+
public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction)
33+
{
34+
transaction.AttachToAsync(); // all methods are async
35+
36+
var operation = instrumentedMethodCall.MethodCall.Method.MethodName;
37+
string model = GetBucketName(instrumentedMethodCall.MethodCall.InvocationTarget);
38+
39+
string commandText = operation.StartsWith("Search") ? null : instrumentedMethodCall.MethodCall.MethodArguments[0] as string;
40+
41+
var segment = transaction.StartDatastoreSegment(
42+
instrumentedMethodCall.MethodCall,
43+
new ParsedSqlStatement(DatastoreVendor.Couchbase, model, operation),
44+
null,
45+
commandText);
46+
47+
return Delegates.GetDelegateFor(segment);
48+
}
49+
50+
private string GetBucketName(object owner)
51+
{
52+
var bucket = GetBucket(owner);
53+
return GetName(bucket);
54+
}
55+
56+
}

0 commit comments

Comments
 (0)