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

[App Search] API logs: Server route + ApiLogsLogic + useEffects #95732

Merged
merged 7 commits into from
Mar 30, 2021

Conversation

cee-chen
Copy link
Member

Summary

3 main goals of this PR:

  1. Server route: b52ae2c
  2. ApiLogsLogic: 3d77232, 389096d, 2ae83ba
  3. View useEffects: 2250d82

QA

This PR doesn't have any UI changes yet (next set of PRs!) but does add polling behavior that you can QA:

  • Go to any engine's API logs:
    • Confirm an api_logs call fires on load
    • Confirm an api_logs call fires every 5 seconds after that
    • (TODO in future PR) - Confirm that paginating correctly calls an api_logs call and updates the table
  • Go to the engine overview:
    • Confirm an api_logs call fires on load
    • Confirm an api_logs call fires every 5 seconds after that

Checklist

@cee-chen cee-chen added Feature:Plugins release_note:skip Skip the PR/issue when compiling release notes v7.13.0 auto-backport Deprecated - use backport:version if exact versions are needed labels Mar 30, 2021
@cee-chen cee-chen requested a review from a team March 30, 2021 01:21
Comment on lines +94 to +99
pollForApiLogs: () => {
if (values.intervalId) return; // Ensure we only have one poll at a time

const id = window.setInterval(() => actions.fetchApiLogs({ isPoll: true }), POLLING_DURATION);
actions.onPollStart(id);
},
Copy link
Member Author

Choose a reason for hiding this comment

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

Changed from the standalone UI:

  • This now uses setInterval instead of setTimeout to poll, which actually fixes an issue in our current UI where XHRs are getting duplicated (api_logs is called twice every 5s instead of just once 😬)
  • I separated the poll start into its own action, which I think will be clearer why in a little bit in the actual view/useEffect usage

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I love this.

Comment on lines +32 to +38
useEffect(() => {
fetchApiLogs();
}, [meta.page.current]);

useEffect(() => {
pollForApiLogs();
}, []);
Copy link
Member Author

Choose a reason for hiding this comment

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

^ I hope with this useEffect example it makes more sense why I split out the concept of an "immediate" fetch and a "poll" fetch in the logic! Also for even more context, check out the different requirements for the Engine Overview:

The table there does not have pagination, so it doesn't need an extra effect and only calls fetchApiLogs once on load.

Comment on lines +30 to +37
fetchApiLogs(options?: { isPoll: boolean }): { isPoll: boolean };
pollForApiLogs(): void;
onPollStart(intervalId: number): { intervalId: number };
onPollInterval(data: ApiLogsData): ApiLogsData;
storePolledData(data: ApiLogsData): ApiLogsData;
updateView(data: ApiLogsData): ApiLogsData;
onUserRefresh(): void;
onPaginate(newPageIndex: number): { newPageIndex: number };
Copy link
Member Author

Choose a reason for hiding this comment

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

I played around with the names a bit more from our Slack convo - let me know what you think! I think it is a bit clearer in terms of imperative vs declarative naming (tying user actions/flows to fn names) but definitely open to suggestions, naming things is hard 😬

Copy link
Contributor

Choose a reason for hiding this comment

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

onPaginationChange would probably have been my pick, this is fine though.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm good with w/e - I've been using onPaginate in other places w/ table pagination (overview, curations, etc.) so we should probably change them all at once. Definitely open to a separate follow-up PR for this

