Skip to content

Commit 6d4a27d

Browse files
committed
feat: Add support for MongoDB.Driver 3.x and above.
1 parent 1f446c2 commit 6d4a27d

3 files changed

Lines changed: 193 additions & 84 deletions

File tree

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

Lines changed: 102 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ SPDX-License-Identifier: Apache-2.0
55
-->
66
<extension xmlns="urn:newrelic-extension">
77
<instrumentation>
8+
89
<tracerFactory name="MongoCollectionImplWrapper">
910
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoCollectionImpl`1">
1011
<exactMethodMatcher methodName="AggregateAsync"/>
@@ -37,86 +38,115 @@ SPDX-License-Identifier: Apache-2.0
3738
</match>
3839
</tracerFactory>
3940

40-
<tracerFactory name="AsyncCursorWrapper">
41-
<match assemblyName="MongoDB.Driver.Core" className="MongoDB.Driver.Core.Operations.AsyncCursor`1">
42-
<exactMethodMatcher methodName="GetNextBatch"/>
43-
<exactMethodMatcher methodName="GetNextBatchAsync"/>
44-
</match>
45-
</tracerFactory>
41+
<tracerFactory name="AsyncCursorWrapper">
42+
<match assemblyName="MongoDB.Driver.Core" className="MongoDB.Driver.Core.Operations.AsyncCursor`1" maxVersion="2.999.0">
43+
<exactMethodMatcher methodName="GetNextBatch"/>
44+
<exactMethodMatcher methodName="GetNextBatchAsync"/>
45+
</match>
46+
47+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.Core.Operations.AsyncCursor`1" minVersion="3.0.0">
48+
<exactMethodMatcher methodName="GetNextBatch"/>
49+
<exactMethodMatcher methodName="GetNextBatchAsync"/>
50+
</match>
51+
</tracerFactory>
4652

47-
<tracerFactory name="MongoDatabaseWrapper">
48-
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoDatabaseImpl">
49-
<exactMethodMatcher methodName="Aggregate"/>
50-
<exactMethodMatcher methodName="AggregateToCollection"/>
51-
<exactMethodMatcher methodName="CreateCollection"/>
52-
<exactMethodMatcher methodName="CreateView"/>
53-
<exactMethodMatcher methodName="DropCollection"/>
54-
<exactMethodMatcher methodName="ListCollections"/>
55-
<exactMethodMatcher methodName="ListCollectionNames"/>
56-
<exactMethodMatcher methodName="RenameCollection"/>
57-
<exactMethodMatcher methodName="RunCommand"/>
58-
<exactMethodMatcher methodName="Watch"/>
53+
<tracerFactory name="MongoDatabaseWrapper">
54+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoDatabaseImpl" maxVersion="2.999.0">
55+
<exactMethodMatcher methodName="Aggregate"/>
56+
<exactMethodMatcher methodName="AggregateToCollection"/>
57+
<exactMethodMatcher methodName="CreateCollection"/>
58+
<exactMethodMatcher methodName="CreateView"/>
59+
<exactMethodMatcher methodName="DropCollection"/>
60+
<exactMethodMatcher methodName="ListCollections"/>
61+
<exactMethodMatcher methodName="ListCollectionNames"/>
62+
<exactMethodMatcher methodName="RenameCollection"/>
63+
<exactMethodMatcher methodName="RunCommand"/>
64+
<exactMethodMatcher methodName="Watch"/>
65+
66+
<exactMethodMatcher methodName="AggregateAsync"/>
67+
<exactMethodMatcher methodName="AggregateToCollectionAsync"/>
68+
<exactMethodMatcher methodName="CreateCollectionAsync"/>
69+
<exactMethodMatcher methodName="CreateViewAsync"/>
70+
<exactMethodMatcher methodName="DropCollectionAsync"/>
71+
<exactMethodMatcher methodName="ListCollectionsAsync"/>
72+
<exactMethodMatcher methodName="ListCollectionNamesAsync"/>
73+
<exactMethodMatcher methodName="RenameCollectionAsync"/>
74+
<exactMethodMatcher methodName="RunCommandAsync"/>
75+
<exactMethodMatcher methodName="WatchAsync"/>
76+
</match>
77+
78+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoDatabase" minVersion="3.0.0">
79+
<exactMethodMatcher methodName="Aggregate"/>
80+
<exactMethodMatcher methodName="AggregateToCollection"/>
81+
<exactMethodMatcher methodName="CreateCollection"/>
82+
<exactMethodMatcher methodName="CreateView"/>
83+
<exactMethodMatcher methodName="DropCollection"/>
84+
<exactMethodMatcher methodName="ListCollections"/>
85+
<exactMethodMatcher methodName="ListCollectionNames"/>
86+
<exactMethodMatcher methodName="RenameCollection"/>
87+
<exactMethodMatcher methodName="RunCommand"/>
88+
<exactMethodMatcher methodName="Watch"/>
5989

60-
<exactMethodMatcher methodName="AggregateAsync"/>
61-
<exactMethodMatcher methodName="AggregateToCollectionAsync"/>
62-
<exactMethodMatcher methodName="CreateCollectionAsync"/>
63-
<exactMethodMatcher methodName="CreateViewAsync"/>
64-
<exactMethodMatcher methodName="DropCollectionAsync"/>
65-
<exactMethodMatcher methodName="ListCollectionsAsync"/>
66-
<exactMethodMatcher methodName="ListCollectionNamesAsync"/>
67-
<exactMethodMatcher methodName="RenameCollectionAsync"/>
68-
<exactMethodMatcher methodName="RunCommandAsync"/>
69-
<exactMethodMatcher methodName="WatchAsync"/>
70-
</match>
71-
</tracerFactory>
90+
<exactMethodMatcher methodName="AggregateAsync"/>
91+
<exactMethodMatcher methodName="AggregateToCollectionAsync"/>
92+
<exactMethodMatcher methodName="CreateCollectionAsync"/>
93+
<exactMethodMatcher methodName="CreateViewAsync"/>
94+
<exactMethodMatcher methodName="DropCollectionAsync"/>
95+
<exactMethodMatcher methodName="ListCollectionsAsync"/>
96+
<exactMethodMatcher methodName="ListCollectionNamesAsync"/>
97+
<exactMethodMatcher methodName="RenameCollectionAsync"/>
98+
<exactMethodMatcher methodName="RunCommandAsync"/>
99+
<exactMethodMatcher methodName="WatchAsync"/>
100+
</match>
101+
</tracerFactory>
72102

73-
<tracerFactory name="MongoQueryProviderImplWrapper">
74-
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.Linq.MongoQueryProviderImpl`1">
75-
<exactMethodMatcher methodName="ExecuteModel"/>
76-
<exactMethodMatcher methodName="ExecuteModelAsync"/>
77-
</match>
78-
</tracerFactory>
103+
<tracerFactory name="MongoQueryProviderImplWrapper">
104+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.Linq.MongoQueryProviderImpl`1">
105+
<exactMethodMatcher methodName="ExecuteModel"/>
106+
<exactMethodMatcher methodName="ExecuteModelAsync"/>
107+
</match>
108+
</tracerFactory>
79109

80-
<tracerFactory name="MongoIndexManagerBaseWrapper">
81-
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoIndexManagerBase`1">
82-
<exactMethodMatcher methodName="CreateOne"/>
83-
<exactMethodMatcher methodName="CreateOneAsync"/>
84-
</match>
85-
</tracerFactory>
110+
<tracerFactory name="MongoIndexManagerBaseWrapper">
111+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoIndexManagerBase`1">
112+
<exactMethodMatcher methodName="CreateOne"/>
113+
<exactMethodMatcher methodName="CreateOneAsync"/>
114+
</match>
115+
</tracerFactory>
86116

87-
<tracerFactory name="MongoIndexManagerWrapper">
88-
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoCollectionImpl`1+MongoIndexManager">
89-
<exactMethodMatcher methodName="CreateMany"/>
90-
<exactMethodMatcher methodName="DropAll"/>
91-
<exactMethodMatcher methodName="DropOne"/>
92-
<exactMethodMatcher methodName="List"/>
117+
<tracerFactory name="MongoIndexManagerWrapper">
118+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoCollectionImpl`1+MongoIndexManager">
119+
<exactMethodMatcher methodName="CreateMany"/>
120+
<exactMethodMatcher methodName="DropAll"/>
121+
<exactMethodMatcher methodName="DropOne"/>
122+
<exactMethodMatcher methodName="List"/>
93123

94-
<exactMethodMatcher methodName="CreateManyAsync"/>
95-
<exactMethodMatcher methodName="DropAllAsync"/>
96-
<exactMethodMatcher methodName="DropOneAsync"/>
97-
<exactMethodMatcher methodName="ListAsync"/>
98-
</match>
99-
</tracerFactory>
124+
<exactMethodMatcher methodName="CreateManyAsync"/>
125+
<exactMethodMatcher methodName="DropAllAsync"/>
126+
<exactMethodMatcher methodName="DropOneAsync"/>
127+
<exactMethodMatcher methodName="ListAsync"/>
128+
</match>
129+
</tracerFactory>
100130

101-
<tracerFactory name="MongoCollectionBaseWrapper">
102-
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoCollectionBase`1">
103-
<exactMethodMatcher methodName="DeleteMany"/>
104-
<exactMethodMatcher methodName="DeleteOne"/>
105-
<exactMethodMatcher methodName="InsertOne"/>
106-
<exactMethodMatcher methodName="InsertMany"/>
107-
<exactMethodMatcher methodName="ReplaceOne"/>
108-
<exactMethodMatcher methodName="UpdateMany"/>
109-
<exactMethodMatcher methodName="UpdateOne"/>
131+
<tracerFactory name="MongoCollectionBaseWrapper">
132+
<match assemblyName="MongoDB.Driver" className="MongoDB.Driver.MongoCollectionBase`1">
133+
<exactMethodMatcher methodName="DeleteMany"/>
134+
<exactMethodMatcher methodName="DeleteOne"/>
135+
<exactMethodMatcher methodName="InsertOne"/>
136+
<exactMethodMatcher methodName="InsertMany"/>
137+
<exactMethodMatcher methodName="ReplaceOne"/>
138+
<exactMethodMatcher methodName="UpdateMany"/>
139+
<exactMethodMatcher methodName="UpdateOne"/>
110140

