is anyone the from the support team avaaible?
Started server process [17390] Waiting for application startup. Application startup complete. api.providers.arize_provider: :key: headers: authorization = Bearer ak-801...tJJWqL x-space-id = U3BhY2U6MTk4MTQ6RnF4Kw== x-project-name = immediatetiger-chatbots x-model-id = TW9kZWw6NDA2NTE4MTI1MzpmNE4z :mag_right: Preparing to send spans to Arize :bar_chart: Number of spans: 1 :clipboard: Span 1: test_arize_connection :id: trace_id = 258185119493044155846723555804574312568 :id: span_id = 10085917664294632387 :label: attributes = { 'test.attribute': 'Hello Arize!', 'test.timestamp': 'now' } :package: resource = { 'telemetry.sdk.language': 'python', 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': '1.36.0', 'service.name': 'immediatetiger-chatbots', 'service.version': '1.0.0', 'deployment.environment': 'development', 'external.model.id': 'TW9kZWw6NDA2NTE4MTI1MzpmNE4z', 'model.name': 'immediatetiger-chatbots' }
response: ✅ Arize export result: SpanExportResult.SUCCESS :clipboard: Full result object: { '_value_': 0, '_name_': 'SUCCESS', '__objclass__': <enum 'SpanExportResult'>, '_sort_order_': 0 } :clipboard: Result type: <enum 'SpanExportResult'> :warning: WatchFiles detected changes in 'api/providers/arize_provider.py'. Reloading...
🔒[private user] 🔒[private user] why I dont see any span stored under the dashboard?
zero spans under my project
these are old ones
look dates
""" Arize Provider Handles all Arize telemetry and monitoring operations """ import os import logging from typing import Dict, Any, Optional from opentelemetry import trace from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.resources import Resource from ..config.settings import ARIZE_API_KEY, ARIZE_SPACE_KEY from ..utils.exceptions import ConfigurationException logger = logging.getLogger(__name__) ANSI_ORANGE = "\033[38;5;208m" ANSI_RESET = "\033[0m" ANSI_PURPLE = "\033[38;5;135m" class ArizeProvider: """Provider for Arize telemetry operations""" def __init__(self, api_key: str = None, space_id: str = None, project_name: str = None): # Prefer explicit env overrides used by Arize self.api_key = api_key or os.getenv("ARIZE_API_KEY") or ARIZE_API_KEY # Use ARIZE_SPACE_ID instead of ARIZE_SPACE_KEY (which may be misused elsewhere) self.space_id = space_id or os.getenv("ARIZE_SPACE_ID") or ARIZE_SPACE_KEY # Prefer ARIZE_SPACE_NAME; fallback to ARIZE_PROJECT_NAME; final fallback to previous string self.project_name = ( project_name or os.getenv("ARIZE_SPACE_NAME") or os.getenv("ARIZE_PROJECT_NAME", "immediatetiger-chatbots") ) self.model_id = os.getenv("ARIZE_MODEL_ID", "TW9kZWw6NDA2NTE4MTI1MzpmNE4z") if not self.api_key: raise ConfigurationException( "Arize API key not provided", error_code="MISSING_ARIZE_API_KEY" ) if not self.space_id: raise ConfigurationException( "Arize Space ID not provided", error_code="MISSING_ARIZE_SPACE_KEY" ) # Initialize Arize telemetry try: self._setup_telemetry() logger.info("Arize provider initialized successfully") except Exception as e: logger.error(f"Failed to initialize Arize provider: {str(e)}") raise ConfigurationException( f"Failed to initialize Arize provider: {str(e)}", error_code="INITIALIZATION_FAILED" ) def _setup_telemetry(self): """Setup OpenTelemetry with Arize configuration""" # Create OTLP exporter for Arize self.otlp_exporter = OTLPSpanExporter( endpoint="https://otlp.arize.com/v1", headers={ "authorization": f"Bearer {self.api_key}", "x-space-id": self.space_id, "x-project-name": self.project_name, "x-model-id": self.model_id, } ) # Create resource resource = Resource.create({ "service.name": self.project_name, "service.version": "1.0.0", "deployment.environment": os.getenv("ENVIRONMENT", "development"), "external.model.id": self.model_id, "model.name": self.project_name, }) # Create tracer provider self.tracer_provider = TracerProvider(resource=resource) # Add Arize exporter to the tracer provider self.tracer_provider.add_span_processor( BatchSpanProcessor(self.otlp_exporter) ) # Add logging exporter to print everything we send and the result from Arize self.tracer_provider.add_span_processor( BatchSpanProcessor(self._create_logging_exporter(self.otlp_exporter)) ) # Set the tracer provider as the global default trace.set_tracer_provider(self.tracer_provider) # Create tracer self.tracer = trace.get_tracer(self.project_name) logger.info("Arize telemetry setup completed") def _create_logging_exporter(self, inner_exporter): """Create a wrapper exporter that logs spans and the export result.""" from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult # Capture config from the provider for use inside the inner class api_key = self.api_key space_id = self.space_id project_name = self.project_name model_id = self.model_id class LoggingExporter(SpanExporter): def export(self, spans): try: # Headers preview (masked) printed in purple for visibility masked_key = (api_key[:6] + "…" + api_key[-6:]) if isinstance(api_key, str) and len(api_key) > 12 else "***" logger.info(f"{ANSI_PURPLE}🔑 headers: authorization=Bearer {masked_key}, x-space-id={space_id}, x-project-name={project_name}, x-model-id={model_id}{ANSI_RESET}") logger.info(f"{ANSI_PURPLE}🔎 Preparing to send spans to Arize{ANSI_RESET}") logger.info(f"{ANSI_PURPLE}📊 Number of spans: {len(spans)}{ANSI_RESET}") for i, span in enumerate(spans, start=1): try: logger.info(f"{ANSI_PURPLE}📋 Span {i}: {getattr(span, 'name', 'unknown')}{ANSI_RESET}") ctx = getattr(span, 'context', None) if ctx: logger.info(f"{ANSI_PURPLE} 🆔 trace_id={ctx.trace_id} span_id={ctx.span_id}{ANSI_RESET}") logger.info(f"{ANSI_PURPLE} 🏷️ attributes={dict(getattr(span, 'attributes', {}))}{ANSI_RESET}") res = getattr(span, 'resource', None) if res and getattr(res, 'attributes', None): logger.info(f"{ANSI_PURPLE} 📦 resource={dict(res.attributes)}{ANSI_RESET}") except Exception as e: logger.warning(f"Failed to log span {i}: {e}") result = inner_exporter.export(spans) # Highlight the entire Arize export response in orange for visibility logger.info(f"{ANSI_ORANGE}✅ Arize export result: {result}{ANSI_RESET}") logger.info(f"{ANSI_ORANGE}📋 Full result object: {result.__dict__ if hasattr(result, '__dict__') else result}{ANSI_RESET}") logger.info(f"{ANSI_ORANGE}📋 Result type: {type(result)}{ANSI_RESET}") if hasattr(result, 'status_code'): logger.info(f"{ANSI_ORANGE}📋 Status code: {result.status_code}{ANSI_RESET}") if hasattr(result, 'success'): logger.info(f"{ANSI_ORANGE}📋 Success: {result.success}{ANSI_RESET}") return result if isinstance(result, SpanExportResult) else SpanExportResult.SUCCESS except Exception as e: logger.error(f"❌ Error exporting/logging spans: {e}") return SpanExportResult.FAILURE def shutdown(self): try: if hasattr(inner_exporter, 'shutdown'): inner_exporter.shutdown() except Exception as e: logger.warning(f"LoggingExporter shutdown warning: {e}") return LoggingExporter() def trace_function(self, function_name: str, attributes: Dict[str, Any] = None): """Decorator to trace function calls""" def decorator(func): def wrapper(*args, **kwargs): with self.tracer.start_as_current_span(function_name) as span: # Add function attributes if attributes: for key, value in attributes.items(): span.set_attribute(key, str(value)) # Add function arguments as attributes span.set_attribute("function.args_count", len(args)) span.set_attribute("function.kwargs_count", len(kwargs)) try: result = func(*args, **kwargs) span.set_attribute("function.success", True) return result except Exception as e: span.set_attribute("function.success", False) span.set_attribute("function.error", str(e)) span.record_exception(e) raise return wrapper return decorator def trace_async_function(self, function_name: str, attributes: Dict[str, Any] = None): """Decorator to trace async function calls""" def decorator(func): async def wrapper(*args, **kwargs): with self.tracer.start_as_current_span(function_name) as span: # Add function attributes if attributes: for key, value in attributes.items(): span.set_attribute(key, str(value)) # Add function arguments as attributes span.set_attribute("function.args_count", len(args)) span.set_attribute("function.kwargs_count", len(kwargs)) try: result = await func(*args, **kwargs) span.set_attribute("function.success", True) return result except Exception as e: span.set_attribute("function.success", False) span.set_attribute("function.error", str(e)) span.record_exception(e) raise return wrapper return decorator
def trace_model_call(self, model_name: str, model_type: str = "llm"): """Decorator to trace AI model calls""" def decorator(func): async def wrapper(*args, **kwargs): with self.tracer.start_as_current_span(f"{model_name}_call") as span: # Add model attributes span.set_attribute("model.name", model_name) span.set_attribute("model.type", model_type) span.set_attribute("model.provider", "openai") # Add input attributes if args and len(args) > 0: prompt = args[0] if isinstance(args[0], str) else str(args[0]) span.set_attribute("model.input_length", len(prompt)) span.set_attribute("model.input_tokens", len(prompt.split())) start_time = trace.get_current_span().get_span_context().trace_id try: result = await func(*args, **kwargs) # Add output attributes if isinstance(result, str): span.set_attribute("model.output_length", len(result)) span.set_attribute("model.output_tokens", len(result.split())) span.set_attribute("model.success", True) return result except Exception as e: span.set_attribute("model.success", False) span.set_attribute("model.error", str(e)) span.record_exception(e) raise return wrapper return decorator def add_span_attribute(self, key: str, value: Any): """Add attribute to current span""" try: current_span = trace.get_current_span() if current_span: current_span.set_attribute(key, str(value)) except Exception as e: logger.warning(f"Failed to add span attribute: {str(e)}") def record_event(self, name: str, attributes: Dict[str, Any] = None): """Record an event in the current span""" try: current_span = trace.get_current_span() if current_span: current_span.add_event(name, attributes or {}) except Exception as e: logger.warning(f"Failed to record event: {str(e)}") def record_exception(self, exception: Exception, attributes: Dict[str, Any] = None): """Record an exception in the current span""" try: current_span = trace.get_current_span() if current_span: current_span.record_exception(exception, attributes or {}) except Exception as e: logger.warning(f"Failed to record exception: {str(e)}") def get_tracer(self): """Get the tracer instance""" return self.tracer def test_connection(self): """Test Arize connection by sending a test span""" try: with self.tracer.start_as_current_span("test_arize_connection") as span: span.set_attribute("test.attribute", "Hello Arize!") span.set_attribute("test.timestamp", str(os.getenv("TIMESTAMP", "now"))) logger.info("Test span sent to Arize. Check your dashboard at app.arize.com") return True except Exception as e: logger.error(f"Failed to test Arize connection: {str(e)}") return False def shutdown(self): """Shutdown Arize telemetry""" try: self.tracer_provider.shutdown() logger.info("Arize telemetry shutdown completed") except Exception as e: logger.error(f"Error shutting down Arize telemetry: {str(e)}")
does it make sense?
🔒[private user] whats the min shape of the fields to store something?
🔒[private user] def trace_model_call(func): """ Decorator to trace model calls with OpenTelemetry. Args: func: The function to trace Returns: Wrapped function with tracing capabilities """ @wraps(func) async def wrapper(*args, **kwargs): start_time = time.time() if tracer: with tracer.start_as_current_span("llm.chat") as span: try: # Extract common parameters messages = kwargs.get("messages", []) prompt = messages[-1]["content"] if messages else kwargs.get("prompt", "") model_name = kwargs.get("model", "unknown") # Import OpenInference semantic conventions from openinference.semconv.trace import SpanAttributes, OpenInferenceSpanKindValues # Set required OpenInference attributes span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, OpenInferenceSpanKindValues.LLM.value) span.set_attribute("llm.model_name", model_name) # Set input and output values (required for useful spans) span.set_attribute(SpanAttributes.INPUT_VALUE, prompt) # Execute model call result = await func(*args, **kwargs) # Extract and set response attributes if hasattr(result, "choices") and result.choices: choice = result.choices[0] response = getattr(choice.message, "content", None) if hasattr(choice, "message") else None finish_reason = getattr(choice, "finish_reason", None) logger.info(f"Tracing: response={response}, finish_reason={finish_reason}") if response is not None: # Set output value using OpenInference attributes span.set_attribute(SpanAttributes.OUTPUT_VALUE, response) else: # Set empty output span.set_attribute(SpanAttributes.OUTPUT_VALUE, "None") else: logger.warning("No choices found in model result.") # Set error output using OpenInference attributes span.set_attribute(SpanAttributes.OUTPUT_VALUE, "No choices") # Set performance metrics duration = time.time() - start_time span.set_attribute("duration_seconds", duration) logger.info(f"Model call traced: {model_name} - Duration: {duration:.2f}s") return result except Exception as e: span.record_exception(e) span.set_status(trace.Status(trace.StatusCode.ERROR)) span.set_attribute("error", str(e)) logger.error(f"Error in model call: {str(e)}") raise else: # Fallback without tracing return await func(*args, **kwargs) return wrapper
what else am I missing?