if (isEmpty && hasNewData) {
actions.updateView(data); // Empty logs should automatically update with new data without a manual action
} else if (hasNewData) {
actions.storePolledData(data); // Otherwise, store any new data until the user manually refreshes the table
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if all these comments are helpful vs. just checking the unit tests - definitely let me know if you have thoughts there. The UX here is significantly different from anything else in our app so I think it could make sense to have that extra context in both places.

Copy link
Contributor

Choose a reason for hiding this comment

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

I love comments like these

}
},
onPollInterval: (data, breakpoint) => {
breakpoint(); // Prevents errors if logic unmounts while fetching
Copy link
Member Author

Choose a reason for hiding this comment

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

Found this in https://kea.js.org/docs/guide/additional#breakpoints!!

If you call breakpoint() without any arguments (and without await), there will be no pause. It'll just check if the listener was called again or the logic was unmounted and terminate if that's the case. You can use this version of breakpoint() after long running calls and network requests to avoid those "out of order" errors.

Super useful and we'll definitely want this anywhere we have heartbeat-type polling

Copy link
Contributor

Choose a reason for hiding this comment

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

GREAT find

'xpack.enterpriseSearch.appSearch.engine.apiLogs.pollingErrorMessage',
{
defaultMessage:
'Could not automatically refresh API logs data. Please check your connection or manually refresh the page.',
Copy link
Member Author

Choose a reason for hiding this comment

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

Feel free to give me copy suggestions here, I just kinda yolo'd something

Copy link
Contributor

Choose a reason for hiding this comment

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

I got nothing here cc @zumwalt

* 2.0.
*/

export const getDateString = (offSetDays?: number) => {
Copy link
Member Author

Choose a reason for hiding this comment

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

FYI this util comes from the standalone UI, I basically just copied it over as-is, def. open to changes if we want them

Comment on lines +11 to +13
const mockDate = jest
.spyOn(global.Date, 'now')
.mockImplementation(() => new Date('1970-01-02').valueOf());
Copy link
Member Author

@cee-chen cee-chen Mar 30, 2021

Choose a reason for hiding this comment

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

I learned this from James when he used this in a Jest test recently!! 🤯

As someone who loves 1. static tests and 2. Jan 1970, the beginning of the universe, I could NOT pass up using it here

full_request_path: string;
user_agent: string;
request_body: string; // JSON string
response_body: string; // JSON string
Copy link
Member Author

Choose a reason for hiding this comment

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

FYI we also get back

path: null,

from our API but I have no idea what it does and we're not using it at all in the standalone UI, so I ignored it. I could have noted it in a comment, but I figured maybe github history (this comment) is sufficient

Copy link
Contributor

Choose a reason for hiding this comment

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

Worth adding it with a comment IMO

Copy link
Member Author

Choose a reason for hiding this comment

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


export interface ApiLogsData {
results: ApiLog[];
meta: Meta;
Copy link
Member Author

Choose a reason for hiding this comment

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

FYI, we get back some extra info in meta:

sort_direction: 'desc',
filters: {
  date: {
    from: // ... 
    to: // ...
  },
},
query: '',

But I'm not using it in the frontend (it's data we're sending to the server and not data we need to receive from the server), and I have no idea why query is even there, so I'm ignoring it

@byronhulcher byronhulcher self-requested a review March 30, 2021 11:05
Copy link
Contributor

@byronhulcher byronhulcher left a comment

Choose a reason for hiding this comment

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

QA looks great! I left some comments which I consider non-blocking

Screen Shot 2021-03-30 at 10 08 20 AM

Screen Shot 2021-03-30 at 10 07 39 AM

Comment on lines +30 to +37
fetchApiLogs(options?: { isPoll: boolean }): { isPoll: boolean };
pollForApiLogs(): void;
onPollStart(intervalId: number): { intervalId: number };
onPollInterval(data: ApiLogsData): ApiLogsData;
storePolledData(data: ApiLogsData): ApiLogsData;
updateView(data: ApiLogsData): ApiLogsData;
onUserRefresh(): void;
onPaginate(newPageIndex: number): { newPageIndex: number };
Copy link
Contributor

Choose a reason for hiding this comment

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

onPaginationChange would probably have been my pick, this is fine though.

onPaginate: (newPageIndex) => ({ newPageIndex }),
}),
reducers: () => ({
dataLoading: [
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this is too pedantic but I think if one of the API calls fails, this will be stuck in dataLoading since updateView will never be called. Is that correct and/or does that matter?

Comment on lines +94 to +99
pollForApiLogs: () => {
if (values.intervalId) return; // Ensure we only have one poll at a time

const id = window.setInterval(() => actions.fetchApiLogs({ isPoll: true }), POLLING_DURATION);
actions.onPollStart(id);
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I love this.

}
},
onPollInterval: (data, breakpoint) => {
breakpoint(); // Prevents errors if logic unmounts while fetching
Copy link
Contributor

Choose a reason for hiding this comment

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

GREAT find

if (isEmpty && hasNewData) {
actions.updateView(data); // Empty logs should automatically update with new data without a manual action
} else if (hasNewData) {
actions.storePolledData(data); // Otherwise, store any new data until the user manually refreshes the table
Copy link
Contributor

Choose a reason for hiding this comment

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

I love comments like these

'xpack.enterpriseSearch.appSearch.engine.apiLogs.pollingErrorMessage',
{
defaultMessage:
'Could not automatically refresh API logs data. Please check your connection or manually refresh the page.',
Copy link
Contributor

Choose a reason for hiding this comment

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

I got nothing here cc @zumwalt

full_request_path: string;
user_agent: string;
request_body: string; // JSON string
response_body: string; // JSON string
Copy link
Contributor

Choose a reason for hiding this comment

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

Worth adding it with a comment IMO

@cee-chen cee-chen enabled auto-merge (squash) March 30, 2021 16:29
@cee-chen
Copy link
Member Author

Thanks Byron!

Enabling auto-merge as I'm leaving early today, but feel free to shout if y'all think of any naming suggestions or anything else for the future - I can add them into upcoming API logs PRs

@byronhulcher
Copy link
Contributor

Enabling auto-merge as I'm leaving early today, but feel free to shout if y'all think of any naming suggestions or anything else for the future - I can add them into upcoming API logs PRs

Sounds great! And thanks for the reminder about auto-merge existing

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
enterpriseSearch 1291 1293 +2

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
enterpriseSearch 1.9MB 1.9MB +3.7KB

History

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

@cee-chen cee-chen merged commit 53d4fa7 into elastic:master Mar 30, 2021
kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Mar 30, 2021
…tic#95732)

* Set up API route

* Set up API types

* Set up date util needed by filters dates

* Add ApiLogsLogic

* Update ApiLogs and EngineOverview views with polling behavior

* Add API type notes - maybe serves as a TODO to clean up our API data some day
@kibanamachine
Copy link
Contributor

💚 Backport successful

7.x / #95831

This backport PR will be merged automatically after passing CI.

@cee-chen cee-chen deleted the api-logs-2 branch March 30, 2021 18:40
kibanamachine added a commit that referenced this pull request Mar 30, 2021
…) (#95831)

* Set up API route

* Set up API types

* Set up date util needed by filters dates

* Add ApiLogsLogic

* Update ApiLogs and EngineOverview views with polling behavior

* Add API type notes - maybe serves as a TODO to clean up our API data some day

Co-authored-by: Constance <constancecchen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed Feature:Plugins release_note:skip Skip the PR/issue when compiling release notes v7.13.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants