Skip to content

Conversation

@mattkime
Copy link
Contributor

@mattkime mattkime commented Jan 16, 2022

Summary

Add usage counters to data views (and legacy index patterns) REST endpoints.

Adding usageCounter calls to the code was trivial but testing it turned out to be very difficult. Functional testing usageCounters turned out to be idiosyncratic and painful so I switched to unit tests which required a fair amount of code refactoring. The jest tests are only checking for usageCounter calls but the functional / api integration tests cover everything else.

Closes: #100185

@mattkime mattkime changed the title add data views rest usage counters [data views] add usage counters to data views REST api endpoints Jan 16, 2022
@mattkime mattkime marked this pull request as ready for review January 17, 2022 03:09
@mattkime mattkime requested a review from a team as a code owner January 17, 2022 03:09
@mattkime mattkime added v8.1.0 Feature:Data Views Data Views code and UI - index patterns before 8.0 docs release_note:skip Skip the PR/issue when compiling release notes Team:AppServicesSv and removed docs labels Jan 17, 2022
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-services (Team:AppServicesSv)

@mattkime
Copy link
Contributor Author

@elasticmachine merge upstream

const savedObjectsClient = ctx.core.savedObjects.client;
const elasticsearchClient = ctx.core.elasticsearch.client.asCurrentUser;
const [, , { dataViewsServiceFactory }] = await getStartServices();
usageCollection?.incrementCounter({ counterName: path });
Copy link
Contributor

Choose a reason for hiding this comment

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

While counterType and incrementBy are optional, you could add even more detail by using counterType as error or legacyError or something along those lines.

There are a few plugins that use counterType to describe the stats, e.g. alerting uses 'legacyTerminology' to track legacy terms.
Here we could do something similar:

usageCollection?.incrementCounter({
        counterName: path,
        counterType: 'legacyError'
      });

Copy link
Contributor

@TinaHeiligers TinaHeiligers left a comment

Choose a reason for hiding this comment

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

The changes look fine to me but I'd be more confident if we had tests for the implementation. I'll leave that decision up to your team though.

Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

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

Did not test this locally, but the code LGTM. Left minor nits and a question about implementation that might be interesting to consider for future.

headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
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 existed before, but it is not necessary to call JSON.stringify here.

registerPutRuntimeFieldRouteLegacy(router, getStartServices);
registerUpdateRuntimeFieldRouteLegacy(router, getStartServices);
// ###
routes.forEach((route) => route(router, getStartServices, dataViewRestCounter));
Copy link
Contributor

Choose a reason for hiding this comment

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

nice!


registerRoutes(core.http, core.getStartServices);
registerRoutes(core.http, core.getStartServices, dataViewRestCounter);

Copy link
Contributor

Choose a reason for hiding this comment

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

@mattkime what do you think of accessing the path pattern at the http service level? Dreaming here:

    http.registerOnPreResponse((req, res, t) => {
      //                                                                      t.matchedRoute does not exist
      usageCollection?.incrementCounter({ counterName: `${req.route.method} ${t.matchedRoute.path}` });
      return t.next();
    });

I'm not sure how common this need is (or what other things that might address). If you agree though perhaps we can suggest it to core. I may also be misunderstanding when onPreResponse is occurring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jloleysens thats an interesting idea - I'll talk to core about it

@mattkime
Copy link
Contributor Author

@elasticmachine merge upstream

@kibana-ci
Copy link

💚 Build Succeeded

Metrics [docs]

✅ unchanged

History

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

Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

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

Great work @mattkime ! I'm approving to unblock progress but a couple ideas came to mind as I was re-reviewing this:

It looks like this implementation will not capture 400 responses that do not make it past the schema check - I'm guessing this would be a small-ish number overall so should be OK! But it is usage info that we can't track.

The other idea was: it still feels like we could address this at a slightly higher level of abstraction. The weakness there would be dealing with exceptions like only wanting to capture this info for a subset of routes, but it might still be a bit less work. Something like an "enhanced" router where we wrapped get, put, post and wrapped the route handler in a function that does the incrementCounter call. But perhaps that does not fit with what you are trying to capture. Just wanted to share the idea :) - I also see the advantage of the logic at a lower level - easier to adapt if needed per case.

[EDIT]

Also did a smoke-test and everything looks to be working as expected!

Copy link
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

Code lgtm,

It will be very useful to know if API is called by Kibana or by someone else.
This way we will know the usage outside of Kibana and can make better decisions about public APIs.

Do we have this reported?
If not automatically, maybe we can add a flag or something based on headers?

export const SERVICE_KEY_LEGACY = 'index_pattern';
export type SERVICE_KEY_TYPE = typeof SERVICE_KEY | typeof SERVICE_KEY_LEGACY;

export const CREATE_DATA_VIEW_COUNTER_NAME = `POST ${DATA_VIEW_PATH}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like this isn't used

@mattkime
Copy link
Contributor Author

mattkime commented Feb 1, 2022

@jloleysens

The other idea was: it still feels like we could address this at a slightly higher level of abstraction

Agreed, just didn't make it in but I'll create a follow up. It seems like this use case (more end points, tracking) will become more common.

It will be very useful to know if API is called by Kibana or by someone else.

As best I know there aren't any internal consumers but its a good idea that I'll put into a follow up.

@mattkime mattkime merged commit 0f0a835 into elastic:main Feb 1, 2022
@kibanamachine kibanamachine added the backport:skip This PR does not require backporting label Feb 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:Data Views Data Views code and UI - index patterns before 8.0 release_note:skip Skip the PR/issue when compiling release notes v8.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[data views] Add telemetry to REST APIs

7 participants