diff --git a/examples/experimental/otel/Makefile b/examples/experimental/otel/Makefile new file mode 100644 index 000000000..bdf668ec0 --- /dev/null +++ b/examples/experimental/otel/Makefile @@ -0,0 +1,45 @@ +POETRY:=poetry run +PYTHON:=python +PIP:=pip +OTEL_AUTO:=opentelemetry-instrument +TRULENS_PROVIDER:=trulens.experimental.otel_tracing.core.trace.TracerProvider + +# Configure OTEL with environment variables: +# https://opentelemetry.io/docs/languages/sdk-configuration/general/ +run_with_otel_env: + OTEL_PYTHON_TRACER_PROVIDER=$(TRULENS_PROVIDER) \ + OTEL_SERVICE_NAME=trulens_otel_test_env \ + OTEL_TRACES_EXPORTER=zipkin \ + OTEL_METRICS_EXPORTER=none \ + $(POETRY) $(OTEL_AUTO) $(PYTHON) dummy.py + +# Configure OTEL with command line arguments: +# https://opentelemetry.io/docs/zero-code/python/configuration/ +run_with_otel_cmd: + $(OTEL_AUTO) \ + --tracer_provider $(TRULENS_PROVIDER) \ + --service_name trulens_otel_test_cmd \ + --traces_exporter zipkin \ + --metrics_exporter none \ + $(POETRY) $(PYTHON) dummy.py + +run_without_otel: + $(POETRY) $(PYTHON) dummy.py + +install: + $(POETRY) $(PIP) install -r requirements.txt + +# Start collector: +start_collector: + docker run -p 4317:4317 \ + -v otel-collector-config.yaml:/etc/otel-collector-config.yaml \ + otel/opentelemetry-collector:latest \ + --config=/etc/otel-collector-config.yaml + +# Start the zipkin docker container: +start_zipkin: + docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin + +# Stop the zipkin docker container: +stop_zipkin: + docker stop $(docker ps -a -q --filter ancestor=openzipkin/zipkin) diff --git a/examples/experimental/otel/README.md b/examples/experimental/otel/README.md new file mode 100644 index 000000000..e3ff23e37 --- /dev/null +++ b/examples/experimental/otel/README.md @@ -0,0 +1,4 @@ +# OTEL Configuration + +This folder features examples of TruLens OTEL integration and how it interacts +with OTEL command line tools. diff --git a/examples/experimental/otel/dummy.py b/examples/experimental/otel/dummy.py new file mode 100644 index 000000000..163333438 --- /dev/null +++ b/examples/experimental/otel/dummy.py @@ -0,0 +1,105 @@ +# ruff: noqa: F401 + +from pathlib import Path +from pprint import pprint +import sys + +import dotenv +from opentelemetry import trace + +# zipkin exporter +from opentelemetry.exporter.zipkin.json import ZipkinExporter + +# console exporter +from trulens.apps.custom import TruCustomApp +from trulens.core import Feedback +from trulens.core import Select +from trulens.core.session import TruSession +from trulens.experimental.otel_tracing.core.trace import TracerProvider +from trulens.feedback.dummy.provider import DummyProvider + +# Add base dir to path to be able to access test folder. +base_dir = Path().cwd().parent.parent.parent.resolve() +if str(base_dir) not in sys.path: + print(f"Adding {base_dir} to sys.path") + sys.path.append(str(base_dir)) + + +from examples.dev.dummy_app.app import DummyApp # noqa: E402 + +dotenv.load_dotenv() + +try: + print("Initial tracer_provider =", trace.get_tracer_provider()) + +except Exception: # pylint: disable=broad-except + print("No tracer provider set yet.") + +# Sets the global default tracer provider to be the trulens one. +trace.set_tracer_provider(TracerProvider()) + +print("Current tracer_provider =", trace.get_tracer_provider()) + +# Creates a tracer for custom spans below. +tracer = trace.get_tracer(__name__) + +# Setup zipkin exporter +# exporter = ZipkinExporter(endpoint="http://localhost:9411/api/v2/spans") + +# Setup session with exporter. +# session = TruSession(_experimental_otel_exporter=exporter) + +# If not using the exporter, manually enable the otel experimental feature: +session = TruSession() +session.experimental_enable_feature("otel_tracing") + +# Create dummy endpoint for a dummy feedback function: +dummy_provider = DummyProvider() +dummy_feedback = Feedback(dummy_provider.sentiment).on( + text=Select.RecordSpans.trulens.call.generate.attributes[ + "trulens.bindings" + ].prompt +) +# Parts of the selector are: +# +# - Select.RecordSpans - Select spans dictionary, organized by span name. +# +# - trulens.call.generate - Span name. TruLens call spans are of the form +# "trulens.call.". +# +# - attributes - Span attributes +# +# - ["trulens.bindings"] - Attributes specific to TruLens spans. Call spans include +# method call arguments in "trulens.bindings". +# +# - prompt - The prompt argument to the method call named. + +# Create custom app: +ca = DummyApp() + +# Create trulens wrapper: +ta = TruCustomApp( + ca, + app_id="customapp", + feedbacks=[dummy_feedback], +) + +# Normal trulens recording context manager: +with ta as recorder: + # Another custom span. + with tracer.start_as_current_span("custom inner span") as inner_span: + inner_span.set_attribute("custom", "value") + + # Normal instrumented call: + print(ca.respond_to_query("hello")) + +record = recorder.get() + +# Check the feedback results. Note that this feedback function is from a dummy +# provider which does not have true sentiment analysis. + +pprint(record.feedback_results[0].result()) + +# Check trulens instrumented calls as spans: + +pprint(record.get(Select.RecordSpans)) diff --git a/examples/experimental/otel/otel-collector-config.yaml b/examples/experimental/otel/otel-collector-config.yaml new file mode 100644 index 000000000..1f6cf8d4f --- /dev/null +++ b/examples/experimental/otel/otel-collector-config.yaml @@ -0,0 +1,23 @@ +# OTEL SDK Configuration for testing TruLens OTEL integration. + +# https://opentelemetry.io/docs/languages/python/getting-started/ + +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 +exporters: + # NOTE: Prior to v0.86.0 use `logging` instead of `debug`. + debug: + verbosity: detailed +processors: + batch: +service: + pipelines: + traces: + receivers: [otlp] + exporters: [debug] + processors: [batch] diff --git a/examples/experimental/otel/requirements.txt b/examples/experimental/otel/requirements.txt new file mode 100644 index 000000000..4bd0d1780 --- /dev/null +++ b/examples/experimental/otel/requirements.txt @@ -0,0 +1,18 @@ +# python deps, OTEL: +opentelemetry-api +opentelemetry-sdk +opentelemetry-exporter-otlp + +# OTEL contrib instrumentors +opentelemetry-instrumentation-sqlalchemy +opentelemetry-instrumentation-requests + +# Traceloop instrumentors +opentelemetry-instrumentation-llamaindex +opentelemetry-instrumentation-openai + +# Arize openinference instrumentors +openinference-instrumentation-llama-index >= 2 + +# OTEL zipkin exporter +opentelemetry-exporter-zipkin-proto-http