111-
<exactMethodMatcher methodName="DeleteManyAsync"/>
112-
<exactMethodMatcher methodName="DeleteOneAsync"/>
113-
<exactMethodMatcher methodName="InsertOneAsync"/>
114-
<exactMethodMatcher methodName="InsertManyAsync"/>
115-
<exactMethodMatcher methodName="ReplaceOneAsync"/>
116-
<exactMethodMatcher methodName="UpdateManyAsync"/>
117-
<exactMethodMatcher methodName="UpdateOneAsync"/>
118-
</match>
119-
</tracerFactory>
141+
<exactMethodMatcher methodName="DeleteManyAsync"/>
142+
<exactMethodMatcher methodName="DeleteOneAsync"/>
143+
<exactMethodMatcher methodName="InsertOneAsync"/>
144+
<exactMethodMatcher methodName="InsertManyAsync"/>
145+
<exactMethodMatcher methodName="ReplaceOneAsync"/>
146+
<exactMethodMatcher methodName="UpdateManyAsync"/>
147+
<exactMethodMatcher methodName="UpdateOneAsync"/>
148+
</match>
149+
</tracerFactory>
120150

121151
</instrumentation>
122152
</extension>

src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/MongoDb26/MongoDbHelper.cs

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
using System;
55
using System.Collections;
66
using System.Collections.Concurrent;
7+
using System.ComponentModel.Design;
78
using System.Net;
9+
using NewRelic.Agent.Extensions.Helpers;
810
using NewRelic.Agent.Extensions.Parsing;
911
using NewRelic.Agent.Extensions.Providers.Wrapper;
1012
using NewRelic.Agent.Extensions.Parsing.ConnectionString;
1113
using NewRelic.Reflection;
14+
using System.Reflection;
1215

