1818import uuid
1919
2020from newrelic .api .function_trace import FunctionTrace
21- from newrelic .api .time_trace import get_trace_linking_metadata
21+ from newrelic .api .time_trace import current_trace , get_trace_linking_metadata
2222from newrelic .api .transaction import current_transaction
2323from newrelic .common .object_wrapper import wrap_function_wrapper
2424from newrelic .common .package_version_utils import get_package_version
2525from newrelic .common .signature import bind_args
2626from newrelic .core .config import global_settings
27+ from newrelic .core .context import context_wrapper
2728
2829_logger = logging .getLogger (__name__ )
2930LANGCHAIN_VERSION = get_package_version ("langchain" )
3031EXCEPTION_HANDLING_FAILURE_LOG_MESSAGE = "Exception occurred in langchain instrumentation: While reporting an exception in langchain, another exception occurred. Report this issue to New Relic Support.\n %s"
3132RECORD_EVENTS_FAILURE_LOG_MESSAGE = "Exception occurred in langchain instrumentation: Failed to record LLM events. Report this issue to New Relic Support.\n %s"
32-
3333VECTORSTORE_CLASSES = {
34+ "langchain_community.vectorstores.aerospike" : "Aerospike" ,
3435 "langchain_community.vectorstores.alibabacloud_opensearch" : "AlibabaCloudOpenSearch" ,
3536 "langchain_community.vectorstores.analyticdb" : "AnalyticDB" ,
3637 "langchain_community.vectorstores.annoy" : "Annoy" ,
3738 "langchain_community.vectorstores.apache_doris" : "ApacheDoris" ,
39+ "langchain_community.vectorstores.aperturedb" : "ApertureDB" ,
3840 "langchain_community.vectorstores.astradb" : "AstraDB" ,
3941 "langchain_community.vectorstores.atlas" : "AtlasDB" ,
4042 "langchain_community.vectorstores.awadb" : "AwaDB" ,
43+ "langchain_community.vectorstores.azure_cosmos_db_no_sql" : "AzureCosmosDBNoSqlVectorSearch" ,
4144 "langchain_community.vectorstores.azure_cosmos_db" : "AzureCosmosDBVectorSearch" ,
4245 "langchain_community.vectorstores.azuresearch" : "AzureSearch" ,
4346 "langchain_community.vectorstores.baiduvectordb" : "BaiduVectorDB" ,
7174 "langchain_community.vectorstores.lancedb" : "LanceDB" ,
7275 "langchain_community.vectorstores.lantern" : "Lantern" ,
7376 "langchain_community.vectorstores.llm_rails" : "LLMRails" ,
77+ "langchain_community.vectorstores.manticore_search" : "ManticoreSearch" ,
7478 "langchain_community.vectorstores.marqo" : "Marqo" ,
7579 "langchain_community.vectorstores.matching_engine" : "MatchingEngine" ,
7680 "langchain_community.vectorstores.meilisearch" : "Meilisearch" ,
7983 "langchain_community.vectorstores.mongodb_atlas" : "MongoDBAtlasVectorSearch" ,
8084 "langchain_community.vectorstores.myscale" : "MyScale" ,
8185 "langchain_community.vectorstores.neo4j_vector" : "Neo4jVector" ,
82- "langchain_community.vectorstores.thirdai_neuraldb" : " NeuralDBVectorStore" ,
86+ "langchain_community.vectorstores.thirdai_neuraldb" : [ "NeuralDBClientVectorStore" , " NeuralDBVectorStore"] ,
8387 "langchain_community.vectorstores.nucliadb" : "NucliaDB" ,
8488 "langchain_community.vectorstores.oraclevs" : "OracleVS" ,
8589 "langchain_community.vectorstores.opensearch_vector_search" : "OpenSearchVectorSearch" ,
118122 "langchain_community.vectorstores.weaviate" : "Weaviate" ,
119123 "langchain_community.vectorstores.xata" : "XataVectorStore" ,
120124 "langchain_community.vectorstores.yellowbrick" : "Yellowbrick" ,
125+ "langchain_community.vectorstores.zep_cloud" : "ZepCloudVectorStore" ,
121126 "langchain_community.vectorstores.zep" : "ZepVectorStore" ,
122127 "langchain_community.vectorstores.docarray.hnsw" : "DocArrayHnswSearch" ,
123128 "langchain_community.vectorstores.docarray.in_memory" : "DocArrayInMemorySearch" ,
124129}
125130
126131
127- def _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata ):
132+ def bind_submit (func , * args , ** kwargs ):
133+ return {"func" : func , "args" : args , "kwargs" : kwargs }
134+
135+
136+ def wrap_ContextThreadPoolExecutor_submit (wrapped , instance , args , kwargs ):
137+ trace = current_trace ()
138+ if not trace :
139+ return wrapped (* args , ** kwargs )
140+
141+ # Use hardened function signature bind so we have safety net catchall of args and kwargs.
142+ bound_args = bind_submit (* args , ** kwargs )
143+ bound_args ["func" ] = context_wrapper (bound_args ["func" ], trace = trace , strict = True )
144+ return wrapped (bound_args ["func" ], * bound_args ["args" ], ** bound_args ["kwargs" ])
145+
146+
147+ def _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata , wrapped ):
128148 settings = transaction .settings if transaction .settings is not None else global_settings ()
129149 span_id = linking_metadata .get ("span.id" )
130150 trace_id = linking_metadata .get ("trace.id" )
131- request_query , request_k = bind_similarity_search (* args , ** kwargs )
151+ bound_args = bind_args (wrapped , args , kwargs )
152+ request_query = bound_args ["query" ]
153+ request_k = bound_args ["k" ]
132154 llm_metadata_dict = _get_llm_metadata (transaction )
133155 vectorstore_error_dict = {
134156 "request.k" : request_k ,
@@ -169,21 +191,17 @@ async def wrap_asimilarity_search(wrapped, instance, args, kwargs):
169191 except Exception as exc :
170192 ft .notice_error (attributes = {"vector_store_id" : search_id })
171193 ft .__exit__ (* sys .exc_info ())
172- _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata )
194+ _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata , wrapped )
173195 raise
174196 ft .__exit__ (None , None , None )
175197
176198 if not response :
177199 return response
178200
179- _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response )
201+ _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response , wrapped )
180202 return response
181203
182204
183- def bind_similarity_search (query , k , * args , ** kwargs ):
184- return query , k
185-
186-
187205def wrap_similarity_search (wrapped , instance , args , kwargs ):
188206 transaction = current_transaction ()
189207 if not transaction :
@@ -206,20 +224,22 @@ def wrap_similarity_search(wrapped, instance, args, kwargs):
206224 except Exception as exc :
207225 ft .notice_error (attributes = {"vector_store_id" : search_id })
208226 ft .__exit__ (* sys .exc_info ())
209- _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata )
227+ _create_error_vectorstore_events (transaction , search_id , args , kwargs , linking_metadata , wrapped )
210228 raise
211229 ft .__exit__ (None , None , None )
212230
213231 if not response :
214232 return response
215233
216- _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response )
234+ _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response , wrapped )
217235 return response
218236
219237
220- def _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response ):
238+ def _record_vector_search_success (transaction , linking_metadata , ft , search_id , args , kwargs , response , wrapped ):
221239 settings = transaction .settings if transaction .settings is not None else global_settings ()
222- request_query , request_k = bind_similarity_search (* args , ** kwargs )
240+ bound_args = bind_args (wrapped , args , kwargs )
241+ request_query = bound_args ["query" ]
242+ request_k = bound_args ["k" ]
223243 duration = ft .duration * 1000
224244 response_number_of_documents = len (response )
225245 llm_metadata_dict = _get_llm_metadata (transaction )
@@ -855,12 +875,20 @@ def instrument_langchain_chains_base(module):
855875
856876
857877def instrument_langchain_vectorstore_similarity_search (module ):
858- vector_class = VECTORSTORE_CLASSES .get (module .__name__ )
859-
860- if vector_class and hasattr (getattr (module , vector_class , "" ), "similarity_search" ):
861- wrap_function_wrapper (module , "%s.similarity_search" % vector_class , wrap_similarity_search )
862- if vector_class and hasattr (getattr (module , vector_class , "" ), "asimilarity_search" ):
863- wrap_function_wrapper (module , "%s.asimilarity_search" % vector_class , wrap_asimilarity_search )
878+ def _instrument_class (module , vector_class ):
879+ if hasattr (getattr (module , vector_class , "" ), "similarity_search" ):
880+ wrap_function_wrapper (module , "%s.similarity_search" % vector_class , wrap_similarity_search )
881+ if hasattr (getattr (module , vector_class , "" ), "asimilarity_search" ):
882+ wrap_function_wrapper (module , "%s.asimilarity_search" % vector_class , wrap_asimilarity_search )
883+
884+ vector_classes = VECTORSTORE_CLASSES .get (module .__name__ )
885+ if vector_classes is None :
886+ return
887+ if isinstance (vector_classes , list ):
888+ for vector_class in vector_classes :
889+ _instrument_class (module , vector_class )
890+ else :
891+ _instrument_class (module , vector_classes )
864892
865893
866894def instrument_langchain_core_tools (module ):
@@ -879,3 +907,8 @@ def instrument_langchain_callbacks_manager(module):
879907 wrap_function_wrapper (module , "CallbackManager.on_chain_start" , wrap_on_chain_start )
880908 if hasattr (getattr (module , "AsyncCallbackManager" ), "on_chain_start" ):
881909 wrap_function_wrapper (module , "AsyncCallbackManager.on_chain_start" , wrap_async_on_chain_start )
910+
911+
912+ def instrument_langchain_core_runnables_config (module ):
913+ if hasattr (module , "ContextThreadPoolExecutor" ):
914+ wrap_function_wrapper (module , "ContextThreadPoolExecutor.submit" , wrap_ContextThreadPoolExecutor_submit )
0 commit comments