Skip to content

Commit dc2480a

Browse files
committed
Add Kiali trace details
Signed-off-by: josunect <[email protected]>
1 parent 0e88935 commit dc2480a

File tree

4 files changed

+89
-6
lines changed

4 files changed

+89
-6
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,16 +462,19 @@ In case multi-cluster support is enabled (default) and you have access to multip
462462
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (optional)
463463
- `tags` (`string`) - JSON string of tags to filter traces (optional)
464464

465-
- **workload_traces** - Get distributed tracing data for a specific workload in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis.
465+
- **workload_traces** - Get distributed tracing data for a specific workload in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis. Note: startMicros and endMicros are typically required by the Kiali API.
466466
- `clusterName` (`string`) - Cluster name for multi-cluster environments (optional)
467-
- `endMicros` (`string`) - End time for traces in microseconds since epoch (optional)
467+
- `endMicros` (`string`) - End time for traces in microseconds since epoch (required by Kiali API)
468468
- `limit` (`integer`) - Maximum number of traces to return (default: 100)
469469
- `minDuration` (`integer`) - Minimum trace duration in microseconds (optional)
470470
- `namespace` (`string`) **(required)** - Namespace containing the workload
471-
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (optional)
471+
- `startMicros` (`string`) - Start time for traces in microseconds since epoch (required by Kiali API)
472472
- `tags` (`string`) - JSON string of tags to filter traces (optional)
473473
- `workload` (`string`) **(required)** - Name of the workload to get traces for
474474

475+
- **trace_details** - Get detailed information for a specific trace by its ID. Returns complete trace information including all spans, timing details, and metadata for in-depth analysis.
476+
- `traceId` (`string`) **(required)** - Unique identifier of the trace to retrieve
477+
475478
</details>
476479

477480

pkg/kiali/mesh_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,29 @@ func (s *KialiSuite) TestMeshStatus() {
3838
})
3939

4040
}
41+
42+
func (s *KialiSuite) TestTraceDetails() {
43+
var capturedURL *url.URL
44+
s.MockServer.Config().BearerToken = "token-xyz"
45+
s.MockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
46+
u := *r.URL
47+
capturedURL = &u
48+
_, _ = w.Write([]byte(`{"traceId":"test-trace-123","spans":[]}`))
49+
}))
50+
51+
s.Config = test.Must(config.ReadToml([]byte(fmt.Sprintf(`
52+
[toolset_configs.kiali]
53+
url = "%s"
54+
`, s.MockServer.Config().Host))))
55+
k := NewKiali(s.Config, s.MockServer.Config())
56+
57+
traceId := "test-trace-123"
58+
out, err := k.TraceDetails(s.T().Context(), traceId)
59+
s.Require().NoError(err, "Expected no error executing request")
60+
s.Run("response body is correct", func() {
61+
s.Contains(out, traceId, "Response should contain trace ID")
62+
})
63+
s.Run("path is correct", func() {
64+
s.Equal("/api/traces/test-trace-123", capturedURL.Path, "Unexpected path")
65+
})
66+
}

pkg/kiali/traces.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,16 @@ func (k *Kiali) WorkloadTraces(ctx context.Context, namespace string, workload s
105105

106106
return k.executeRequest(ctx, http.MethodGet, endpoint, "", nil)
107107
}
108+
109+
// TraceDetails returns detailed information for a specific trace by its ID.
110+
// Parameters:
111+
// - traceId: the unique identifier of the trace
112+
func (k *Kiali) TraceDetails(ctx context.Context, traceId string) (string, error) {
113+
if traceId == "" {
114+
return "", fmt.Errorf("trace ID is required")
115+
}
116+
117+
endpoint := fmt.Sprintf("/api/traces/%s", url.PathEscape(traceId))
118+
119+
return k.executeRequest(ctx, http.MethodGet, endpoint, "", nil)
120+
}

pkg/toolsets/kiali/traces.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func initTraces() []api.ServerTool {
128128
ret = append(ret, api.ServerTool{
129129
Tool: api.Tool{
130130
Name: "workload_traces",
131-
Description: "Get distributed tracing data for a specific workload in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis.",
131+
Description: "Get distributed tracing data for a specific workload in a namespace. Returns trace information including spans, duration, and error details for troubleshooting and performance analysis. Note: startMicros and endMicros are typically required by the Kiali API.",
132132
InputSchema: &jsonschema.Schema{
133133
Type: "object",
134134
Properties: map[string]*jsonschema.Schema{
@@ -142,11 +142,11 @@ func initTraces() []api.ServerTool {
142142
},
143143
"startMicros": {
144144
Type: "string",
145-
Description: "Start time for traces in microseconds since epoch (optional)",
145+
Description: "Start time for traces in microseconds since epoch (required by Kiali API)",
146146
},
147147
"endMicros": {
148148
Type: "string",
149-
Description: "End time for traces in microseconds since epoch (optional)",
149+
Description: "End time for traces in microseconds since epoch (required by Kiali API)",
150150
},
151151
"limit": {
152152
Type: "integer",
@@ -180,6 +180,32 @@ func initTraces() []api.ServerTool {
180180
Handler: workloadTracesHandler,
181181
})
182182

183+
// Trace details tool
184+
ret = append(ret, api.ServerTool{
185+
Tool: api.Tool{
186+
Name: "trace_details",
187+
Description: "Get detailed information for a specific trace by its ID. Returns complete trace information including all spans, timing details, and metadata for in-depth analysis.",
188+
InputSchema: &jsonschema.Schema{
189+
Type: "object",
190+
Properties: map[string]*jsonschema.Schema{
191+
"traceId": {
192+
Type: "string",
193+
Description: "Unique identifier of the trace to retrieve",
194+
},
195+
},
196+
Required: []string{"traceId"},
197+
},
198+
Annotations: api.ToolAnnotations{
199+
Title: "Trace: Details",
200+
ReadOnlyHint: ptr.To(true),
201+
DestructiveHint: ptr.To(false),
202+
IdempotentHint: ptr.To(true),
203+
OpenWorldHint: ptr.To(true),
204+
},
205+
},
206+
Handler: traceDetailsHandler,
207+
})
208+
183209
return ret
184210
}
185211

@@ -283,3 +309,18 @@ func workloadTracesHandler(params api.ToolHandlerParams) (*api.ToolCallResult, e
283309
}
284310
return api.NewToolCallResult(content, nil), nil
285311
}
312+
313+
func traceDetailsHandler(params api.ToolHandlerParams) (*api.ToolCallResult, error) {
314+
// Extract required parameter
315+
traceId, ok := params.GetArguments()["traceId"].(string)
316+
if !ok || traceId == "" {
317+
return api.NewToolCallResult("", fmt.Errorf("traceId parameter is required")), nil
318+
}
319+
320+
k := params.NewKiali()
321+
content, err := k.TraceDetails(params.Context, traceId)
322+
if err != nil {
323+
return api.NewToolCallResult("", fmt.Errorf("failed to get trace details: %v", err)), nil
324+
}
325+
return api.NewToolCallResult(content, nil), nil
326+
}

0 commit comments

Comments
 (0)