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

[APM] Service maps anomaly detection status in popover #65217

Merged

Conversation

ogupte
Copy link
Contributor

@ogupte ogupte commented May 5, 2020

Partially addresses #64205 and closes #64278 & #65244.

Adds ML status to the service maps popover. Modifies the query a bit to get the actual vs typical values necessary to generate a proper anomaly description
service-maps-ml-popover-4

get the actual vs typical values necessary to generate a proper anomaly description
@ogupte ogupte added release_note:skip Skip the PR/issue when compiling release notes v7.8.0 labels May 5, 2020
@ogupte
Copy link
Contributor Author

ogupte commented May 5, 2020

The main difference with the existing query was that i filtered by result_type: 'record' rather than checking for documents with bucket_span. The reason is that records have record_score which is the same as anomaly_score as well as the actual and typical fields which are necessary to calculate the description text (1.1x higher, 4x higher, etc.). I also pass along the job_id along with the anomaly data so that we can link directly to ML from service maps without requiring any knowledge of anomalous transaction type.

@ogupte ogupte marked this pull request as ready for review May 5, 2020 04:25
@ogupte ogupte requested review from a team as code owners May 5, 2020 04:25
@formgeist
Copy link
Contributor

formgeist commented May 5, 2020

@ogupte Great to see this in 🙌 I have some immediate feedback on the link and the value display;

  1. We should change the link copy to "View anomalies" since we're linking to the time series explorer, not the anomaly explorer, which in hindsight I think is the right choice, but we need to change the label.

  2. The link should open a new tab/window. You fixed this as I was writing this 😉

  3. The anomaly score should be rounded without a decimal point value.

Screenshot 2020-05-05 at 09 46 07

If it's possible while you're in there, could you please remove the framework badge? #64278 - it will make the content of the popover a little easier on the eyes.

- changes anomaly score display to integer formatting
- update link test to 'View anomalies'
Copy link
Member

@jgowdyelastic jgowdyelastic left a comment

Choose a reason for hiding this comment

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

ML changes LGTM

Comment on lines 167 to 173
sort: [
{
record_score: {
order: 'desc' as const
}
}
],
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
sort: [
{
record_score: {
order: 'desc' as const
}
}
],
sort: [{ record_score: { order: 'desc' as const } }],

term: {
result_type: 'record'
}
}
Copy link
Member

@sorenlouv sorenlouv May 5, 2020

Choose a reason for hiding this comment

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

Two things:

  1. shouldn't the query be limited by a couple of things (environment*, date range etc.)? Was this left out intentionally in the previous PR (cc @smith )?

  2. What is record_score exactly? Is the the record within a time range? Or the highest score ever recorded? We can only use it if it's the highest score within the time range we are querying for

* it doesn't seem like ML jobs take environment into account (only service name and transaction type). This seems like a big deal if i'm not mistaken.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. we can make sure to add a date range filter, but i don't think we can filter by environment currently since it's not retained in the ml index.
  2. this is a case where record_score seems appropriate to use after reading https://www.elastic.co/blog/machine-learning-anomaly-scoring-elasticsearch-how-it-works last paragraph

@formgeist
Copy link
Contributor

@ogupte Not sure if this is feasible or not, but I opened a design issue for adding a message when anomaly detection job is not available for a given service, indicating to the user that they can create them in the Service details view. #65244 This is is to mitigate any confusion and because we cannot supply users with a flow to enable it from within the Service maps UI.

…nomalies detected

- removes unecessary service framework name in service map queries
- adds date range filter for anomaly detection
Comment on lines +137 to +141
// ensure all elements get latest data properties
elements.forEach(elementDefinition => {
const el = cy.getElementById(elementDefinition.data.id as string);
el.data(elementDefinition.data);
});
Copy link
Contributor Author

@ogupte ogupte May 5, 2020

Choose a reason for hiding this comment

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

This was necessary to add since the data of each node wasn't being updated when existing elements were re-added. Before adding this, the displayed anomaly data was stale after updating date ranges.

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@ogupte ogupte requested a review from sorenlouv May 5, 2020 18:48
@ogupte ogupte merged commit 4896b65 into elastic:master May 5, 2020
ogupte added a commit to ogupte/kibana that referenced this pull request May 5, 2020
* Adds ML status to the service maps popover. Modifies the query a bit to
get the actual vs typical values necessary to generate a proper anomaly description

* fixed failures and updated tests

* component clean up

* makes the ML link open in a new window

* - Closes elastic#64278 by removing the framework badge.
- changes anomaly score display to integer formatting
- update link test to 'View anomalies'

