diff --git a/docs/02-getting-started.md b/docs/02-getting-started.md index 95b9b00..1894fb1 100644 --- a/docs/02-getting-started.md +++ b/docs/02-getting-started.md @@ -54,6 +54,7 @@ from basalt.observability import start_observe, observe @start_observe( + feature_slug="workflow", name="my_workflow", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -89,6 +90,7 @@ from basalt.observability import start_observe, observe def process_request(user_id, data): # Create root span with identity with start_observe( + feature_slug="request-processing", name="process_request", identity={"user": user_id}, metadata={"source": "api"} @@ -119,6 +121,7 @@ from basalt.observability import start_observe, observe # Method 1: Set on root span (recommended) @start_observe( + feature_slug="chat-handler", name="chat_handler", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -131,7 +134,7 @@ def handle_chat(message): # Method 2: Set dynamically -@start_observe(name="api_handler") +@start_observe(feature_slug="api-handler", name="api_handler") def handle_request(auth_token): user_data = verify_token(auth_token) # Returns {"id": "user-123", "name": "John Doe"} observe.set_identity({"user": user_data}) @@ -144,7 +147,7 @@ Add custom key-value pairs to your spans: ```python # On root span -@start_observe(name="workflow", metadata={"model": "gpt-4", "temperature": 0.7}) +@start_observe(feature_slug="workflow", name="workflow", metadata={"model": "gpt-4", "temperature": 0.7}) def workflow(): pass diff --git a/docs/03-prompts.md b/docs/03-prompts.md index 70ca78a..63b2493 100644 --- a/docs/03-prompts.md +++ b/docs/03-prompts.md @@ -514,7 +514,7 @@ Combine prompt context managers with manual spans: from basalt import Basalt from basalt.observability import start_observe, observe -@start_observe(name="QA System", identity={"user": {"id": "user_123"}}) +@start_observe(feature_slug="qa-system", name="QA System", identity={"user": {"id": "user_123"}}) def answer_question(question: str): with basalt.prompts.get_sync("qa-prompt", variables={"question": question}) as prompt: # Prompt span is a child of "QA System" diff --git a/docs/05-observability.md b/docs/05-observability.md index 68bec10..cb20728 100644 --- a/docs/05-observability.md +++ b/docs/05-observability.md @@ -15,6 +15,7 @@ from basalt.observability import start_observe, observe, ObserveKind # Root span with identity tracking @start_observe( + feature_slug="request-processing", name="process_request", identity={"user": {"id": "user_123", "name": "Alice"}, "organization": {"id": "org_abc"}}, metadata={"environment": "production", "version": "2.0"} @@ -25,6 +26,7 @@ def process(): # Root span with experiment tracking @start_observe( + feature_slug="ml-workflow", name="ml_workflow", experiment={"id": "exp_456", "name": "Model Comparison"}, identity={"user": "analyst_001"} @@ -34,6 +36,7 @@ def run_experiment(): # Context manager form with start_observe( + feature_slug="batch-processing", name="batch_job", identity={"organization": {"id": "org_xyz", "name": "Acme Corp"}}, metadata={"job_id": "batch_123"} @@ -43,6 +46,8 @@ with start_observe( ``` **Key features of `start_observe`:** +- **`feature_slug`** (required): A unique identifier for the feature or workflow being traced (e.g., "user-auth", "payment-flow"). +- **`name`** (required): A descriptive name for the root span. - **`identity`**: Dict with `user` and/or `organization` keys for tracking. Can also use simple string format or callables for dynamic resolution. - **`experiment`**: Dict with `id`, `name`, and `variant` keys for A/B testing and feature tracking. - **`evaluate_config`**: Configuration for evaluators attached to the root span. @@ -57,6 +62,7 @@ from basalt.observability import observe, start_observe, ObserveKind # Root span (required as entry point) @start_observe( + feature_slug="request-handler", name="process_request", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -182,7 +188,7 @@ Sometimes you need to set metadata or identity on the root span from deeply nest from basalt.observability import observe, start_observe -@start_observe(name="API Handler") +@start_observe(feature_slug="api-handler", name="API Handler") def handle_request(user_id): # Root span starts here with identity tracking observe.set_input({"user_id": user_id}) diff --git a/docs/06-manual-tracing.md b/docs/06-manual-tracing.md index d743621..1c4c665 100644 --- a/docs/06-manual-tracing.md +++ b/docs/06-manual-tracing.md @@ -24,6 +24,7 @@ Every trace must begin with a root span created using `start_observe`: from basalt.observability import start_observe, observe @start_observe( + feature_slug="data-processing", name="Data Processing Workflow", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -62,6 +63,7 @@ from basalt.observability import start_observe def process_request(): with start_observe( + feature_slug="request-processing", name="Request Processing", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -85,6 +87,7 @@ from basalt.observability import start_observe # With identity tracking @start_observe( + feature_slug="main-workflow", name="Main Workflow", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -97,6 +100,7 @@ def main_workflow(data): # With experiment tracking @start_observe( + feature_slug="ab-test", name="A/B Test", experiment={"id": "exp_001", "name": "Model Comparison", "variant": "model_a"}, identity={ @@ -109,6 +113,7 @@ def run_experiment(): # Context manager form with start_observe( + feature_slug="batch-job", name="Batch Job", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -121,7 +126,8 @@ with start_observe( **Key `start_observe` parameters:** -- `name`: Span name (defaults to function name if used as decorator) +- `feature_slug` (required): A unique identifier for the feature or workflow being traced +- `name` (required): Span name (defaults to function name if used as decorator) - `identity`: Dict with `user` and/or `organization` keys for tracking - `experiment`: Dict with `id`, `name`, and `variant` for A/B testing - `evaluate_config`: Evaluator configuration for the root span @@ -178,6 +184,7 @@ Decorators automatically create parent-child relationships. Always start with `s from basalt.observability import start_observe, observe @start_observe( + feature_slug="main-workflow", name="Main Workflow", identity={ "organization": {"id": "123", "name": "ACME"}, @@ -347,7 +354,7 @@ You can mix decorators and context managers: ```python from basalt.observability import start_observe, observe -@start_observe(name="Main Workflow") +@start_observe(feature_slug="main-workflow", name="Main Workflow") def main_workflow(data): # Root span via decorator prepare_data(data) @@ -426,7 +433,7 @@ basalt = Basalt(api_key="your-api-key") openai_client = OpenAI(api_key="your-openai-key") # Root trace -with start_observe(name="process_request", feature_slug="support-ticket"): +with start_observe(feature_slug="support-ticket", name="process_request"): # Fetch prompt with context manager with basalt.prompts.get_sync("joke-analyzer", variables={"jokeText": "..."}) as prompt: # Auto-instrumented OpenAI call automatically receives prompt attributes diff --git a/docs/08-async-observability.md b/docs/08-async-observability.md index 2c856d6..df33694 100644 --- a/docs/08-async-observability.md +++ b/docs/08-async-observability.md @@ -18,7 +18,7 @@ import asyncio from basalt.observability import async_start_observe, async_observe async def main(): - async with async_start_observe(name="async_workflow") as span: + async with async_start_observe(feature_slug="async-workflow", name="async_workflow") as span: span.set_input({"task": "process_data"}) result = await process_data() span.set_output(result) @@ -42,6 +42,7 @@ from basalt.observability import async_start_observe # Context manager form async def workflow(): async with async_start_observe( + feature_slug="user-request", name="User Request", identity={"user": {"id": "user_123"}}, metadata={"environment": "production"} @@ -52,6 +53,7 @@ async def workflow(): # Decorator form @async_start_observe( + feature_slug="api-handler", name="API Handler", identity={"user": {"id": "user_456"}} ) @@ -95,7 +97,7 @@ The `@observe` and `@start_observe` decorators automatically detect async functi from basalt.observability import observe, start_observe # These automatically work with async functions -@start_observe(name="Async Root") +@start_observe(feature_slug="async-root", name="Async Root") async def async_root(): await nested_operation() @@ -133,6 +135,7 @@ async def generate_greeting(user: dict) -> str: async def handle_user_request(user_id: str) -> str: """Main handler with root span""" async with async_start_observe( + feature_slug="user-request", name="user_request", identity={"user": {"id": user_id}}, metadata={"version": "2.0"} diff --git a/docs/11-experiments.md b/docs/11-experiments.md index e803131..7403fc6 100644 --- a/docs/11-experiments.md +++ b/docs/11-experiments.md @@ -54,6 +54,7 @@ from basalt.observability import start_observe, observe @start_observe( + feature_slug="ab-test", name="experiment.variant_a", experiment="exp-456", identity={ @@ -73,6 +74,7 @@ def run_variant_a(): # Or using context manager with start_observe( + feature_slug="ab-test", name="experiment.variant_b", experiment="exp-456", ): diff --git a/docs/12-user-org-tracking.md b/docs/12-user-org-tracking.md index cda0c84..d88ca32 100644 --- a/docs/12-user-org-tracking.md +++ b/docs/12-user-org-tracking.md @@ -81,7 +81,7 @@ You can also set identity dynamically within a span using `observe.set_identity( ```python from basalt.observability import observe, start_observe -@start_observe(name="workflow") +@start_observe(feature_slug="data-workflow", name="workflow") def process_data(auth_token): # Authenticate and get user info user_info = authenticate(auth_token) @@ -105,7 +105,7 @@ When using context managers, you can set identity on the span handle: from basalt.observability import async_start_observe async def workflow(): - async with async_start_observe(name="process", feature_slug="task") as span: + async with async_start_observe(feature_slug="task", name="process") as span: # Set identity on the span handle span.set_identity({ "user": {"id": "user-789"}, @@ -197,7 +197,7 @@ def get_identity_from_request(): } @app.route("/api/orders/") -@start_observe(name="get_order", feature_slug="orders", identity=get_identity_from_request) +@start_observe(feature_slug="orders", name="get_order", identity=get_identity_from_request) def get_order(order_id): # Identity automatically set from request order = fetch_order(order_id) @@ -212,8 +212,8 @@ Identity works seamlessly with async/await: from basalt.observability import async_start_observe @async_start_observe( - name="async_workflow", feature_slug="background-jobs", + name="async_workflow", identity={"user": {"id": "user-123"}} ) async def process_async(data):