1316
namespace NewRelic.Providers.Wrapper.MongoDb26
1417
{
@@ -31,38 +34,45 @@ public static class MongoDbHelper
3134
private static Func<object, string> _getHost;
3235
private static Func<object, int> _getPort;
3336

37+
private static readonly Version _mongo3Version = Version.Parse("3.0.0.0");
38+
private static Version _version;
3439

3540
public static string GetCollectionName(object collectionNamespace)
3641
{
37-
var getter = _getCollectionName ?? (_getCollectionName = VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver.Core", "MongoDB.Driver.CollectionNamespace", "CollectionName"));
42+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(collectionNamespace.GetType().AssemblyQualifiedName));
43+
var getter = _version >= _mongo3Version ? GetCollectionNameV3(collectionNamespace) : GetCollectionNameV2(collectionNamespace);
3844
return getter(collectionNamespace);
3945
}
4046

4147
public static string GetDatabaseNameFromCollectionNamespace(object collectionNamespace)
4248
{
43-
var databaseNamespaceGetter = _getDatabaseNamespaceFromCollectionNamespace ?? (_getDatabaseNamespaceFromCollectionNamespace = VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver.Core", "MongoDB.Driver.CollectionNamespace", "DatabaseNamespace"));
49+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(collectionNamespace.GetType().AssemblyQualifiedName));
50+
var databaseNamespaceGetter = _version >= _mongo3Version ? GetDatabaseNameFromCollectionNamespaceV3(collectionNamespace) : GetDatabaseNameFromCollectionNamespaceV2(collectionNamespace);
4451
var databaseNamespace = databaseNamespaceGetter(collectionNamespace);
4552

4653
return GetDatabaseNameFromDatabaseNamespace(databaseNamespace);
4754
}
4855

4956
public static string GetDatabaseNameFromDatabase(object database)
5057
{
51-
var databaseNamespaceGetter = _getDatabaseNamespaceFromDatabase ?? (_getDatabaseNamespaceFromDatabase = VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabaseImpl", "DatabaseNamespace"));
58+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(database.GetType().AssemblyQualifiedName));
59+
var databaseNamespaceGetter = _version >= _mongo3Version ? GetDatabaseNameFromDatabaseV3(database) : GetDatabaseNameFromDatabaseV2(database);
5260
var databaseNamespace = databaseNamespaceGetter(database);
5361

5462
return GetDatabaseNameFromDatabaseNamespace(databaseNamespace);
5563
}
5664

5765
private static string GetDatabaseNameFromDatabaseNamespace(object databaseNamespace)
5866
{
59-
var databaseNameGetter = _getDatabaseName ?? (_getDatabaseName = VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver.Core", "MongoDB.Driver.DatabaseNamespace", "DatabaseName"));
67+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(databaseNamespace.GetType().AssemblyQualifiedName));
68+
var databaseNameGetter = _version >= _mongo3Version ? GetDatabaseNameFromDatabaseNamespaceV3(databaseNamespace) : GetDatabaseNameFromDatabaseNamespaceV2(databaseNamespace);
6069
return databaseNameGetter(databaseNamespace);
6170
}
6271

6372
private static EndPoint GetEndPoint(object owner)
6473
{
65-
var getter = _getEndPoint ?? (_getEndPoint = VisibilityBypasser.Instance.GeneratePropertyAccessor<EndPoint>("MongoDB.Driver.Core", "MongoDB.Driver.Core.Servers.Server", "EndPoint"));
74+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(owner.GetType().AssemblyQualifiedName));
75+
var getter = _version >= _mongo3Version ? GetEndPointV3(owner) : GetEndPointV2(owner);
6676
return getter(owner);
6777
}
6878