* - Closes elastic#65244 by displaying a message for services without anomalies detected
- removes unecessary service framework name in service map queries
- adds date range filter for anomaly detection
ogupte added a commit that referenced this pull request May 5, 2020
* Adds ML status to the service maps popover. Modifies the query a bit to
get the actual vs typical values necessary to generate a proper anomaly description

* fixed failures and updated tests

* component clean up

* makes the ML link open in a new window

* - Closes #64278 by removing the framework badge.
- changes anomaly score display to integer formatting
- update link test to 'View anomalies'

* - Closes #65244 by displaying a message for services without anomalies detected
- removes unecessary service framework name in service map queries
- adds date range filter for anomaly detection
Comment on lines +57 to +68
if (serviceAnomalies) {
const maxScore = serviceAnomalies.max_score;
return {
...service,
max_score: maxScore,
severity: getSeverity(maxScore),
actual_value: serviceAnomalies.actual_value,
typical_value: serviceAnomalies.typical_value,
job_id: serviceAnomalies.job_id
};
}
return service;
Copy link
Member

@sorenlouv sorenlouv May 5, 2020

Choose a reason for hiding this comment

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

I don't think we need the conditional here since serviceAnomalies is not optional:

  const servicesDataWithAnomalies = servicesData.map(service => {
    const serviceAnomalies = anomaliesMap[service[SERVICE_NAME]];
    const maxScore = serviceAnomalies.max_score;
    return {
      ...service,
      max_score: maxScore,
      severity: getSeverity(maxScore),
      actual_value: serviceAnomalies.actual_value,
      typical_value: serviceAnomalies.typical_value,
      job_id: serviceAnomalies.job_id
    };
  });

children
}) => {
const jobId = getMlJobId(serviceName, transactionType);
export const MLJobLink: React.FC<Props> = props => {
Copy link
Member

@sorenlouv sorenlouv May 6, 2020

Choose a reason for hiding this comment

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

In this case, are there any advantages to having a union over making some of the props optional?

interface Props {
  serviceName: string;
  transactionType?: string;
  jobId?: string;
  external?: boolean;
}

export const MLJobLink: React.FC<Props> = props => {
  const jobId = props.jobId
    ? props.jobId
    : getMlJobId(props.serviceName, props.transactionType);

const maxScore = selectedNodeData.max_score;
const actualValue = selectedNodeData.actual_value;
const typicalValue = selectedNodeData.typical_value;
const jobId = selectedNodeData.job_id;
Copy link
Member

@sorenlouv sorenlouv May 6, 2020

Choose a reason for hiding this comment

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

These are all any because selectedNodeData is vaguely typed. Currently:

  selectedNodeData: cytoscape.NodeDataDefinition;

Should be changed to something like:

  selectedNodeData: ServiceNode;

where ServiceNode an intersection type:

type ServiceNode = cytoscape.NodeDataDefinition & TypeWithAnomalyDetectionFields

I expect TypeWithAnomalyDetectionFields is defined somewhere on the backend like:

interface TypeWithAnomalyDetectionFields {
  severity?: string;
  maxScore?: string;
 ...
}

(or perhaps it can be inferred from a ReturnType)

@@ -129,38 +124,32 @@ async function getServicesData(options: IEnvOptions) {
[SERVICE_NAME]: bucket.key as string,
[AGENT_NAME]:
(bucket.agent_name.buckets[0]?.key as string | undefined) || '',
Copy link
Member

@sorenlouv sorenlouv May 6, 2020

Choose a reason for hiding this comment

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

It seems like a hack to default agent name to an empty string (''). What's wrong with making it optional and handle that explicitly downstream?

};
}) || []
);
}

function getAnomaliesData(options: IEnvOptions) {
const { client } = options.setup;
const { start, end, client } = options.setup;
const rangeQuery = { range: rangeFilter(start, end, 'timestamp') };
Copy link
Member

@sorenlouv sorenlouv May 6, 2020

Choose a reason for hiding this comment

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

I don't think that extracting rangeQuery from the es query improves the readability. Additionally, what about just writing the query out without the helper?

{ 
  range: { timestamp: { gte: start, lte: end, format: 'epoch_millis' } } 
}

I think the helper is best if it's kept super simple, and only solves one case. if we extend it and try to make it more generic it loses its value.

@cauemarcondes
Copy link
Contributor

Tested:

  • Chrome ✅
  • FF ✅
  • Safari ✅

@cauemarcondes cauemarcondes added the apm:test-plan-done Pull request that was successfully tested during the test plan label May 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apm:test-plan-7.8.0 apm:test-plan-done Pull request that was successfully tested during the test plan release_note:skip Skip the PR/issue when compiling release notes v7.8.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[APM] Service maps: Remove the service.framework badge from the popover information
7 participants