-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Monitor query updates #17459
Monitor query updates #17459
Conversation
8ef3e6a
to
26a3440
Compare
@@ -66,15 +65,19 @@ export interface LogsColumn { | |||
export type LogsColumnType = string; | |||
|
|||
// @public | |||
export type LogsQueryBatchOptions = OperationOptions; | |||
export interface LogsQueryBatchOptions extends OperationOptions { | |||
throwOnAnyFailure?: boolean; |
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.
Since we return a promise that can be rejected, I think rejectOnAnyFailure
might be more accurate.
But remind me...so if I set this to true, then if any of the queries in the batch fails, the whole thing fails? The scenario you talked to me about before was disabling throwing an error on partial failures, so I'm curious about this.
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.
Yes - this one will throw for both complete and partial failures. And the whole thing will fail in this case. But the users will get the data about all the responses. We wanted to follow similar approach across all JS sdks -
if (options.throwOnAnyFailure && result._response.status === 207) { |
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.
Ah gotcha, if search-documents already uses that flag, then disregard my suggestion. Rather keep it consistent with throwOnAnyFailure
then.
while (!result.done) { | ||
console.log(` metricDefinitions - ${result.value.id}, ${result.value.name}`); | ||
secondMetricName = result.value.name!; |
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.
Can we use for await(const result of iterator)
instead?
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.
Also...this has the potential to return lots of results right? Otherwise you'd exit the loop as soon as you got the 2nd metric. Can you collect all the names to pass to the query
method?
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.
yeah we can collect all the names and pass it to query method. Should I change the sample to that?
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 am thinking of letting this be - and may be adding a comment that they can pass in all the names to the query method. What do you think? @chradek
return convertResponseForQueryBatch(flatResponse, rawResponse); | ||
const result: LogsQueryBatchResult = convertResponseForQueryBatch(flatResponse, rawResponse); | ||
if (options?.throwOnAnyFailure && result.batchResultStatus !== "AllSucceeded") { | ||
throw result; |
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.
Same as above
result.logsQueryResultStatus = "Success"; | ||
} | ||
if (options?.throwOnAnyFailure && result.logsQueryResultStatus !== "Success") { | ||
throw result; |
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.
hmmm I'm not sure if throwing a result object is the right thing here - we should throw something that is an Error object
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.
Yeah - we are just following what search documents is doing - in case if i throw an error - then the user won't get the data for queries that succeeded.
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 looked at the guidelines on error handling and while it's not definitively stated that we should always use an ErrorLike I can think of a few reasons why we should be careful with this approach:
- I expect an error to have a name and message property (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/message)
- I am writing a UI app and I just put error.toString() in a banner - what would that look like? [object Object]?
- I guess it's better if I use promise API but even then,
catch
expectsrejected
with a reason as the argument...
Not sure, I think it feels weird to throw something that is not an error. @bterlson or @chradek might convince me otherwise and maybe I have it all wrong in which case it'll be a good chance to learn what is right 😄
Edit to add: maybe I'm just not thinking about it right because it's a partial failure / partial success scenario...
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 think I agree we should have a name, code, and message property (i.e. be error-like), otherwise error handling becomes awkward. Additional properties are fine if needed, though should be used sparingly since TS tooling doesn't help with them without the user explicitly casting.
It's unfortunate that search-documents isn't this way, probably in part because thrown errors don't show up in the API review 😕 I wonder what motivated the search-documents design, does anyone know?
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.
We'd have to ask @xirzec but I wouldn't be surprised if it was an oversight. It wouldn't have shown up in the API review file and the PR that added it was pretty massive (#7482)
I do also think we should throw something error-like. I suspect users would expect message to be available at the very least.
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 am not sure about the complete reasoning for search-documents, but for monitor-query and search-documents - one thing is true that we have multiple results being returned in that one response. For monitor query, in a single response we have multiple result objects and each of them has an error property that has the structure - similar to the guidelines - https://apiview.dev/Assemblies/Review/06691b2d79d543a58a95ad4d0ea22ed4#@azure/monitor-query!ErrorInfo:interface
We need to figure out what to do when user sets the "throwOnAnyError" flag -
- Should we throw the first error?
- Should we throw a list of all errors
- In cases of partial errors (i.e, for responses that have both table property and error property), should we throw both table and error property ?
- Other languages (.NET and Java) are throwing the errors on cases of complete errors and are throwing on partial errors if that flag is set.
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.
This is what python is doing - https://gist.github.com/rakshith91/d08caf649feac0081703d4c1e5850326
sdk/monitor/monitor-query/test/internal/unit/modelConverters.unittest.spec.ts
Show resolved
Hide resolved
Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com>
sdk/monitor/monitor-query/samples/v1/javascript/metricsQuery.js
Outdated
Show resolved
Hide resolved
getMetricByName(metricName) { | ||
return this.metrics.find((it) => it.name === metricName); | ||
} |
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 think you could optimize this by defining the function getMetricByName
outside of this function, and just assigned it to the MetricsQueryResult
object.
Currently, you're creating a new function for every metric result. Changing how this is built would allow you to re-use a single function.
Rough example:
function getMetricByName(metricName: string) {
return this.metrics.find((it) => it.name === metricName);
}
function createMetricsQueryResult(...params): MetricsQueryResult {
return { ...params, getMetricByName };
}
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.
} catch (e) { | ||
return { | ||
visualization: response.body?.render, | ||
status: "Success", |
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 error occurred, but the status is Success
?
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 am updating it in the conditions later. I couldn't put a complex logic in this one line
if (result.tables && result.error) { | ||
result.status = "Partial"; | ||
} else if (result.error && !result.tables) { | ||
result.status = "Failed"; | ||
} else { | ||
result.status = "Success"; | ||
} |
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.
That's interesting. In a different part of your code, you have Failed
as the fall-through case, but here it's success. Any reason for the difference?
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.
No reason really. But now I am thinking if i should refine this - since the tables is never optional in the single query response.
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.
if (!result.error) {
// if there is no error field, it is success
result.status = "Success";
} else {
// result.tables is always present in single query response, even is there is error
if (result.tables.length === 0) {
result.status = "Failed";
} else {
result.status = "Partial";
}
}
```
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.
How about this? So in the other batch query response - the tables can be undefined, but in single query response the "tables" field is always returned. So I think the above code snippet in the comment seems more appropriate for single query.
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.
@chradek wanted follow up on this
Co-authored-by: chradek <51000525+chradek@users.noreply.github.com>
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.
🚀 a few nits but I'll leave up to you! We should make an issue for addressing the throw result
before GA'ing this library
status?: number; | ||
/** The list of tables, columns and rows. */ | ||
// (hoisted up from `LogQueryResult`) | ||
results: { |
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.
Is this just LogsQueryResult[]
or Array<LogsQueryResult>
? Maybe we can reuse the type instead of duplicating if so
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.
Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com>
Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com>
Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com>
…iya/azure-sdk-for-js into monitor-query-updates
Addresses #15988 and #17066