@@ -151,9 +161,10 @@ public static ConnectionInfo GetConnectionInfoFromDatabase(object database, stri
151161

152162
private static IList GetServersFromDatabase(object database)
153163
{
154-
var clientGetter = _getClient ?? (_getClient = VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabaseImpl", "Client"));
155-
var settingsGetter = _getSettings ?? (_getSettings = VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoClient", "Settings"));
156-
var serversGetter = _getServers ?? (_getServers = VisibilityBypasser.Instance.GenerateFieldReadAccessor<IList>("MongoDB.Driver", "MongoDB.Driver.MongoClientSettings", "_servers"));
164+
_version ??= Version.Parse(VersionHelpers.GetLibraryVersion(database.GetType().AssemblyQualifiedName));
165+
var clientGetter = _version >= _mongo3Version ? GetClientFromDatabaseV3(database) : GetClientFromDatabaseV2(database);
166+
var settingsGetter = _getSettings ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoClient", "Settings");
167+
var serversGetter = _getServers ??= VisibilityBypasser.Instance.GenerateFieldReadAccessor<IList>("MongoDB.Driver", "MongoDB.Driver.MongoClientSettings", "_servers");
157168

158169
var client = clientGetter(database);
159170
var settings = settingsGetter(client);
@@ -162,12 +173,80 @@ private static IList GetServersFromDatabase(object database)
162173

163174
private static void GetHostAndPortFromServer(object server, out string host, out int port)
164175
{
165-
var hostGetter = _getHost ?? (_getHost = VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver", "MongoDB.Driver.MongoServerAddress", "Host"));
166-
var portGetter = _getPort ?? (_getPort = VisibilityBypasser.Instance.GeneratePropertyAccessor<int>("MongoDB.Driver", "MongoDB.Driver.MongoServerAddress", "Port"));
176+
var hostGetter = _getHost ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver", "MongoDB.Driver.MongoServerAddress", "Host");
177+
var portGetter = _getPort ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<int>("MongoDB.Driver", "MongoDB.Driver.MongoServerAddress", "Port");
167178

168179
host = hostGetter(server);
169180
port = portGetter(server);
170181
}
171182

183+
184+
#region Client V2
185+
186+
private static Func<object, string> GetCollectionNameV2(object collectionNamespace)
187+
{
188+
return _getCollectionName ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver.Core", "MongoDB.Driver.CollectionNamespace", "CollectionName");
189+
}
190+
191+
private static Func<object, object> GetDatabaseNameFromCollectionNamespaceV2(object collectionNamespace)
192+
{
193+
return _getDatabaseNamespaceFromCollectionNamespace ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver.Core", "MongoDB.Driver.CollectionNamespace", "DatabaseNamespace");
194+
}
195+
196+
private static Func<object, object> GetDatabaseNameFromDatabaseV2(object database)
197+
{
198+
return _getDatabaseNamespaceFromDatabase ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabaseImpl", "DatabaseNamespace");
199+
}
200+
201+
private static Func<object, string> GetDatabaseNameFromDatabaseNamespaceV2(object databaseNamespace)
202+
{
203+
return _getDatabaseName ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver.Core", "MongoDB.Driver.DatabaseNamespace", "DatabaseName");
204+
}
205+
206+
private static Func<object, EndPoint> GetEndPointV2(object owner)
207+
{
208+
return _getEndPoint ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<EndPoint>("MongoDB.Driver.Core", "MongoDB.Driver.Core.Servers.Server", "EndPoint");
209+
}
210+
211+
private static Func<object, object> GetClientFromDatabaseV2(object database)
212+
{
213+
return _getClient ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabaseImpl", "Client");
214+
}
215+
216+
#endregion
217+
218+
#region Client V3
219+
220+
private static Func<object, string> GetCollectionNameV3(object collectionNamespace)
221+
{
222+
return _getCollectionName ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver", "MongoDB.Driver.CollectionNamespace", "CollectionName");
223+
}
224+
225+
private static Func<object, object> GetDatabaseNameFromCollectionNamespaceV3(object collectionNamespace)
226+
{
227+
return _getDatabaseNamespaceFromCollectionNamespace ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.CollectionNamespace", "DatabaseNamespace");
228+
}
229+
230+
private static Func<object, object> GetDatabaseNameFromDatabaseV3(object database)
231+
{
232+
return _getDatabaseNamespaceFromDatabase ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabase", "DatabaseNamespace");
233+
}
234+
235+
private static Func<object, string> GetDatabaseNameFromDatabaseNamespaceV3(object databaseNamespace)
236+
{
237+
return _getDatabaseName ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<string>("MongoDB.Driver", "MongoDB.Driver.DatabaseNamespace", "DatabaseName");
238+
}
239+
240+
private static Func<object, EndPoint> GetEndPointV3(object owner)
241+
{
242+
return _getEndPoint ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<EndPoint>("MongoDB.Driver", "MongoDB.Driver.Core.Servers.Server", "EndPoint");
243+
}
244+
245+
private static Func<object, object> GetClientFromDatabaseV3(object database)
246+
{
247+
return _getClient ??= VisibilityBypasser.Instance.GeneratePropertyAccessor<object>("MongoDB.Driver", "MongoDB.Driver.MongoDatabase", "Client");
248+
}
249+
250+
#endregion
172251
}
173252
}

0 commit comments

Comments
 (0)