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

[lens] Basic usage telemetry for total visualizations, and by type #47597

Merged
merged 8 commits into from
Oct 10, 2019

Conversation

wylieconlon
Copy link
Contributor

@wylieconlon wylieconlon commented Oct 8, 2019

This implements new telemetry that tracks saved Lens visualizations broken down by type, and also by three categories: overall, 30 day window, 90 day window.

Because we have the XY visualization type which contains sub-types, this splits that visualization into subtypes. It does not account for each of the layers.

The shape of this telemetry object is:

"lens": {
  "visualization_types_overall": {
    "area_stacked": 2,
    "lnsDatatable": 1
  },
  "visualization_types_last_30_days": {
    "area_stacked": 2,
    "lnsDatatable": 1
  },
  "visualization_types_last_90_days": {
    "area_stacked": 2,
    "lnsDatatable": 1
  },
  "saved_total": 3,
  "saved_last_30_days": 3,
  "saved_last_90_days": 3
},

@wylieconlon wylieconlon added Feature:Telemetry Team:Visualizations Visualization editors, elastic-charts and infrastructure v8.0.0 Feature:Lens v7.5.0 labels Oct 8, 2019
@wylieconlon wylieconlon requested a review from a team October 8, 2019 16:00
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

@wylieconlon wylieconlon added the release_note:skip Skip the PR/issue when compiling release notes label Oct 8, 2019
Copy link

@AlonaNadler AlonaNadler left a comment

Choose a reason for hiding this comment

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

Thanks @wylieconlon this is a good start.
Can we do the same for the last 30 days? only counting the saved objects that were done in the last 30 days

@elasticmachine
Copy link
Contributor

💔 Build Failed

@wylieconlon
Copy link
Contributor Author

@AlonaNadler Yes, I'll be adding that as soon as I understand whether there is some way of doing that automatically.

@wylieconlon wylieconlon requested a review from tsullivan October 8, 2019 22:15
@elasticmachine
Copy link
Contributor

💔 Build Failed

Copy link
Contributor

@chrisdavies chrisdavies left a comment

Choose a reason for hiding this comment

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

LGTM w/ tweaks. This all looks fine to me, except I think we should probably optimize the querying a bit.

import { getVisualizationCounts } from './visualization_counts';
import { LensUsage } from './types';

export function getSavedObjectsClient(
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to only be used internally. Maybe don't export it?

return getVisualizationCounts(savedObjectsClient);
} catch (err) {
return {
saved_total: 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the right behavior? It seems like it'd skew our data if errors are happening. Not sure what else we should do, and I know nothing about the usage collector system, so this may be the right thing. It just feels wrong, and makes me doubt our metrics, if this is the recommended approach.

*/

export interface LensUsage {
visualization_types_overall: Record<string, number>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason you're using snake_case instead of camelCase? JavaScript is generally camel cased.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the pattern being used in the rest of the metrics we collect

function groupByType(response: SavedObjectsFindResponse) {
const byVisType: Record<string, number> = {};

response.saved_objects.forEach(({ attributes }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: this feels like it should be a reduce, since that's basically what you're doing in the forEach.

  return response.saved_objects.reduce((acc, { attributes }) => {
    const type = getTypeName(attributes as Document);
    byVisType[type] = (byVisType[type] || 0) + 1;
    return acc;
  }, {} as Record<string, number>);

export async function getVisualizationCounts(
savedObjectsClient: SavedObjectsClient
): Promise<LensUsage> {
const [overall, last30, last90] = await Promise.all([
Copy link
Contributor

Choose a reason for hiding this comment

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

You're doing three fetches, when you only need one: the first one. You can change your groupByType function to return overall, 30_days, and 90_days. That may be premature optimization, but it seems worth it. To me, telemetry should be very light-weight and have as low an impact on the system as possible, since it is not a primary feature.

I also think we should filter this down to only fetch the subset of fields that we care about, rather than fetching the entire saved object. I think all that we care about is type, visualizationType, and updated_at, right?

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Contributor

@chrisdavies chrisdavies left a comment

Choose a reason for hiding this comment

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

LGTM I know next to nothing about painless, so can't speak to the accuracy of it, but it looks right based on a read-through and glancing at the docs.

// without this kind of mapping we would not be able to access `lens.state` in painless
map_script: `
String visType = doc['lens.visualizationType'].value;
String niceType = visType == 'lnsXY' ? doc['lens.state.visualization.preferredSeriesType'].value : visType;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fine for now, but I really don't like special casing like this. Eventually, we should solve this more generally so that if other visualizations / Lens plugins have sub-types, we still get metrics about that.

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@wylieconlon wylieconlon merged commit 976cf47 into elastic:master Oct 10, 2019
@wylieconlon wylieconlon deleted the lens/telemetry branch October 10, 2019 20:36
wylieconlon pushed a commit to wylieconlon/kibana that referenced this pull request Oct 10, 2019
…lastic#47597)

* [lens] Basic usage telemetry for total visualizations, and by type

* Implement overall, 30 day, 90 day tracking for saved visualizations

* Add forgotten file

* Implement collection using scripted metrics

* Add functional test to ensure painless script is working
wylieconlon pushed a commit that referenced this pull request Oct 10, 2019
…47597) (#47899)

* [lens] Basic usage telemetry for total visualizations, and by type

* Implement overall, 30 day, 90 day tracking for saved visualizations

* Add forgotten file

* Implement collection using scripted metrics

* Add functional test to ensure painless script is working
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Lens Feature:Telemetry release_note:skip Skip the PR/issue when compiling release notes Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.5.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants