From 866c13cdc25de1143fca2872b64549ed9a229d22 Mon Sep 17 00:00:00 2001 From: ehhuang Date: Tue, 14 Oct 2025 13:48:40 -0700 Subject: [PATCH 1/3] chore(api)!: BREAKING CHANGE: remove ALL telemetry APIs (#3740) # What does this PR do? As discussed on discord, we do not need to reinvent the wheel for telemetry. Instead we'll lean into the canonical OTEL stack. Logs/traces/metrics will still be sent via OTEL - they just won't be stored on, queried through Stack. This is the first of many PRs to remove telemetry API from Stack. 1) removed webmethod decorators to remove from API spec 2) removed tests as @iamemilio is adding them on otel directly. ## Test Plan --- docs/static/deprecated-llama-stack-spec.html | 897 ------------ docs/static/deprecated-llama-stack-spec.yaml | 663 --------- .../static/experimental-llama-stack-spec.html | 899 +----------- .../static/experimental-llama-stack-spec.yaml | 663 --------- docs/static/llama-stack-spec.html | 391 ----- docs/static/llama-stack-spec.yaml | 291 ---- docs/static/stainless-llama-stack-spec.html | 1274 ----------------- docs/static/stainless-llama-stack-spec.yaml | 942 ------------ llama_stack/apis/telemetry/telemetry.py | 76 +- ...e8083caf34f49147ad1c25efae1de3f0b25e5.json | 57 - .../telemetry/test_openai_telemetry.py | 194 --- tests/integration/telemetry/test_telemetry.py | 187 --- .../telemetry/test_telemetry_metrics.py | 206 --- 13 files changed, 2 insertions(+), 6738 deletions(-) delete mode 100644 tests/integration/telemetry/recordings/0de60cd6a6ec3dbfc4a7601e77be8083caf34f49147ad1c25efae1de3f0b25e5.json delete mode 100644 tests/integration/telemetry/test_openai_telemetry.py delete mode 100644 tests/integration/telemetry/test_telemetry.py delete mode 100644 tests/integration/telemetry/test_telemetry_metrics.py diff --git a/docs/static/deprecated-llama-stack-spec.html b/docs/static/deprecated-llama-stack-spec.html index 46417522c..0fa8c9adc 100644 --- a/docs/static/deprecated-llama-stack-spec.html +++ b/docs/static/deprecated-llama-stack-spec.html @@ -3526,343 +3526,6 @@ }, "deprecated": true } - }, - "/v1/telemetry/metrics/{metric_name}": { - "post": { - "responses": { - "200": { - "description": "A QueryMetricsResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query metrics.", - "description": "Query metrics.", - "parameters": [ - { - "name": "metric_name", - "in": "path", - "description": "The name of the metric to query.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsRequest" - } - } - }, - "required": true - }, - "deprecated": true - } - }, - "/v1/telemetry/spans": { - "post": { - "responses": { - "200": { - "description": "A QuerySpansResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query spans.", - "description": "Query spans.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansRequest" - } - } - }, - "required": true - }, - "deprecated": true - } - }, - "/v1/telemetry/spans/export": { - "post": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Save spans to a dataset.", - "description": "Save spans to a dataset.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SaveSpansToDatasetRequest" - } - } - }, - "required": true - }, - "deprecated": true - } - }, - "/v1/telemetry/spans/{span_id}/tree": { - "post": { - "responses": { - "200": { - "description": "A QuerySpanTreeResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpanTreeResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span tree by its ID.", - "description": "Get a span tree by its ID.", - "parameters": [ - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get the tree from.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetSpanTreeRequest" - } - } - }, - "required": true - }, - "deprecated": true - } - }, - "/v1/telemetry/traces": { - "post": { - "responses": { - "200": { - "description": "A QueryTracesResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query traces.", - "description": "Query traces.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesRequest" - } - } - }, - "required": true - }, - "deprecated": true - } - }, - "/v1/telemetry/traces/{trace_id}": { - "get": { - "responses": { - "200": { - "description": "A Trace.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Trace" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a trace by its ID.", - "description": "Get a trace by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": true - } - }, - "/v1/telemetry/traces/{trace_id}/spans/{span_id}": { - "get": { - "responses": { - "200": { - "description": "A Span.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Span" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span by its ID.", - "description": "Get a span by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get the span from.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": true - } } }, "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", @@ -13673,561 +13336,6 @@ "logger_config" ], "title": "SupervisedFineTuneRequest" - }, - "QueryMetricsRequest": { - "type": "object", - "properties": { - "start_time": { - "type": "integer", - "description": "The start time of the metric to query." - }, - "end_time": { - "type": "integer", - "description": "The end time of the metric to query." - }, - "granularity": { - "type": "string", - "description": "The granularity of the metric to query." - }, - "query_type": { - "type": "string", - "enum": [ - "range", - "instant" - ], - "description": "The type of query to perform." - }, - "label_matchers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label to match" - }, - "value": { - "type": "string", - "description": "The value to match against" - }, - "operator": { - "type": "string", - "enum": [ - "=", - "!=", - "=~", - "!~" - ], - "description": "The comparison operator to use for matching", - "default": "=" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value", - "operator" - ], - "title": "MetricLabelMatcher", - "description": "A matcher for filtering metrics by label values." - }, - "description": "The label matchers to apply to the metric." - } - }, - "additionalProperties": false, - "required": [ - "start_time", - "query_type" - ], - "title": "QueryMetricsRequest" - }, - "MetricDataPoint": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer", - "description": "Unix timestamp when the metric value was recorded" - }, - "value": { - "type": "number", - "description": "The numeric value of the metric at this timestamp" - }, - "unit": { - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "timestamp", - "value", - "unit" - ], - "title": "MetricDataPoint", - "description": "A single data point in a metric time series." - }, - "MetricLabel": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label" - }, - "value": { - "type": "string", - "description": "The value of the label" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value" - ], - "title": "MetricLabel", - "description": "A label associated with a metric." - }, - "MetricSeries": { - "type": "object", - "properties": { - "metric": { - "type": "string", - "description": "The name of the metric" - }, - "labels": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricLabel" - }, - "description": "List of labels associated with this metric series" - }, - "values": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricDataPoint" - }, - "description": "List of data points in chronological order" - } - }, - "additionalProperties": false, - "required": [ - "metric", - "labels", - "values" - ], - "title": "MetricSeries", - "description": "A time series of metric data points." - }, - "QueryMetricsResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricSeries" - }, - "description": "List of metric series matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryMetricsResponse", - "description": "Response containing metric time series data." - }, - "QueryCondition": { - "type": "object", - "properties": { - "key": { - "type": "string", - "description": "The attribute key to filter on" - }, - "op": { - "$ref": "#/components/schemas/QueryConditionOp", - "description": "The comparison operator to apply" - }, - "value": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ], - "description": "The value to compare against" - } - }, - "additionalProperties": false, - "required": [ - "key", - "op", - "value" - ], - "title": "QueryCondition", - "description": "A condition for filtering query results." - }, - "QueryConditionOp": { - "type": "string", - "enum": [ - "eq", - "ne", - "gt", - "lt" - ], - "title": "QueryConditionOp", - "description": "Comparison operators for query conditions." - }, - "QuerySpansRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the spans." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_return" - ], - "title": "QuerySpansRequest" - }, - "Span": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "Span", - "description": "A span representing a single operation within a trace." - }, - "QuerySpansResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Span" - }, - "description": "List of spans matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpansResponse", - "description": "Response containing a list of spans." - }, - "SaveSpansToDatasetRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_save": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to save to the dataset." - }, - "dataset_id": { - "type": "string", - "description": "The ID of the dataset to save the spans to." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_save", - "dataset_id" - ], - "title": "SaveSpansToDatasetRequest" - }, - "GetSpanTreeRequest": { - "type": "object", - "properties": { - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the tree." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "title": "GetSpanTreeRequest" - }, - "SpanStatus": { - "type": "string", - "enum": [ - "ok", - "error" - ], - "title": "SpanStatus", - "description": "The status of a span indicating whether it completed successfully or with an error." - }, - "SpanWithStatus": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - }, - "status": { - "$ref": "#/components/schemas/SpanStatus", - "description": "(Optional) The current status of the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "SpanWithStatus", - "description": "A span that includes status information." - }, - "QuerySpanTreeResponse": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/SpanWithStatus" - }, - "description": "Dictionary mapping span IDs to spans with status information" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpanTreeResponse", - "description": "Response containing a tree structure of spans." - }, - "QueryTracesRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the traces." - }, - "limit": { - "type": "integer", - "description": "The limit of traces to return." - }, - "offset": { - "type": "integer", - "description": "The offset of the traces to return." - }, - "order_by": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The order by of the traces to return." - } - }, - "additionalProperties": false, - "title": "QueryTracesRequest" - }, - "Trace": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace" - }, - "root_span_id": { - "type": "string", - "description": "Unique identifier for the root span that started this trace" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the trace began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the trace finished, if completed" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "root_span_id", - "start_time" - ], - "title": "Trace", - "description": "A trace representing the complete execution path of a request across multiple operations." - }, - "QueryTracesResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Trace" - }, - "description": "List of traces matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryTracesResponse", - "description": "Response containing a list of traces." } }, "responses": { @@ -14344,10 +13452,6 @@ "description": "OpenAI-compatible Moderations API.", "x-displayName": "Safety" }, - { - "name": "Telemetry", - "description": "" - }, { "name": "VectorIO", "description": "" @@ -14367,7 +13471,6 @@ "Models", "PostTraining (Coming Soon)", "Safety", - "Telemetry", "VectorIO" ] } diff --git a/docs/static/deprecated-llama-stack-spec.yaml b/docs/static/deprecated-llama-stack-spec.yaml index ffdfd8bc7..ef388e5d1 100644 --- a/docs/static/deprecated-llama-stack-spec.yaml +++ b/docs/static/deprecated-llama-stack-spec.yaml @@ -2600,238 +2600,6 @@ paths: $ref: '#/components/schemas/SupervisedFineTuneRequest' required: true deprecated: true - /v1/telemetry/metrics/{metric_name}: - post: - responses: - '200': - description: A QueryMetricsResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query metrics. - description: Query metrics. - parameters: - - name: metric_name - in: path - description: The name of the metric to query. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsRequest' - required: true - deprecated: true - /v1/telemetry/spans: - post: - responses: - '200': - description: A QuerySpansResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query spans. - description: Query spans. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansRequest' - required: true - deprecated: true - /v1/telemetry/spans/export: - post: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Save spans to a dataset. - description: Save spans to a dataset. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SaveSpansToDatasetRequest' - required: true - deprecated: true - /v1/telemetry/spans/{span_id}/tree: - post: - responses: - '200': - description: A QuerySpanTreeResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpanTreeResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span tree by its ID. - description: Get a span tree by its ID. - parameters: - - name: span_id - in: path - description: The ID of the span to get the tree from. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/GetSpanTreeRequest' - required: true - deprecated: true - /v1/telemetry/traces: - post: - responses: - '200': - description: A QueryTracesResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query traces. - description: Query traces. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesRequest' - required: true - deprecated: true - /v1/telemetry/traces/{trace_id}: - get: - responses: - '200': - description: A Trace. - content: - application/json: - schema: - $ref: '#/components/schemas/Trace' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a trace by its ID. - description: Get a trace by its ID. - parameters: - - name: trace_id - in: path - description: The ID of the trace to get. - required: true - schema: - type: string - deprecated: true - /v1/telemetry/traces/{trace_id}/spans/{span_id}: - get: - responses: - '200': - description: A Span. - content: - application/json: - schema: - $ref: '#/components/schemas/Span' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span by its ID. - description: Get a span by its ID. - parameters: - - name: trace_id - in: path - description: >- - The ID of the trace to get the span from. - required: true - schema: - type: string - - name: span_id - in: path - description: The ID of the span to get. - required: true - schema: - type: string - deprecated: true jsonSchemaDialect: >- https://json-schema.org/draft/2020-12/schema components: @@ -10341,434 +10109,6 @@ components: - hyperparam_search_config - logger_config title: SupervisedFineTuneRequest - QueryMetricsRequest: - type: object - properties: - start_time: - type: integer - description: The start time of the metric to query. - end_time: - type: integer - description: The end time of the metric to query. - granularity: - type: string - description: The granularity of the metric to query. - query_type: - type: string - enum: - - range - - instant - description: The type of query to perform. - label_matchers: - type: array - items: - type: object - properties: - name: - type: string - description: The name of the label to match - value: - type: string - description: The value to match against - operator: - type: string - enum: - - '=' - - '!=' - - =~ - - '!~' - description: >- - The comparison operator to use for matching - default: '=' - additionalProperties: false - required: - - name - - value - - operator - title: MetricLabelMatcher - description: >- - A matcher for filtering metrics by label values. - description: >- - The label matchers to apply to the metric. - additionalProperties: false - required: - - start_time - - query_type - title: QueryMetricsRequest - MetricDataPoint: - type: object - properties: - timestamp: - type: integer - description: >- - Unix timestamp when the metric value was recorded - value: - type: number - description: >- - The numeric value of the metric at this timestamp - unit: - type: string - additionalProperties: false - required: - - timestamp - - value - - unit - title: MetricDataPoint - description: >- - A single data point in a metric time series. - MetricLabel: - type: object - properties: - name: - type: string - description: The name of the label - value: - type: string - description: The value of the label - additionalProperties: false - required: - - name - - value - title: MetricLabel - description: A label associated with a metric. - MetricSeries: - type: object - properties: - metric: - type: string - description: The name of the metric - labels: - type: array - items: - $ref: '#/components/schemas/MetricLabel' - description: >- - List of labels associated with this metric series - values: - type: array - items: - $ref: '#/components/schemas/MetricDataPoint' - description: >- - List of data points in chronological order - additionalProperties: false - required: - - metric - - labels - - values - title: MetricSeries - description: A time series of metric data points. - QueryMetricsResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/MetricSeries' - description: >- - List of metric series matching the query criteria - additionalProperties: false - required: - - data - title: QueryMetricsResponse - description: >- - Response containing metric time series data. - QueryCondition: - type: object - properties: - key: - type: string - description: The attribute key to filter on - op: - $ref: '#/components/schemas/QueryConditionOp' - description: The comparison operator to apply - value: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: The value to compare against - additionalProperties: false - required: - - key - - op - - value - title: QueryCondition - description: A condition for filtering query results. - QueryConditionOp: - type: string - enum: - - eq - - ne - - gt - - lt - title: QueryConditionOp - description: >- - Comparison operators for query conditions. - QuerySpansRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the spans. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_return - title: QuerySpansRequest - Span: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: Span - description: >- - A span representing a single operation within a trace. - QuerySpansResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Span' - description: >- - List of spans matching the query criteria - additionalProperties: false - required: - - data - title: QuerySpansResponse - description: Response containing a list of spans. - SaveSpansToDatasetRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_save: - type: array - items: - type: string - description: The attributes to save to the dataset. - dataset_id: - type: string - description: >- - The ID of the dataset to save the spans to. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_save - - dataset_id - title: SaveSpansToDatasetRequest - GetSpanTreeRequest: - type: object - properties: - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the tree. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - title: GetSpanTreeRequest - SpanStatus: - type: string - enum: - - ok - - error - title: SpanStatus - description: >- - The status of a span indicating whether it completed successfully or with - an error. - SpanWithStatus: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - status: - $ref: '#/components/schemas/SpanStatus' - description: >- - (Optional) The current status of the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: SpanWithStatus - description: A span that includes status information. - QuerySpanTreeResponse: - type: object - properties: - data: - type: object - additionalProperties: - $ref: '#/components/schemas/SpanWithStatus' - description: >- - Dictionary mapping span IDs to spans with status information - additionalProperties: false - required: - - data - title: QuerySpanTreeResponse - description: >- - Response containing a tree structure of spans. - QueryTracesRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the traces. - limit: - type: integer - description: The limit of traces to return. - offset: - type: integer - description: The offset of the traces to return. - order_by: - type: array - items: - type: string - description: The order by of the traces to return. - additionalProperties: false - title: QueryTracesRequest - Trace: - type: object - properties: - trace_id: - type: string - description: Unique identifier for the trace - root_span_id: - type: string - description: >- - Unique identifier for the root span that started this trace - start_time: - type: string - format: date-time - description: Timestamp when the trace began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the trace finished, if completed - additionalProperties: false - required: - - trace_id - - root_span_id - - start_time - title: Trace - description: >- - A trace representing the complete execution path of a request across multiple - operations. - QueryTracesResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Trace' - description: >- - List of traces matching the query criteria - additionalProperties: false - required: - - data - title: QueryTracesResponse - description: Response containing a list of traces. responses: BadRequest400: description: The request was invalid or malformed @@ -10874,8 +10214,6 @@ tags: - name: Safety description: OpenAI-compatible Moderations API. x-displayName: Safety - - name: Telemetry - description: '' - name: VectorIO description: '' x-tagGroups: @@ -10891,5 +10229,4 @@ x-tagGroups: - Models - PostTraining (Coming Soon) - Safety - - Telemetry - VectorIO diff --git a/docs/static/experimental-llama-stack-spec.html b/docs/static/experimental-llama-stack-spec.html index a84226c05..e3edf2ffc 100644 --- a/docs/static/experimental-llama-stack-spec.html +++ b/docs/static/experimental-llama-stack-spec.html @@ -1711,343 +1711,6 @@ }, "deprecated": false } - }, - "/v1alpha/telemetry/metrics/{metric_name}": { - "post": { - "responses": { - "200": { - "description": "A QueryMetricsResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query metrics.", - "description": "Query metrics.", - "parameters": [ - { - "name": "metric_name", - "in": "path", - "description": "The name of the metric to query.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans": { - "post": { - "responses": { - "200": { - "description": "A QuerySpansResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query spans.", - "description": "Query spans.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans/export": { - "post": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Save spans to a dataset.", - "description": "Save spans to a dataset.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SaveSpansToDatasetRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans/{span_id}/tree": { - "post": { - "responses": { - "200": { - "description": "A QuerySpanTreeResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpanTreeResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span tree by its ID.", - "description": "Get a span tree by its ID.", - "parameters": [ - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get the tree from.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetSpanTreeRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/traces": { - "post": { - "responses": { - "200": { - "description": "A QueryTracesResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query traces.", - "description": "Query traces.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/traces/{trace_id}": { - "get": { - "responses": { - "200": { - "description": "A Trace.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Trace" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a trace by its ID.", - "description": "Get a trace by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": false - } - }, - "/v1alpha/telemetry/traces/{trace_id}/spans/{span_id}": { - "get": { - "responses": { - "200": { - "description": "A Span.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Span" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span by its ID.", - "description": "Get a span by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get the span from.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": false - } } }, "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", @@ -5765,561 +5428,6 @@ "logger_config" ], "title": "SupervisedFineTuneRequest" - }, - "QueryMetricsRequest": { - "type": "object", - "properties": { - "start_time": { - "type": "integer", - "description": "The start time of the metric to query." - }, - "end_time": { - "type": "integer", - "description": "The end time of the metric to query." - }, - "granularity": { - "type": "string", - "description": "The granularity of the metric to query." - }, - "query_type": { - "type": "string", - "enum": [ - "range", - "instant" - ], - "description": "The type of query to perform." - }, - "label_matchers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label to match" - }, - "value": { - "type": "string", - "description": "The value to match against" - }, - "operator": { - "type": "string", - "enum": [ - "=", - "!=", - "=~", - "!~" - ], - "description": "The comparison operator to use for matching", - "default": "=" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value", - "operator" - ], - "title": "MetricLabelMatcher", - "description": "A matcher for filtering metrics by label values." - }, - "description": "The label matchers to apply to the metric." - } - }, - "additionalProperties": false, - "required": [ - "start_time", - "query_type" - ], - "title": "QueryMetricsRequest" - }, - "MetricDataPoint": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer", - "description": "Unix timestamp when the metric value was recorded" - }, - "value": { - "type": "number", - "description": "The numeric value of the metric at this timestamp" - }, - "unit": { - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "timestamp", - "value", - "unit" - ], - "title": "MetricDataPoint", - "description": "A single data point in a metric time series." - }, - "MetricLabel": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label" - }, - "value": { - "type": "string", - "description": "The value of the label" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value" - ], - "title": "MetricLabel", - "description": "A label associated with a metric." - }, - "MetricSeries": { - "type": "object", - "properties": { - "metric": { - "type": "string", - "description": "The name of the metric" - }, - "labels": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricLabel" - }, - "description": "List of labels associated with this metric series" - }, - "values": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricDataPoint" - }, - "description": "List of data points in chronological order" - } - }, - "additionalProperties": false, - "required": [ - "metric", - "labels", - "values" - ], - "title": "MetricSeries", - "description": "A time series of metric data points." - }, - "QueryMetricsResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricSeries" - }, - "description": "List of metric series matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryMetricsResponse", - "description": "Response containing metric time series data." - }, - "QueryCondition": { - "type": "object", - "properties": { - "key": { - "type": "string", - "description": "The attribute key to filter on" - }, - "op": { - "$ref": "#/components/schemas/QueryConditionOp", - "description": "The comparison operator to apply" - }, - "value": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ], - "description": "The value to compare against" - } - }, - "additionalProperties": false, - "required": [ - "key", - "op", - "value" - ], - "title": "QueryCondition", - "description": "A condition for filtering query results." - }, - "QueryConditionOp": { - "type": "string", - "enum": [ - "eq", - "ne", - "gt", - "lt" - ], - "title": "QueryConditionOp", - "description": "Comparison operators for query conditions." - }, - "QuerySpansRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the spans." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_return" - ], - "title": "QuerySpansRequest" - }, - "Span": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "Span", - "description": "A span representing a single operation within a trace." - }, - "QuerySpansResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Span" - }, - "description": "List of spans matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpansResponse", - "description": "Response containing a list of spans." - }, - "SaveSpansToDatasetRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_save": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to save to the dataset." - }, - "dataset_id": { - "type": "string", - "description": "The ID of the dataset to save the spans to." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_save", - "dataset_id" - ], - "title": "SaveSpansToDatasetRequest" - }, - "GetSpanTreeRequest": { - "type": "object", - "properties": { - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the tree." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "title": "GetSpanTreeRequest" - }, - "SpanStatus": { - "type": "string", - "enum": [ - "ok", - "error" - ], - "title": "SpanStatus", - "description": "The status of a span indicating whether it completed successfully or with an error." - }, - "SpanWithStatus": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - }, - "status": { - "$ref": "#/components/schemas/SpanStatus", - "description": "(Optional) The current status of the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "SpanWithStatus", - "description": "A span that includes status information." - }, - "QuerySpanTreeResponse": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/SpanWithStatus" - }, - "description": "Dictionary mapping span IDs to spans with status information" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpanTreeResponse", - "description": "Response containing a tree structure of spans." - }, - "QueryTracesRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the traces." - }, - "limit": { - "type": "integer", - "description": "The limit of traces to return." - }, - "offset": { - "type": "integer", - "description": "The offset of the traces to return." - }, - "order_by": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The order by of the traces to return." - } - }, - "additionalProperties": false, - "title": "QueryTracesRequest" - }, - "Trace": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace" - }, - "root_span_id": { - "type": "string", - "description": "Unique identifier for the root span that started this trace" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the trace began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the trace finished, if completed" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "root_span_id", - "start_time" - ], - "title": "Trace", - "description": "A trace representing the complete execution path of a request across multiple operations." - }, - "QueryTracesResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Trace" - }, - "description": "List of traces matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryTracesResponse", - "description": "Response containing a list of traces." } }, "responses": { @@ -6416,10 +5524,6 @@ { "name": "PostTraining (Coming Soon)", "description": "" - }, - { - "name": "Telemetry", - "description": "" } ], "x-tagGroups": [ @@ -6431,8 +5535,7 @@ "DatasetIO", "Datasets", "Eval", - "PostTraining (Coming Soon)", - "Telemetry" + "PostTraining (Coming Soon)" ] } ] diff --git a/docs/static/experimental-llama-stack-spec.yaml b/docs/static/experimental-llama-stack-spec.yaml index a08c0cc87..7ee5a6cdf 100644 --- a/docs/static/experimental-llama-stack-spec.yaml +++ b/docs/static/experimental-llama-stack-spec.yaml @@ -1224,238 +1224,6 @@ paths: $ref: '#/components/schemas/SupervisedFineTuneRequest' required: true deprecated: false - /v1alpha/telemetry/metrics/{metric_name}: - post: - responses: - '200': - description: A QueryMetricsResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query metrics. - description: Query metrics. - parameters: - - name: metric_name - in: path - description: The name of the metric to query. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans: - post: - responses: - '200': - description: A QuerySpansResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query spans. - description: Query spans. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans/export: - post: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Save spans to a dataset. - description: Save spans to a dataset. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SaveSpansToDatasetRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans/{span_id}/tree: - post: - responses: - '200': - description: A QuerySpanTreeResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpanTreeResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span tree by its ID. - description: Get a span tree by its ID. - parameters: - - name: span_id - in: path - description: The ID of the span to get the tree from. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/GetSpanTreeRequest' - required: true - deprecated: false - /v1alpha/telemetry/traces: - post: - responses: - '200': - description: A QueryTracesResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query traces. - description: Query traces. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesRequest' - required: true - deprecated: false - /v1alpha/telemetry/traces/{trace_id}: - get: - responses: - '200': - description: A Trace. - content: - application/json: - schema: - $ref: '#/components/schemas/Trace' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a trace by its ID. - description: Get a trace by its ID. - parameters: - - name: trace_id - in: path - description: The ID of the trace to get. - required: true - schema: - type: string - deprecated: false - /v1alpha/telemetry/traces/{trace_id}/spans/{span_id}: - get: - responses: - '200': - description: A Span. - content: - application/json: - schema: - $ref: '#/components/schemas/Span' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span by its ID. - description: Get a span by its ID. - parameters: - - name: trace_id - in: path - description: >- - The ID of the trace to get the span from. - required: true - schema: - type: string - - name: span_id - in: path - description: The ID of the span to get. - required: true - schema: - type: string - deprecated: false jsonSchemaDialect: >- https://json-schema.org/draft/2020-12/schema components: @@ -4249,434 +4017,6 @@ components: - hyperparam_search_config - logger_config title: SupervisedFineTuneRequest - QueryMetricsRequest: - type: object - properties: - start_time: - type: integer - description: The start time of the metric to query. - end_time: - type: integer - description: The end time of the metric to query. - granularity: - type: string - description: The granularity of the metric to query. - query_type: - type: string - enum: - - range - - instant - description: The type of query to perform. - label_matchers: - type: array - items: - type: object - properties: - name: - type: string - description: The name of the label to match - value: - type: string - description: The value to match against - operator: - type: string - enum: - - '=' - - '!=' - - =~ - - '!~' - description: >- - The comparison operator to use for matching - default: '=' - additionalProperties: false - required: - - name - - value - - operator - title: MetricLabelMatcher - description: >- - A matcher for filtering metrics by label values. - description: >- - The label matchers to apply to the metric. - additionalProperties: false - required: - - start_time - - query_type - title: QueryMetricsRequest - MetricDataPoint: - type: object - properties: - timestamp: - type: integer - description: >- - Unix timestamp when the metric value was recorded - value: - type: number - description: >- - The numeric value of the metric at this timestamp - unit: - type: string - additionalProperties: false - required: - - timestamp - - value - - unit - title: MetricDataPoint - description: >- - A single data point in a metric time series. - MetricLabel: - type: object - properties: - name: - type: string - description: The name of the label - value: - type: string - description: The value of the label - additionalProperties: false - required: - - name - - value - title: MetricLabel - description: A label associated with a metric. - MetricSeries: - type: object - properties: - metric: - type: string - description: The name of the metric - labels: - type: array - items: - $ref: '#/components/schemas/MetricLabel' - description: >- - List of labels associated with this metric series - values: - type: array - items: - $ref: '#/components/schemas/MetricDataPoint' - description: >- - List of data points in chronological order - additionalProperties: false - required: - - metric - - labels - - values - title: MetricSeries - description: A time series of metric data points. - QueryMetricsResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/MetricSeries' - description: >- - List of metric series matching the query criteria - additionalProperties: false - required: - - data - title: QueryMetricsResponse - description: >- - Response containing metric time series data. - QueryCondition: - type: object - properties: - key: - type: string - description: The attribute key to filter on - op: - $ref: '#/components/schemas/QueryConditionOp' - description: The comparison operator to apply - value: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: The value to compare against - additionalProperties: false - required: - - key - - op - - value - title: QueryCondition - description: A condition for filtering query results. - QueryConditionOp: - type: string - enum: - - eq - - ne - - gt - - lt - title: QueryConditionOp - description: >- - Comparison operators for query conditions. - QuerySpansRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the spans. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_return - title: QuerySpansRequest - Span: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: Span - description: >- - A span representing a single operation within a trace. - QuerySpansResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Span' - description: >- - List of spans matching the query criteria - additionalProperties: false - required: - - data - title: QuerySpansResponse - description: Response containing a list of spans. - SaveSpansToDatasetRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_save: - type: array - items: - type: string - description: The attributes to save to the dataset. - dataset_id: - type: string - description: >- - The ID of the dataset to save the spans to. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_save - - dataset_id - title: SaveSpansToDatasetRequest - GetSpanTreeRequest: - type: object - properties: - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the tree. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - title: GetSpanTreeRequest - SpanStatus: - type: string - enum: - - ok - - error - title: SpanStatus - description: >- - The status of a span indicating whether it completed successfully or with - an error. - SpanWithStatus: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - status: - $ref: '#/components/schemas/SpanStatus' - description: >- - (Optional) The current status of the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: SpanWithStatus - description: A span that includes status information. - QuerySpanTreeResponse: - type: object - properties: - data: - type: object - additionalProperties: - $ref: '#/components/schemas/SpanWithStatus' - description: >- - Dictionary mapping span IDs to spans with status information - additionalProperties: false - required: - - data - title: QuerySpanTreeResponse - description: >- - Response containing a tree structure of spans. - QueryTracesRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the traces. - limit: - type: integer - description: The limit of traces to return. - offset: - type: integer - description: The offset of the traces to return. - order_by: - type: array - items: - type: string - description: The order by of the traces to return. - additionalProperties: false - title: QueryTracesRequest - Trace: - type: object - properties: - trace_id: - type: string - description: Unique identifier for the trace - root_span_id: - type: string - description: >- - Unique identifier for the root span that started this trace - start_time: - type: string - format: date-time - description: Timestamp when the trace began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the trace finished, if completed - additionalProperties: false - required: - - trace_id - - root_span_id - - start_time - title: Trace - description: >- - A trace representing the complete execution path of a request across multiple - operations. - QueryTracesResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Trace' - description: >- - List of traces matching the query criteria - additionalProperties: false - required: - - data - title: QueryTracesResponse - description: Response containing a list of traces. responses: BadRequest400: description: The request was invalid or malformed @@ -4784,8 +4124,6 @@ tags: Llama Stack Evaluation API for running evaluations on model and agent candidates. - name: PostTraining (Coming Soon) description: '' - - name: Telemetry - description: '' x-tagGroups: - name: Operations tags: @@ -4795,4 +4133,3 @@ x-tagGroups: - Datasets - Eval - PostTraining (Coming Soon) - - Telemetry diff --git a/docs/static/llama-stack-spec.html b/docs/static/llama-stack-spec.html index 24e88b5f6..9887a5778 100644 --- a/docs/static/llama-stack-spec.html +++ b/docs/static/llama-stack-spec.html @@ -2525,44 +2525,6 @@ "deprecated": false } }, - "/v1/telemetry/events": { - "post": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Log an event.", - "description": "Log an event.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LogEventRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, "/v1/tool-runtime/invoke": { "post": { "responses": { @@ -11172,354 +11134,6 @@ "title": "SyntheticDataGenerationResponse", "description": "Response from the synthetic data generation. Batch of (prompt, response, score) tuples that pass the threshold." }, - "Event": { - "oneOf": [ - { - "$ref": "#/components/schemas/UnstructuredLogEvent" - }, - { - "$ref": "#/components/schemas/MetricEvent" - }, - { - "$ref": "#/components/schemas/StructuredLogEvent" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "unstructured_log": "#/components/schemas/UnstructuredLogEvent", - "metric": "#/components/schemas/MetricEvent", - "structured_log": "#/components/schemas/StructuredLogEvent" - } - } - }, - "EventType": { - "type": "string", - "enum": [ - "unstructured_log", - "structured_log", - "metric" - ], - "title": "EventType", - "description": "The type of telemetry event being logged." - }, - "LogSeverity": { - "type": "string", - "enum": [ - "verbose", - "debug", - "info", - "warn", - "error", - "critical" - ], - "title": "LogSeverity", - "description": "The severity level of a log message." - }, - "MetricEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "metric", - "default": "metric", - "description": "Event type identifier set to METRIC" - }, - "metric": { - "type": "string", - "description": "The name of the metric being measured" - }, - "value": { - "oneOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ], - "description": "The numeric value of the metric measurement" - }, - "unit": { - "type": "string", - "description": "The unit of measurement for the metric value" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "metric", - "value", - "unit" - ], - "title": "MetricEvent", - "description": "A metric event containing a measured value." - }, - "SpanEndPayload": { - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/StructuredLogType", - "const": "span_end", - "default": "span_end", - "description": "Payload type identifier set to SPAN_END" - }, - "status": { - "$ref": "#/components/schemas/SpanStatus", - "description": "The final status of the span indicating success or failure" - } - }, - "additionalProperties": false, - "required": [ - "type", - "status" - ], - "title": "SpanEndPayload", - "description": "Payload for a span end event." - }, - "SpanStartPayload": { - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/StructuredLogType", - "const": "span_start", - "default": "span_start", - "description": "Payload type identifier set to SPAN_START" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - } - }, - "additionalProperties": false, - "required": [ - "type", - "name" - ], - "title": "SpanStartPayload", - "description": "Payload for a span start event." - }, - "SpanStatus": { - "type": "string", - "enum": [ - "ok", - "error" - ], - "title": "SpanStatus", - "description": "The status of a span indicating whether it completed successfully or with an error." - }, - "StructuredLogEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "structured_log", - "default": "structured_log", - "description": "Event type identifier set to STRUCTURED_LOG" - }, - "payload": { - "oneOf": [ - { - "$ref": "#/components/schemas/SpanStartPayload" - }, - { - "$ref": "#/components/schemas/SpanEndPayload" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "span_start": "#/components/schemas/SpanStartPayload", - "span_end": "#/components/schemas/SpanEndPayload" - } - }, - "description": "The structured payload data for the log event" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "payload" - ], - "title": "StructuredLogEvent", - "description": "A structured log event containing typed payload data." - }, - "StructuredLogType": { - "type": "string", - "enum": [ - "span_start", - "span_end" - ], - "title": "StructuredLogType", - "description": "The type of structured log event payload." - }, - "UnstructuredLogEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "unstructured_log", - "default": "unstructured_log", - "description": "Event type identifier set to UNSTRUCTURED_LOG" - }, - "message": { - "type": "string", - "description": "The log message text" - }, - "severity": { - "$ref": "#/components/schemas/LogSeverity", - "description": "The severity level of the log message" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "message", - "severity" - ], - "title": "UnstructuredLogEvent", - "description": "An unstructured log event containing a simple text message." - }, - "LogEventRequest": { - "type": "object", - "properties": { - "event": { - "$ref": "#/components/schemas/Event", - "description": "The event to log." - }, - "ttl_seconds": { - "type": "integer", - "description": "The time to live of the event." - } - }, - "additionalProperties": false, - "required": [ - "event", - "ttl_seconds" - ], - "title": "LogEventRequest" - }, "InvokeToolRequest": { "type": "object", "properties": { @@ -13655,10 +13269,6 @@ "name": "SyntheticDataGeneration (Coming Soon)", "description": "" }, - { - "name": "Telemetry", - "description": "" - }, { "name": "ToolGroups", "description": "" @@ -13689,7 +13299,6 @@ "ScoringFunctions", "Shields", "SyntheticDataGeneration (Coming Soon)", - "Telemetry", "ToolGroups", "ToolRuntime", "VectorIO" diff --git a/docs/static/llama-stack-spec.yaml b/docs/static/llama-stack-spec.yaml index ac1641079..98e5f9cbb 100644 --- a/docs/static/llama-stack-spec.yaml +++ b/docs/static/llama-stack-spec.yaml @@ -1944,33 +1944,6 @@ paths: $ref: '#/components/schemas/SyntheticDataGenerateRequest' required: true deprecated: false - /v1/telemetry/events: - post: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Log an event. - description: Log an event. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/LogEventRequest' - required: true - deprecated: false /v1/tool-runtime/invoke: post: responses: @@ -8565,267 +8538,6 @@ components: description: >- Response from the synthetic data generation. Batch of (prompt, response, score) tuples that pass the threshold. - Event: - oneOf: - - $ref: '#/components/schemas/UnstructuredLogEvent' - - $ref: '#/components/schemas/MetricEvent' - - $ref: '#/components/schemas/StructuredLogEvent' - discriminator: - propertyName: type - mapping: - unstructured_log: '#/components/schemas/UnstructuredLogEvent' - metric: '#/components/schemas/MetricEvent' - structured_log: '#/components/schemas/StructuredLogEvent' - EventType: - type: string - enum: - - unstructured_log - - structured_log - - metric - title: EventType - description: >- - The type of telemetry event being logged. - LogSeverity: - type: string - enum: - - verbose - - debug - - info - - warn - - error - - critical - title: LogSeverity - description: The severity level of a log message. - MetricEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: metric - default: metric - description: Event type identifier set to METRIC - metric: - type: string - description: The name of the metric being measured - value: - oneOf: - - type: integer - - type: number - description: >- - The numeric value of the metric measurement - unit: - type: string - description: >- - The unit of measurement for the metric value - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - metric - - value - - unit - title: MetricEvent - description: >- - A metric event containing a measured value. - SpanEndPayload: - type: object - properties: - type: - $ref: '#/components/schemas/StructuredLogType' - const: span_end - default: span_end - description: Payload type identifier set to SPAN_END - status: - $ref: '#/components/schemas/SpanStatus' - description: >- - The final status of the span indicating success or failure - additionalProperties: false - required: - - type - - status - title: SpanEndPayload - description: Payload for a span end event. - SpanStartPayload: - type: object - properties: - type: - $ref: '#/components/schemas/StructuredLogType' - const: span_start - default: span_start - description: >- - Payload type identifier set to SPAN_START - name: - type: string - description: >- - Human-readable name describing the operation this span represents - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - additionalProperties: false - required: - - type - - name - title: SpanStartPayload - description: Payload for a span start event. - SpanStatus: - type: string - enum: - - ok - - error - title: SpanStatus - description: >- - The status of a span indicating whether it completed successfully or with - an error. - StructuredLogEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: structured_log - default: structured_log - description: >- - Event type identifier set to STRUCTURED_LOG - payload: - oneOf: - - $ref: '#/components/schemas/SpanStartPayload' - - $ref: '#/components/schemas/SpanEndPayload' - discriminator: - propertyName: type - mapping: - span_start: '#/components/schemas/SpanStartPayload' - span_end: '#/components/schemas/SpanEndPayload' - description: >- - The structured payload data for the log event - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - payload - title: StructuredLogEvent - description: >- - A structured log event containing typed payload data. - StructuredLogType: - type: string - enum: - - span_start - - span_end - title: StructuredLogType - description: >- - The type of structured log event payload. - UnstructuredLogEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: unstructured_log - default: unstructured_log - description: >- - Event type identifier set to UNSTRUCTURED_LOG - message: - type: string - description: The log message text - severity: - $ref: '#/components/schemas/LogSeverity' - description: The severity level of the log message - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - message - - severity - title: UnstructuredLogEvent - description: >- - An unstructured log event containing a simple text message. - LogEventRequest: - type: object - properties: - event: - $ref: '#/components/schemas/Event' - description: The event to log. - ttl_seconds: - type: integer - description: The time to live of the event. - additionalProperties: false - required: - - event - - ttl_seconds - title: LogEventRequest InvokeToolRequest: type: object properties: @@ -10465,8 +10177,6 @@ tags: description: '' - name: SyntheticDataGeneration (Coming Soon) description: '' - - name: Telemetry - description: '' - name: ToolGroups description: '' - name: ToolRuntime @@ -10489,7 +10199,6 @@ x-tagGroups: - ScoringFunctions - Shields - SyntheticDataGeneration (Coming Soon) - - Telemetry - ToolGroups - ToolRuntime - VectorIO diff --git a/docs/static/stainless-llama-stack-spec.html b/docs/static/stainless-llama-stack-spec.html index 4184f1379..932d9fd96 100644 --- a/docs/static/stainless-llama-stack-spec.html +++ b/docs/static/stainless-llama-stack-spec.html @@ -2525,44 +2525,6 @@ "deprecated": false } }, - "/v1/telemetry/events": { - "post": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Log an event.", - "description": "Log an event.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LogEventRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, "/v1/tool-runtime/invoke": { "post": { "responses": { @@ -5714,343 +5676,6 @@ }, "deprecated": false } - }, - "/v1alpha/telemetry/metrics/{metric_name}": { - "post": { - "responses": { - "200": { - "description": "A QueryMetricsResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query metrics.", - "description": "Query metrics.", - "parameters": [ - { - "name": "metric_name", - "in": "path", - "description": "The name of the metric to query.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryMetricsRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans": { - "post": { - "responses": { - "200": { - "description": "A QuerySpansResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query spans.", - "description": "Query spans.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpansRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans/export": { - "post": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Save spans to a dataset.", - "description": "Save spans to a dataset.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SaveSpansToDatasetRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/spans/{span_id}/tree": { - "post": { - "responses": { - "200": { - "description": "A QuerySpanTreeResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuerySpanTreeResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span tree by its ID.", - "description": "Get a span tree by its ID.", - "parameters": [ - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get the tree from.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetSpanTreeRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/traces": { - "post": { - "responses": { - "200": { - "description": "A QueryTracesResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Query traces.", - "description": "Query traces.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTracesRequest" - } - } - }, - "required": true - }, - "deprecated": false - } - }, - "/v1alpha/telemetry/traces/{trace_id}": { - "get": { - "responses": { - "200": { - "description": "A Trace.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Trace" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a trace by its ID.", - "description": "Get a trace by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": false - } - }, - "/v1alpha/telemetry/traces/{trace_id}/spans/{span_id}": { - "get": { - "responses": { - "200": { - "description": "A Span.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Span" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Telemetry" - ], - "summary": "Get a span by its ID.", - "description": "Get a span by its ID.", - "parameters": [ - { - "name": "trace_id", - "in": "path", - "description": "The ID of the trace to get the span from.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "span_id", - "in": "path", - "description": "The ID of the span to get.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "deprecated": false - } } }, "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", @@ -13181,354 +12806,6 @@ "title": "SyntheticDataGenerationResponse", "description": "Response from the synthetic data generation. Batch of (prompt, response, score) tuples that pass the threshold." }, - "Event": { - "oneOf": [ - { - "$ref": "#/components/schemas/UnstructuredLogEvent" - }, - { - "$ref": "#/components/schemas/MetricEvent" - }, - { - "$ref": "#/components/schemas/StructuredLogEvent" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "unstructured_log": "#/components/schemas/UnstructuredLogEvent", - "metric": "#/components/schemas/MetricEvent", - "structured_log": "#/components/schemas/StructuredLogEvent" - } - } - }, - "EventType": { - "type": "string", - "enum": [ - "unstructured_log", - "structured_log", - "metric" - ], - "title": "EventType", - "description": "The type of telemetry event being logged." - }, - "LogSeverity": { - "type": "string", - "enum": [ - "verbose", - "debug", - "info", - "warn", - "error", - "critical" - ], - "title": "LogSeverity", - "description": "The severity level of a log message." - }, - "MetricEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "metric", - "default": "metric", - "description": "Event type identifier set to METRIC" - }, - "metric": { - "type": "string", - "description": "The name of the metric being measured" - }, - "value": { - "oneOf": [ - { - "type": "integer" - }, - { - "type": "number" - } - ], - "description": "The numeric value of the metric measurement" - }, - "unit": { - "type": "string", - "description": "The unit of measurement for the metric value" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "metric", - "value", - "unit" - ], - "title": "MetricEvent", - "description": "A metric event containing a measured value." - }, - "SpanEndPayload": { - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/StructuredLogType", - "const": "span_end", - "default": "span_end", - "description": "Payload type identifier set to SPAN_END" - }, - "status": { - "$ref": "#/components/schemas/SpanStatus", - "description": "The final status of the span indicating success or failure" - } - }, - "additionalProperties": false, - "required": [ - "type", - "status" - ], - "title": "SpanEndPayload", - "description": "Payload for a span end event." - }, - "SpanStartPayload": { - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/StructuredLogType", - "const": "span_start", - "default": "span_start", - "description": "Payload type identifier set to SPAN_START" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - } - }, - "additionalProperties": false, - "required": [ - "type", - "name" - ], - "title": "SpanStartPayload", - "description": "Payload for a span start event." - }, - "SpanStatus": { - "type": "string", - "enum": [ - "ok", - "error" - ], - "title": "SpanStatus", - "description": "The status of a span indicating whether it completed successfully or with an error." - }, - "StructuredLogEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "structured_log", - "default": "structured_log", - "description": "Event type identifier set to STRUCTURED_LOG" - }, - "payload": { - "oneOf": [ - { - "$ref": "#/components/schemas/SpanStartPayload" - }, - { - "$ref": "#/components/schemas/SpanEndPayload" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "span_start": "#/components/schemas/SpanStartPayload", - "span_end": "#/components/schemas/SpanEndPayload" - } - }, - "description": "The structured payload data for the log event" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "payload" - ], - "title": "StructuredLogEvent", - "description": "A structured log event containing typed payload data." - }, - "StructuredLogType": { - "type": "string", - "enum": [ - "span_start", - "span_end" - ], - "title": "StructuredLogType", - "description": "The type of structured log event payload." - }, - "UnstructuredLogEvent": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this event belongs to" - }, - "span_id": { - "type": "string", - "description": "Unique identifier for the span this event belongs to" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the event occurred" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the event" - }, - "type": { - "$ref": "#/components/schemas/EventType", - "const": "unstructured_log", - "default": "unstructured_log", - "description": "Event type identifier set to UNSTRUCTURED_LOG" - }, - "message": { - "type": "string", - "description": "The log message text" - }, - "severity": { - "$ref": "#/components/schemas/LogSeverity", - "description": "The severity level of the log message" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "span_id", - "timestamp", - "type", - "message", - "severity" - ], - "title": "UnstructuredLogEvent", - "description": "An unstructured log event containing a simple text message." - }, - "LogEventRequest": { - "type": "object", - "properties": { - "event": { - "$ref": "#/components/schemas/Event", - "description": "The event to log." - }, - "ttl_seconds": { - "type": "integer", - "description": "The time to live of the event." - } - }, - "additionalProperties": false, - "required": [ - "event", - "ttl_seconds" - ], - "title": "LogEventRequest" - }, "InvokeToolRequest": { "type": "object", "properties": { @@ -18534,552 +17811,6 @@ "logger_config" ], "title": "SupervisedFineTuneRequest" - }, - "QueryMetricsRequest": { - "type": "object", - "properties": { - "start_time": { - "type": "integer", - "description": "The start time of the metric to query." - }, - "end_time": { - "type": "integer", - "description": "The end time of the metric to query." - }, - "granularity": { - "type": "string", - "description": "The granularity of the metric to query." - }, - "query_type": { - "type": "string", - "enum": [ - "range", - "instant" - ], - "description": "The type of query to perform." - }, - "label_matchers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label to match" - }, - "value": { - "type": "string", - "description": "The value to match against" - }, - "operator": { - "type": "string", - "enum": [ - "=", - "!=", - "=~", - "!~" - ], - "description": "The comparison operator to use for matching", - "default": "=" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value", - "operator" - ], - "title": "MetricLabelMatcher", - "description": "A matcher for filtering metrics by label values." - }, - "description": "The label matchers to apply to the metric." - } - }, - "additionalProperties": false, - "required": [ - "start_time", - "query_type" - ], - "title": "QueryMetricsRequest" - }, - "MetricDataPoint": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer", - "description": "Unix timestamp when the metric value was recorded" - }, - "value": { - "type": "number", - "description": "The numeric value of the metric at this timestamp" - }, - "unit": { - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "timestamp", - "value", - "unit" - ], - "title": "MetricDataPoint", - "description": "A single data point in a metric time series." - }, - "MetricLabel": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the label" - }, - "value": { - "type": "string", - "description": "The value of the label" - } - }, - "additionalProperties": false, - "required": [ - "name", - "value" - ], - "title": "MetricLabel", - "description": "A label associated with a metric." - }, - "MetricSeries": { - "type": "object", - "properties": { - "metric": { - "type": "string", - "description": "The name of the metric" - }, - "labels": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricLabel" - }, - "description": "List of labels associated with this metric series" - }, - "values": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricDataPoint" - }, - "description": "List of data points in chronological order" - } - }, - "additionalProperties": false, - "required": [ - "metric", - "labels", - "values" - ], - "title": "MetricSeries", - "description": "A time series of metric data points." - }, - "QueryMetricsResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricSeries" - }, - "description": "List of metric series matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryMetricsResponse", - "description": "Response containing metric time series data." - }, - "QueryCondition": { - "type": "object", - "properties": { - "key": { - "type": "string", - "description": "The attribute key to filter on" - }, - "op": { - "$ref": "#/components/schemas/QueryConditionOp", - "description": "The comparison operator to apply" - }, - "value": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ], - "description": "The value to compare against" - } - }, - "additionalProperties": false, - "required": [ - "key", - "op", - "value" - ], - "title": "QueryCondition", - "description": "A condition for filtering query results." - }, - "QueryConditionOp": { - "type": "string", - "enum": [ - "eq", - "ne", - "gt", - "lt" - ], - "title": "QueryConditionOp", - "description": "Comparison operators for query conditions." - }, - "QuerySpansRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the spans." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_return" - ], - "title": "QuerySpansRequest" - }, - "Span": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "Span", - "description": "A span representing a single operation within a trace." - }, - "QuerySpansResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Span" - }, - "description": "List of spans matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpansResponse", - "description": "Response containing a list of spans." - }, - "SaveSpansToDatasetRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the spans." - }, - "attributes_to_save": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to save to the dataset." - }, - "dataset_id": { - "type": "string", - "description": "The ID of the dataset to save the spans to." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "required": [ - "attribute_filters", - "attributes_to_save", - "dataset_id" - ], - "title": "SaveSpansToDatasetRequest" - }, - "GetSpanTreeRequest": { - "type": "object", - "properties": { - "attributes_to_return": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The attributes to return in the tree." - }, - "max_depth": { - "type": "integer", - "description": "The maximum depth of the tree." - } - }, - "additionalProperties": false, - "title": "GetSpanTreeRequest" - }, - "SpanWithStatus": { - "type": "object", - "properties": { - "span_id": { - "type": "string", - "description": "Unique identifier for the span" - }, - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace this span belongs to" - }, - "parent_span_id": { - "type": "string", - "description": "(Optional) Unique identifier for the parent span, if this is a child span" - }, - "name": { - "type": "string", - "description": "Human-readable name describing the operation this span represents" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the operation began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the operation finished, if completed" - }, - "attributes": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "array" - }, - { - "type": "object" - } - ] - }, - "description": "(Optional) Key-value pairs containing additional metadata about the span" - }, - "status": { - "$ref": "#/components/schemas/SpanStatus", - "description": "(Optional) The current status of the span" - } - }, - "additionalProperties": false, - "required": [ - "span_id", - "trace_id", - "name", - "start_time" - ], - "title": "SpanWithStatus", - "description": "A span that includes status information." - }, - "QuerySpanTreeResponse": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/SpanWithStatus" - }, - "description": "Dictionary mapping span IDs to spans with status information" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QuerySpanTreeResponse", - "description": "Response containing a tree structure of spans." - }, - "QueryTracesRequest": { - "type": "object", - "properties": { - "attribute_filters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QueryCondition" - }, - "description": "The attribute filters to apply to the traces." - }, - "limit": { - "type": "integer", - "description": "The limit of traces to return." - }, - "offset": { - "type": "integer", - "description": "The offset of the traces to return." - }, - "order_by": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The order by of the traces to return." - } - }, - "additionalProperties": false, - "title": "QueryTracesRequest" - }, - "Trace": { - "type": "object", - "properties": { - "trace_id": { - "type": "string", - "description": "Unique identifier for the trace" - }, - "root_span_id": { - "type": "string", - "description": "Unique identifier for the root span that started this trace" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the trace began" - }, - "end_time": { - "type": "string", - "format": "date-time", - "description": "(Optional) Timestamp when the trace finished, if completed" - } - }, - "additionalProperties": false, - "required": [ - "trace_id", - "root_span_id", - "start_time" - ], - "title": "Trace", - "description": "A trace representing the complete execution path of a request across multiple operations." - }, - "QueryTracesResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Trace" - }, - "description": "List of traces matching the query criteria" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "QueryTracesResponse", - "description": "Response containing a list of traces." } }, "responses": { @@ -19232,10 +17963,6 @@ "name": "SyntheticDataGeneration (Coming Soon)", "description": "" }, - { - "name": "Telemetry", - "description": "" - }, { "name": "ToolGroups", "description": "" @@ -19271,7 +17998,6 @@ "ScoringFunctions", "Shields", "SyntheticDataGeneration (Coming Soon)", - "Telemetry", "ToolGroups", "ToolRuntime", "VectorIO" diff --git a/docs/static/stainless-llama-stack-spec.yaml b/docs/static/stainless-llama-stack-spec.yaml index b01779abb..b28b3d8f7 100644 --- a/docs/static/stainless-llama-stack-spec.yaml +++ b/docs/static/stainless-llama-stack-spec.yaml @@ -1947,33 +1947,6 @@ paths: $ref: '#/components/schemas/SyntheticDataGenerateRequest' required: true deprecated: false - /v1/telemetry/events: - post: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Log an event. - description: Log an event. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/LogEventRequest' - required: true - deprecated: false /v1/tool-runtime/invoke: post: responses: @@ -4285,238 +4258,6 @@ paths: $ref: '#/components/schemas/SupervisedFineTuneRequest' required: true deprecated: false - /v1alpha/telemetry/metrics/{metric_name}: - post: - responses: - '200': - description: A QueryMetricsResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query metrics. - description: Query metrics. - parameters: - - name: metric_name - in: path - description: The name of the metric to query. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryMetricsRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans: - post: - responses: - '200': - description: A QuerySpansResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query spans. - description: Query spans. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpansRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans/export: - post: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Save spans to a dataset. - description: Save spans to a dataset. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SaveSpansToDatasetRequest' - required: true - deprecated: false - /v1alpha/telemetry/spans/{span_id}/tree: - post: - responses: - '200': - description: A QuerySpanTreeResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpanTreeResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span tree by its ID. - description: Get a span tree by its ID. - parameters: - - name: span_id - in: path - description: The ID of the span to get the tree from. - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/GetSpanTreeRequest' - required: true - deprecated: false - /v1alpha/telemetry/traces: - post: - responses: - '200': - description: A QueryTracesResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Query traces. - description: Query traces. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryTracesRequest' - required: true - deprecated: false - /v1alpha/telemetry/traces/{trace_id}: - get: - responses: - '200': - description: A Trace. - content: - application/json: - schema: - $ref: '#/components/schemas/Trace' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a trace by its ID. - description: Get a trace by its ID. - parameters: - - name: trace_id - in: path - description: The ID of the trace to get. - required: true - schema: - type: string - deprecated: false - /v1alpha/telemetry/traces/{trace_id}/spans/{span_id}: - get: - responses: - '200': - description: A Span. - content: - application/json: - schema: - $ref: '#/components/schemas/Span' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Telemetry - summary: Get a span by its ID. - description: Get a span by its ID. - parameters: - - name: trace_id - in: path - description: >- - The ID of the trace to get the span from. - required: true - schema: - type: string - - name: span_id - in: path - description: The ID of the span to get. - required: true - schema: - type: string - deprecated: false jsonSchemaDialect: >- https://json-schema.org/draft/2020-12/schema components: @@ -10010,267 +9751,6 @@ components: description: >- Response from the synthetic data generation. Batch of (prompt, response, score) tuples that pass the threshold. - Event: - oneOf: - - $ref: '#/components/schemas/UnstructuredLogEvent' - - $ref: '#/components/schemas/MetricEvent' - - $ref: '#/components/schemas/StructuredLogEvent' - discriminator: - propertyName: type - mapping: - unstructured_log: '#/components/schemas/UnstructuredLogEvent' - metric: '#/components/schemas/MetricEvent' - structured_log: '#/components/schemas/StructuredLogEvent' - EventType: - type: string - enum: - - unstructured_log - - structured_log - - metric - title: EventType - description: >- - The type of telemetry event being logged. - LogSeverity: - type: string - enum: - - verbose - - debug - - info - - warn - - error - - critical - title: LogSeverity - description: The severity level of a log message. - MetricEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: metric - default: metric - description: Event type identifier set to METRIC - metric: - type: string - description: The name of the metric being measured - value: - oneOf: - - type: integer - - type: number - description: >- - The numeric value of the metric measurement - unit: - type: string - description: >- - The unit of measurement for the metric value - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - metric - - value - - unit - title: MetricEvent - description: >- - A metric event containing a measured value. - SpanEndPayload: - type: object - properties: - type: - $ref: '#/components/schemas/StructuredLogType' - const: span_end - default: span_end - description: Payload type identifier set to SPAN_END - status: - $ref: '#/components/schemas/SpanStatus' - description: >- - The final status of the span indicating success or failure - additionalProperties: false - required: - - type - - status - title: SpanEndPayload - description: Payload for a span end event. - SpanStartPayload: - type: object - properties: - type: - $ref: '#/components/schemas/StructuredLogType' - const: span_start - default: span_start - description: >- - Payload type identifier set to SPAN_START - name: - type: string - description: >- - Human-readable name describing the operation this span represents - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - additionalProperties: false - required: - - type - - name - title: SpanStartPayload - description: Payload for a span start event. - SpanStatus: - type: string - enum: - - ok - - error - title: SpanStatus - description: >- - The status of a span indicating whether it completed successfully or with - an error. - StructuredLogEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: structured_log - default: structured_log - description: >- - Event type identifier set to STRUCTURED_LOG - payload: - oneOf: - - $ref: '#/components/schemas/SpanStartPayload' - - $ref: '#/components/schemas/SpanEndPayload' - discriminator: - propertyName: type - mapping: - span_start: '#/components/schemas/SpanStartPayload' - span_end: '#/components/schemas/SpanEndPayload' - description: >- - The structured payload data for the log event - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - payload - title: StructuredLogEvent - description: >- - A structured log event containing typed payload data. - StructuredLogType: - type: string - enum: - - span_start - - span_end - title: StructuredLogType - description: >- - The type of structured log event payload. - UnstructuredLogEvent: - type: object - properties: - trace_id: - type: string - description: >- - Unique identifier for the trace this event belongs to - span_id: - type: string - description: >- - Unique identifier for the span this event belongs to - timestamp: - type: string - format: date-time - description: Timestamp when the event occurred - attributes: - type: object - additionalProperties: - oneOf: - - type: string - - type: integer - - type: number - - type: boolean - - type: 'null' - description: >- - (Optional) Key-value pairs containing additional metadata about the event - type: - $ref: '#/components/schemas/EventType' - const: unstructured_log - default: unstructured_log - description: >- - Event type identifier set to UNSTRUCTURED_LOG - message: - type: string - description: The log message text - severity: - $ref: '#/components/schemas/LogSeverity' - description: The severity level of the log message - additionalProperties: false - required: - - trace_id - - span_id - - timestamp - - type - - message - - severity - title: UnstructuredLogEvent - description: >- - An unstructured log event containing a simple text message. - LogEventRequest: - type: object - properties: - event: - $ref: '#/components/schemas/Event' - description: The event to log. - ttl_seconds: - type: integer - description: The time to live of the event. - additionalProperties: false - required: - - event - - ttl_seconds - title: LogEventRequest InvokeToolRequest: type: object properties: @@ -13981,425 +13461,6 @@ components: - hyperparam_search_config - logger_config title: SupervisedFineTuneRequest - QueryMetricsRequest: - type: object - properties: - start_time: - type: integer - description: The start time of the metric to query. - end_time: - type: integer - description: The end time of the metric to query. - granularity: - type: string - description: The granularity of the metric to query. - query_type: - type: string - enum: - - range - - instant - description: The type of query to perform. - label_matchers: - type: array - items: - type: object - properties: - name: - type: string - description: The name of the label to match - value: - type: string - description: The value to match against - operator: - type: string - enum: - - '=' - - '!=' - - =~ - - '!~' - description: >- - The comparison operator to use for matching - default: '=' - additionalProperties: false - required: - - name - - value - - operator - title: MetricLabelMatcher - description: >- - A matcher for filtering metrics by label values. - description: >- - The label matchers to apply to the metric. - additionalProperties: false - required: - - start_time - - query_type - title: QueryMetricsRequest - MetricDataPoint: - type: object - properties: - timestamp: - type: integer - description: >- - Unix timestamp when the metric value was recorded - value: - type: number - description: >- - The numeric value of the metric at this timestamp - unit: - type: string - additionalProperties: false - required: - - timestamp - - value - - unit - title: MetricDataPoint - description: >- - A single data point in a metric time series. - MetricLabel: - type: object - properties: - name: - type: string - description: The name of the label - value: - type: string - description: The value of the label - additionalProperties: false - required: - - name - - value - title: MetricLabel - description: A label associated with a metric. - MetricSeries: - type: object - properties: - metric: - type: string - description: The name of the metric - labels: - type: array - items: - $ref: '#/components/schemas/MetricLabel' - description: >- - List of labels associated with this metric series - values: - type: array - items: - $ref: '#/components/schemas/MetricDataPoint' - description: >- - List of data points in chronological order - additionalProperties: false - required: - - metric - - labels - - values - title: MetricSeries - description: A time series of metric data points. - QueryMetricsResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/MetricSeries' - description: >- - List of metric series matching the query criteria - additionalProperties: false - required: - - data - title: QueryMetricsResponse - description: >- - Response containing metric time series data. - QueryCondition: - type: object - properties: - key: - type: string - description: The attribute key to filter on - op: - $ref: '#/components/schemas/QueryConditionOp' - description: The comparison operator to apply - value: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: The value to compare against - additionalProperties: false - required: - - key - - op - - value - title: QueryCondition - description: A condition for filtering query results. - QueryConditionOp: - type: string - enum: - - eq - - ne - - gt - - lt - title: QueryConditionOp - description: >- - Comparison operators for query conditions. - QuerySpansRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the spans. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_return - title: QuerySpansRequest - Span: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: Span - description: >- - A span representing a single operation within a trace. - QuerySpansResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Span' - description: >- - List of spans matching the query criteria - additionalProperties: false - required: - - data - title: QuerySpansResponse - description: Response containing a list of spans. - SaveSpansToDatasetRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the spans. - attributes_to_save: - type: array - items: - type: string - description: The attributes to save to the dataset. - dataset_id: - type: string - description: >- - The ID of the dataset to save the spans to. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - required: - - attribute_filters - - attributes_to_save - - dataset_id - title: SaveSpansToDatasetRequest - GetSpanTreeRequest: - type: object - properties: - attributes_to_return: - type: array - items: - type: string - description: The attributes to return in the tree. - max_depth: - type: integer - description: The maximum depth of the tree. - additionalProperties: false - title: GetSpanTreeRequest - SpanWithStatus: - type: object - properties: - span_id: - type: string - description: Unique identifier for the span - trace_id: - type: string - description: >- - Unique identifier for the trace this span belongs to - parent_span_id: - type: string - description: >- - (Optional) Unique identifier for the parent span, if this is a child span - name: - type: string - description: >- - Human-readable name describing the operation this span represents - start_time: - type: string - format: date-time - description: Timestamp when the operation began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the operation finished, if completed - attributes: - type: object - additionalProperties: - oneOf: - - type: 'null' - - type: boolean - - type: number - - type: string - - type: array - - type: object - description: >- - (Optional) Key-value pairs containing additional metadata about the span - status: - $ref: '#/components/schemas/SpanStatus' - description: >- - (Optional) The current status of the span - additionalProperties: false - required: - - span_id - - trace_id - - name - - start_time - title: SpanWithStatus - description: A span that includes status information. - QuerySpanTreeResponse: - type: object - properties: - data: - type: object - additionalProperties: - $ref: '#/components/schemas/SpanWithStatus' - description: >- - Dictionary mapping span IDs to spans with status information - additionalProperties: false - required: - - data - title: QuerySpanTreeResponse - description: >- - Response containing a tree structure of spans. - QueryTracesRequest: - type: object - properties: - attribute_filters: - type: array - items: - $ref: '#/components/schemas/QueryCondition' - description: >- - The attribute filters to apply to the traces. - limit: - type: integer - description: The limit of traces to return. - offset: - type: integer - description: The offset of the traces to return. - order_by: - type: array - items: - type: string - description: The order by of the traces to return. - additionalProperties: false - title: QueryTracesRequest - Trace: - type: object - properties: - trace_id: - type: string - description: Unique identifier for the trace - root_span_id: - type: string - description: >- - Unique identifier for the root span that started this trace - start_time: - type: string - format: date-time - description: Timestamp when the trace began - end_time: - type: string - format: date-time - description: >- - (Optional) Timestamp when the trace finished, if completed - additionalProperties: false - required: - - trace_id - - root_span_id - - start_time - title: Trace - description: >- - A trace representing the complete execution path of a request across multiple - operations. - QueryTracesResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Trace' - description: >- - List of traces matching the query criteria - additionalProperties: false - required: - - data - title: QueryTracesResponse - description: Response containing a list of traces. responses: BadRequest400: description: The request was invalid or malformed @@ -14513,8 +13574,6 @@ tags: description: '' - name: SyntheticDataGeneration (Coming Soon) description: '' - - name: Telemetry - description: '' - name: ToolGroups description: '' - name: ToolRuntime @@ -14542,7 +13601,6 @@ x-tagGroups: - ScoringFunctions - Shields - SyntheticDataGeneration (Coming Soon) - - Telemetry - ToolGroups - ToolRuntime - VectorIO diff --git a/llama_stack/apis/telemetry/telemetry.py b/llama_stack/apis/telemetry/telemetry.py index 0e772da6a..b2999ad33 100644 --- a/llama_stack/apis/telemetry/telemetry.py +++ b/llama_stack/apis/telemetry/telemetry.py @@ -16,15 +16,12 @@ from typing import ( from pydantic import BaseModel, Field -from llama_stack.apis.version import LLAMA_STACK_API_V1, LLAMA_STACK_API_V1ALPHA from llama_stack.models.llama.datatypes import Primitive -from llama_stack.schema_utils import json_schema_type, register_schema, webmethod +from llama_stack.schema_utils import json_schema_type, register_schema # Add this constant near the top of the file, after the imports DEFAULT_TTL_DAYS = 7 -REQUIRED_SCOPE = "telemetry.read" - @json_schema_type class SpanStatus(Enum): @@ -413,7 +410,6 @@ class QueryMetricsResponse(BaseModel): @runtime_checkable class Telemetry(Protocol): - @webmethod(route="/telemetry/events", method="POST", level=LLAMA_STACK_API_V1) async def log_event( self, event: Event, @@ -426,14 +422,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/traces", - method="POST", - required_scope=REQUIRED_SCOPE, - deprecated=True, - level=LLAMA_STACK_API_V1, - ) - @webmethod(route="/telemetry/traces", method="POST", required_scope=REQUIRED_SCOPE, level=LLAMA_STACK_API_V1ALPHA) async def query_traces( self, attribute_filters: list[QueryCondition] | None = None, @@ -451,19 +439,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/traces/{trace_id:path}", - method="GET", - required_scope=REQUIRED_SCOPE, - deprecated=True, - level=LLAMA_STACK_API_V1, - ) - @webmethod( - route="/telemetry/traces/{trace_id:path}", - method="GET", - required_scope=REQUIRED_SCOPE, - level=LLAMA_STACK_API_V1ALPHA, - ) async def get_trace(self, trace_id: str) -> Trace: """Get a trace by its ID. @@ -472,19 +447,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/traces/{trace_id:path}/spans/{span_id:path}", - method="GET", - required_scope=REQUIRED_SCOPE, - deprecated=True, - level=LLAMA_STACK_API_V1, - ) - @webmethod( - route="/telemetry/traces/{trace_id:path}/spans/{span_id:path}", - method="GET", - required_scope=REQUIRED_SCOPE, - level=LLAMA_STACK_API_V1ALPHA, - ) async def get_span(self, trace_id: str, span_id: str) -> Span: """Get a span by its ID. @@ -494,19 +456,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/spans/{span_id:path}/tree", - method="POST", - deprecated=True, - required_scope=REQUIRED_SCOPE, - level=LLAMA_STACK_API_V1, - ) - @webmethod( - route="/telemetry/spans/{span_id:path}/tree", - method="POST", - required_scope=REQUIRED_SCOPE, - level=LLAMA_STACK_API_V1ALPHA, - ) async def get_span_tree( self, span_id: str, @@ -522,14 +471,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/spans", - method="POST", - required_scope=REQUIRED_SCOPE, - deprecated=True, - level=LLAMA_STACK_API_V1, - ) - @webmethod(route="/telemetry/spans", method="POST", required_scope=REQUIRED_SCOPE, level=LLAMA_STACK_API_V1ALPHA) async def query_spans( self, attribute_filters: list[QueryCondition], @@ -545,8 +486,6 @@ class Telemetry(Protocol): """ ... - @webmethod(route="/telemetry/spans/export", method="POST", deprecated=True, level=LLAMA_STACK_API_V1) - @webmethod(route="/telemetry/spans/export", method="POST", level=LLAMA_STACK_API_V1ALPHA) async def save_spans_to_dataset( self, attribute_filters: list[QueryCondition], @@ -563,19 +502,6 @@ class Telemetry(Protocol): """ ... - @webmethod( - route="/telemetry/metrics/{metric_name}", - method="POST", - required_scope=REQUIRED_SCOPE, - deprecated=True, - level=LLAMA_STACK_API_V1, - ) - @webmethod( - route="/telemetry/metrics/{metric_name}", - method="POST", - required_scope=REQUIRED_SCOPE, - level=LLAMA_STACK_API_V1ALPHA, - ) async def query_metrics( self, metric_name: str, diff --git a/tests/integration/telemetry/recordings/0de60cd6a6ec3dbfc4a7601e77be8083caf34f49147ad1c25efae1de3f0b25e5.json b/tests/integration/telemetry/recordings/0de60cd6a6ec3dbfc4a7601e77be8083caf34f49147ad1c25efae1de3f0b25e5.json deleted file mode 100644 index 427e0295b..000000000 --- a/tests/integration/telemetry/recordings/0de60cd6a6ec3dbfc4a7601e77be8083caf34f49147ad1c25efae1de3f0b25e5.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "test_id": "tests/integration/telemetry/test_openai_telemetry.py::test_openai_completion_creates_telemetry[txt=ollama/llama3.2:3b-instruct-fp16]", - "request": { - "method": "POST", - "url": "http://0.0.0.0:11434/v1/v1/chat/completions", - "headers": {}, - "body": { - "model": "llama3.2:3b-instruct-fp16", - "messages": [ - { - "role": "user", - "content": "Test OpenAI telemetry creation" - } - ], - "stream": false - }, - "endpoint": "/v1/chat/completions", - "model": "llama3.2:3b-instruct-fp16" - }, - "response": { - "body": { - "__type__": "openai.types.chat.chat_completion.ChatCompletion", - "__data__": { - "id": "rec-0de60cd6a6ec", - "choices": [ - { - "finish_reason": "stop", - "index": 0, - "logprobs": null, - "message": { - "content": "I'm happy to help you test this! This type of model is designed to provide information and answer questions, rather than engage in conversation or generate creative content. Feel free to ask me anything or test out any features you'd like. I'll do my best to assist you.\r\n\r\nIf you're looking for a way to engage with the model more creatively, there are several things you could try:\r\n\r\n1. Ask me a question on a topic unrelated to the ones I was trained on. This can give me a chance to demonstrate my ability to learn and generalize.\r\n2. Ask me to generate a piece of content - such as a short story or poem - on a specific topic. I can use patterns in the data I was trained on to generate text that is similar in style and structure to what you might find in a published book or article.\r\n3. Play a game with me. We could play games like \"20 Questions\" (where you think of an object, and I try to guess what it is by asking yes-or-no questions), or \"Hangman\". Let me know if there's something else you'd like to do!", - "refusal": null, - "role": "assistant", - "annotations": null, - "audio": null, - "function_call": null, - "tool_calls": null - } - } - ], - "created": 0, - "model": "llama3.2:3b-instruct-fp16", - "object": "chat.completion", - "service_tier": null, - "system_fingerprint": "fp_ollama", - "usage": { - "completion_tokens": 229, - "prompt_tokens": 30, - "total_tokens": 259, - "completion_tokens_details": null, - "prompt_tokens_details": null - } - } - }, - "is_streaming": false - } -} diff --git a/tests/integration/telemetry/test_openai_telemetry.py b/tests/integration/telemetry/test_openai_telemetry.py deleted file mode 100644 index b3ffb6b09..000000000 --- a/tests/integration/telemetry/test_openai_telemetry.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# All rights reserved. -# -# This source code is licensed under the terms described in the LICENSE file in -# the root directory of this source tree. - -import time -from datetime import UTC, datetime - -import pytest - - -@pytest.fixture(scope="module", autouse=True) -def setup_openai_telemetry_data(llama_stack_client, text_model_id): - """Setup fixture that creates telemetry data specifically for OpenAI completions testing.""" - - # Create OpenAI completion traces - for i in range(3): - llama_stack_client.chat.completions.create( - model=text_model_id, - messages=[ - { - "role": "user", - "content": f"Test trace openai {i}", - } - ], - # stream=False to always capture Metrics. - stream=False, - ) - - # Create additional OpenAI completion traces with different parameters - for i in range(2): - llama_stack_client.chat.completions.create( - model=text_model_id, - messages=[ - { - "role": "user", - "content": f"Test trace openai with temperature {i}", - } - ], - temperature=0.7, - max_tokens=100, - stream=False, - ) - - start_time = time.time() - - while time.time() - start_time < 30: - traces = llama_stack_client.telemetry.query_traces(limit=10) - if len(traces) >= 5: # 5 OpenAI completion traces - break - time.sleep(0.1) - - if len(traces) < 5: - pytest.fail( - f"Failed to create sufficient OpenAI completion telemetry data after 30s. Got {len(traces)} traces." - ) - - yield - - -def test_openai_traces_basic(llama_stack_client): - """Test basic trace querying functionality for OpenAI completions.""" - all_traces = llama_stack_client.telemetry.query_traces(limit=10) - - assert isinstance(all_traces, list), "Should return a list of traces" - assert len(all_traces) >= 5, "Should have at least 5 traces from OpenAI setup" - - # Verify trace structure and data quality - first_trace = all_traces[0] - assert hasattr(first_trace, "trace_id"), "Trace should have trace_id" - assert hasattr(first_trace, "start_time"), "Trace should have start_time" - assert hasattr(first_trace, "root_span_id"), "Trace should have root_span_id" - - # Validate trace_id is a valid UUID format - assert isinstance(first_trace.trace_id, str) and len(first_trace.trace_id) > 0, ( - "trace_id should be non-empty string" - ) - - # Validate start_time format and not in the future - now = datetime.now(UTC) - if isinstance(first_trace.start_time, str): - trace_time = datetime.fromisoformat(first_trace.start_time.replace("Z", "+00:00")) - else: - # start_time is already a datetime object - trace_time = first_trace.start_time - if trace_time.tzinfo is None: - trace_time = trace_time.replace(tzinfo=UTC) - - # Ensure trace time is not in the future - time_diff = (now - trace_time).total_seconds() - assert time_diff >= 0, f"Trace start_time should not be in the future, got {time_diff}s" - - # Validate root_span_id exists and is non-empty - assert isinstance(first_trace.root_span_id, str) and len(first_trace.root_span_id) > 0, ( - "root_span_id should be non-empty string" - ) - - # Test querying specific trace by ID - specific_trace = llama_stack_client.telemetry.get_trace(trace_id=first_trace.trace_id) - assert specific_trace.trace_id == first_trace.trace_id, "Retrieved trace should match requested ID" - assert specific_trace.start_time == first_trace.start_time, "Retrieved trace should have same start_time" - assert specific_trace.root_span_id == first_trace.root_span_id, "Retrieved trace should have same root_span_id" - - # Test pagination with proper validation - recent_traces = llama_stack_client.telemetry.query_traces(limit=3, offset=0) - assert len(recent_traces) <= 3, "Should return at most 3 traces when limit=3" - assert len(recent_traces) >= 1, "Should return at least 1 trace" - - # Verify all traces have required fields - for trace in recent_traces: - assert hasattr(trace, "trace_id") and trace.trace_id, "Each trace should have non-empty trace_id" - assert hasattr(trace, "start_time") and trace.start_time, "Each trace should have non-empty start_time" - assert hasattr(trace, "root_span_id") and trace.root_span_id, "Each trace should have non-empty root_span_id" - - -def test_openai_spans_basic(llama_stack_client): - """Test basic span querying functionality for OpenAI completions.""" - spans = llama_stack_client.telemetry.query_spans(attribute_filters=[], attributes_to_return=[]) - - assert isinstance(spans, list), "Should return a list of spans" - assert len(spans) >= 1, "Should have at least one span from OpenAI setup" - - # Verify span structure and data quality - first_span = spans[0] - required_attrs = ["span_id", "name", "trace_id"] - for attr in required_attrs: - assert hasattr(first_span, attr), f"Span should have {attr} attribute" - assert getattr(first_span, attr), f"Span {attr} should not be empty" - - # Validate span data types and content - assert isinstance(first_span.span_id, str) and len(first_span.span_id) > 0, "span_id should be non-empty string" - assert isinstance(first_span.name, str) and len(first_span.name) > 0, "span name should be non-empty string" - assert isinstance(first_span.trace_id, str) and len(first_span.trace_id) > 0, "trace_id should be non-empty string" - - # Verify span belongs to a valid trace - all_traces = llama_stack_client.telemetry.query_traces(limit=10) - trace_ids = {t.trace_id for t in all_traces} - if first_span.trace_id in trace_ids: - trace = llama_stack_client.telemetry.get_trace(trace_id=first_span.trace_id) - assert trace is not None, "Should be able to retrieve trace for valid trace_id" - assert trace.trace_id == first_span.trace_id, "Trace ID should match span's trace_id" - - # Test with span filtering and validate results - filtered_spans = llama_stack_client.telemetry.query_spans( - attribute_filters=[{"key": "name", "op": "eq", "value": first_span.name}], - attributes_to_return=["name", "span_id"], - ) - assert isinstance(filtered_spans, list), "Should return a list with span name filter" - - # Validate filtered spans if filtering works - if len(filtered_spans) > 0: - for span in filtered_spans: - assert hasattr(span, "name"), "Filtered spans should have name attribute" - assert hasattr(span, "span_id"), "Filtered spans should have span_id attribute" - assert span.name == first_span.name, "Filtered spans should match the filter criteria" - assert isinstance(span.span_id, str) and len(span.span_id) > 0, "Filtered span_id should be valid" - - # Test that all spans have consistent structure - for span in spans: - for attr in required_attrs: - assert hasattr(span, attr) and getattr(span, attr), f"All spans should have non-empty {attr}" - - -def test_openai_completion_creates_telemetry(llama_stack_client, text_model_id): - """Test that making OpenAI completion calls actually creates telemetry data.""" - - # Get initial trace count - initial_traces = llama_stack_client.telemetry.query_traces(limit=20) - initial_count = len(initial_traces) - - # Make a new OpenAI completion call - response = llama_stack_client.chat.completions.create( - model=text_model_id, - messages=[{"role": "user", "content": "Test OpenAI telemetry creation"}], - stream=False, - ) - - # Verify we got a response - assert response is not None, "Should get a response from OpenAI completion" - assert hasattr(response, "choices"), "Response should have choices" - assert len(response.choices) > 0, "Response should have at least one choice" - - # Wait for telemetry to be recorded - start_time = time.time() - while time.time() - start_time < 30: - final_traces = llama_stack_client.telemetry.query_traces(limit=20) - final_count = len(final_traces) - if final_count > initial_count: - break - time.sleep(0.1) - - # Should have at least as many traces as before (might have more due to other activity) - assert final_count >= initial_count, "Should have at least as many traces after OpenAI call" diff --git a/tests/integration/telemetry/test_telemetry.py b/tests/integration/telemetry/test_telemetry.py deleted file mode 100644 index aff337e35..000000000 --- a/tests/integration/telemetry/test_telemetry.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# All rights reserved. -# -# This source code is licensed under the terms described in the LICENSE file in -# the root directory of this source tree. - -import time -from datetime import UTC, datetime -from uuid import uuid4 - -import pytest -from llama_stack_client import Agent - - -@pytest.fixture(scope="module", autouse=True) -def setup_telemetry_data(llama_stack_client, text_model_id): - """Setup fixture that creates telemetry data before tests run.""" - agent = Agent(llama_stack_client, model=text_model_id, instructions="You are a helpful assistant") - - session_id = agent.create_session(f"test-setup-session-{uuid4()}") - - messages = [ - "What is 2 + 2?", - "Tell me a short joke", - ] - - for msg in messages: - agent.create_turn( - messages=[{"role": "user", "content": msg}], - session_id=session_id, - stream=False, - ) - - for i in range(2): - llama_stack_client.chat.completions.create( - model=text_model_id, messages=[{"role": "user", "content": f"Test trace {i}"}] - ) - - start_time = time.time() - - while time.time() - start_time < 30: - traces = llama_stack_client.telemetry.query_traces(limit=10) - if len(traces) >= 4: - break - time.sleep(0.1) - - if len(traces) < 4: - pytest.fail(f"Failed to create sufficient telemetry data after 30s. Got {len(traces)} traces.") - - yield - - -def test_query_traces_basic(llama_stack_client): - """Test basic trace querying functionality with proper data validation.""" - all_traces = llama_stack_client.telemetry.query_traces(limit=5) - - assert isinstance(all_traces, list), "Should return a list of traces" - assert len(all_traces) >= 4, "Should have at least 4 traces from setup" - - # Verify trace structure and data quality - first_trace = all_traces[0] - assert hasattr(first_trace, "trace_id"), "Trace should have trace_id" - assert hasattr(first_trace, "start_time"), "Trace should have start_time" - assert hasattr(first_trace, "root_span_id"), "Trace should have root_span_id" - - # Validate trace_id is a valid UUID format - assert isinstance(first_trace.trace_id, str) and len(first_trace.trace_id) > 0, ( - "trace_id should be non-empty string" - ) - - # Validate start_time format and not in the future - now = datetime.now(UTC) - if isinstance(first_trace.start_time, str): - trace_time = datetime.fromisoformat(first_trace.start_time.replace("Z", "+00:00")) - else: - # start_time is already a datetime object - trace_time = first_trace.start_time - if trace_time.tzinfo is None: - trace_time = trace_time.replace(tzinfo=UTC) - - # Ensure trace time is not in the future (but allow any age in the past for persistent test data) - time_diff = (now - trace_time).total_seconds() - assert time_diff >= 0, f"Trace start_time should not be in the future, got {time_diff}s" - - # Validate root_span_id exists and is non-empty - assert isinstance(first_trace.root_span_id, str) and len(first_trace.root_span_id) > 0, ( - "root_span_id should be non-empty string" - ) - - # Test querying specific trace by ID - specific_trace = llama_stack_client.telemetry.get_trace(trace_id=first_trace.trace_id) - assert specific_trace.trace_id == first_trace.trace_id, "Retrieved trace should match requested ID" - assert specific_trace.start_time == first_trace.start_time, "Retrieved trace should have same start_time" - assert specific_trace.root_span_id == first_trace.root_span_id, "Retrieved trace should have same root_span_id" - - # Test pagination with proper validation - recent_traces = llama_stack_client.telemetry.query_traces(limit=3, offset=0) - assert len(recent_traces) <= 3, "Should return at most 3 traces when limit=3" - assert len(recent_traces) >= 1, "Should return at least 1 trace" - - # Verify all traces have required fields - for trace in recent_traces: - assert hasattr(trace, "trace_id") and trace.trace_id, "Each trace should have non-empty trace_id" - assert hasattr(trace, "start_time") and trace.start_time, "Each trace should have non-empty start_time" - assert hasattr(trace, "root_span_id") and trace.root_span_id, "Each trace should have non-empty root_span_id" - - -def test_query_spans_basic(llama_stack_client): - """Test basic span querying functionality with proper validation.""" - spans = llama_stack_client.telemetry.query_spans(attribute_filters=[], attributes_to_return=[]) - - assert isinstance(spans, list), "Should return a list of spans" - assert len(spans) >= 1, "Should have at least one span from setup" - - # Verify span structure and data quality - first_span = spans[0] - required_attrs = ["span_id", "name", "trace_id"] - for attr in required_attrs: - assert hasattr(first_span, attr), f"Span should have {attr} attribute" - assert getattr(first_span, attr), f"Span {attr} should not be empty" - - # Validate span data types and content - assert isinstance(first_span.span_id, str) and len(first_span.span_id) > 0, "span_id should be non-empty string" - assert isinstance(first_span.name, str) and len(first_span.name) > 0, "span name should be non-empty string" - assert isinstance(first_span.trace_id, str) and len(first_span.trace_id) > 0, "trace_id should be non-empty string" - - # Verify span belongs to a valid trace (test with traces we know exist) - all_traces = llama_stack_client.telemetry.query_traces(limit=10) - trace_ids = {t.trace_id for t in all_traces} - if first_span.trace_id in trace_ids: - trace = llama_stack_client.telemetry.get_trace(trace_id=first_span.trace_id) - assert trace is not None, "Should be able to retrieve trace for valid trace_id" - assert trace.trace_id == first_span.trace_id, "Trace ID should match span's trace_id" - - # Test with span filtering and validate results - filtered_spans = llama_stack_client.telemetry.query_spans( - attribute_filters=[{"key": "name", "op": "eq", "value": first_span.name}], - attributes_to_return=["name", "span_id"], - ) - assert isinstance(filtered_spans, list), "Should return a list with span name filter" - - # Validate filtered spans if filtering works - if len(filtered_spans) > 0: - for span in filtered_spans: - assert hasattr(span, "name"), "Filtered spans should have name attribute" - assert hasattr(span, "span_id"), "Filtered spans should have span_id attribute" - assert span.name == first_span.name, "Filtered spans should match the filter criteria" - assert isinstance(span.span_id, str) and len(span.span_id) > 0, "Filtered span_id should be valid" - - # Test that all spans have consistent structure - for span in spans: - for attr in required_attrs: - assert hasattr(span, attr) and getattr(span, attr), f"All spans should have non-empty {attr}" - - -def test_telemetry_pagination(llama_stack_client): - """Test pagination in telemetry queries.""" - # Get total count of traces - all_traces = llama_stack_client.telemetry.query_traces(limit=20) - total_count = len(all_traces) - assert total_count >= 4, "Should have at least 4 traces from setup" - - # Test trace pagination - page1 = llama_stack_client.telemetry.query_traces(limit=2, offset=0) - page2 = llama_stack_client.telemetry.query_traces(limit=2, offset=2) - - assert len(page1) == 2, "First page should have exactly 2 traces" - assert len(page2) >= 1, "Second page should have at least 1 trace" - - # Verify no overlap between pages - page1_ids = {t.trace_id for t in page1} - page2_ids = {t.trace_id for t in page2} - assert len(page1_ids.intersection(page2_ids)) == 0, "Pages should contain different traces" - - # Test ordering - ordered_traces = llama_stack_client.telemetry.query_traces(limit=5, order_by=["start_time"]) - assert len(ordered_traces) >= 4, "Should have at least 4 traces for ordering test" - - # Verify ordering by start_time - for i in range(len(ordered_traces) - 1): - current_time = ordered_traces[i].start_time - next_time = ordered_traces[i + 1].start_time - assert current_time <= next_time, f"Traces should be ordered by start_time: {current_time} > {next_time}" - - # Test limit behavior - limited = llama_stack_client.telemetry.query_traces(limit=3) - assert len(limited) == 3, "Should return exactly 3 traces when limit=3" diff --git a/tests/integration/telemetry/test_telemetry_metrics.py b/tests/integration/telemetry/test_telemetry_metrics.py deleted file mode 100644 index 1d8312ae2..000000000 --- a/tests/integration/telemetry/test_telemetry_metrics.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# All rights reserved. -# -# This source code is licensed under the terms described in the LICENSE file in -# the root directory of this source tree. - -import time -from datetime import UTC, datetime, timedelta - -import pytest - - -@pytest.fixture(scope="module", autouse=True) -def setup_telemetry_metrics_data(openai_client, client_with_models, text_model_id): - """Setup fixture that creates telemetry metrics data before tests run.""" - - # Skip OpenAI tests if running in library mode - if not hasattr(client_with_models, "base_url"): - pytest.skip("OpenAI client tests not supported with library client") - - prompt_tokens = [] - completion_tokens = [] - total_tokens = [] - - # Create OpenAI completions to generate metrics using the proper OpenAI client - for i in range(5): - response = openai_client.chat.completions.create( - model=text_model_id, - messages=[{"role": "user", "content": f"OpenAI test {i}"}], - stream=False, - ) - prompt_tokens.append(response.usage.prompt_tokens) - completion_tokens.append(response.usage.completion_tokens) - total_tokens.append(response.usage.total_tokens) - - # Wait for metrics to be logged - start_time = time.time() - while time.time() - start_time < 30: - try: - # Try to query metrics to see if they're available - metrics_response = client_with_models.telemetry.query_metrics( - metric_name="completion_tokens", - start_time=int((datetime.now(UTC) - timedelta(minutes=5)).timestamp()), - ) - if len(metrics_response[0].values) > 0: - break - except Exception: - pass - time.sleep(0.1) - - # Return the token lists for use in tests - return {"prompt_tokens": prompt_tokens, "completion_tokens": completion_tokens, "total_tokens": total_tokens} - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_prompt_tokens(client_with_models, text_model_id, setup_telemetry_metrics_data): - """Test that prompt_tokens metrics are queryable.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - response = client_with_models.telemetry.query_metrics( - metric_name="prompt_tokens", - start_time=start_time, - ) - - assert isinstance(response, list) - - assert isinstance(response[0].values, list), "Should return a list of metric series" - - assert response[0].metric == "prompt_tokens" - - # Use the actual values from setup instead of hardcoded values - expected_values = setup_telemetry_metrics_data["prompt_tokens"] - assert response[0].values[-1].value in expected_values, ( - f"Expected one of {expected_values}, got {response[0].values[-1].value}" - ) - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_completion_tokens(client_with_models, text_model_id, setup_telemetry_metrics_data): - """Test that completion_tokens metrics are queryable.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - response = client_with_models.telemetry.query_metrics( - metric_name="completion_tokens", - start_time=start_time, - ) - - assert isinstance(response, list) - - assert isinstance(response[0].values, list), "Should return a list of metric series" - - assert response[0].metric == "completion_tokens" - - # Use the actual values from setup instead of hardcoded values - expected_values = setup_telemetry_metrics_data["completion_tokens"] - assert response[0].values[-1].value in expected_values, ( - f"Expected one of {expected_values}, got {response[0].values[-1].value}" - ) - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_total_tokens(client_with_models, text_model_id, setup_telemetry_metrics_data): - """Test that total_tokens metrics are queryable.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - response = client_with_models.telemetry.query_metrics( - metric_name="total_tokens", - start_time=start_time, - ) - - assert isinstance(response, list) - - assert isinstance(response[0].values, list), "Should return a list of metric series" - - assert response[0].metric == "total_tokens" - - # Use the actual values from setup instead of hardcoded values - expected_values = setup_telemetry_metrics_data["total_tokens"] - assert response[0].values[-1].value in expected_values, ( - f"Expected one of {expected_values}, got {response[0].values[-1].value}" - ) - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_with_time_range(llama_stack_client, text_model_id): - """Test that metrics are queryable with time range.""" - end_time = int(datetime.now(UTC).timestamp()) - start_time = end_time - 600 # 10 minutes ago - - response = llama_stack_client.telemetry.query_metrics( - metric_name="prompt_tokens", - start_time=start_time, - end_time=end_time, - ) - - assert isinstance(response, list) - - assert isinstance(response[0].values, list), "Should return a list of metric series" - - assert response[0].metric == "prompt_tokens" - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_with_label_matchers(llama_stack_client, text_model_id): - """Test that metrics are queryable with label matchers.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - response = llama_stack_client.telemetry.query_metrics( - metric_name="prompt_tokens", - start_time=start_time, - label_matchers=[{"name": "model_id", "value": text_model_id, "operator": "="}], - ) - - assert isinstance(response[0].values, list), "Should return a list of metric series" - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_nonexistent_metric(llama_stack_client): - """Test that querying a nonexistent metric returns empty data.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - response = llama_stack_client.telemetry.query_metrics( - metric_name="nonexistent_metric", - start_time=start_time, - ) - - assert isinstance(response, list), "Should return an empty list for nonexistent metric" - assert len(response) == 0 - - -@pytest.mark.skip(reason="Skipping this test until client is regenerated") -def test_query_metrics_with_granularity(llama_stack_client, text_model_id): - """Test that metrics are queryable with different granularity levels.""" - start_time = int((datetime.now(UTC) - timedelta(minutes=10)).timestamp()) - - # Test hourly granularity - hourly_response = llama_stack_client.telemetry.query_metrics( - metric_name="total_tokens", - start_time=start_time, - granularity="1h", - ) - - # Test daily granularity - daily_response = llama_stack_client.telemetry.query_metrics( - metric_name="total_tokens", - start_time=start_time, - granularity="1d", - ) - - # Test no granularity (raw data points) - raw_response = llama_stack_client.telemetry.query_metrics( - metric_name="total_tokens", - start_time=start_time, - granularity=None, - ) - - # All should return valid data - assert isinstance(hourly_response[0].values, list), "Hourly granularity should return data" - assert isinstance(daily_response[0].values, list), "Daily granularity should return data" - assert isinstance(raw_response[0].values, list), "No granularity should return data" - - # Verify that different granularities produce different aggregation levels - # (The exact number depends on data distribution, but they should be queryable) - assert len(hourly_response[0].values) >= 0, "Hourly granularity should be queryable" - assert len(daily_response[0].values) >= 0, "Daily granularity should be queryable" - assert len(raw_response[0].values) >= 0, "No granularity should be queryable" From d875e427bf301587d5f20c0119f028b47101112c Mon Sep 17 00:00:00 2001 From: Jiayi Ni Date: Tue, 14 Oct 2025 13:52:55 -0700 Subject: [PATCH 2/3] refactor: use `extra_body` to pass in `input_type` params for asymmetric embedding models for NVIDIA Inference Provider (#3804) # What does this PR do? Previously, the NVIDIA inference provider implemented a custom `openai_embeddings` method with a hardcoded `input_type="query"` parameter, which is required by NVIDIA asymmetric embedding models([https://github.com/llamastack/llama-stack/pull/3205](https://github.com/llamastack/llama-stack/pull/3205)). Recently `extra_body` parameter is added to the embeddings API ([https://github.com/llamastack/llama-stack/pull/3794](https://github.com/llamastack/llama-stack/pull/3794)). So, this PR updates the NVIDIA inference provider to use the base `OpenAIMixin.openai_embeddings` method instead and pass the `input_type` through the `extra_body` parameter for asymmetric embedding models. ## Test Plan Run the following command for the ```embedding_model```: ```nvidia/llama-3.2-nv-embedqa-1b-v2```, ```nvidia/nv-embedqa-e5-v5```, ```nvidia/nv-embedqa-mistral-7b-v2```, and ```snowflake/arctic-embed-l```. ``` pytest -s -v tests/integration/inference/test_openai_embeddings.py --stack-config="inference=nvidia" --embedding-model={embedding_model} --env NVIDIA_API_KEY={nvidia_api_key} --env NVIDIA_BASE_URL="https://integrate.api.nvidia.com" --inference-mode=record ``` --- .../remote/inference/nvidia/NVIDIA.md | 13 ++-- .../remote/inference/nvidia/nvidia.py | 55 ------------- .../inference/test_openai_embeddings.py | 77 +++++++++++++++++-- 3 files changed, 75 insertions(+), 70 deletions(-) diff --git a/llama_stack/providers/remote/inference/nvidia/NVIDIA.md b/llama_stack/providers/remote/inference/nvidia/NVIDIA.md index 625be6088..096ff28ac 100644 --- a/llama_stack/providers/remote/inference/nvidia/NVIDIA.md +++ b/llama_stack/providers/remote/inference/nvidia/NVIDIA.md @@ -139,16 +139,13 @@ print(f"Structured Response: {structured_response.choices[0].message.content}") The following example shows how to create embeddings for an NVIDIA NIM. -> [!NOTE] -> NVIDIA asymmetric embedding models (e.g., `nvidia/llama-3.2-nv-embedqa-1b-v2`) require an `input_type` parameter not present in the standard OpenAI embeddings API. The NVIDIA Inference Adapter automatically sets `input_type="query"` when using the OpenAI-compatible embeddings endpoint for NVIDIA. For passage embeddings, use the `embeddings` API with `task_type="document"`. - ```python -response = client.inference.embeddings( - model_id="nvidia/llama-3.2-nv-embedqa-1b-v2", - contents=["What is the capital of France?"], - task_type="query", +response = client.embeddings.create( + model="nvidia/llama-3.2-nv-embedqa-1b-v2", + input=["What is the capital of France?"], + extra_body={"input_type": "query"}, ) -print(f"Embeddings: {response.embeddings}") +print(f"Embeddings: {response.data}") ``` ### Vision Language Models Example diff --git a/llama_stack/providers/remote/inference/nvidia/nvidia.py b/llama_stack/providers/remote/inference/nvidia/nvidia.py index 37864b040..eab665d63 100644 --- a/llama_stack/providers/remote/inference/nvidia/nvidia.py +++ b/llama_stack/providers/remote/inference/nvidia/nvidia.py @@ -5,14 +5,6 @@ # the root directory of this source tree. -from openai import NOT_GIVEN - -from llama_stack.apis.inference import ( - OpenAIEmbeddingData, - OpenAIEmbeddingsRequestWithExtraBody, - OpenAIEmbeddingsResponse, - OpenAIEmbeddingUsage, -) from llama_stack.log import get_logger from llama_stack.providers.utils.inference.openai_mixin import OpenAIMixin @@ -76,50 +68,3 @@ class NVIDIAInferenceAdapter(OpenAIMixin): :return: The NVIDIA API base URL """ return f"{self.config.url}/v1" if self.config.append_api_version else self.config.url - - async def openai_embeddings( - self, - params: OpenAIEmbeddingsRequestWithExtraBody, - ) -> OpenAIEmbeddingsResponse: - """ - OpenAI-compatible embeddings for NVIDIA NIM. - - Note: NVIDIA NIM asymmetric embedding models require an "input_type" field not present in the standard OpenAI embeddings API. - We default this to "query" to ensure requests succeed when using the - OpenAI-compatible endpoint. For passage embeddings, use the embeddings API with - `task_type='document'`. - """ - extra_body: dict[str, object] = {"input_type": "query"} - logger.warning( - "NVIDIA OpenAI-compatible embeddings: defaulting to input_type='query'. " - "For passage embeddings, use the embeddings API with task_type='document'." - ) - - response = await self.client.embeddings.create( - model=await self._get_provider_model_id(params.model), - input=params.input, - encoding_format=params.encoding_format if params.encoding_format is not None else NOT_GIVEN, - dimensions=params.dimensions if params.dimensions is not None else NOT_GIVEN, - user=params.user if params.user is not None else NOT_GIVEN, - extra_body=extra_body, - ) - - data = [] - for i, embedding_data in enumerate(response.data): - data.append( - OpenAIEmbeddingData( - embedding=embedding_data.embedding, - index=i, - ) - ) - - usage = OpenAIEmbeddingUsage( - prompt_tokens=response.usage.prompt_tokens, - total_tokens=response.usage.total_tokens, - ) - - return OpenAIEmbeddingsResponse( - data=data, - model=response.model, - usage=usage, - ) diff --git a/tests/integration/inference/test_openai_embeddings.py b/tests/integration/inference/test_openai_embeddings.py index fc2f66b9c..00de56f3a 100644 --- a/tests/integration/inference/test_openai_embeddings.py +++ b/tests/integration/inference/test_openai_embeddings.py @@ -12,6 +12,15 @@ from openai import OpenAI from llama_stack.core.library_client import LlamaStackAsLibraryClient +ASYMMETRIC_EMBEDDING_MODELS_BY_PROVIDER = { + "remote::nvidia": [ + "nvidia/llama-3.2-nv-embedqa-1b-v2", + "nvidia/nv-embedqa-e5-v5", + "nvidia/nv-embedqa-mistral-7b-v2", + "snowflake/arctic-embed-l", + ], +} + def decode_base64_to_floats(base64_string: str) -> list[float]: """Helper function to decode base64 string to list of float32 values.""" @@ -29,6 +38,28 @@ def provider_from_model(client_with_models, model_id): return providers[provider_id] +def is_asymmetric_model(client_with_models, model_id): + provider = provider_from_model(client_with_models, model_id) + provider_type = provider.provider_type + + if provider_type not in ASYMMETRIC_EMBEDDING_MODELS_BY_PROVIDER: + return False + + return model_id in ASYMMETRIC_EMBEDDING_MODELS_BY_PROVIDER[provider_type] + + +def get_extra_body_for_model(client_with_models, model_id, input_type="query"): + if not is_asymmetric_model(client_with_models, model_id): + return None + + provider = provider_from_model(client_with_models, model_id) + + if provider.provider_type == "remote::nvidia": + return {"input_type": input_type} + + return None + + def skip_if_model_doesnt_support_user_param(client, model_id): provider = provider_from_model(client, model_id) if provider.provider_type in ( @@ -40,17 +71,29 @@ def skip_if_model_doesnt_support_user_param(client, model_id): def skip_if_model_doesnt_support_encoding_format_base64(client, model_id): provider = provider_from_model(client, model_id) - if provider.provider_type in ( + + should_skip = provider.provider_type in ( "remote::databricks", # param silently ignored, always returns floats "remote::fireworks", # param silently ignored, always returns list of floats "remote::ollama", # param silently ignored, always returns list of floats - ): + ) or ( + provider.provider_type == "remote::nvidia" + and model_id + in [ + "nvidia/nv-embedqa-e5-v5", + "nvidia/nv-embedqa-mistral-7b-v2", + "snowflake/arctic-embed-l", + ] + ) + + if should_skip: pytest.skip(f"Model {model_id} hosted by {provider.provider_type} does not support encoding_format='base64'.") def skip_if_model_doesnt_support_variable_dimensions(client_with_models, model_id): provider = provider_from_model(client_with_models, model_id) - if ( + + should_skip = ( provider.provider_type in ( "remote::together", # returns 400 @@ -59,11 +102,19 @@ def skip_if_model_doesnt_support_variable_dimensions(client_with_models, model_i "remote::databricks", "remote::watsonx", # openai.BadRequestError: Error code: 400 - {'detail': "litellm.UnsupportedParamsError: watsonx does not support parameters: {'dimensions': 384} ) - ): - pytest.skip( - f"Model {model_id} hosted by {provider.provider_type} does not support variable output embedding dimensions." + or (provider.provider_type == "remote::openai" and "text-embedding-3" not in model_id) + or ( + provider.provider_type == "remote::nvidia" + and model_id + in [ + "nvidia/nv-embedqa-e5-v5", + "nvidia/nv-embedqa-mistral-7b-v2", + "snowflake/arctic-embed-l", + ] ) - if provider.provider_type == "remote::openai" and "text-embedding-3" not in model_id: + ) + + if should_skip: pytest.skip( f"Model {model_id} hosted by {provider.provider_type} does not support variable output embedding dimensions." ) @@ -105,6 +156,7 @@ def test_openai_embeddings_single_string(compat_client, client_with_models, embe model=embedding_model_id, input=input_text, encoding_format="float", + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) assert response.object == "list" @@ -129,6 +181,7 @@ def test_openai_embeddings_multiple_strings(compat_client, client_with_models, e model=embedding_model_id, input=input_texts, encoding_format="float", + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) assert response.object == "list" @@ -155,6 +208,7 @@ def test_openai_embeddings_with_encoding_format_float(compat_client, client_with model=embedding_model_id, input=input_text, encoding_format="float", + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) assert response.object == "list" @@ -175,6 +229,7 @@ def test_openai_embeddings_with_dimensions(compat_client, client_with_models, em model=embedding_model_id, input=input_text, dimensions=dimensions, + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) assert response.object == "list" @@ -196,6 +251,7 @@ def test_openai_embeddings_with_user_parameter(compat_client, client_with_models model=embedding_model_id, input=input_text, user=user_id, + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) assert response.object == "list" @@ -212,6 +268,7 @@ def test_openai_embeddings_empty_list_error(compat_client, client_with_models, e compat_client.embeddings.create( model=embedding_model_id, input=[], + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) @@ -223,6 +280,7 @@ def test_openai_embeddings_invalid_model_error(compat_client, client_with_models compat_client.embeddings.create( model="invalid-model-id", input="Test text", + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) @@ -233,16 +291,19 @@ def test_openai_embeddings_different_inputs_different_outputs(compat_client, cli input_text1 = "This is the first text" input_text2 = "This is completely different content" + extra_body = get_extra_body_for_model(client_with_models, embedding_model_id) response1 = compat_client.embeddings.create( model=embedding_model_id, input=input_text1, encoding_format="float", + extra_body=extra_body, ) response2 = compat_client.embeddings.create( model=embedding_model_id, input=input_text2, encoding_format="float", + extra_body=extra_body, ) embedding1 = response1.data[0].embedding @@ -267,6 +328,7 @@ def test_openai_embeddings_with_encoding_format_base64(compat_client, client_wit input=input_text, encoding_format="base64", dimensions=dimensions, + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) # Validate response structure @@ -298,6 +360,7 @@ def test_openai_embeddings_base64_batch_processing(compat_client, client_with_mo model=embedding_model_id, input=input_texts, encoding_format="base64", + extra_body=get_extra_body_for_model(client_with_models, embedding_model_id), ) # Validate response structure assert response.object == "list" From 44ac023755d0c8f88693a3a81086c8ff3ed53510 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Tue, 14 Oct 2025 13:56:59 -0700 Subject: [PATCH 3/3] chore!: BREAKING CHANGE: remove sqlite from telemetry config # What does this PR do? ## Test Plan --- docs/docs/building_applications/telemetry.mdx | 136 +------ .../telemetry/inline_meta-reference.mdx | 6 +- llama_stack/distributions/ci-tests/run.yaml | 3 +- .../distributions/dell/run-with-safety.yaml | 3 +- llama_stack/distributions/dell/run.yaml | 3 +- .../meta-reference-gpu/run-with-safety.yaml | 3 +- .../distributions/meta-reference-gpu/run.yaml | 3 +- .../distributions/nvidia/run-with-safety.yaml | 3 +- llama_stack/distributions/nvidia/run.yaml | 3 +- .../distributions/open-benchmark/run.yaml | 3 +- .../distributions/starter-gpu/run.yaml | 3 +- llama_stack/distributions/starter/run.yaml | 3 +- llama_stack/distributions/watsonx/run.yaml | 3 +- .../inline/telemetry/meta_reference/config.py | 16 +- .../meta_reference/sqlite_span_processor.py | 190 --------- .../telemetry/meta_reference/telemetry.py | 53 --- .../utils/telemetry/sqlite_trace_store.py | 383 ------------------ 17 files changed, 20 insertions(+), 797 deletions(-) delete mode 100644 llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py delete mode 100644 llama_stack/providers/utils/telemetry/sqlite_trace_store.py diff --git a/docs/docs/building_applications/telemetry.mdx b/docs/docs/building_applications/telemetry.mdx index d991d97a1..91afa4a32 100644 --- a/docs/docs/building_applications/telemetry.mdx +++ b/docs/docs/building_applications/telemetry.mdx @@ -10,58 +10,8 @@ import TabItem from '@theme/TabItem'; # Telemetry -The Llama Stack telemetry system provides comprehensive tracing, metrics, and logging capabilities. It supports multiple sink types including OpenTelemetry, SQLite, and Console output for complete observability of your AI applications. +The Llama Stack uses OpenTelemetry to provide comprehensive tracing, metrics, and logging capabilities. -## Event Types - -The telemetry system supports three main types of events: - - - - -Free-form log messages with severity levels for general application logging: - -```python -unstructured_log_event = UnstructuredLogEvent( - message="This is a log message", - severity=LogSeverity.INFO -) -``` - - - - -Numerical measurements with units for tracking performance and usage: - -```python -metric_event = MetricEvent( - metric="my_metric", - value=10, - unit="count" -) -``` - - - - -System events like span start/end that provide structured operation tracking: - -```python -structured_log_event = SpanStartPayload( - name="my_span", - parent_span_id="parent_span_id" -) -``` - - - - -## Spans and Traces - -- **Spans**: Represent individual operations with timing information and hierarchical relationships -- **Traces**: Collections of related spans that form a complete request flow across your application - -This hierarchical structure allows you to understand the complete execution path of requests through your Llama Stack application. ## Automatic Metrics Generation @@ -129,21 +79,6 @@ Send events to an OpenTelemetry Collector for integration with observability pla - Compatible with all OpenTelemetry collectors - Supports both traces and metrics - - - -Store events in a local SQLite database for direct querying: - -**Use Cases:** -- Local development and debugging -- Custom analytics and reporting -- Offline analysis of application behavior - -**Features:** -- Direct SQL querying capabilities -- Persistent local storage -- No external dependencies - @@ -174,9 +109,8 @@ telemetry: provider_type: inline::meta-reference config: service_name: "llama-stack-service" - sinks: ['console', 'sqlite', 'otel_trace', 'otel_metric'] + sinks: ['console', 'otel_trace', 'otel_metric'] otel_exporter_otlp_endpoint: "http://localhost:4318" - sqlite_db_path: "/path/to/telemetry.db" ``` ### Environment Variables @@ -185,7 +119,7 @@ Configure telemetry behavior using environment variables: - **`OTEL_EXPORTER_OTLP_ENDPOINT`**: OpenTelemetry Collector endpoint (default: `http://localhost:4318`) - **`OTEL_SERVICE_NAME`**: Service name for telemetry (default: empty string) -- **`TELEMETRY_SINKS`**: Comma-separated list of sinks (default: `console,sqlite`) +- **`TELEMETRY_SINKS`**: Comma-separated list of sinks (default: `console`) ### Quick Setup: Complete Telemetry Stack @@ -248,37 +182,10 @@ Forward metrics to other observability systems: -## SQLite Querying - -The `sqlite` sink allows you to query traces without an external system. This is particularly useful for development and custom analytics. - -### Example Queries - -```sql --- Query recent traces -SELECT * FROM traces WHERE timestamp > datetime('now', '-1 hour'); - --- Analyze span durations -SELECT name, AVG(duration_ms) as avg_duration -FROM spans -GROUP BY name -ORDER BY avg_duration DESC; - --- Find slow operations -SELECT * FROM spans -WHERE duration_ms > 1000 -ORDER BY duration_ms DESC; -``` - -:::tip[Advanced Analytics] -Refer to the [Getting Started notebook](https://github.com/meta-llama/llama-stack/blob/main/docs/getting_started.ipynb) for more examples on querying traces and spans programmatically. -::: - ## Best Practices ### 🔍 **Monitoring Strategy** - Use OpenTelemetry for production environments -- Combine multiple sinks for development (console + SQLite) - Set up alerts on key metrics like token usage and error rates ### 📊 **Metrics Analysis** @@ -293,45 +200,8 @@ Refer to the [Getting Started notebook](https://github.com/meta-llama/llama-stac ### 🔧 **Configuration Management** - Use environment variables for flexible deployment -- Configure appropriate retention policies for SQLite - Ensure proper network access to OpenTelemetry collectors -## Integration Examples - -### Basic Telemetry Setup - -```python -from llama_stack_client import LlamaStackClient - -# Client with telemetry headers -client = LlamaStackClient( - base_url="http://localhost:8000", - extra_headers={ - "X-Telemetry-Service": "my-ai-app", - "X-Telemetry-Version": "1.0.0" - } -) - -# All API calls will be automatically traced -response = client.chat.completions.create( - model="meta-llama/Llama-3.2-3B-Instruct", - messages=[{"role": "user", "content": "Hello!"}] -) -``` - -### Custom Telemetry Context - -```python -# Add custom span attributes for better tracking -with tracer.start_as_current_span("custom_operation") as span: - span.set_attribute("user_id", "user123") - span.set_attribute("operation_type", "chat_completion") - - response = client.chat.completions.create( - model="meta-llama/Llama-3.2-3B-Instruct", - messages=[{"role": "user", "content": "Hello!"}] - ) -``` ## Related Resources diff --git a/docs/docs/providers/telemetry/inline_meta-reference.mdx b/docs/docs/providers/telemetry/inline_meta-reference.mdx index ea2a690b3..d8b3157d1 100644 --- a/docs/docs/providers/telemetry/inline_meta-reference.mdx +++ b/docs/docs/providers/telemetry/inline_meta-reference.mdx @@ -16,14 +16,12 @@ Meta's reference implementation of telemetry and observability using OpenTelemet |-------|------|----------|---------|-------------| | `otel_exporter_otlp_endpoint` | `str \| None` | No | | The OpenTelemetry collector endpoint URL (base URL for traces, metrics, and logs). If not set, the SDK will use OTEL_EXPORTER_OTLP_ENDPOINT environment variable. | | `service_name` | `` | No | ​ | The service name to use for telemetry | -| `sinks` | `list[inline.telemetry.meta_reference.config.TelemetrySink` | No | [<TelemetrySink.SQLITE: 'sqlite'>] | List of telemetry sinks to enable (possible values: otel_trace, otel_metric, sqlite, console) | -| `sqlite_db_path` | `` | No | ~/.llama/runtime/trace_store.db | The path to the SQLite database to use for storing traces | +| `sinks` | `list[inline.telemetry.meta_reference.config.TelemetrySink` | No | [] | List of telemetry sinks to enable (possible values: otel_trace, otel_metric, console) | ## Sample Configuration ```yaml service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" -sinks: ${env.TELEMETRY_SINKS:=sqlite} -sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/dummy}/trace_store.db +sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} ``` diff --git a/llama_stack/distributions/ci-tests/run.yaml b/llama_stack/distributions/ci-tests/run.yaml index 40f4d8a0a..0a8587328 100644 --- a/llama_stack/distributions/ci-tests/run.yaml +++ b/llama_stack/distributions/ci-tests/run.yaml @@ -159,8 +159,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} post_training: - provider_id: torchtune-cpu diff --git a/llama_stack/distributions/dell/run-with-safety.yaml b/llama_stack/distributions/dell/run-with-safety.yaml index 2c55c7b8c..0196f40c3 100644 --- a/llama_stack/distributions/dell/run-with-safety.yaml +++ b/llama_stack/distributions/dell/run-with-safety.yaml @@ -50,8 +50,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/dell}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/distributions/dell/run.yaml b/llama_stack/distributions/dell/run.yaml index 4779e7607..19b02dc9a 100644 --- a/llama_stack/distributions/dell/run.yaml +++ b/llama_stack/distributions/dell/run.yaml @@ -46,8 +46,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/dell}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml b/llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml index 5c56f34ec..4acd19b38 100644 --- a/llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml +++ b/llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml @@ -61,8 +61,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/meta-reference-gpu}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/distributions/meta-reference-gpu/run.yaml b/llama_stack/distributions/meta-reference-gpu/run.yaml index a2ec94454..1d0aa5172 100644 --- a/llama_stack/distributions/meta-reference-gpu/run.yaml +++ b/llama_stack/distributions/meta-reference-gpu/run.yaml @@ -51,8 +51,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/meta-reference-gpu}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/distributions/nvidia/run-with-safety.yaml b/llama_stack/distributions/nvidia/run-with-safety.yaml index edd258ee4..3ee15b7c1 100644 --- a/llama_stack/distributions/nvidia/run-with-safety.yaml +++ b/llama_stack/distributions/nvidia/run-with-safety.yaml @@ -53,8 +53,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/nvidia}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: nvidia diff --git a/llama_stack/distributions/nvidia/run.yaml b/llama_stack/distributions/nvidia/run.yaml index daa93093b..e947e1e2a 100644 --- a/llama_stack/distributions/nvidia/run.yaml +++ b/llama_stack/distributions/nvidia/run.yaml @@ -48,8 +48,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/nvidia}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: nvidia diff --git a/llama_stack/distributions/open-benchmark/run.yaml b/llama_stack/distributions/open-benchmark/run.yaml index 89442d502..ef17a4d3b 100644 --- a/llama_stack/distributions/open-benchmark/run.yaml +++ b/llama_stack/distributions/open-benchmark/run.yaml @@ -81,8 +81,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/open-benchmark}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/distributions/starter-gpu/run.yaml b/llama_stack/distributions/starter-gpu/run.yaml index b28121815..05b88f012 100644 --- a/llama_stack/distributions/starter-gpu/run.yaml +++ b/llama_stack/distributions/starter-gpu/run.yaml @@ -159,8 +159,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/starter-gpu}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} post_training: - provider_id: huggingface-gpu diff --git a/llama_stack/distributions/starter/run.yaml b/llama_stack/distributions/starter/run.yaml index 341b51a97..74bbc6fca 100644 --- a/llama_stack/distributions/starter/run.yaml +++ b/llama_stack/distributions/starter/run.yaml @@ -159,8 +159,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/starter}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} post_training: - provider_id: torchtune-cpu diff --git a/llama_stack/distributions/watsonx/run.yaml b/llama_stack/distributions/watsonx/run.yaml index aea2189bc..3fc2c9d0e 100644 --- a/llama_stack/distributions/watsonx/run.yaml +++ b/llama_stack/distributions/watsonx/run.yaml @@ -46,8 +46,7 @@ providers: provider_type: inline::meta-reference config: service_name: "${env.OTEL_SERVICE_NAME:=\u200B}" - sinks: ${env.TELEMETRY_SINKS:=sqlite} - sqlite_db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/watsonx}/trace_store.db + sinks: ${env.TELEMETRY_SINKS:=} otel_exporter_otlp_endpoint: ${env.OTEL_EXPORTER_OTLP_ENDPOINT:=} eval: - provider_id: meta-reference diff --git a/llama_stack/providers/inline/telemetry/meta_reference/config.py b/llama_stack/providers/inline/telemetry/meta_reference/config.py index 06420c671..ade552dc5 100644 --- a/llama_stack/providers/inline/telemetry/meta_reference/config.py +++ b/llama_stack/providers/inline/telemetry/meta_reference/config.py @@ -9,13 +9,10 @@ from typing import Any from pydantic import BaseModel, Field, field_validator -from llama_stack.core.utils.config_dirs import RUNTIME_BASE_DIR - class TelemetrySink(StrEnum): OTEL_TRACE = "otel_trace" OTEL_METRIC = "otel_metric" - SQLITE = "sqlite" CONSOLE = "console" @@ -30,12 +27,8 @@ class TelemetryConfig(BaseModel): description="The service name to use for telemetry", ) sinks: list[TelemetrySink] = Field( - default=[TelemetrySink.SQLITE], - description="List of telemetry sinks to enable (possible values: otel_trace, otel_metric, sqlite, console)", - ) - sqlite_db_path: str = Field( - default_factory=lambda: (RUNTIME_BASE_DIR / "trace_store.db").as_posix(), - description="The path to the SQLite database to use for storing traces", + default=[], + description="List of telemetry sinks to enable (possible values: otel_trace, otel_metric, console)", ) @field_validator("sinks", mode="before") @@ -43,13 +36,12 @@ class TelemetryConfig(BaseModel): def validate_sinks(cls, v): if isinstance(v, str): return [TelemetrySink(sink.strip()) for sink in v.split(",")] - return v + return v or [] @classmethod def sample_run_config(cls, __distro_dir__: str, db_name: str = "trace_store.db") -> dict[str, Any]: return { "service_name": "${env.OTEL_SERVICE_NAME:=\u200b}", - "sinks": "${env.TELEMETRY_SINKS:=sqlite}", - "sqlite_db_path": "${env.SQLITE_STORE_DIR:=" + __distro_dir__ + "}/" + db_name, + "sinks": "${env.TELEMETRY_SINKS:=}", "otel_exporter_otlp_endpoint": "${env.OTEL_EXPORTER_OTLP_ENDPOINT:=}", } diff --git a/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py b/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py deleted file mode 100644 index 8ab491189..000000000 --- a/llama_stack/providers/inline/telemetry/meta_reference/sqlite_span_processor.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# All rights reserved. -# -# This source code is licensed under the terms described in the LICENSE file in -# the root directory of this source tree. - -import json -import os -import sqlite3 -import threading -from datetime import UTC, datetime - -from opentelemetry.sdk.trace import SpanProcessor -from opentelemetry.trace import Span -from opentelemetry.trace.span import format_span_id, format_trace_id - -from llama_stack.providers.utils.telemetry.tracing import LOCAL_ROOT_SPAN_MARKER - - -class SQLiteSpanProcessor(SpanProcessor): - def __init__(self, conn_string): - """Initialize the SQLite span processor with a connection string.""" - self.conn_string = conn_string - self._local = threading.local() # Thread-local storage for connections - self.setup_database() - - def _get_connection(self): - """Get a thread-local database connection.""" - if not hasattr(self._local, "conn"): - try: - self._local.conn = sqlite3.connect(self.conn_string) - except Exception as e: - print(f"Error connecting to SQLite database: {e}") - raise - return self._local.conn - - def setup_database(self): - """Create the necessary tables if they don't exist.""" - # Create directory if it doesn't exist - os.makedirs(os.path.dirname(self.conn_string), exist_ok=True) - - conn = self._get_connection() - cursor = conn.cursor() - - cursor.execute( - """ - CREATE TABLE IF NOT EXISTS traces ( - trace_id TEXT PRIMARY KEY, - service_name TEXT, - root_span_id TEXT, - start_time TIMESTAMP, - end_time TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - """ - ) - - cursor.execute( - """ - CREATE TABLE IF NOT EXISTS spans ( - span_id TEXT PRIMARY KEY, - trace_id TEXT REFERENCES traces(trace_id), - parent_span_id TEXT, - name TEXT, - start_time TIMESTAMP, - end_time TIMESTAMP, - attributes TEXT, - status TEXT, - kind TEXT - ) - """ - ) - - cursor.execute( - """ - CREATE TABLE IF NOT EXISTS span_events ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - span_id TEXT REFERENCES spans(span_id), - name TEXT, - timestamp TIMESTAMP, - attributes TEXT - ) - """ - ) - - cursor.execute( - """ - CREATE INDEX IF NOT EXISTS idx_traces_created_at - ON traces(created_at) - """ - ) - - conn.commit() - cursor.close() - - def on_start(self, span: Span, parent_context=None): - """Called when a span starts.""" - pass - - def on_end(self, span: Span): - """Called when a span ends. Export the span data to SQLite.""" - try: - conn = self._get_connection() - cursor = conn.cursor() - - trace_id = format_trace_id(span.get_span_context().trace_id) - span_id = format_span_id(span.get_span_context().span_id) - service_name = span.resource.attributes.get("service.name", "unknown") - - parent_span_id = None - parent_context = span.parent - if parent_context: - parent_span_id = format_span_id(parent_context.span_id) - - # Insert into traces - cursor.execute( - """ - INSERT INTO traces ( - trace_id, service_name, root_span_id, start_time, end_time - ) VALUES (?, ?, ?, ?, ?) - ON CONFLICT(trace_id) DO UPDATE SET - root_span_id = COALESCE(root_span_id, excluded.root_span_id), - start_time = MIN(excluded.start_time, start_time), - end_time = MAX(excluded.end_time, end_time) - """, - ( - trace_id, - service_name, - (span_id if span.attributes.get(LOCAL_ROOT_SPAN_MARKER) else None), - datetime.fromtimestamp(span.start_time / 1e9, UTC).isoformat(), - datetime.fromtimestamp(span.end_time / 1e9, UTC).isoformat(), - ), - ) - - # Insert into spans - cursor.execute( - """ - INSERT INTO spans ( - span_id, trace_id, parent_span_id, name, - start_time, end_time, attributes, status, - kind - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - span_id, - trace_id, - parent_span_id, - span.name, - datetime.fromtimestamp(span.start_time / 1e9, UTC).isoformat(), - datetime.fromtimestamp(span.end_time / 1e9, UTC).isoformat(), - json.dumps(dict(span.attributes)), - span.status.status_code.name, - span.kind.name, - ), - ) - - for event in span.events: - cursor.execute( - """ - INSERT INTO span_events ( - span_id, name, timestamp, attributes - ) VALUES (?, ?, ?, ?) - """, - ( - span_id, - event.name, - datetime.fromtimestamp(event.timestamp / 1e9, UTC).isoformat(), - json.dumps(dict(event.attributes)), - ), - ) - - conn.commit() - cursor.close() - except Exception as e: - print(f"Error exporting span to SQLite: {e}") - - def shutdown(self): - """Cleanup any resources.""" - # We can't access other threads' connections, so we just close our own - if hasattr(self._local, "conn"): - try: - self._local.conn.close() - except Exception as e: - print(f"Error closing SQLite connection: {e}") - finally: - del self._local.conn - - def force_flush(self, timeout_millis=30000): - """Force export of spans.""" - pass diff --git a/llama_stack/providers/inline/telemetry/meta_reference/telemetry.py b/llama_stack/providers/inline/telemetry/meta_reference/telemetry.py index 4d30cbba3..94afdfe22 100644 --- a/llama_stack/providers/inline/telemetry/meta_reference/telemetry.py +++ b/llama_stack/providers/inline/telemetry/meta_reference/telemetry.py @@ -4,7 +4,6 @@ # This source code is licensed under the terms described in the LICENSE file in # the root directory of this source tree. -import datetime import threading from typing import Any @@ -22,10 +21,7 @@ from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapProp from llama_stack.apis.telemetry import ( Event, MetricEvent, - MetricLabelMatcher, - MetricQueryType, QueryCondition, - QueryMetricsResponse, QuerySpanTreeResponse, QueryTracesResponse, Span, @@ -42,11 +38,7 @@ from llama_stack.log import get_logger from llama_stack.providers.inline.telemetry.meta_reference.console_span_processor import ( ConsoleSpanProcessor, ) -from llama_stack.providers.inline.telemetry.meta_reference.sqlite_span_processor import ( - SQLiteSpanProcessor, -) from llama_stack.providers.utils.telemetry.dataset_mixin import TelemetryDatasetMixin -from llama_stack.providers.utils.telemetry.sqlite_trace_store import SQLiteTraceStore from llama_stack.providers.utils.telemetry.tracing import ROOT_SPAN_MARKERS from .config import TelemetryConfig, TelemetrySink @@ -111,15 +103,11 @@ class TelemetryAdapter(TelemetryDatasetMixin, Telemetry): metric_provider = MeterProvider(resource=resource, metric_readers=[metric_reader]) metrics.set_meter_provider(metric_provider) - if TelemetrySink.SQLITE in self.config.sinks: - trace.get_tracer_provider().add_span_processor(SQLiteSpanProcessor(self.config.sqlite_db_path)) if TelemetrySink.CONSOLE in self.config.sinks: trace.get_tracer_provider().add_span_processor(ConsoleSpanProcessor(print_attributes=True)) if TelemetrySink.OTEL_METRIC in self.config.sinks: self.meter = metrics.get_meter(__name__) - if TelemetrySink.SQLITE in self.config.sinks: - self.trace_store = SQLiteTraceStore(self.config.sqlite_db_path) self._lock = _global_lock @@ -139,47 +127,6 @@ class TelemetryAdapter(TelemetryDatasetMixin, Telemetry): else: raise ValueError(f"Unknown event type: {event}") - async def query_metrics( - self, - metric_name: str, - start_time: int, - end_time: int | None = None, - granularity: str | None = None, - query_type: MetricQueryType = MetricQueryType.RANGE, - label_matchers: list[MetricLabelMatcher] | None = None, - ) -> QueryMetricsResponse: - """Query metrics from the telemetry store. - - Args: - metric_name: The name of the metric to query (e.g., "prompt_tokens") - start_time: Start time as Unix timestamp - end_time: End time as Unix timestamp (defaults to now if None) - granularity: Time granularity for aggregation - query_type: Type of query (RANGE or INSTANT) - label_matchers: Label filters to apply - - Returns: - QueryMetricsResponse with metric time series data - """ - # Convert timestamps to datetime objects - start_dt = datetime.datetime.fromtimestamp(start_time, datetime.UTC) - end_dt = datetime.datetime.fromtimestamp(end_time, datetime.UTC) if end_time else None - - # Use SQLite trace store if available - if hasattr(self, "trace_store") and self.trace_store: - return await self.trace_store.query_metrics( - metric_name=metric_name, - start_time=start_dt, - end_time=end_dt, - granularity=granularity, - query_type=query_type, - label_matchers=label_matchers, - ) - else: - raise ValueError( - f"In order to query_metrics, you must have {TelemetrySink.SQLITE} set in your telemetry sinks" - ) - def _log_unstructured(self, event: UnstructuredLogEvent, ttl_seconds: int) -> None: with self._lock: # Use global storage instead of instance storage diff --git a/llama_stack/providers/utils/telemetry/sqlite_trace_store.py b/llama_stack/providers/utils/telemetry/sqlite_trace_store.py deleted file mode 100644 index 71480364c..000000000 --- a/llama_stack/providers/utils/telemetry/sqlite_trace_store.py +++ /dev/null @@ -1,383 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# All rights reserved. -# -# This source code is licensed under the terms described in the LICENSE file in -# the root directory of this source tree. - -import json -from datetime import UTC, datetime -from typing import Protocol - -import aiosqlite - -from llama_stack.apis.telemetry import ( - MetricDataPoint, - MetricLabel, - MetricLabelMatcher, - MetricQueryType, - MetricSeries, - QueryCondition, - QueryMetricsResponse, - Span, - SpanWithStatus, - Trace, -) - - -class TraceStore(Protocol): - async def query_traces( - self, - attribute_filters: list[QueryCondition] | None = None, - limit: int | None = 100, - offset: int | None = 0, - order_by: list[str] | None = None, - ) -> list[Trace]: ... - - async def get_span_tree( - self, - span_id: str, - attributes_to_return: list[str] | None = None, - max_depth: int | None = None, - ) -> dict[str, SpanWithStatus]: ... - - async def query_metrics( - self, - metric_name: str, - start_time: datetime, - end_time: datetime | None = None, - granularity: str | None = "1d", - query_type: MetricQueryType = MetricQueryType.RANGE, - label_matchers: list[MetricLabelMatcher] | None = None, - ) -> QueryMetricsResponse: ... - - -class SQLiteTraceStore(TraceStore): - def __init__(self, conn_string: str): - self.conn_string = conn_string - - async def query_metrics( - self, - metric_name: str, - start_time: datetime, - end_time: datetime | None = None, - granularity: str | None = None, - query_type: MetricQueryType = MetricQueryType.RANGE, - label_matchers: list[MetricLabelMatcher] | None = None, - ) -> QueryMetricsResponse: - if end_time is None: - end_time = datetime.now(UTC) - - # Build base query - if query_type == MetricQueryType.INSTANT: - query = """ - SELECT - se.name, - SUM(CAST(json_extract(se.attributes, '$.value') AS REAL)) as value, - json_extract(se.attributes, '$.unit') as unit, - se.attributes - FROM span_events se - WHERE se.name = ? - AND se.timestamp BETWEEN ? AND ? - """ - else: - if granularity: - time_format = self._get_time_format_for_granularity(granularity) - query = f""" - SELECT - se.name, - SUM(CAST(json_extract(se.attributes, '$.value') AS REAL)) as value, - json_extract(se.attributes, '$.unit') as unit, - se.attributes, - strftime('{time_format}', se.timestamp) as bucket_start - FROM span_events se - WHERE se.name = ? - AND se.timestamp BETWEEN ? AND ? - """ - else: - query = """ - SELECT - se.name, - json_extract(se.attributes, '$.value') as value, - json_extract(se.attributes, '$.unit') as unit, - se.attributes, - se.timestamp - FROM span_events se - WHERE se.name = ? - AND se.timestamp BETWEEN ? AND ? - """ - - params = [f"metric.{metric_name}", start_time.isoformat(), end_time.isoformat()] - - # Labels that will be attached to the MetricSeries (preserve matcher labels) - all_labels: list[MetricLabel] = [] - matcher_label_names = set() - if label_matchers: - for matcher in label_matchers: - json_path = f"$.{matcher.name}" - if matcher.operator == "=": - query += f" AND json_extract(se.attributes, '{json_path}') = ?" - params.append(matcher.value) - elif matcher.operator == "!=": - query += f" AND json_extract(se.attributes, '{json_path}') != ?" - params.append(matcher.value) - elif matcher.operator == "=~": - query += f" AND json_extract(se.attributes, '{json_path}') LIKE ?" - params.append(f"%{matcher.value}%") - elif matcher.operator == "!~": - query += f" AND json_extract(se.attributes, '{json_path}') NOT LIKE ?" - params.append(f"%{matcher.value}%") - # Preserve filter context in output - all_labels.append(MetricLabel(name=matcher.name, value=str(matcher.value))) - matcher_label_names.add(matcher.name) - - # GROUP BY / ORDER BY logic - if query_type == MetricQueryType.RANGE and granularity: - group_time_format = self._get_time_format_for_granularity(granularity) - query += f" GROUP BY strftime('{group_time_format}', se.timestamp), json_extract(se.attributes, '$.unit')" - query += " ORDER BY bucket_start" - elif query_type == MetricQueryType.INSTANT: - query += " GROUP BY json_extract(se.attributes, '$.unit')" - else: - query += " ORDER BY se.timestamp" - - # Execute query - async with aiosqlite.connect(self.conn_string) as conn: - conn.row_factory = aiosqlite.Row - async with conn.execute(query, params) as cursor: - rows = await cursor.fetchall() - - if not rows: - return QueryMetricsResponse(data=[]) - - data_points = [] - # We want to add attribute labels, but only those not already present as matcher labels. - attr_label_names = set() - for row in rows: - # Parse JSON attributes safely, if there are no attributes (weird), just don't add the labels to the result. - try: - attributes = json.loads(row["attributes"] or "{}") - except (TypeError, json.JSONDecodeError): - attributes = {} - - value = row["value"] - unit = row["unit"] or "" - - # Add labels from attributes without duplicating matcher labels, if we don't do this, there will be a lot of duplicate label in the result. - for k, v in attributes.items(): - if k not in ["value", "unit"] and k not in matcher_label_names and k not in attr_label_names: - all_labels.append(MetricLabel(name=k, value=str(v))) - attr_label_names.add(k) - - # Determine timestamp - if query_type == MetricQueryType.RANGE and granularity: - try: - bucket_start_raw = row["bucket_start"] - except KeyError as e: - raise ValueError( - "DB did not have a bucket_start time in row when using granularity, this indicates improper formatting" - ) from e - # this value could also be there, but be NULL, I think. - if bucket_start_raw is None: - raise ValueError("bucket_start is None check time format and data") - bucket_start = datetime.fromisoformat(bucket_start_raw) - timestamp = int(bucket_start.timestamp()) - elif query_type == MetricQueryType.INSTANT: - timestamp = int(datetime.now(UTC).timestamp()) - else: - try: - timestamp_raw = row["timestamp"] - except KeyError as e: - raise ValueError( - "DB did not have a timestamp in row, this indicates improper formatting" - ) from e - # this value could also be there, but be NULL, I think. - if timestamp_raw is None: - raise ValueError("timestamp is None check time format and data") - timestamp_iso = datetime.fromisoformat(timestamp_raw) - timestamp = int(timestamp_iso.timestamp()) - - data_points.append( - MetricDataPoint( - timestamp=timestamp, - value=value, - unit=unit, - ) - ) - - metric_series = [MetricSeries(metric=metric_name, labels=all_labels, values=data_points)] - return QueryMetricsResponse(data=metric_series) - - def _get_time_format_for_granularity(self, granularity: str | None) -> str: - """Get the SQLite strftime format string for a given granularity. - Args: - granularity: Granularity string (e.g., "1m", "5m", "1h", "1d") - Returns: - SQLite strftime format string for the granularity - """ - if granularity is None: - raise ValueError("granularity cannot be None for this method - use separate logic for no aggregation") - - if granularity.endswith("d"): - return "%Y-%m-%d 00:00:00" - elif granularity.endswith("h"): - return "%Y-%m-%d %H:00:00" - elif granularity.endswith("m"): - return "%Y-%m-%d %H:%M:00" - else: - return "%Y-%m-%d %H:%M:00" # Default to most granular which will give us the most timestamps. - - async def query_traces( - self, - attribute_filters: list[QueryCondition] | None = None, - limit: int | None = 100, - offset: int | None = 0, - order_by: list[str] | None = None, - ) -> list[Trace]: - def build_where_clause() -> tuple[str, list]: - if not attribute_filters: - return "", [] - - ops_map = {"eq": "=", "ne": "!=", "gt": ">", "lt": "<"} - - conditions = [ - f"json_extract(s.attributes, '$.{condition.key}') {ops_map[condition.op.value]} ?" - for condition in attribute_filters - ] - params = [condition.value for condition in attribute_filters] - where_clause = " WHERE " + " AND ".join(conditions) - return where_clause, params - - def build_order_clause() -> str: - if not order_by: - return "" - - order_clauses = [] - for field in order_by: - desc = field.startswith("-") - clean_field = field[1:] if desc else field - order_clauses.append(f"t.{clean_field} {'DESC' if desc else 'ASC'}") - return " ORDER BY " + ", ".join(order_clauses) - - # Build the main query - base_query = """ - WITH matching_traces AS ( - SELECT DISTINCT t.trace_id - FROM traces t - JOIN spans s ON t.trace_id = s.trace_id - {where_clause} - ), - filtered_traces AS ( - SELECT t.trace_id, t.root_span_id, t.start_time, t.end_time - FROM matching_traces mt - JOIN traces t ON mt.trace_id = t.trace_id - LEFT JOIN spans s ON t.trace_id = s.trace_id - {order_clause} - ) - SELECT DISTINCT trace_id, root_span_id, start_time, end_time - FROM filtered_traces - WHERE root_span_id IS NOT NULL - LIMIT {limit} OFFSET {offset} - """ - - where_clause, params = build_where_clause() - query = base_query.format( - where_clause=where_clause, - order_clause=build_order_clause(), - limit=limit, - offset=offset, - ) - - # Execute query and return results - async with aiosqlite.connect(self.conn_string) as conn: - conn.row_factory = aiosqlite.Row - async with conn.execute(query, params) as cursor: - rows = await cursor.fetchall() - return [ - Trace( - trace_id=row["trace_id"], - root_span_id=row["root_span_id"], - start_time=datetime.fromisoformat(row["start_time"]), - end_time=datetime.fromisoformat(row["end_time"]), - ) - for row in rows - ] - - async def get_span_tree( - self, - span_id: str, - attributes_to_return: list[str] | None = None, - max_depth: int | None = None, - ) -> dict[str, SpanWithStatus]: - # Build the attributes selection - attributes_select = "s.attributes" - if attributes_to_return: - json_object = ", ".join(f"'{key}', json_extract(s.attributes, '$.{key}')" for key in attributes_to_return) - attributes_select = f"json_object({json_object})" - - # SQLite CTE query with filtered attributes - query = f""" - WITH RECURSIVE span_tree AS ( - SELECT s.*, 1 as depth, {attributes_select} as filtered_attributes - FROM spans s - WHERE s.span_id = ? - - UNION ALL - - SELECT s.*, st.depth + 1, {attributes_select} as filtered_attributes - FROM spans s - JOIN span_tree st ON s.parent_span_id = st.span_id - WHERE (? IS NULL OR st.depth < ?) - ) - SELECT * - FROM span_tree - ORDER BY depth, start_time - """ - - spans_by_id = {} - async with aiosqlite.connect(self.conn_string) as conn: - conn.row_factory = aiosqlite.Row - async with conn.execute(query, (span_id, max_depth, max_depth)) as cursor: - rows = await cursor.fetchall() - - if not rows: - raise ValueError(f"Span {span_id} not found") - - for row in rows: - span = SpanWithStatus( - span_id=row["span_id"], - trace_id=row["trace_id"], - parent_span_id=row["parent_span_id"], - name=row["name"], - start_time=datetime.fromisoformat(row["start_time"]), - end_time=datetime.fromisoformat(row["end_time"]), - attributes=json.loads(row["filtered_attributes"]), - status=row["status"].lower(), - ) - - spans_by_id[span.span_id] = span - - return spans_by_id - - async def get_trace(self, trace_id: str) -> Trace: - query = """ - SELECT * - FROM traces t - WHERE t.trace_id = ? - """ - async with aiosqlite.connect(self.conn_string) as conn: - conn.row_factory = aiosqlite.Row - async with conn.execute(query, (trace_id,)) as cursor: - row = await cursor.fetchone() - if row is None: - raise ValueError(f"Trace {trace_id} not found") - return Trace(**row) - - async def get_span(self, trace_id: str, span_id: str) -> Span: - query = "SELECT * FROM spans WHERE trace_id = ? AND span_id = ?" - async with aiosqlite.connect(self.conn_string) as conn: - conn.row_factory = aiosqlite.Row - async with conn.execute(query, (trace_id, span_id)) as cursor: - row = await cursor.fetchone() - if row is None: - raise ValueError(f"Span {span_id} not found") - return Span(**row)