diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/README.rst b/instrumentation-genai/opentelemetry-instrumentation-weaviate/README.rst index e69de29bb2..d455d338b1 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-weaviate/README.rst +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/README.rst @@ -0,0 +1,50 @@ +OpenTelemetry Weaviate Instrumentation +==================================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-weaviate.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-weaviate/ + +This library allows tracing vector database operations made by the +`Weaviate Python Client `_. It also captures +the duration of the operations and usage metrics. + +Installation +------------ + +If your application is already instrumented with OpenTelemetry, add this +package to your requirements. +:: + + pip install opentelemetry-instrumentation-weaviate + +Usage +----- + +.. code:: python + + from weaviate import Client + from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor + + WeaviateInstrumentor().instrument() + + client = Client("http://localhost:8080") + # Your Weaviate operations will now be traced + +Configuration +~~~~~~~~~~~~~ + +You can configure the instrumentation using environment variables: + +- ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT``: Set to ``true`` to capture query content and results (default: ``false``) + +Supported Operations +~~~~~~~~~~~~~~~~~~~~ + +This instrumentation supports tracing the following Weaviate client operations: + +# TODO: Update this to the actual operations supported by the Weaviate client + +API +--- \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/Dockerfile b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/Dockerfile new file mode 100644 index 0000000000..fe85051290 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/Dockerfile @@ -0,0 +1,12 @@ +# Use the official Ollama base image +FROM ollama/ollama:latest + +# Run ollama pull commands to download the models during the image build process +# The 'ollama serve' is needed for 'ollama pull' to work during build +# We run it in the background, pull models, then kill it using its PID. +RUN ollama serve & \ + OLLAMA_PID=$! && \ + sleep 5 && \ + ollama pull nomic-embed-text:latest && \ + ollama pull llama3.2:latest && \ + kill $OLLAMA_PID \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/docker-compose.yml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/docker-compose.yml new file mode 100644 index 0000000000..07407b21f0 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/docker-compose.yml @@ -0,0 +1,48 @@ +--- +services: + weaviate: + command: + - --host + - 0.0.0.0 + - --port + - '8080' + - --scheme + - http + image: cr.weaviate.io/semitechnologies/weaviate:1.31.2 + ports: + - 8080:8080 + - 50051:50051 + - 2112:2112 + volumes: + - weaviate_data:/var/lib/weaviate + restart: on-failure:0 + environment: + QUERY_DEFAULTS_LIMIT: 25 + AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true' + PERSISTENCE_DATA_PATH: '/var/lib/weaviate' + ENABLE_API_BASED_MODULES: 'true' + ENABLE_MODULES: 'text2vec-ollama,generative-ollama' + + DEFAULT_VECTORIZER_MODULE: 'text2vec-ollama' + TEXT2VEC_OLLAMA_API_ENDPOINT: 'http://ollama:11434' + TEXT2VEC_OLLAMA_MODEL: 'nomic-embed-text:latest' + GENERATIVE_OLLAMA_API_ENDPOINT: 'http://ollama:11434' + GENERATIVE_OLLAMA_MODEL: 'llama3.2:latest' + + CLUSTER_HOSTNAME: 'node1' + PROMETHEUS_MONITORING_ENABLED: 'true' + depends_on: + - ollama + + ollama: + build: + context: . + dockerfile: Dockerfile + image: my-ollama-with-models:latest + ports: + - "11434:11434" + restart: on-failure + +volumes: + weaviate_data: + ollama_models: \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/.env b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/.env new file mode 100644 index 0000000000..e0f260c5da --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/.env @@ -0,0 +1,4 @@ +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 +OTEL_EXPORTER_OTLP_PROTOCOL=grpc + +OTEL_SERVICE_NAME=opentelemetry-python-weaviate \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/README.rst b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/README.rst new file mode 100644 index 0000000000..4de2b5cec0 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/README.rst @@ -0,0 +1,42 @@ +OpenTelemetry Weaviate-Client Manual Instrumentation Example +====================================================== + +This is an example of how to instrument weaviate-client manually, +using `opentelemetry-instrument`. + +When :code:`example_v{3,4}.py `_ is run, it exports traces to an OTLP-compatible endpoint. +Traces include details such as the span name and other attributes. + +Note: :code:`.env <.env>`_ file configures additional environment variables: +- :code:`OTEL_LOGS_EXPORTER=otlp` to specify exporter type. +- :code:`OTEL_EXPORTER_OTLP_ENDPOINT` to specify the endpoint for exporting traces (default is http://localhost:4317). + +Setup +----- + +Anytime a bash example has {3,4}, choose which version of weaviate-client you mean to use. + +Run the docker environment contained in ../docker-compose.yml to start a Weaviate instance and ollama with built in embeddings. + +An OTLP compatible endpoint should be listening for traces http://localhost:4317. +If not, update :code:`OTEL_EXPORTER_OTLP_ENDPOINT` as well. + +Next, set up a virtual environment like this: + +:: + + python3 -m venv .venv + source .venv/bin/activate + pip install "python-dotenv[cli]" + pip install -r requirements_v{3,4}.txt + +Run +--- + +Run the example like this: + +:: + + dotenv run -- python example_v{3,4}.py + +You should see spans around article creation, retrieval, and deletion. There should be an example span on near_text search as well \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v3.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v3.py new file mode 100644 index 0000000000..18aecce0ac --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v3.py @@ -0,0 +1,292 @@ +# Tested with weaviate-client==3.26.7 +# Code is adapted from official documentation. +# V3 documentation: https://weaviate.io/developers/weaviate/client-libraries/python/python_v3 +# Some parts were also adapted from: +# https://towardsdatascience.com/getting-started-with-weaviate-python-client-e85d14f19e4f +import json +import os + +import weaviate + +# Load environment variables +from dotenv import load_dotenv + +from opentelemetry import trace +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( + OTLPSpanExporter, +) +from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ( + BatchSpanProcessor, + ConsoleSpanExporter, +) + +load_dotenv() + +CLASS_NAME = "Article" +RAW_QUERY = """ + { + Get { + Article(limit: 2) { + author + text + } + } + } + """ + +# Set up the tracer provider +tracer_provider = TracerProvider() +trace.set_tracer_provider(tracer_provider) + +# Add OTLP exporter (reads from OTEL_EXPORTER_OTLP_ENDPOINT env var) +otlp_exporter = OTLPSpanExporter( + endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"), + headers=(), +) +otlp_processor = BatchSpanProcessor(otlp_exporter) +tracer_provider.add_span_processor(otlp_processor) + +# Add console exporter to see traces in terminal as well +console_exporter = ConsoleSpanExporter() +console_processor = BatchSpanProcessor(console_exporter) +tracer_provider.add_span_processor(console_processor) + +# Now instrument Weaviate +WeaviateInstrumentor().instrument() + + +def create_schema(client): + client.schema.create_class( + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "vectorizer": "text2vec-ollama", + "moduleConfig": { + "text2vec-ollama": { + "apiEndpoint": "http://ollama:11434", + "model": "nomic-embed-text:latest", + } + }, + "properties": [ + { + "name": "author", + "dataType": ["string"], + "description": "The name of the author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + } + ) + + +def get_schema(client): + """Get the schema to test connection""" + return client.schema.get(CLASS_NAME) + + +def delete_schema(client): + client.schema.delete_class(CLASS_NAME) + + +def create_object(client): + return client.data_object.create( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + class_name=CLASS_NAME, + ) + + +def create_batch(client): + objs = [ + { + "author": "Robert", + "text": "Once upon a time, R. wrote a book...", + }, + { + "author": "Johnson", + "text": "Once upon a time, J. wrote some news...", + }, + { + "author": "Maverick", + "text": "Never again, M. will write a book...", + }, + { + "author": "Wilson", + "text": "Lost in the island, W. did not write anything...", + }, + { + "author": "Ludwig", + "text": "As king, he ruled...", + }, + ] + with client.batch as batch: + for obj in objs: + batch.add_data_object(obj, class_name=CLASS_NAME) + + +def query_get(client): + return client.query.get(class_name=CLASS_NAME, properties=["author"]).do() + + +def query_aggregate(client): + return client.query.aggregate(class_name=CLASS_NAME).with_meta_count().do() + + +def query_raw(client): + return client.query.raw(RAW_QUERY) + + +def query_near_text(client, text): + """Query using nearText to find similar articles.""" + near_text_filter = { + "concepts": ["lost while writing"], + } + + query_result = ( + client.query.get(CLASS_NAME, ["text", "author"]) + .with_additional(["id", "distance"]) + .with_near_text(near_text_filter) + .do() + ) + + return query_result + + +def validate(client, uuid=None): + return client.data_object.validate( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + uuid=uuid, + class_name=CLASS_NAME, + ) + + +def create_schemas(client): + client.schema.create( + { + "classes": [ + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "vectorizer": "text2vec-ollama", + "moduleConfig": { + "text2vec-ollama": { + "apiEndpoint": "http://ollama:11434", + "model": "nomic-embed-text:latest", + } + }, + "properties": [ + { + "name": "author", + "dataType": ["Author"], + "description": "The author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + }, + { + "class": "Author", + "description": "An author that writes an article", + "properties": [ + { + "name": "name", + "dataType": ["string"], + "description": "The name of the author", + }, + ], + }, + ] + } + ) + + +def delete_all(client): + client.schema.delete_all() + + +def example_schema_workflow(client): + delete_all(client) + + create_schema(client) + print("Created schema") + schema = get_schema(client) + print("Retrieved schema: ", json.dumps(schema, indent=2)) + result = validate(client) + print(f"Object found: {result.get('valid')}") + + uuid = create_object(client) + print("Created object of UUID: ", uuid) + client.data_object.exists(uuid, class_name=CLASS_NAME) + obj = client.data_object.get(uuid, class_name=CLASS_NAME) + print("Retrieved obj: ", json.dumps(obj, indent=2)) + result = validate(client, uuid=uuid) + print(f"Object found: {result.get('valid')}") + + create_batch(client) + result = query_get(client) + print("Query result:", json.dumps(result, indent=2)) + aggregate_result = query_aggregate(client) + print("Aggregate result:", json.dumps(aggregate_result, indent=2)) + raw_result = query_raw(client) + print("Raw result: ", json.dumps(raw_result, indent=2)) + near_text_result = query_near_text(client, "book") + print("Near text result: ", json.dumps(near_text_result, indent=2)) + + delete_schema(client) + print("Deleted schema") + + +def example_schema_workflow2(client): + delete_all(client) + create_schemas(client) + + +if __name__ == "__main__": + print("OpenTelemetry Weaviate instrumentation initialized") + + additional_headers = {} + if (key := os.getenv("COHERE_API_KEY")) is not None: + additional_headers.update({"X-Cohere-Api-Key": key}) + elif (key := os.getenv("OPENAI_API_KEY")) is not None: + additional_headers.update({"X-OpenAI-Api-Key": key}) + else: + print("Warning: No API key found for Cohere or OpenAI") + + if (cluster_name := os.getenv("WEAVIATE_CLUSTER_URL")) is not None: + auth_config = weaviate.auth.AuthApiKey( + api_key=os.environ["WEAVIATE_API_KEY"] + ) + client = weaviate.Client( + url=os.getenv("WEAVIATE_CLUSTER_URL"), + auth_client_secret=auth_config, + timeout_config=(5, 15), + additional_headers=additional_headers, + ) + else: + client = weaviate.Client( + url="http://localhost:8080", + additional_headers=additional_headers, + ) + print("Client connected") + + try: + example_schema_workflow2(client) + example_schema_workflow(client) + delete_all(client) + finally: + # Ensure all spans are exported before exiting + tracer_provider.force_flush(timeout_millis=5000) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v4.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v4.py new file mode 100644 index 0000000000..0699908385 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/example_v4.py @@ -0,0 +1,270 @@ +# Tested with weaviate-client==3.26.7 +# Code is adapted from official documentation. +# V3 documentation: https://weaviate.io/developers/weaviate/client-libraries/python/python_v3 +# Some parts were also adapted from: +# https://towardsdatascience.com/getting-started-with-weaviate-python-client-e85d14f19e4f +import os + +import weaviate +import weaviate.classes as wvc + +# Load environment variables +from dotenv import load_dotenv + +from opentelemetry import trace +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( + OTLPSpanExporter, +) +from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ( + BatchSpanProcessor, + ConsoleSpanExporter, +) + +load_dotenv() + +CLASS_NAME = "Article" +RAW_QUERY = """ + { + Get { + Article(limit: 2) { + author + text + } + } + } + """ + +# Set up the tracer provider +tracer_provider = TracerProvider() +trace.set_tracer_provider(tracer_provider) + +# Add OTLP exporter (reads from OTEL_EXPORTER_OTLP_ENDPOINT env var) +otlp_exporter = OTLPSpanExporter( + endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"), + headers=(), +) +otlp_processor = BatchSpanProcessor(otlp_exporter) +tracer_provider.add_span_processor(otlp_processor) + +# Add console exporter to see traces in terminal as well +console_exporter = ConsoleSpanExporter() +console_processor = BatchSpanProcessor(console_exporter) +tracer_provider.add_span_processor(console_processor) + +# Now instrument Weaviate +WeaviateInstrumentor().instrument() + + +def create_schema(client): + client.collections.create( + name=CLASS_NAME, + description="An Article class to store a text", + vectorizer_config=wvc.config.Configure.Vectorizer.text2vec_ollama( + api_endpoint="http://ollama:11434" + ), + generative_config=wvc.config.Configure.Generative.ollama( + api_endpoint="http://ollama:11434" + ), + properties=[ + wvc.config.Property( + name="author", + data_type=wvc.config.DataType.TEXT, + description="The name of the author", + ), + wvc.config.Property( + name="text", + data_type=wvc.config.DataType.TEXT, + description="The text content", + ), + ], + ) + + +def get_collection(client): + """Get the collection to test connection""" + return client.collections.get(CLASS_NAME) + + +def delete_collection(client): + client.collections.delete(CLASS_NAME) + + +def create_object(collection): + return collection.data.insert( + { + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + } + ) + + +def create_batch(collection): + objs = [ + { + "author": "Robert", + "text": "Once upon a time, R. wrote a book...", + }, + { + "author": "Johnson", + "text": "Once upon a time, J. wrote some news...", + }, + { + "author": "Maverick", + "text": "Never again, M. will write a book...", + }, + { + "author": "Wilson", + "text": "Lost in the island, W. did not write anything...", + }, + { + "author": "Ludwig", + "text": "As king, he ruled...", + }, + ] + with collection.batch.dynamic() as batch: + for obj in objs: + batch.add_object(properties=obj) + + +def query_get(collection): + return collection.query.fetch_objects( + return_properties=[ + "author", + ] + ) + + +def query_aggregate(collection): + return collection.aggregate.over_all(total_count=True) + + +def query_raw(client): + return client.graphql_raw_query(RAW_QUERY) + + +def query_near_text(collection, text): + """Query using nearText to find similar articles.""" + query_result = collection.query.near_text( + query=text, + limit=2, + return_metadata=weaviate.classes.query.MetadataQuery(distance=True), + ) + + return query_result + + +def validate(client, uuid=None): + return client.data_object.validate( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + uuid=uuid, + class_name=CLASS_NAME, + ) + + +def create_schemas(client): + client.collections.create_from_dict( + { + "class": "Author", + "description": "An author that writes an article", + "properties": [ + { + "name": "name", + "dataType": ["string"], + "description": "The name of the author", + }, + ], + }, + ) + client.collections.create_from_dict( + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "properties": [ + { + "name": "author", + "dataType": ["Author"], + "description": "The author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + }, + ) + + +def delete_all(client): + client.collections.delete_all() + + +def example_schema_workflow(client): + delete_all(client) + + create_schema(client) + print("Created schema") + collection = get_collection(client) + print("Retrieved collection: ", collection.name) + + uuid = create_object(collection) + print("Created object of UUID: ", uuid) + obj = collection.query.fetch_object_by_id(uuid) + print("Retrieved obj: ", obj) + + create_batch(collection) + result = query_get(collection) + print("Query result:", result) + aggregate_result = query_aggregate(collection) + print("Aggregate result:", aggregate_result) + raw_result = query_raw(client) + print("Raw result: ", raw_result) + near_text_result = query_near_text(collection, "book") + print("Near text result: ", near_text_result) + + delete_collection(client) + print("Deleted schema") + + +def example_schema_workflow2(client): + delete_all(client) + create_schemas(client) + + +if __name__ == "__main__": + print("OpenTelemetry Weaviate instrumentation initialized") + + additional_headers = {} + if (key := os.getenv("COHERE_API_KEY")) is not None: + additional_headers.update({"X-Cohere-Api-Key": key}) + elif (key := os.getenv("OPENAI_API_KEY")) is not None: + additional_headers.update({"X-OpenAI-Api-Key": key}) + else: + print("Warning: No API key found for Cohere or OpenAI") + + if (cluster_name := os.getenv("WEAVIATE_CLUSTER_URL")) is not None: + auth_config = weaviate.auth.AuthApiKey( + api_key=os.environ["WEAVIATE_API_KEY"] + ) + client = weaviate.Client( + url=os.getenv("WEAVIATE_CLUSTER_URL"), + auth_client_secret=auth_config, + timeout_config=(5, 15), + additional_headers=additional_headers, + ) + else: + client = weaviate.connect_to_local(headers=additional_headers) + print("Client connected") + + try: + example_schema_workflow2(client) + example_schema_workflow(client) + delete_all(client) + finally: + # Ensure all spans are exported before exiting + tracer_provider.force_flush(timeout_millis=5000) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v3.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v3.txt new file mode 100644 index 0000000000..8871f449da --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v3.txt @@ -0,0 +1,7 @@ +weaviate-client>=3.0.0,<4.0.0 +opentelemetry-sdk~=1.36.0 +opentelemetry-exporter-otlp-proto-grpc~=1.36.0 +opentelemetry-distro~=0.57b0 + +# Uncomment after weaviate instrumetation is released +# opentelemetry-instrumentation-weaviate~=2.0b0.dev \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v4.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v4.txt new file mode 100644 index 0000000000..217d60ad32 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/manual/requirements-v4.txt @@ -0,0 +1,7 @@ +weaviate-client>=4.0 +opentelemetry-sdk~=1.36.0 +opentelemetry-exporter-otlp-proto-grpc~=1.36.0 +opentelemetry-distro~=0.57b0 + +# Uncomment after weaviate instrumetation is released +# opentelemetry-instrumentation-weaviate~=2.0b0.dev \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/.env b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/.env new file mode 100644 index 0000000000..e0f260c5da --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/.env @@ -0,0 +1,4 @@ +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 +OTEL_EXPORTER_OTLP_PROTOCOL=grpc + +OTEL_SERVICE_NAME=opentelemetry-python-weaviate \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/README.rst b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/README.rst new file mode 100644 index 0000000000..25128b43d9 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/README.rst @@ -0,0 +1,42 @@ +OpenTelemetry Weaviate-Client Zero-Code Instrumentation Example +====================================================== + +This is an example of how to instrument weaviate-client with zero code changes, +using `opentelemetry-instrument`. + +When :code:`example_v{3,4}.py `_ is run, it exports traces to an OTLP-compatible endpoint. +Traces include details such as the span name and other attributes. + +Note: :code:`.env <.env>`_ file configures additional environment variables: +- :code:`OTEL_LOGS_EXPORTER=otlp` to specify exporter type. +- :code:`OTEL_EXPORTER_OTLP_ENDPOINT` to specify the endpoint for exporting traces (default is http://localhost:4317). + +Setup +----- + +Anytime a bash example has {3,4}, choose which version of weaviate-client you mean to use. + +Run the docker environment contained in ../docker-compose.yml to start a Weaviate instance and ollama with built in embeddings. + +An OTLP compatible endpoint should be listening for traces http://localhost:4317. +If not, update :code:`OTEL_EXPORTER_OTLP_ENDPOINT` as well. + +Next, set up a virtual environment like this: + +:: + + python3 -m venv .venv + source .venv/bin/activate + pip install "python-dotenv[cli]" + pip install -r requirements_v{3,4}.txt + +Run +--- + +Run the example like this: + +:: + + dotenv run -- opentelemetry-instrument python example_v{3,4}.py + +You should see spans around article creation, retrieval, and deletion. There should be an example span on near_text search as well diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v3.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v3.py new file mode 100644 index 0000000000..d8af7c6d7b --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v3.py @@ -0,0 +1,250 @@ +# Tested with weaviate-client==3.26.7 +# Code is adapted from official documentation. +# V3 documentation: https://weaviate.io/developers/weaviate/client-libraries/python/python_v3 +# Some parts were also adapted from: +# https://towardsdatascience.com/getting-started-with-weaviate-python-client-e85d14f19e4f +import json +import os + +import weaviate + +CLASS_NAME = "Article" +RAW_QUERY = """ + { + Get { + Article(limit: 2) { + author + text + } + } + } + """ + + +def create_schema(client): + client.schema.create_class( + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "vectorizer": "text2vec-ollama", + "moduleConfig": { + "text2vec-ollama": { + "apiEndpoint": "http://ollama:11434", + "model": "nomic-embed-text:latest", + } + }, + "properties": [ + { + "name": "author", + "dataType": ["string"], + "description": "The name of the author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + } + ) + + +def get_schema(client): + """Get the schema to test connection""" + return client.schema.get(CLASS_NAME) + + +def delete_schema(client): + client.schema.delete_class(CLASS_NAME) + + +def create_object(client): + return client.data_object.create( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + class_name=CLASS_NAME, + ) + + +def create_batch(client): + objs = [ + { + "author": "Robert", + "text": "Once upon a time, R. wrote a book...", + }, + { + "author": "Johnson", + "text": "Once upon a time, J. wrote some news...", + }, + { + "author": "Maverick", + "text": "Never again, M. will write a book...", + }, + { + "author": "Wilson", + "text": "Lost in the island, W. did not write anything...", + }, + { + "author": "Ludwig", + "text": "As king, he ruled...", + }, + ] + with client.batch as batch: + for obj in objs: + batch.add_data_object(obj, class_name=CLASS_NAME) + + +def query_get(client): + return client.query.get(class_name=CLASS_NAME, properties=["author"]).do() + + +def query_aggregate(client): + return client.query.aggregate(class_name=CLASS_NAME).with_meta_count().do() + + +def query_raw(client): + return client.query.raw(RAW_QUERY) + + +def query_near_text(client, text): + """Query using nearText to find similar articles.""" + near_text_filter = { + "concepts": ["lost while writing"], + } + + query_result = ( + client.query.get(CLASS_NAME, ["text", "author"]) + .with_additional(["id", "distance"]) + .with_near_text(near_text_filter) + .do() + ) + + return query_result + + +def validate(client, uuid=None): + return client.data_object.validate( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + uuid=uuid, + class_name=CLASS_NAME, + ) + + +def create_schemas(client): + client.schema.create( + { + "classes": [ + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "vectorizer": "text2vec-ollama", + "moduleConfig": { + "text2vec-ollama": { + "apiEndpoint": "http://ollama:11434", + "model": "nomic-embed-text:latest", + } + }, + "properties": [ + { + "name": "author", + "dataType": ["Author"], + "description": "The author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + }, + { + "class": "Author", + "description": "An author that writes an article", + "properties": [ + { + "name": "name", + "dataType": ["string"], + "description": "The name of the author", + }, + ], + }, + ] + } + ) + + +def delete_all(client): + client.schema.delete_all() + + +def example_schema_workflow(client): + delete_all(client) + + create_schema(client) + print("Created schema") + schema = get_schema(client) + print("Retrieved schema: ", json.dumps(schema, indent=2)) + result = validate(client) + print(f"Object found: {result.get('valid')}") + + uuid = create_object(client) + print("Created object of UUID: ", uuid) + client.data_object.exists(uuid, class_name=CLASS_NAME) + obj = client.data_object.get(uuid, class_name=CLASS_NAME) + print("Retrieved obj: ", json.dumps(obj, indent=2)) + result = validate(client, uuid=uuid) + print(f"Object found: {result.get('valid')}") + + create_batch(client) + result = query_get(client) + print("Query result:", json.dumps(result, indent=2)) + aggregate_result = query_aggregate(client) + print("Aggregate result:", json.dumps(aggregate_result, indent=2)) + raw_result = query_raw(client) + print("Raw result: ", json.dumps(raw_result, indent=2)) + near_text_result = query_near_text(client, "book") + print("Near text result: ", json.dumps(near_text_result, indent=2)) + + delete_schema(client) + print("Deleted schema") + + +def example_schema_workflow2(client): + delete_all(client) + create_schemas(client) + + +if __name__ == "__main__": + additional_headers = {} + if (key := os.getenv("COHERE_API_KEY")) is not None: + additional_headers.update({"X-Cohere-Api-Key": key}) + elif (key := os.getenv("OPENAI_API_KEY")) is not None: + additional_headers.update({"X-OpenAI-Api-Key": key}) + else: + print("Warning: No API key found for Cohere or OpenAI") + + if (cluster_name := os.getenv("WEAVIATE_CLUSTER_URL")) is not None: + auth_config = weaviate.auth.AuthApiKey( + api_key=os.environ["WEAVIATE_API_KEY"] + ) + client = weaviate.Client( + url=os.getenv("WEAVIATE_CLUSTER_URL"), + auth_client_secret=auth_config, + timeout_config=(5, 15), + additional_headers=additional_headers, + ) + else: + client = weaviate.Client( + url="http://localhost:8080", + additional_headers=additional_headers, + ) + print("Client connected") + + example_schema_workflow2(client) + example_schema_workflow(client) + delete_all(client) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v4.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v4.py new file mode 100644 index 0000000000..2c9846fc0b --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/example_v4.py @@ -0,0 +1,228 @@ +# Tested with weaviate-client==3.26.7 +# Code is adapted from official documentation. +# V3 documentation: https://weaviate.io/developers/weaviate/client-libraries/python/python_v3 +# Some parts were also adapted from: +# https://towardsdatascience.com/getting-started-with-weaviate-python-client-e85d14f19e4f +import os + +import weaviate +import weaviate.classes as wvc + +CLASS_NAME = "Article" +RAW_QUERY = """ + { + Get { + Article(limit: 2) { + author + text + } + } + } + """ + + +def create_schema(client): + client.collections.create( + name=CLASS_NAME, + description="An Article class to store a text", + vectorizer_config=wvc.config.Configure.Vectorizer.text2vec_ollama( + api_endpoint="http://ollama:11434" + ), + generative_config=wvc.config.Configure.Generative.ollama( + api_endpoint="http://ollama:11434" + ), + properties=[ + wvc.config.Property( + name="author", + data_type=wvc.config.DataType.TEXT, + description="The name of the author", + ), + wvc.config.Property( + name="text", + data_type=wvc.config.DataType.TEXT, + description="The text content", + ), + ], + ) + + +def get_collection(client): + """Get the collection to test connection""" + return client.collections.get(CLASS_NAME) + + +def delete_collection(client): + client.collections.delete(CLASS_NAME) + + +def create_object(collection): + return collection.data.insert( + { + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + } + ) + + +def create_batch(collection): + objs = [ + { + "author": "Robert", + "text": "Once upon a time, R. wrote a book...", + }, + { + "author": "Johnson", + "text": "Once upon a time, J. wrote some news...", + }, + { + "author": "Maverick", + "text": "Never again, M. will write a book...", + }, + { + "author": "Wilson", + "text": "Lost in the island, W. did not write anything...", + }, + { + "author": "Ludwig", + "text": "As king, he ruled...", + }, + ] + with collection.batch.dynamic() as batch: + for obj in objs: + batch.add_object(properties=obj) + + +def query_get(collection): + return collection.query.fetch_objects( + return_properties=[ + "author", + ] + ) + + +def query_aggregate(collection): + return collection.aggregate.over_all(total_count=True) + + +def query_raw(client): + return client.graphql_raw_query(RAW_QUERY) + + +def query_near_text(collection, text): + """Query using nearText to find similar articles.""" + query_result = collection.query.near_text( + query=text, + limit=2, + return_metadata=weaviate.classes.query.MetadataQuery(distance=True), + ) + + return query_result + + +def validate(client, uuid=None): + return client.data_object.validate( + data_object={ + "author": "Robert", + "text": "Once upon a time, someone wrote a book...", + }, + uuid=uuid, + class_name=CLASS_NAME, + ) + + +def create_schemas(client): + client.collections.create_from_dict( + { + "class": "Author", + "description": "An author that writes an article", + "properties": [ + { + "name": "name", + "dataType": ["string"], + "description": "The name of the author", + }, + ], + }, + ) + client.collections.create_from_dict( + { + "class": CLASS_NAME, + "description": "An Article class to store a text", + "properties": [ + { + "name": "author", + "dataType": ["Author"], + "description": "The author", + }, + { + "name": "text", + "dataType": ["text"], + "description": "The text content", + }, + ], + }, + ) + + +def delete_all(client): + client.collections.delete_all() + + +def example_schema_workflow(client): + delete_all(client) + + create_schema(client) + print("Created schema") + collection = get_collection(client) + print("Retrieved collection: ", collection.name) + + uuid = create_object(collection) + print("Created object of UUID: ", uuid) + obj = collection.query.fetch_object_by_id(uuid) + print("Retrieved obj: ", obj) + + create_batch(collection) + result = query_get(collection) + print("Query result:", result) + aggregate_result = query_aggregate(collection) + print("Aggregate result:", aggregate_result) + raw_result = query_raw(client) + print("Raw result: ", raw_result) + near_text_result = query_near_text(collection, "book") + print("Near text result: ", near_text_result) + + delete_collection(client) + print("Deleted schema") + + +def example_schema_workflow2(client): + delete_all(client) + create_schemas(client) + + +if __name__ == "__main__": + additional_headers = {} + if (key := os.getenv("COHERE_API_KEY")) is not None: + additional_headers.update({"X-Cohere-Api-Key": key}) + elif (key := os.getenv("OPENAI_API_KEY")) is not None: + additional_headers.update({"X-OpenAI-Api-Key": key}) + else: + print("Warning: No API key found for Cohere or OpenAI") + + if (cluster_name := os.getenv("WEAVIATE_CLUSTER_URL")) is not None: + auth_config = weaviate.auth.AuthApiKey( + api_key=os.environ["WEAVIATE_API_KEY"] + ) + client = weaviate.Client( + url=os.getenv("WEAVIATE_CLUSTER_URL"), + auth_client_secret=auth_config, + timeout_config=(5, 15), + additional_headers=additional_headers, + ) + else: + client = weaviate.connect_to_local(headers=additional_headers) + print("Client connected") + + example_schema_workflow2(client) + example_schema_workflow(client) + delete_all(client) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v3.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v3.txt new file mode 100644 index 0000000000..8871f449da --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v3.txt @@ -0,0 +1,7 @@ +weaviate-client>=3.0.0,<4.0.0 +opentelemetry-sdk~=1.36.0 +opentelemetry-exporter-otlp-proto-grpc~=1.36.0 +opentelemetry-distro~=0.57b0 + +# Uncomment after weaviate instrumetation is released +# opentelemetry-instrumentation-weaviate~=2.0b0.dev \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v4.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v4.txt new file mode 100644 index 0000000000..217d60ad32 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/examples/zero-code/requirements-v4.txt @@ -0,0 +1,7 @@ +weaviate-client>=4.0 +opentelemetry-sdk~=1.36.0 +opentelemetry-exporter-otlp-proto-grpc~=1.36.0 +opentelemetry-distro~=0.57b0 + +# Uncomment after weaviate instrumetation is released +# opentelemetry-instrumentation-weaviate~=2.0b0.dev \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/pyproject.toml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/pyproject.toml index c2be94f112..02d7ac7642 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-weaviate/pyproject.toml +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/pyproject.toml @@ -35,6 +35,9 @@ instruments = [ "weaviate-client >= 3.0", ] +[project.entry-points.opentelemetry_instrumentor] +weaviate-client = "opentelemetry.instrumentation.weaviate:WeaviateInstrumentor" + [project.urls] Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation-genai/opentelemetry-instrumentation-weaviate" Repository = "https://github.com/open-telemetry/opentelemetry-python-contrib" diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/__init__.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/__init__.py index e69de29bb2..185760abdc 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/__init__.py +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/__init__.py @@ -0,0 +1,401 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Weaviate client instrumentation supporting `weaviate-client`, it can be enabled by +using ``WeaviateInstrumentor``. + +.. _weaviate-client: https://pypi.org/project/weaviate-client/ + +Usage +----- + +.. code:: python + + import weaviate + from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor + + WeaviateInstrumentor().instrument() + + client = weaviate.Client("http://localhost:8080") + # Your Weaviate operations will now be traced + +API +--- +""" + +import json +from contextvars import ContextVar +from typing import Any, Collection, Dict, Optional + +import weaviate +from wrapt import wrap_function_wrapper # type: ignore + +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import ( + is_instrumentation_enabled, + unwrap, +) +from opentelemetry.instrumentation.weaviate.config import Config +from opentelemetry.instrumentation.weaviate.version import __version__ + +# from opentelemetry.metrics import get_meter +# from opentelemetry._events import get_event_logger +from opentelemetry.semconv.attributes import ( + db_attributes as DbAttributes, +) +from opentelemetry.semconv.attributes import ( + server_attributes as ServerAttributes, +) + +# Potentially not needed. +from opentelemetry.semconv.schemas import Schemas +from opentelemetry.trace import SpanKind, Tracer, get_tracer + +from .mapping import MAPPING_V3, MAPPING_V4, SPAN_NAME_PREFIX +from .utils import ( + extract_collection_name, + parse_url_to_host_port, +) + +WEAVIATE_V3 = 3 +WEAVIATE_V4 = 4 + +weaviate_version = None +_instruments = ("weaviate-client >= 3.0.0, < 5",) + + +# Context variable for passing connection info within operation call stacks +_connection_host_context: ContextVar[Optional[str]] = ContextVar( + "weaviate_connection_host", default=None +) +_connection_port_context: ContextVar[Optional[int]] = ContextVar( + "weaviate_connection_port", default=None +) + + +class WeaviateInstrumentor(BaseInstrumentor): + """An instrumentor for Weaviate's client library.""" + + def __init__(self, exception_logger: Optional[Any] = None) -> None: + super().__init__() + Config.exception_logger = exception_logger + + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + + def _instrument(self, **kwargs: Any) -> None: + global weaviate_version + tracer_provider = kwargs.get("tracer_provider") + tracer = get_tracer( + __name__, + __version__, + tracer_provider, + schema_url=Schemas.V1_28_0.value, + ) + + try: + major_version = int(weaviate.__version__.split(".")[0]) + if major_version >= 4: + weaviate_version = WEAVIATE_V4 + else: + weaviate_version = WEAVIATE_V3 + except (ValueError, IndexError): + # Default to V3 if version parsing fails + weaviate_version = WEAVIATE_V3 + + self._get_server_details(weaviate_version, tracer) + + wrappings = ( + MAPPING_V3 if weaviate_version == WEAVIATE_V3 else MAPPING_V4 + ) + for to_wrap in wrappings: + name = ".".join([to_wrap["name"], to_wrap["function"]]) + wrap_function_wrapper( + module=to_wrap["module"], + name=name, + wrapper=_WeaviateTraceInjectionWrapper( + tracer, wrap_properties=to_wrap + ), + ) + + def _uninstrument(self, **kwargs: Any) -> None: + global weaviate_version + wrappings = ( + MAPPING_V3 if weaviate_version == WEAVIATE_V3 else MAPPING_V4 + ) + for to_unwrap in wrappings: + try: + module = ".".join([to_unwrap["module"], to_unwrap["name"]]) + unwrap( + module, + to_unwrap["function"], + ) + except (ImportError, AttributeError, ValueError): + # Ignore errors when unwrapping - module might not be loaded + # or function might not be wrapped + pass + + # unwrap the connection initialization to remove the context variable injection + try: + if weaviate_version == WEAVIATE_V3: + unwrap("weaviate.Client", "__init__") + elif weaviate_version == WEAVIATE_V4: + unwrap("weaviate.WeaviateClient", "__init__") + except (ImportError, AttributeError, ValueError): + # Ignore errors when unwrapping connection methods + pass + + def _get_server_details(self, version: int, tracer: Tracer) -> None: + name = "Client.__init__" + if version == WEAVIATE_V4: + name = "WeaviateClient.__init__" + + wrap_function_wrapper( + module="weaviate", + name=name, + wrapper=_WeaviateConnectionInjectionWrapper(tracer), + ) + + +class _WeaviateConnectionInjectionWrapper: + """ + A wrapper that intercepts calls to weaviate connection methods to inject tracing headers. + This is used to create spans for Weaviate connection operations. + """ + + def __init__(self, tracer: Tracer): + self.tracer = tracer + + def __call__( + self, wrapped: Any, instance: Any, args: Any, kwargs: Any + ) -> Any: + if not is_instrumentation_enabled(): + return wrapped(*args, **kwargs) + + # Extract connection details from args/kwargs before calling wrapped function + connection_host = None + connection_port = None + connection_url = None + + # For v3, extract URL from constructor arguments + # weaviate.Client(url="http://localhost:8080", ...) + if args and len(args) > 0: + # First positional argument is typically the URL + connection_url = args[0] + elif "url" in kwargs: + # URL passed as keyword argument + connection_url = kwargs["url"] + + if connection_url: + connection_host, connection_port = parse_url_to_host_port( + connection_url + ) + + return_value = wrapped(*args, **kwargs) + + # For v4, try to extract from instance after creation (fallback) + if ( + not connection_url + and hasattr(instance, "_connection") + and instance._connection is not None + ): + connection_url = instance._connection.url + if connection_url: + connection_host, connection_port = parse_url_to_host_port( + connection_url + ) + + _connection_host_context.set(connection_host) + _connection_port_context.set(connection_port) + return return_value + + +class _WeaviateTraceInjectionWrapper: + """ + A wrapper that intercepts calls to weaviate to inject tracing headers. + This is used to create spans for Weaviate operations. + """ + + def __init__( + self, tracer: Tracer, wrap_properties: Optional[Dict[str, str]] = None + ) -> None: + self.tracer = tracer + self.wrap_properties = wrap_properties or {} + + def __call__( + self, wrapped: Any, instance: Any, args: Any, kwargs: Any + ) -> Any: + """ + Wraps the original function to inject tracing headers. + """ + if not is_instrumentation_enabled(): + return wrapped(*args, **kwargs) + + name = self.wrap_properties.get( + "span_name", + getattr(wrapped, "__name__", "unknown"), + ) + name = f"{SPAN_NAME_PREFIX}.{name}" + with self.tracer.start_as_current_span( + name, kind=SpanKind.CLIENT + ) as span: + span.set_attribute(DbAttributes.DB_SYSTEM_NAME, "weaviate") + + # Extract operation name dynamically from the function call + module_name = self.wrap_properties.get("module", "") + function_name = self.wrap_properties.get("function", "") + span.set_attribute(DbAttributes.DB_OPERATION_NAME, function_name) + + # Extract collection name from the operation + collection_name = extract_collection_name( + wrapped, instance, args, kwargs, module_name, function_name + ) + if collection_name: + # Use a Weaviate-specific collection attribute similar to MongoDB's DB_MONGODB_COLLECTION + span.set_attribute( + "db.weaviate.collection.name", collection_name + ) + + connection_host = _connection_host_context.get() + connection_port = _connection_port_context.get() + if connection_host is not None: + span.set_attribute( + ServerAttributes.SERVER_ADDRESS, connection_host + ) + if connection_port is not None: + span.set_attribute( + ServerAttributes.SERVER_PORT, connection_port + ) + + return_value = wrapped(*args, **kwargs) + + # Extract documents from similarity search operations + if self._is_similarity_search(): + documents = self._extract_documents_from_response(return_value) + if documents: + span.set_attribute( + "db.weaviate.documents.count", len(documents) + ) + # emit the documents as events + for doc in documents: + # emit the document content as an event + query = "" + if "query" in kwargs: + query = json.dumps(kwargs["query"]) + attributes = { + "db.weaviate.document.content": json.dumps( + doc["content"] + ), + } + + # Only add non-None values to attributes + if doc.get("distance") is not None: + attributes["db.weaviate.document.distance"] = doc[ + "distance" + ] + if doc.get("certainty") is not None: + attributes["db.weaviate.document.certainty"] = doc[ + "certainty" + ] + if doc.get("score") is not None: + attributes["db.weaviate.document.score"] = doc[ + "score" + ] + if query: + attributes["db.weaviate.document.query"] = query + span.add_event( + "weaviate.document", attributes=attributes + ) + + return return_value + + def _is_similarity_search(self) -> bool: + """ + Check if this is a similarity search operation. + """ + module_name = self.wrap_properties.get("module", "") + function_name = self.wrap_properties.get("function", "") + return ( + "query" in module_name.lower() + or "do" in function_name.lower() + or "near_text" in function_name.lower() + or "fetch_objects" in function_name.lower() + ) + + def _extract_documents_from_response( + self, response: Any + ) -> list[dict[str, Any]]: + """ + Extract documents from weaviate response. + """ + # TODO: Pagination, cursor? + documents: list[dict[str, Any]] = [] + try: + if hasattr(response, "objects"): + for obj in response.objects: + doc: dict[str, Any] = {} + if hasattr(obj, "properties"): + doc["content"] = obj.properties + + # Extract similarity scores + if hasattr(obj, "metadata") and obj.metadata: + metadata = obj.metadata + if ( + hasattr(metadata, "distance") + and metadata.distance is not None + ): + doc["distance"] = metadata.distance + if ( + hasattr(metadata, "certainty") + and metadata.certainty is not None + ): + doc["certainty"] = metadata.certainty + if ( + hasattr(metadata, "score") + and metadata.score is not None + ): + doc["score"] = metadata.score + + documents.append(doc) + elif "data" in response: + # Handle GraphQL responses + for response_key in response["data"].keys(): + for collection in response["data"][response_key]: + for obj in response["data"][response_key][collection]: + doc: dict[str, Any] = {} + doc["content"] = dict(obj) + del doc["content"]["_additional"] + if "_additional" in obj: + metadata = obj["_additional"] + if ( + "distance" in metadata + and metadata["distance"] is not None + ): + doc["distance"] = metadata["distance"] + if ( + "certainty" in metadata + and metadata["certainty"] is not None + ): + doc["certainty"] = metadata["certainty"] + if ( + "score" in metadata + and metadata["score"] is not None + ): + doc["score"] = metadata["score"] + documents.append(doc) + except Exception: + # silently handle extraction errors + pass + return documents diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/config.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/config.py new file mode 100644 index 0000000000..f80b607e10 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/config.py @@ -0,0 +1,22 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class Config: + """ + Shared static configuration for Weaviate instrumentation. + """ + + # logger to handle exceptions during instrumentation + exception_logger = None diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/mapping.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/mapping.py new file mode 100644 index 0000000000..bec91e63c5 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/mapping.py @@ -0,0 +1,176 @@ +SPAN_NAME_PREFIX: str = "db.weaviate" + +CONNECTION_WRAPPING: list[dict[str, str]] = [ + {"module": "weaviate", "name": "connect_to_local"}, + {"module": "weaviate", "name": "connect_to_weaviate_cloud"}, + {"module": "weaviate", "name": "connect_to_custom"}, +] + +MAPPING_V3: list[dict[str, str]] = [ + # Schema operations + { + "module": "weaviate.schema", + "name": "Schema", + "function": "get", + "span_name": "schema.get", + }, + { + "module": "weaviate.schema", + "name": "Schema", + "function": "create_class", + "span_name": "schema.create_class", + }, + { + "module": "weaviate.schema", + "name": "Schema", + "function": "create", + "span_name": "schema.create", + }, + { + "module": "weaviate.schema", + "name": "Schema", + "function": "delete_class", + "span_name": "schema.delete_class", + }, + { + "module": "weaviate.schema", + "name": "Schema", + "function": "delete_all", + "span_name": "schema.delete_all", + }, + # Data CRUD operations + { + "module": "weaviate.data.crud_data", + "name": "DataObject", + "function": "create", + "span_name": "data.crud_data.create", + }, + { + "module": "weaviate.data.crud_data", + "name": "DataObject", + "function": "validate", + "span_name": "data.crud_data.validate", + }, + { + "module": "weaviate.data.crud_data", + "name": "DataObject", + "function": "get", + "span_name": "data.crud_data.get", + }, + # Batch operations + { + "module": "weaviate.batch.crud_batch", + "name": "Batch", + "function": "add_data_object", + "span_name": "batch.crud_batch.add_data_object", + }, + { + "module": "weaviate.batch.crud_batch", + "name": "Batch", + "function": "flush", + "span_name": "batch.crud_batch.flush", + }, + # GraphQL query operations + { + "module": "weaviate.gql.query", + "name": "Query", + "function": "get", + "span_name": "gql.query.get", + }, + { + "module": "weaviate.gql.query", + "name": "Query", + "function": "aggregate", + "span_name": "gql.query.aggregate", + }, + { + "module": "weaviate.gql.query", + "name": "Query", + "function": "raw", + "span_name": "gql.query.raw", + }, + { + "module": "weaviate.gql.get", + "name": "GetBuilder", + "function": "do", + "span_name": "gql.query.get.do", + }, +] + + +MAPPING_V4: list[dict[str, str]] = [ + { + "module": "weaviate.collections.queries.near_text.query", + "name": "_NearTextQuery", + "function": "near_text", + "span_name": "collections.query.near_text", + }, + { + "module": "weaviate.collections.queries.fetch_objects.query", + "name": "_FetchObjectsQuery", + "function": "fetch_objects", + "span_name": "collections.query.fetch_objects", + }, + { + "module": "weaviate.collections.grpc.query", + "name": "_QueryGRPC", + "function": "get", + "span_name": "collections.query.get", + }, + { + "module": "weaviate.collections.data", + "name": "_DataCollection", + "function": "insert", + "span_name": "collections.data.insert", + }, + { + "module": "weaviate.collections.data", + "name": "_DataCollection", + "function": "replace", + "span_name": "collections.data.replace", + }, + { + "module": "weaviate.collections.data", + "name": "_DataCollection", + "function": "update", + "span_name": "collections.data.update", + }, + # Collections + { + "module": "weaviate.collections.collections", + "name": "_Collections", + "function": "get", + "span_name": "collections.get", + }, + { + "module": "weaviate.collections.collections", + "name": "_Collections", + "function": "create", + "span_name": "collections.create", + }, + { + "module": "weaviate.collections.collections", + "name": "_Collections", + "function": "delete", + "span_name": "collections.delete", + }, + { + "module": "weaviate.collections.collections", + "name": "_Collections", + "function": "delete_all", + "span_name": "collections.delete_all", + }, + { + "module": "weaviate.collections.collections", + "name": "_Collections", + "function": "create_from_dict", + "span_name": "collections.create_from_dict", + }, + # Batch + { + "module": "weaviate.collections.batch.collection", + "name": "_BatchCollection", + "function": "add_object", + "span_name": "collections.batch.add_object", + }, +] diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/utils.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/utils.py new file mode 100644 index 0000000000..3d612c426a --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/src/opentelemetry/instrumentation/weaviate/utils.py @@ -0,0 +1,80 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from typing import Any, Optional, Tuple +from urllib.parse import urlparse + +# TODO: get semconv for vector databases +# from opentelemetry.semconv._incubating.attributes import gen_ai_attributes as GenAI + +logger = logging.getLogger(__name__) + + +def parse_url_to_host_port(url: str) -> Tuple[Optional[str], Optional[int]]: + parsed = urlparse(url) + host: Optional[str] = parsed.hostname + port: Optional[int] = parsed.port + return host, port + + +def extract_collection_name( + wrapped: Any, + instance: Any, + args: Any, + kwargs: Any, + module_name: str, + function_name: str, +) -> Optional[str]: + """ + Extract collection name from Weaviate function calls. + + Args: + wrapped: The wrapped function + instance: The instance object (if any) + args: Function arguments + kwargs: Function keyword arguments + module_name: The module name from mapping + function_name: The function name from mapping + + Returns: + Collection name if found, None otherwise + """ + collection_name = None + + try: + # Weaviate Client V4 stores this in the "request" attribute of the kwargs + if ( + kwargs + and "request" in kwargs + and hasattr(kwargs["request"], "collection") + ): + collection_name = kwargs["request"].collection + + # Check if the instance has a collection attribute + # TODO: Check V3 + elif hasattr(instance, "_collection"): + if hasattr(instance._collection, "_name"): + collection_name = instance._collection._name + elif hasattr(instance._collection, "name"): + collection_name = instance._collection.name + + return collection_name + + except Exception: + # Silently ignore any errors during extraction to avoid breaking the tracing + + pass + + return None diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v3.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v3.txt new file mode 100644 index 0000000000..11c6e1783a --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v3.txt @@ -0,0 +1,6 @@ +weaviate-client>=3.0.0,<4.0.0 +pytest>=7.0.0 +pytest-mock>=3.0.0 +pytest-vcr==1.0.2 +-e opentelemetry-instrumentation +-e instrumentation-genai/opentelemetry-instrumentation-weaviate \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v4.txt b/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v4.txt new file mode 100644 index 0000000000..373a05a6c3 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v4.txt @@ -0,0 +1,6 @@ +weaviate-client>=4.0.0,<5.0.0 +pytest>=7.0.0 +pytest-mock>=3.0.0 +pytest-vcr==1.0.2 +-e opentelemetry-instrumentation +-e instrumentation-genai/opentelemetry-instrumentation-weaviate \ No newline at end of file diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/__init__.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/__init__.py index e69de29bb2..b0a6f42841 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/__init__.py +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v3.yaml new file mode 100644 index 0000000000..b6aa542702 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v3.yaml @@ -0,0 +1,210 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:32 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: '{"query": "{Get{Article(nearText: {concepts: [\"lost while writing\"]} + ){text author _additional {distance id }}}}"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '116' + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: POST + uri: http://localhost:8080/v1/graphql + response: + body: + string: '{"data":{"Get":{"Article":[{"_additional":{"distance":0.38068163,"id":"c99c2c4b-fd06-4ca2-a02d-da12f12290fc"},"author":"Wilson","text":"Lost + in the island, W. did not write anything..."},{"_additional":{"distance":0.49162787,"id":"3c06911d-b0af-48b3-8c83-11fe6071f8db"},"author":"Robert","text":"Once + upon a time, someone wrote a book..."},{"_additional":{"distance":0.5148766,"id":"3bd2147f-e490-48a5-a65a-88dbf7c5172d"},"author":"Robert","text":"Once + upon a time, R. wrote a book..."},{"_additional":{"distance":0.53570545,"id":"82c42b1e-8c83-407a-a3a7-ca5adc76d6d0"},"author":"Maverick","text":"Never + again, M. will write a book..."},{"_additional":{"distance":0.5812365,"id":"a06d8d53-c437-4d0f-9ff2-2c12c696febf"},"author":"Johnson","text":"Once + upon a time, J. wrote some news..."},{"_additional":{"distance":0.6401162,"id":"3746c112-ca20-48d2-a2d7-386d0f595708"},"author":"Ludwig","text":"As + king, he ruled..."}]}}} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '923' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v4.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v4.yaml new file mode 100644 index 0000000000..bbe5da3ea5 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_distance_attribute_v4.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-type: + - application/json + host: + - localhost:8080 + user-agent: + - python-httpx/0.28.1 + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 21:53:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v3.yaml new file mode 100644 index 0000000000..def12a65c7 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v3.yaml @@ -0,0 +1,209 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/schema + response: + body: + string: '{"classes":[{"class":"TestClass","description":"This property was generated + by Weaviate''s auto-schema feature on Mon Jul 28 21:39:09 2025","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"This + property was generated by Weaviate''s auto-schema feature on Mon Jul 28 21:39:09 + 2025","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"title","tokenization":"word"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"},{"class":"Author","description":"An + author that writes an article","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + name of the author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"name","tokenization":"whitespace"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"},{"class":"Article","description":"An + Article class to store a text","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + text content","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"text","tokenization":"word"},{"dataType":["Author"],"description":"The + author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":false,"name":"author"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"}]} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v4.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v4.yaml new file mode 100644 index 0000000000..12a5470add --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_instrument_uninstrument_v4.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-type: + - application/json + host: + - localhost:8080 + user-agent: + - python-httpx/0.28.1 + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_parent_child_span_relationship_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_parent_child_span_relationship_v3.yaml new file mode 100644 index 0000000000..7deae439f1 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_parent_child_span_relationship_v3.yaml @@ -0,0 +1,204 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Thu, 07 Aug 2025 17:53:56 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Thu, 07 Aug 2025 17:53:56 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Thu, 07 Aug 2025 17:53:56 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/schema + response: + body: + string: '{"classes":[{"class":"Article","description":"An Article class to store + a text","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"moduleConfig":{"text2vec-ollama":{"apiEndpoint":"http://ollama:11434","model":"nomic-embed-text:latest","vectorizeClassName":false}},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + name of the author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"author","tokenization":"whitespace"},{"dataType":["text"],"description":"The + text content","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"text","tokenization":"word"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"text2vec-ollama"}]} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '1973' + Content-Type: + - application/json + Date: + - Thu, 07 Aug 2025 17:53:56 GMT + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v3.yaml new file mode 100644 index 0000000000..c9014b8b2d --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v3.yaml @@ -0,0 +1,204 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/schema + response: + body: + string: '{"classes":[{"class":"Article","description":"An Article class to store + a text","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"moduleConfig":{"text2vec-ollama":{"apiEndpoint":"http://ollama:11434","model":"nomic-embed-text:latest","vectorizeClassName":false}},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + name of the author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"author","tokenization":"whitespace"},{"dataType":["text"],"description":"The + text content","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"text","tokenization":"word"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"text2vec-ollama"}]} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '1973' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v4.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v4.yaml new file mode 100644 index 0000000000..bbe5da3ea5 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_schema_get_span_v4.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-type: + - application/json + host: + - localhost:8080 + user-agent: + - python-httpx/0.28.1 + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 21:53:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v3.yaml new file mode 100644 index 0000000000..c9014b8b2d --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v3.yaml @@ -0,0 +1,204 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/schema + response: + body: + string: '{"classes":[{"class":"Article","description":"An Article class to store + a text","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"moduleConfig":{"text2vec-ollama":{"apiEndpoint":"http://ollama:11434","model":"nomic-embed-text:latest","vectorizeClassName":false}},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + name of the author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"author","tokenization":"whitespace"},{"dataType":["text"],"description":"The + text content","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"moduleConfig":{"text2vec-ollama":{"skip":false,"vectorizePropertyName":false}},"name":"text","tokenization":"word"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"text2vec-ollama"}]} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '1973' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 20:55:33 GMT + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v4.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v4.yaml new file mode 100644 index 0000000000..bbe5da3ea5 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_server_connection_attributes_v4.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-type: + - application/json + host: + - localhost:8080 + user-agent: + - python-httpx/0.28.1 + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Tue, 05 Aug 2025 21:53:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v3.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v3.yaml new file mode 100644 index 0000000000..3bc15dc60c --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v3.yaml @@ -0,0 +1,210 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/ready + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/.well-known/openid-configuration + response: + body: + string: '' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Length: + - '0' + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Vary: + - Origin + status: + code: 404 + message: Not Found +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.4 + content-type: + - application/json + method: GET + uri: http://localhost:8080/v1/schema + response: + body: + string: '{"classes":[{"class":"Article","description":"An Article class to store + a text","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + text content","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"text","tokenization":"word"},{"dataType":["Author"],"description":"The + author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":false,"name":"author"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"},{"class":"TestClass","description":"This + property was generated by Weaviate''s auto-schema feature on Mon Jul 28 21:39:09 + 2025","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"This + property was generated by Weaviate''s auto-schema feature on Mon Jul 28 21:39:09 + 2025","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"title","tokenization":"word"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"},{"class":"Author","description":"An + author that writes an article","invertedIndexConfig":{"bm25":{"b":0.75,"k1":1.2},"cleanupIntervalSeconds":60,"stopwords":{"additions":null,"preset":"en","removals":null},"usingBlockMaxWAND":true},"multiTenancyConfig":{"autoTenantActivation":false,"autoTenantCreation":false,"enabled":false},"properties":[{"dataType":["text"],"description":"The + name of the author","indexFilterable":true,"indexRangeFilters":false,"indexSearchable":true,"name":"name","tokenization":"whitespace"}],"replicationConfig":{"asyncEnabled":false,"deletionStrategy":"NoAutomatedResolution","factor":1},"shardingConfig":{"actualCount":1,"actualVirtualCount":128,"desiredCount":1,"desiredVirtualCount":128,"function":"murmur3","key":"_id","strategy":"hash","virtualPerPhysical":128},"vectorIndexConfig":{"bq":{"enabled":false},"cleanupIntervalSeconds":300,"distance":"cosine","dynamicEfFactor":8,"dynamicEfMax":500,"dynamicEfMin":100,"ef":-1,"efConstruction":128,"filterStrategy":"sweeping","flatSearchCutoff":40000,"maxConnections":32,"multivector":{"aggregation":"maxSim","enabled":false,"muvera":{"dprojections":16,"enabled":false,"ksim":4,"repetitions":10}},"pq":{"bitCompression":false,"centroids":256,"enabled":false,"encoder":{"distribution":"log-normal","type":"kmeans"},"segments":0,"trainingLimit":100000},"skip":false,"sq":{"enabled":false,"rescoreLimit":20,"trainingLimit":100000},"vectorCacheMaxObjects":1000000000000},"vectorIndexType":"hnsw","vectorizer":"none"}]} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v4.yaml b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v4.yaml new file mode 100644 index 0000000000..12a5470add --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/cassettes/test_span_creation_basic_v4.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-type: + - application/json + host: + - localhost:8080 + user-agent: + - python-httpx/0.28.1 + method: GET + uri: http://localhost:8080/v1/meta + response: + body: + string: '{"grpcMaxMessageSize":104858000,"hostname":"http://[::]:8080","modules":{"generative-anthropic":{"documentationHref":"https://docs.anthropic.com/en/api/getting-started","name":"Generative + Search - Anthropic"},"generative-anyscale":{"documentationHref":"https://docs.anyscale.com/endpoints/overview","name":"Generative + Search - Anyscale"},"generative-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html","name":"Generative + Search - AWS"},"generative-cohere":{"documentationHref":"https://docs.cohere.com/reference/chat","name":"Generative + Search - Cohere"},"generative-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#completion-task","name":"Generative + Search - Databricks"},"generative-friendliai":{"documentationHref":"https://docs.friendli.ai/openapi/create-chat-completions","name":"Generative + Search - FriendliAI"},"generative-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/chat/test-chat-prompts","name":"Generative + Search - Google"},"generative-mistral":{"documentationHref":"https://docs.mistral.ai/api/","name":"Generative + Search - Mistral"},"generative-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/llm-apis","name":"Generative + Search - NVIDIA"},"generative-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"Generative + Search - OctoAI (deprecated)"},"generative-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion","name":"Generative + Search - Ollama"},"generative-openai":{"documentationHref":"https://platform.openai.com/docs/api-reference/completions","name":"Generative + Search - OpenAI"},"generative-xai":{"documentationHref":"https://docs.x.ai/docs/overview","name":"Generative + Search - xAI"},"multi2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"multi2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-multimodal-embeddings","name":"Google + Multimodal Module"},"multi2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + CLIP Module"},"multi2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + CLIP Module"},"multi2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/multimodal-embeddings","name":"VoyageAI + Multi Modal Module"},"reranker-cohere":{"documentationHref":"https://txt.cohere.com/rerank/","name":"Reranker + - Cohere"},"reranker-jinaai":{"documentationHref":"https://jina.ai/reranker","name":"Reranker + - Jinaai"},"reranker-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"Reranker + - NVIDIA"},"reranker-voyageai":{"documentationHref":"https://docs.voyageai.com/reference/reranker-api","name":"Reranker + - VoyageAI"},"text2colbert-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-aws":{"documentationHref":"https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html","name":"AWS + Module"},"text2vec-cohere":{"documentationHref":"https://docs.cohere.ai/embedding-wiki/","name":"Cohere + Module"},"text2vec-databricks":{"documentationHref":"https://docs.databricks.com/en/machine-learning/foundation-models/api-reference.html#embedding-task","name":"Databricks + Foundation Models Module - Embeddings"},"text2vec-google":{"documentationHref":"https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings","name":"Google + Module"},"text2vec-huggingface":{"documentationHref":"https://huggingface.co/docs/api-inference/detailed_parameters#feature-extraction-task","name":"Hugging + Face Module"},"text2vec-jinaai":{"documentationHref":"https://jina.ai/embeddings/","name":"JinaAI + Module"},"text2vec-mistral":{"documentationHref":"https://docs.mistral.ai/api/#operation/createEmbedding","name":"Mistral + Module"},"text2vec-nvidia":{"documentationHref":"https://docs.api.nvidia.com/nim/reference/retrieval-apis","name":"NVIDIA + Module"},"text2vec-octoai":{"documentationHref":"https://octo.ai/docs/text-gen-solution/getting-started","name":"OctoAI + Module (deprecated)"},"text2vec-ollama":{"documentationHref":"https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings","name":"Ollama + Module"},"text2vec-openai":{"documentationHref":"https://platform.openai.com/docs/guides/embeddings/what-are-embeddings","name":"OpenAI + Module"},"text2vec-voyageai":{"documentationHref":"https://docs.voyageai.com/docs/embeddings","name":"VoyageAI + Module"},"text2vec-weaviate":{"documentationHref":"https://api.embedding.weaviate.io","name":"Weaviate + Embedding Module"}},"version":"1.31.2"} + + ' + headers: + Access-Control-Allow-Headers: + - Content-Type, Authorization, Batch, X-Openai-Api-Key, X-Openai-Organization, + X-Openai-Baseurl, X-Anyscale-Baseurl, X-Anyscale-Api-Key, X-Cohere-Api-Key, + X-Cohere-Baseurl, X-Huggingface-Api-Key, X-Azure-Api-Key, X-Azure-Deployment-Id, + X-Azure-Resource-Name, X-Azure-Concurrency, X-Azure-Block-Size, X-Google-Api-Key, + X-Google-Vertex-Api-Key, X-Google-Studio-Api-Key, X-Goog-Api-Key, X-Goog-Vertex-Api-Key, + X-Goog-Studio-Api-Key, X-Palm-Api-Key, X-Jinaai-Api-Key, X-Aws-Access-Key, + X-Aws-Secret-Key, X-Voyageai-Baseurl, X-Voyageai-Api-Key, X-Mistral-Baseurl, + X-Mistral-Api-Key, X-Anthropic-Baseurl, X-Anthropic-Api-Key, X-Databricks-Endpoint, + X-Databricks-Token, X-Databricks-User-Agent, X-Friendli-Token, X-Friendli-Baseurl, + X-Weaviate-Api-Key, X-Weaviate-Cluster-Url, X-Nvidia-Api-Key, X-Nvidia-Baseurl + Access-Control-Allow-Methods: + - '*' + Access-Control-Allow-Origin: + - '*' + Content-Type: + - application/json + Date: + - Wed, 30 Jul 2025 21:19:54 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_span_common.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_span_common.py new file mode 100644 index 0000000000..df717fe040 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_span_common.py @@ -0,0 +1,59 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import vcr + +from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor + +from .test_utils import WeaviateSpanTestBase + + +class TestWeaviateSpanCommon(WeaviateSpanTestBase): + """Common span generation tests for both Weaviate v3 and v4.""" + + def test_instrument_uninstrument(self): + """Test that instrumentor can be enabled and disabled.""" + cassette_path = f"{self.cassette_path}test_instrument_uninstrument_v{self.version}.yaml" + with vcr.use_cassette(cassette_path): + # Uninstrument first + WeaviateInstrumentor().uninstrument() + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 0) + + # Re-instrument + WeaviateInstrumentor().instrument( + tracer_provider=self.tracer_provider + ) + client = self.get_weaviate_client() + # Perform an operation to generate spans + self.get_basic_call(client) + + spans = self.memory_exporter.get_finished_spans() + self.assertGreater(len(spans), 0) + + def test_span_creation_basic(self): + """Test that basic spans are created for instrumented operations.""" + cassette_path = f"{self.cassette_path}test_span_creation_basic_v{self.version}.yaml" + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + # Perform an operation to generate spans + self.get_basic_call(client) + self.assert_span_count(1) + + # def test_span_kind_is_client(self): + # """Test that all spans have CLIENT kind.""" + # spans = self.assert_span_count(1) + # for span in spans: + # self.assertEqual(span.kind, SpanKind.CLIENT) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_utils.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_utils.py new file mode 100644 index 0000000000..6c6f4e275c --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_utils.py @@ -0,0 +1,102 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from typing import List + +import weaviate + +from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor +from opentelemetry.semconv._incubating.attributes import ( + server_attributes as ServerAttributes, +) +from opentelemetry.test.test_base import TestBase +from opentelemetry.trace import Span, SpanKind + + +class WeaviateSpanTestBase(TestBase): + """Base class for all Weaviate span generation tests""" + + def setUp(self): + super().setUp() + self.cassette_path = os.path.join( + os.path.dirname(__file__), "cassettes/" + ) + self.version = self.get_weaviate_version() + WeaviateInstrumentor().instrument(tracer_provider=self.tracer_provider) + + def tearDown(self): + super().tearDown() + WeaviateInstrumentor().uninstrument() + + def get_weaviate_version(self): + # Try to get the version from the weaviate module or client + try: + return int(weaviate.__version__.split(".")[0]) + except AttributeError: + # Fallback: try to get from client instance if available + client = weaviate.Client("http://localhost:8080") + return int(client.get_version().split(".")[0]) + + def get_weaviate_client(self): + """Get a Weaviate client instance.""" + if self.get_weaviate_version() >= 4: + return weaviate.connect_to_local(skip_init_checks=True) + return weaviate.Client("http://localhost:8080") + + def get_basic_call(self, client): + """Perform a basic operation to generate spans.""" + # This can be any operation that generates a span, e.g., getting schema + if self.get_weaviate_version() >= 4: + return client.collections.get("TestCollection") + else: + return client.schema.get() + + def assert_span_count(self, count: int) -> List[Span]: + """Assert that the memory exporter has the expected number of spans.""" + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), count) + return spans + + def assert_parent_child_relationship( + self, parent_span: Span, child_span: Span + ): + """Assert that child_span is a child of parent_span.""" + self.assertIsNotNone(child_span.parent) + self.assertEqual( + child_span.parent.span_id, parent_span.context.span_id + ) + self.assertEqual( + child_span.parent.trace_id, parent_span.context.trace_id + ) + + def assert_span_properties( + self, + span: Span, + expected_name: str, + expected_kind: SpanKind = SpanKind.CLIENT, + ): + """Assert basic span properties.""" + self.assertEqual(span.name, expected_name) + self.assertEqual(span.kind, expected_kind) + + def assert_server_attributes( + self, span: Span, host: str = None, port: int = None + ): + """Assert server-related span attributes.""" + attributes = span.attributes + if host: + self.assertEqual(attributes[ServerAttributes.SERVER_ADDRESS], host) + if port: + self.assertEqual(attributes[ServerAttributes.SERVER_PORT], port) diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v3.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v3.py new file mode 100644 index 0000000000..ed36a9973a --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v3.py @@ -0,0 +1,67 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import unittest + +import vcr +import weaviate + +from opentelemetry.instrumentation.weaviate.mapping import ( + SPAN_NAME_PREFIX, +) +from opentelemetry.trace import SpanKind + +from .test_utils import WeaviateSpanTestBase + + +def should_skip_tests(): + version = int(weaviate.__version__.split(".")[0]) + return version != 3 + + +@unittest.skipIf( + should_skip_tests(), "Skipping Weaviate v3 tests for versions < 4" +) +class TestWeaviateV3SpanGeneration(WeaviateSpanTestBase): + def test_schema_get_span(self): + cassette_path = ( + f"{self.cassette_path}test_schema_get_span_v{self.version}.yaml" + ) + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + client.schema.get() + spans = self.assert_span_count(1) + span = spans[0] + self.assert_span_properties( + span, f"{SPAN_NAME_PREFIX}.schema.get", SpanKind.CLIENT + ) + + def test_server_connection_attributes(self): + cassette_path = f"{self.cassette_path}test_server_connection_attributes_v{self.version}.yaml" + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + client.schema.get() + spans = self.assert_span_count(1) + span = spans[0] + self.assert_server_attributes(span, "localhost", 8080) + + def test_parent_child_span_relationship(self): + cassette_path = f"{self.cassette_path}test_parent_child_span_relationship_v{self.version}.yaml" + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + client.schema.get() + spans = self.assert_span_count(1) + span = spans[0] + self.assertIsNone(span.parent) + + # TODO: find a child span to assert against diff --git a/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v4.py b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v4.py new file mode 100644 index 0000000000..ca6097a525 --- /dev/null +++ b/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests/test_weaviate_v4.py @@ -0,0 +1,56 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import unittest + +import vcr +import weaviate + +from opentelemetry.instrumentation.weaviate.mapping import ( + SPAN_NAME_PREFIX, +) +from opentelemetry.trace import SpanKind + +from .test_utils import WeaviateSpanTestBase + + +def should_skip_tests(): + version = int(weaviate.__version__.split(".")[0]) + return version != 4 + + +@unittest.skipIf( + should_skip_tests(), "Skipping Weaviate v4 tests for versions != 4" +) +class TestWeaviateV4SpanGeneration(WeaviateSpanTestBase): + def test_schema_get_span(self): + cassette_path = ( + f"{self.cassette_path}test_schema_get_span_v{self.version}.yaml" + ) + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + client.collections.get("Article") + spans = self.assert_span_count(1) + span = spans[0] + self.assert_span_properties( + span, f"{SPAN_NAME_PREFIX}.collections.get", SpanKind.CLIENT + ) + + def test_server_connection_attributes(self): + cassette_path = f"{self.cassette_path}test_server_connection_attributes_v{self.version}.yaml" + with vcr.use_cassette(cassette_path): + client = self.get_weaviate_client() + client.collections.get("Article") + spans = self.assert_span_count(1) + span = spans[0] + self.assert_server_attributes(span, "localhost", 8080) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py index 15c5536941..c9ab1f76f4 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py @@ -24,6 +24,10 @@ "library": "google-cloud-aiplatform >= 1.64", "instrumentation": "opentelemetry-instrumentation-vertexai>=2.0b0", }, + { + "library": "weaviate-client >= 3.0", + "instrumentation": "opentelemetry-instrumentation-weaviate==2.0b0.dev", + }, { "library": "aio_pika >= 7.2.0, < 10.0.0", "instrumentation": "opentelemetry-instrumentation-aio-pika==0.58b0.dev", diff --git a/scripts/generate_instrumentation_bootstrap.py b/scripts/generate_instrumentation_bootstrap.py index 23d5ba172e..6b57fa5d62 100755 --- a/scripts/generate_instrumentation_bootstrap.py +++ b/scripts/generate_instrumentation_bootstrap.py @@ -68,10 +68,6 @@ # development. This filter will get removed once it is further along in its # development lifecycle and ready to be included by default. "opentelemetry-instrumentation-langchain", - # Weaviate instrumentation is currently excluded because it is still in early - # development. This filter will get removed once it is further along in its - # development lifecycle and ready to be included by default. - "opentelemetry-instrumentation-weaviate", ] # Static version specifiers for instrumentations that are released independently diff --git a/tox.ini b/tox.ini index b37982567a..d583038297 100644 --- a/tox.ini +++ b/tox.ini @@ -418,6 +418,10 @@ envlist = ; requires snappy headers to be available on the system lint-processor-baggage + ; instrumentation-weaviate + py3{9,10,11,12,13}-test-instrumentation-weaviate-{v3,v4} + lint-instrumentation-weaviate + spellcheck docker-tests docs @@ -715,6 +719,10 @@ deps = util-http: {[testenv]test_deps} util-http: -r {toxinidir}/util/opentelemetry-util-http/test-requirements.txt util-http: {toxinidir}/util/opentelemetry-util-http + + weaviate: {[testenv]test_deps} + weaviate-v3: -r {toxinidir}/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v3.txt + weaviate-v4: -r {toxinidir}/instrumentation-genai/opentelemetry-instrumentation-weaviate/test-requirements-v4.txt ; FIXME: add coverage testing allowlist_externals = sh @@ -935,6 +943,9 @@ commands = test-exporter-prometheus-remote-write: pytest {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write/tests {posargs} lint-exporter-prometheus-remote-write: sh -c "cd exporter && pylint --rcfile ../.pylintrc opentelemetry-exporter-prometheus-remote-write" + test-instrumentation-weaviate: pytest {toxinidir}/instrumentation-genai/opentelemetry-instrumentation-weaviate/tests {posargs} + lint-instrumentation-weaviate: sh -c "cd instrumentation-genai && pylint --rcfile ../.pylintrc opentelemetry-instrumentation-weaviate" + coverage: {toxinidir}/scripts/coverage.sh [testenv:docs]