Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ES] Refactored a part of SpanReader to make it reusable for V2 APIs #6824

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

Manik2708
Copy link
Contributor

Which problem is this PR solving?

Fixes a part of: #6458

Description of the changes

  • Refactored a part of SpanReader to make it reusable for V2 APIs

How was this change tested?

  • Unit Tests

Checklist

@Manik2708 Manik2708 requested a review from a team as a code owner March 6, 2025 22:05
@Manik2708 Manik2708 requested a review from jkowall March 6, 2025 22:05
Copy link

codecov bot commented Mar 6, 2025

Codecov Report

Attention: Patch coverage is 96.82540% with 6 lines in your changes missing coverage. Please review.

Project coverage is 96.00%. Comparing base (6037db2) to head (319183f).

Files with missing lines Patch % Lines
...ernal/storage/v1/elasticsearch/spanstore/reader.go 94.91% 2 Missing and 1 partial ⚠️
...nal/storage/v1/elasticsearch/spanstore/readerv1.go 97.47% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6824      +/-   ##
==========================================
- Coverage   96.06%   96.00%   -0.07%     
==========================================
  Files         364      366       +2     
  Lines       20712    20819     +107     
==========================================
+ Hits        19897    19987      +90     
- Misses        622      634      +12     
- Partials      193      198       +5     
Flag Coverage Δ
badger_v1 9.75% <0.00%> (-0.11%) ⬇️
badger_v2 1.96% <0.00%> (-0.03%) ⬇️
cassandra-4.x-v1-manual 14.72% <0.00%> (-0.16%) ⬇️
cassandra-4.x-v2-auto 1.95% <0.00%> (-0.03%) ⬇️
cassandra-4.x-v2-manual 1.95% <0.00%> (-0.03%) ⬇️
cassandra-5.x-v1-manual 14.72% <0.00%> (-0.16%) ⬇️
cassandra-5.x-v2-auto 1.95% <0.00%> (-0.03%) ⬇️
cassandra-5.x-v2-manual 1.95% <0.00%> (-0.03%) ⬇️
elasticsearch-6.x-v1 19.87% <78.30%> (+0.61%) ⬆️
elasticsearch-7.x-v1 19.95% <78.30%> (+0.61%) ⬆️
elasticsearch-8.x-v1 20.12% <78.30%> (+0.61%) ⬆️
elasticsearch-8.x-v2 1.96% <0.00%> (-0.14%) ⬇️
grpc_v1 10.79% <0.00%> (-0.12%) ⬇️
grpc_v2 7.86% <0.00%> (-0.09%) ⬇️
kafka-3.x-v1 10.05% <0.00%> (-0.11%) ⬇️
kafka-3.x-v2 1.96% <0.00%> (-0.03%) ⬇️
memory_v2 1.96% <0.00%> (-0.03%) ⬇️
opensearch-1.x-v1 20.00% <78.30%> (+0.61%) ⬆️
opensearch-2.x-v1 20.00% <78.30%> (+0.61%) ⬆️
opensearch-2.x-v2 1.96% <0.00%> (-0.03%) ⬇️
tailsampling-processor 0.47% <0.00%> (-0.01%) ⬇️
unittests 94.89% <96.82%> (-0.06%) ⬇️

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.

@Manik2708
Copy link
Contributor Author

Manik2708 commented Mar 6, 2025

@mahadzaryab1 @yurishkuro This PR tries to make GetOperations, GetServices and FindTraceIDs of SpanReader ready for V2. But GetTraces, FindTraces can't be fixed because for that we need to make multiread either independent of TraceId or make it generic. First option is not feasible as TraceId is not there in dbmodel. Therefore I suggest usage of generics, like this way:

func [T model.TraceId | otel.TraceId] multiread(traceIds T[], ...other_parameters) dbmodel.Span[] {} 

Or we have to re-implement the multiread method by making some query methods as public (which will be used in the new multiread)
If the generic approach seems fine, then I would raise another PR to implement this seperately!

@yurishkuro
Copy link
Member

yurishkuro commented Mar 6, 2025

