Skip to content

fix(memory): accept string-form error filters in trace search#8217

Merged
yurishkuro merged 9 commits into
jaegertracing:mainfrom
YoungHypo:haibo-fix-error-type
Mar 27, 2026
Merged

fix(memory): accept string-form error filters in trace search#8217
yurishkuro merged 9 commits into
jaegertracing:mainfrom
YoungHypo:haibo-fix-error-type

Conversation

@YoungHypo
Copy link
Copy Markdown
Contributor

@YoungHypo YoungHypo commented Mar 21, 2026

Which problem is this PR solving?

The existing query stack encodes tag filters as strings. In particular, MCP search_traces translates with_errors=true into the query attribute error="true".

The v2 memory backend handled the error query attribute as bool-only during trace filtering, which made it inconsistent with the existing query convention and caused string-form error filters to be misinterpreted.

Description of the changes

  • keep MCP search_traces aligned with the existing string-based query attribute convention
  • update the memory backend to accept both boolean and string forms of the error query attribute
  • add regression coverage for string-form error filters in the memory backend
  • add an MCP -> QueryService -> memory integration test to verify the end-to-end with_errors flow

Here is a Mermaid diagram to help explain why the current code had a bug from TestSearchTracesHandler_Handle_WithErrorsFilter_UsingMemoryStore.

sequenceDiagram
    participant T as Test
    participant H as handle()
    participant BQ as buildQuery()
    participant FT as FindTraces()
    participant M as memory.FindTraces()
    participant VS as validSpan()
    
    T->>H: handle(ctx, req, input)
    H->>BQ: buildQuery(input)
    Note over BQ: PutStr("error", "true")
    BQ-->>H: Attributes: {error: "true" (string)}
    H->>FT: FindTraces(ctx, query)
    FT->>M: FindTraces(ctx, query)
    M->>VS: validSpan(span, query)
    
    Note over VS: errAttribute.Bool()
    Note over VS: String.Bool() = false
    
    VS->>VS: !false && Error != Ok = true
    VS-->>M: return false
    M-->>FT: (no trace)
    FT-->>H: empty iterator
    H-->>T: output.Traces = []
Loading

How was this change tested?

go test -v ./cmd/jaeger/internal/extension/jaegermcp/internal/handlers/... -run "TestSearchTracesHandler_Handle_WithErrorsFilter_UsingMemoryStore"

go test -v ./internal/storage/v2/memory/... -run "TestFindTraces_ErrorAttributeStringCompatibility"  

Checklist

AI Usage in this PR (choose one)

See AI Usage Policy.

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@YoungHypo YoungHypo requested a review from a team as a code owner March 21, 2026 07:50
Copilot AI review requested due to automatic review settings March 21, 2026 07:50
@dosubot dosubot Bot added the bug label Mar 21, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Jaeger MCP’s search_traces.with_errors query construction to encode the internal error attribute as a boolean (instead of a string), aligning behavior across storage backends (notably the v2 memory store).

Changes:

  • Update search_traces query building to use attributes.PutBool("error", true).
  • Add a handler test that exercises WithErrors filtering against the v2 memory store implementation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
