From 2e91405433ab46981191fe7054b3484a8ae7371a Mon Sep 17 00:00:00 2001 From: abhishek9sharma <17585931+abhishek9sharma@users.noreply.github.com> Date: Sat, 25 Jan 2025 21:11:46 +0800 Subject: [PATCH 1/2] - Add OpenInference span kind attribute to Guardrails telemetry spans. - Updated version to 0.6.3 in pyproject.toml. --- guardrails/telemetry/guard_tracing.py | 15 +++++++++++++-- guardrails/telemetry/open_inference.py | 3 ++- guardrails/telemetry/runner_tracing.py | 11 +++++++++++ guardrails/telemetry/validator_tracing.py | 9 +++++++++ pyproject.toml | 2 +- 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/guardrails/telemetry/guard_tracing.py b/guardrails/telemetry/guard_tracing.py index 24062564f..68a3d8a0e 100644 --- a/guardrails/telemetry/guard_tracing.py +++ b/guardrails/telemetry/guard_tracing.py @@ -10,6 +10,7 @@ Union, ) +from openinference.semconv.trace import SpanAttributes from opentelemetry import context, trace from opentelemetry.trace import StatusCode, Tracer, Span, Link, get_tracer @@ -153,6 +154,9 @@ def trace_stream_guard( guard_span = new_span add_guard_attributes(guard_span, history, res) add_user_attributes(guard_span) + new_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) yield res except StopIteration: next_exists = False @@ -179,7 +183,9 @@ def trace_guard_execution( guard_span.set_attribute("guardrails.version", GUARDRAILS_VERSION) guard_span.set_attribute("type", "guardrails/guard") guard_span.set_attribute("guard.name", guard_name) - + guard_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) try: result = _execute_fn(*args, **kwargs) if isinstance(result, Iterator) and not isinstance( @@ -218,6 +224,9 @@ async def trace_async_stream_guard( add_guard_attributes(guard_span, history, res) add_user_attributes(guard_span) + guard_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) yield res except StopIteration: next_exists = False @@ -259,7 +268,9 @@ async def trace_async_guard_execution( guard_span.set_attribute("guardrails.version", GUARDRAILS_VERSION) guard_span.set_attribute("type", "guardrails/guard") guard_span.set_attribute("guard.name", guard_name) - + guard_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) try: result = await _execute_fn(*args, **kwargs) if isinstance(result, AsyncIterator): diff --git a/guardrails/telemetry/open_inference.py b/guardrails/telemetry/open_inference.py index 1fc33e08e..e2029b922 100644 --- a/guardrails/telemetry/open_inference.py +++ b/guardrails/telemetry/open_inference.py @@ -8,6 +8,7 @@ recursive_key_operation, redact, ) +from openinference.semconv.trace import SpanAttributes def trace_operation( @@ -82,7 +83,7 @@ def trace_llm_call( if current_span is None: return - + current_span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL") ser_function_call = serialize(function_call) if ser_function_call: current_span.set_attribute("llm.function_call", ser_function_call) diff --git a/guardrails/telemetry/runner_tracing.py b/guardrails/telemetry/runner_tracing.py index cbf5b6ac2..8d09f31a6 100644 --- a/guardrails/telemetry/runner_tracing.py +++ b/guardrails/telemetry/runner_tracing.py @@ -7,6 +7,7 @@ Iterator, Optional, ) +from openinference.semconv.trace import SpanAttributes from opentelemetry import context, trace from opentelemetry.trace import StatusCode, Span @@ -26,6 +27,7 @@ ) from guardrails.utils.safe_get import safe_get from guardrails.version import GUARDRAILS_VERSION +from openinference.semconv.trace import SpanAttributes import sys @@ -83,6 +85,9 @@ def trace_step_wrapper(*args, **kwargs) -> Iteration: name="step", # type: ignore context=current_otel_context, # type: ignore ) as step_span: + step_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) try: response = fn(*args, **kwargs) add_step_attributes(step_span, response, *args, **kwargs) @@ -111,6 +116,7 @@ def trace_stream_step_generator( name="step", # type: ignore context=current_otel_context, # type: ignore ) as step_span: + step_span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL") try: gen = fn(*args, **kwargs) next_exists = True @@ -157,10 +163,14 @@ async def trace_async_step_wrapper(*args, **kwargs) -> Iteration: name="step", # type: ignore context=current_otel_context, # type: ignore ) as step_span: + step_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) try: response = await fn(*args, **kwargs) add_user_attributes(step_span) add_step_attributes(step_span, response, *args, **kwargs) + return response except Exception as e: step_span.set_status(status=StatusCode.ERROR, description=str(e)) @@ -186,6 +196,7 @@ async def trace_async_stream_step_generator( name="step", # type: ignore context=current_otel_context, # type: ignore ) as step_span: + step_span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL") try: gen = fn(*args, **kwargs) next_exists = True diff --git a/guardrails/telemetry/validator_tracing.py b/guardrails/telemetry/validator_tracing.py index e9114b7be..41641e4c0 100644 --- a/guardrails/telemetry/validator_tracing.py +++ b/guardrails/telemetry/validator_tracing.py @@ -9,6 +9,7 @@ from opentelemetry import context, trace from opentelemetry.trace import StatusCode, Tracer, Span +from openinference.semconv.trace import SpanAttributes from guardrails.settings import settings @@ -103,6 +104,10 @@ def trace_validator_wrapper(*args, **kwargs): name=validator_span_name, # type: ignore context=current_otel_context, # type: ignore ) as validator_span: + validator_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) + try: resp = fn(*args, **kwargs) add_user_attributes(validator_span) @@ -167,6 +172,10 @@ async def trace_validator_wrapper(*args, **kwargs): name=validator_span_name, # type: ignore context=current_otel_context, # type: ignore ) as validator_span: + validator_span.set_attribute( + SpanAttributes.OPENINFERENCE_SPAN_KIND, "GUARDRAIL" + ) # see here for a list of span kinds: https://github.com/Arize-ai/openinference/blob/main/python/openinference-semantic-conventions/src/openinference/semconv/trace/__init__.py#L271 + try: resp = await fn(*args, **kwargs) add_user_attributes(validator_span) diff --git a/pyproject.toml b/pyproject.toml index c1a108152..809243d38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "guardrails-ai" -version = "0.6.2" +version = "0.6.3" description = "Adding guardrails to large language models." authors = ["Guardrails AI "] license = "Apache License 2.0" From 3a9513de0b0d1326950339c93a507cf37be1f669 Mon Sep 17 00:00:00 2001 From: abhishek9sharma <17585931+abhishek9sharma@users.noreply.github.com> Date: Thu, 30 Jan 2025 22:50:59 +0800 Subject: [PATCH 2/2] - Enhance the `CallInputs` class with a custom `__str__` method for better - string representation. This includes redacting sensitive information such as - keys and tokens while preserving other attributes, improving security and - usability when logging or displaying instances of the class. --- guardrails/classes/history/call_inputs.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/guardrails/classes/history/call_inputs.py b/guardrails/classes/history/call_inputs.py index 25a71cbd3..5cbf3f384 100644 --- a/guardrails/classes/history/call_inputs.py +++ b/guardrails/classes/history/call_inputs.py @@ -78,3 +78,29 @@ def from_dict(cls, obj: Dict[str, Any]): i_call_inputs = ICallInputs.from_dict(obj) or ICallInputs() return cls.from_interface(i_call_inputs) + + def __str__(self): + attributes = {} + for k, v in self.__dict__.items(): + if not k.startswith("_"): + if k == "kwargs": + redacted_kwargs = {} + for sk, sv in v.items(): + if ( + "key" in sk.lower() or "token" in sk.lower() + ) and isinstance(sv, str): + redaction_length = len(sv) - 4 + stars = "*" * redaction_length + redacted_kwargs[sk] = f"{stars}{sv[-4:]}" + else: + redacted_kwargs[sk] = sv + attributes[k] = redacted_kwargs + else: + attributes[k] = v + class_name = self.__class__.__name__ + return ( + f"{class_name}(\n" + + ",\ + \n".join(f" {k}={v}" for k, v in attributes.items()) + + "\n)" + )