@Manik2708 the DB layer treats IDs as strings, so the underlying reader can accept them as strings and make it the responsibility of v1/v2 readers to do a conversion

Signed-off-by: Manik2708 <[email protected]>
multiSearchService := &mocks.MultiSearchService{}
firstMultiSearch := &mocks.MultiSearchService{}
secondMultiSearch := &mocks.MultiSearchService{}
multiSearchService.On("Add", id1Search, id2Search).Return(firstMultiSearch)
multiSearchService.On("Add", id1SearchSpanTime).Return(secondMultiSearch)
multiSearchService.On("Add", mock.AnythingOfType("*elastic.SearchRequest"), mock.AnythingOfType("*elastic.SearchRequest")).Return(firstMultiSearch)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason to do this is because currently it is giving the weired unequal address error:

Add(elastic.SearchRequest) 0: &elastic.SearchRequest{searchType:"", indices:[]string(nil), types:[]string(nil), routing:(string)(nil), preference:(string)(nil), requestCache:(bool)(nil), allowPartialSearchResults:(bool)(nil), ignoreUnavailable:(bool)(0xc00032d320), allowNoIndices:(bool)(nil), expandWildcards:"", scroll:"", source:(elastic.SearchSource)(0xc000349040), searchSource:(elastic.SearchSource)(0xc0003491e0), batchedReduceSize:(int)(nil), maxConcurrentShardRequests:(int)(nil), preFilterShardSize:(int)(nil)}
The closest call I have is: 
Add(elastic.SearchRequest) 0: &elastic.SearchRequest{searchType:"", indices:[]string(nil), types:[]string(nil), routing:(string)(nil), preference:(string)(nil), requestCache:(bool)(nil), allowPartialSearchResults:(bool)(nil), ignoreUnavailable:(bool)(0xc00032cf30), allowNoIndices:(bool)(nil), expandWildcards:"", scroll:"", source:(elastic.SearchSource)(0xc000348820), searchSource:(elastic.SearchSource)(0xc000348680), batchedReduceSize:(int)(nil), maxConcurrentShardRequests:(int)(nil), preFilterShardSize:(int)(nil)}

Copy link
Member

Choose a reason for hiding this comment

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

how did it work before? what changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Earlier the On event was getting triggered on specific parameters but when I changed the parameter of buildTraceByIDQuery from model.TraceID to dbmodel.TraceID it started giving unequal address error as displayed in above comment. This is because (according to my analysis) we are passing model.TraceID in multiread but the query builder is expecting parameters in dbmodel.TraceID causing change in the address. Therefore I made the mock independent of these addresses!

@Manik2708
Copy link
Contributor Author

@yurishkuro Have given a try to refactor the multiread. Please review!

Signed-off-by: Manik2708 <[email protected]>
Signed-off-by: Manik2708 <[email protected]>
@Manik2708 Manik2708 requested a review from yurishkuro March 7, 2025 22:34
@Manik2708
Copy link
Contributor Author

Going to fix the tests!

Signed-off-by: Manik2708 <[email protected]>
@Manik2708 Manik2708 requested a review from yurishkuro March 8, 2025 17:18
Signed-off-by: Manik2708 <[email protected]>
@@ -222,35 +220,14 @@ func timeRangeIndices(indexName, indexDateLayout string, startTime time.Time, en
return indices
}

// GetTrace takes a traceID and returns a Trace associated with that traceID
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand any of these changes anymore. We said multiple times - keep the diffs to a minimum. This file is 75% rewritten, where all we needed is to slightly change the entry point signatures.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But it was asked in the comment #6824 (comment) to move SpanReaderV1 in new file. That's what I was aiming for!

Copy link
Member

Choose a reason for hiding this comment

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

Yes because reader v1 is a net new code which is supposed to be a very thin shim over the main reader. But you are introducing massive changes for the main reader, which should only have cosmetic changes to the signatures of the entry points.

Copy link
Member

Choose a reason for hiding this comment

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

Suggestion - start with get services / operations only to get the refactoring in place, and for other functions keep the signatures the same between v1 and main writer, so just a straight pass through.

Copy link
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.

this is what I am expecting to see:

  1. new readerv1 struct that has the same public methods as reader and implements the official storage API.
  2. each method performs a translation of the arguments and delegates to the reader. Also translates the results back into model/*
  3. the existing reader has almost no changes except all its public methods are modified to accept/return dbmodel types. NO OTHER CHANGES are needed to the existing reader.

This reverts commit d1155d2.

Signed-off-by: Manik2708 <[email protected]>
This reverts commit db96536.

Signed-off-by: Manik2708 <[email protected]>
Signed-off-by: Manik2708 <[email protected]>
Signed-off-by: Manik2708 <[email protected]>
@Manik2708
Copy link
Contributor Author

Manik2708 commented Mar 8, 2025

this is what I am expecting to see:

  1. new readerv1 struct that has the same public methods as reader and implements the official storage API.
  2. each method performs a translation of the arguments and delegates to the reader. Also translates the results back into model/*
  3. the existing reader has almost no changes except all its public methods are modified to accept/return dbmodel types. NO OTHER CHANGES are needed to the existing reader.

@yurishkuro Thanks for the explanation! I have given a try, and now all public methods of reader.go are retained and changes are done in order to accept/return dbmodel.Span except FindTraces, that can't be implemented in SpanReader because it deals with dbmodel.TraceID, from which legacy trace id can't be created. If the changes in reader.go still look high, then will break this PR into multiple small PRs! Please review it!

Signed-off-by: Manik2708 <[email protected]>
@Manik2708 Manik2708 requested a review from yurishkuro March 8, 2025 21:39
@@ -223,34 +222,29 @@ func timeRangeIndices(indexName, indexDateLayout string, startTime time.Time, en
}

// GetTrace takes a traceID and returns a Trace associated with that traceID
func (s *SpanReader) GetTrace(ctx context.Context, query spanstore.GetTraceParameters) (*model.Trace, error) {
func (s *SpanReader) GetTrace(ctx context.Context, traceIDs map[dbmodel.TraceID]string) (map[dbmodel.TraceID][]*dbmodel.Span, error) {
Copy link
Member

Choose a reason for hiding this comment

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

traceIDs map[dbmodel.TraceID]string

what is this a map into? What are the string values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

String values are the legacy trace ids. Please follow this implementation of legacy trace id:

func getLegacyTraceId(traceID model.TraceID) string {
	// https://github.com/jaegertracing/jaeger/pull/1956 added leading zeros to IDs
	// So we need to also read IDs without leading zeros for compatibility with previously saved data.
	// TODO remove in newer versions, added in Jaeger 1.16
	if traceID.High == 0 {
		return strconv.FormatUint(traceID.Low, 16)
	}
	return fmt.Sprintf("%x%016x", traceID.High, traceID.Low)
}

The logic is not changed, it is directly taken from here

var legacyTraceID string
if traceID.High == 0 {
legacyTraceID = strconv.FormatUint(traceID.Low, 16)
} else {
legacyTraceID = fmt.Sprintf("%x%016x", traceID.High, traceID.Low)
}
return elastic.NewBoolQuery().Should(
elastic.NewTermQuery(traceIDField, traceIDStr).Boost(2),
elastic.NewTermQuery(traceIDField, legacyTraceID))

func (s *SpanReader) collectSpans(esSpansRaw []*elastic.SearchHit) ([]*model.Span, error) {
spans := make([]*model.Span, len(esSpansRaw))

func (s *SpanReader) collectJsonSpans(esSpansRaw []*elastic.SearchHit) ([]*dbmodel.Span, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func (s *SpanReader) collectJsonSpans(esSpansRaw []*elastic.SearchHit) ([]*dbmodel.Span, error) {
func (s *SpanReader) collectSpans(esSpansRaw []*elastic.SearchHit) ([]*dbmodel.Span, error) {

unnecessary renaming

Copy link
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.

please split the PR into one that only affects GetServices/Operations. Too many changes at once.

@Manik2708 Manik2708 marked this pull request as draft March 9, 2025 04:27
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.

2 participants