cmd/jaeger/internal/extension/jaegermcp/internal/handlers/search_traces.go Switches the error attribute filter from string to boolean in buildQuery.
cmd/jaeger/internal/extension/jaegermcp/internal/handlers/search_traces_test.go Adds a memory-store-backed test for WithErrors filtering and imports the v2 memory store.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.65%. Comparing base (0c52c06) to head (600299e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8217   +/-   ##
=======================================
  Coverage   95.65%   95.65%           
=======================================
  Files         318      318           
  Lines       16804    16818   +14     
=======================================
+ Hits        16074    16088   +14     
  Misses        577      577           
  Partials      153      153           
Flag Coverage Δ
badger_direct 9.05% <0.00%> (-0.02%) ⬇️
badger_e2e 1.04% <0.00%> (-0.01%) ⬇️
cassandra-4.x-direct-manual 13.23% <0.00%> (-0.02%) ⬇️
cassandra-4.x-e2e-auto 1.03% <0.00%> (-0.01%) ⬇️
cassandra-4.x-e2e-manual 1.03% <0.00%> (-0.01%) ⬇️
cassandra-5.x-direct-manual 13.23% <0.00%> (-0.02%) ⬇️
cassandra-5.x-e2e-auto 1.03% <0.00%> (-0.01%) ⬇️
cassandra-5.x-e2e-manual 1.03% <0.00%> (-0.01%) ⬇️
clickhouse 1.16% <0.00%> (-0.01%) ⬇️
elasticsearch-6.x-direct 16.81% <0.00%> (-0.03%) ⬇️
elasticsearch-7.x-direct 16.84% <0.00%> (-0.03%) ⬇️
elasticsearch-8.x-direct 16.99% <0.00%> (-0.03%) ⬇️
elasticsearch-8.x-e2e 1.04% <0.00%> (-0.01%) ⬇️
elasticsearch-9.x-e2e 1.04% <0.00%> (-0.01%) ⬇️
grpc_direct 7.78% <0.00%> (-0.02%) ⬇️
grpc_e2e 1.04% <0.00%> (-0.01%) ⬇️
kafka-3.x-v2 1.04% <0.00%> (-0.01%) ⬇️
memory_v2 1.04% <0.00%> (-0.01%) ⬇️
opensearch-1.x-direct 16.88% <0.00%> (-0.03%) ⬇️
opensearch-2.x-direct 16.88% <0.00%> (-0.03%) ⬇️
opensearch-2.x-e2e 1.04% <0.00%> (-0.01%) ⬇️
opensearch-3.x-e2e 1.04% <0.00%> (-0.01%) ⬇️
query 1.04% <0.00%> (-0.01%) ⬇️
tailsampling-processor 0.52% <0.00%> (-0.01%) ⬇️
unittests 94.35% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI sends all tag filters as strings today, and they are converted to Attributes object using PutStr:

func convertTagsToAttributes(tags map[string]string) pcommon.Map {
attrs := pcommon.NewMap()
for k, v := range tags {
attrs.PutStr(k, v)
}
return attrs
}

Why is this MCP tool need to do differently?

@YoungHypo
Copy link
Copy Markdown
Contributor Author

As you pointed out, existing query paths normalize tag filters to strings, for example in convertTagsToAttributes, so MCP should follow the same internal convention even though types.SearchTracesInput.WithErrors is a boolean at the API layer.

// WithErrors filters to only return traces containing error spans (optional).
WithErrors bool `json:"with_errors,omitempty" jsonschema:"If true only return traces containing error spans"`

That means WithErrors being a bool in MCP input is fine. buildQuery will encode it into query attributes in String type.

if input.WithErrors {
attributes.PutStr("error", "true")
}

The inconsistency seems to be in the memory backend. In validSpan, the error filter is interpreted as bool-only via errAttribute.Bool(), instead of also accepting "true" / "false" string values. That makes memory narrower than the existing query convention.

if errAttribute, ok := query.Attributes.Get(errorAttribute); ok {
if errAttribute.Bool() && span.Status().Code() != ptrace.StatusCodeError {
return false
}
if !errAttribute.Bool() && span.Status().Code() != ptrace.StatusCodeOk {
return false
}
}

Would you prefer the fix to be in the memory backend, by making it accept both string and boolean forms of the error query attribute? @yurishkuro

Copilot AI review requested due to automatic review settings March 23, 2026 00:25
@YoungHypo YoungHypo force-pushed the haibo-fix-error-type branch from 9f5b64e to 271b35b Compare March 23, 2026 00:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/storage/v2/memory/tenant.go
Comment on lines 163 to 167
// Verify that error attribute filter is added
val, ok := query.Attributes.Get("error")
errorAttr, ok := query.Attributes.Get("error")
assert.True(t, ok)
assert.Equal(t, "true", val.Str())
assert.Equal(t, "true", errorAttr.Str())

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test still asserts the error query attribute is a string (errorAttr.Str() == "true"). Per the PR intent (and to avoid backend-specific behavior), the error attribute should be encoded as a boolean. Update the assertion to require a boolean type/value (e.g., errorAttr.Type() == pcommon.ValueTypeBool and errorAttr.Bool() == true), and ensure the handler builds the query accordingly.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree. This 271b35b reverts the error attribute from bool to string. The errorQueryValue() function in tenant.go adds backward compatibility to handle both types. The test correctly asserts string type.

Comment on lines +191 to +227
func TestSearchTracesHandler_Handle_WithErrorsFilter_UsingMemoryStore(t *testing.T) {
store, err := memory.NewStore(memory.Configuration{MaxTraces: 10})
require.NoError(t, err)

require.NoError(t, store.WriteTraces(context.Background(), createTestTrace(
"trace111",
"test",
"/ok",
false,
)))
require.NoError(t, store.WriteTraces(context.Background(), createTestTrace(
"trace222",
"test",
"/error",
true,
)))

handler := &searchTracesHandler{
queryService: querysvc.NewQueryService(store, store, querysvc.QueryServiceOptions{}),
maxResults: 100,
}

input := types.SearchTracesInput{
StartTimeMin: "-1h",
ServiceName: "test",
WithErrors: true,
}

_, output, err := handler.handle(context.Background(), &mcp.CallToolRequest{}, input)

require.NoError(t, err)
require.Len(t, output.Traces, 1)
assert.True(t, output.Traces[0].HasErrors)
assert.Equal(t, "test", output.Traces[0].RootService)
assert.Equal(t, "/error", output.Traces[0].RootSpanName)
assert.Empty(t, output.Error)
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new memory-store test validates returned results, but it does not actually assert that the handler encodes the error query attribute as a boolean. If the memory backend accepts both string and bool (as it now does), this test won’t catch regressions back to string encoding. Consider asserting the query attribute type/value (via a mock query service) or tightening the memory backend behavior for this handler path so the test enforces boolean semantics.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree. This test is intended to verify the end-to-end MCP -> QueryService -> memory behavior, not to enforce a boolean encoding in the handler.

The handler encoding is already covered by TestSearchTracesHandler_Handle_WithErrorsFilter, which explicitly checks that WithErrors is translated to the string query attribute error="true".

For this PR, string encoding is the intended behavior, and the memory backend change is specifically to make that existing query convention work correctly.

@YoungHypo
Copy link
Copy Markdown
Contributor Author

@yurishkuro I’ve updated this PR to fix the issue in the memory backend instead of changing MCP.

The memory backend now accepts both string and boolean forms of the error query attribute, and I added both regression coverage and an MCP -> memory integration test. Please take another look when convenient.

@YoungHypo YoungHypo changed the title fix(jaegermcp): use PutBool instead of PutStr for error attribute in … fix(memory): accept string-form error filters in trace search Mar 23, 2026
@YoungHypo YoungHypo requested a review from yurishkuro March 23, 2026 01:13
Copilot AI review requested due to automatic review settings March 23, 2026 01:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 24, 2026 15:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yurishkuro yurishkuro merged commit d732152 into jaegertracing:main Mar 27, 2026
69 of 70 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants