-
Notifications
You must be signed in to change notification settings - Fork 12.1k
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
Loki: Display error with label filter conflicts #63109
Conversation
Backend code coverage report for PR #63109 |
Frontend code coverage report for PR #63109
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gwdawson Could you also do {job="tns/app", job!="tns/app"}?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/loki/querybuilder/operationUtils.test.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.test.ts
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.tsx
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! This is a partial review, will share some more feedback shortly.
public/app/plugins/datasource/loki/querybuilder/operationUtils.test.ts
Outdated
Show resolved
Hide resolved
public/app/plugins/datasource/loki/querybuilder/operationUtils.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some suggestions for your consideration. If you don't plan to implement them, I'd appreciate if you can share the reason with me.
export function isConflictingFilter( | ||
operation: QueryBuilderOperation, | ||
queryOperations: QueryBuilderOperation[] | ||
): boolean { | ||
let conflictingFilter = false; | ||
|
||
const labelFilters = queryOperations.filter((op) => { | ||
return op.id === LokiOperationId.LabelFilter && op.params !== operation.params; | ||
}); | ||
|
||
// check if the new filter conflicts with any other label filter | ||
labelFilters.forEach((filter) => { | ||
if (operation.params[0] !== filter.params[0] || operation.params[2] !== filter.params[2]) { | ||
return; | ||
} | ||
|
||
if ( | ||
(String(operation.params[1]).startsWith('!') && !String(filter.params[1]).startsWith('!')) || | ||
(String(filter.params[1]).startsWith('!') && !String(operation.params[1]).startsWith('!')) | ||
) { | ||
conflictingFilter = true; | ||
} | ||
}); | ||
|
||
return conflictingFilter; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative approach to consider.
export function isConflictingFilter( | |
operation: QueryBuilderOperation, | |
queryOperations: QueryBuilderOperation[] | |
): boolean { | |
let conflictingFilter = false; | |
const labelFilters = queryOperations.filter((op) => { | |
return op.id === LokiOperationId.LabelFilter && op.params !== operation.params; | |
}); | |
// check if the new filter conflicts with any other label filter | |
labelFilters.forEach((filter) => { | |
if (operation.params[0] !== filter.params[0] || operation.params[2] !== filter.params[2]) { | |
return; | |
} | |
if ( | |
(String(operation.params[1]).startsWith('!') && !String(filter.params[1]).startsWith('!')) || | |
(String(filter.params[1]).startsWith('!') && !String(operation.params[1]).startsWith('!')) | |
) { | |
conflictingFilter = true; | |
} | |
}); | |
return conflictingFilter; | |
} | |
export function isConflictingFilter( | |
operation: QueryBuilderOperation, | |
queryOperations: QueryBuilderOperation[] | |
): boolean { | |
const operationIsNegative = operation.params[1].toString().startsWith('!'); | |
// Discard non label filters and different params | |
const candidates = queryOperations.filter(queryOperation => (queryOperation.id === LokiOperationId.LabelFilter && queryOperation.params[0] === operation.params[0] && queryOperation.params[2] === operation.params[2])); | |
const conflict = candidates.find((candidate) => { | |
if (operationIsNegative && candidate.params[1].toString().startsWith('!') === false) { | |
return true; | |
} | |
if (operationIsNegative === false && candidate.params[1].toString().startsWith('!')) { | |
return true; | |
} | |
return false; | |
}); | |
return conflict !== undefined; | |
} |
A limitation of the current implementation is that it will continue iterating over all the label filters, even if one has already been found in line 180. I would suggest to change the forEach
to a find
or findIndex
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess some
would also be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely. And it looks like it's potentially faster https://www.measurethat.net/Benchmarks/Show/4337/0/array-find-vs-some
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matyax cool website, based off the fact some
is faster, ill update to use that.
public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx
Show resolved
Hide resolved
public/app/plugins/datasource/prometheus/querybuilder/shared/operationUtils.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 👏 great work! Really appreciate that you were on board with the latest iterations.
* feat: add logic to check for conflicting operator * feat: display error if there is a conflict * feat: check if label filter conflicts with other filters * fix: remove capitalisation from "no data" * test: add tests for isConflictingFilter function * feat(labels): add validation for label matchers * test(labels): add tests for isConflictingSelector * refactor(labels): add suggestions from code review * test(labels): add case for labels without op * refactor(operations): add suggestions from code review * feat(operations): display tooltip when you have conflicts * fix: remove unused props from test * fix: remove old test * fix(labels): error message now displays in the correct location * fix(operations): operations can be dragged, even with error * fix: remove unused vars * fix: failing tests * fix(operations): hide error message whilst dragging * refactor: use more appropriate variable naming * refactor: add suggestions from code review * perf: use array.some instead of array.find
What is this feature?
Why do we need this feature?
...
Who is this feature for?
...
Which issue(s) does this PR fix?:
Fixes #59548
Special notes for your reviewer
test queries should be constructed in the builder mode.
Testing these conflict errors
construct the following query in the builder mode.
{job="tns/app", job!="tns/app"} | level = 'error' | level != 'error'