From 20185f37abcd515e1a9eeb11d57d40607ae0968e Mon Sep 17 00:00:00 2001 From: Pascal Hartig Date: Fri, 1 Oct 2021 12:17:30 -0700 Subject: [PATCH] Init and error logging Summary: Set up some basic logging for deep link usage at the entry point and error cases. More granular logging coming up next. Reviewed By: nikoant Differential Revision: D31337822 fbshipit-source-id: 171eae68fb3d9a11aa155087baf6f8309bbd7295 --- desktop/app/src/__tests__/deeplink.node.tsx | 50 +++++++++++++++++++++ desktop/app/src/deeplink.tsx | 38 +++++++++++++--- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/desktop/app/src/__tests__/deeplink.node.tsx b/desktop/app/src/__tests__/deeplink.node.tsx index 3e8c3d884..3df509039 100644 --- a/desktop/app/src/__tests__/deeplink.node.tsx +++ b/desktop/app/src/__tests__/deeplink.node.tsx @@ -97,4 +97,54 @@ test('Will throw error on invalid deeplinks', async () => { expect(() => handleDeeplink(undefined as any, logger, `flipper://test`), ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`); + + expect(logger.track).toHaveBeenCalledTimes(2); + expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', { + query: 'flipper://test', + state: 'ERROR', + errorMessage: 'Unknown deeplink', + }); +}); + +test('Will throw error on invalid protocol', async () => { + const logger: Logger = { + track: jest.fn(), + } as any; + + expect(() => + handleDeeplink(undefined as any, logger, `notflipper://test`), + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`); + + expect(logger.track).toHaveBeenCalledTimes(2); + expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', { + query: 'notflipper://test', + state: 'ERROR', + errorMessage: 'Unknown deeplink', + }); +}); + +test('Will track deeplinks', async () => { + const definition = new _SandyPluginDefinition( + TestUtils.createMockPluginDetails(), + { + plugin: () => {}, + Component() { + return

{'world'}

; + }, + }, + ); + const {store, logger} = await renderMockFlipperWithPlugin(definition); + logger.track = jest.fn(); + + await handleDeeplink( + store, + logger, + 'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe', + ); + + expect(logger.track).toHaveBeenCalledWith('usage', 'deeplink', { + query: + 'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe', + state: 'INIT', + }); }); diff --git a/desktop/app/src/deeplink.tsx b/desktop/app/src/deeplink.tsx index c66b7d047..99e752db2 100644 --- a/desktop/app/src/deeplink.tsx +++ b/desktop/app/src/deeplink.tsx @@ -21,6 +21,22 @@ import {Dialog} from 'flipper-plugin'; import {handleOpenPluginDeeplink} from './dispatcher/handleOpenPluginDeeplink'; import {message} from 'antd'; +type DeeplinkInteraction = { + state: 'INIT' | 'ERROR'; + errorMessage?: string; +}; + +function track( + logger: Logger, + query: string, + interaction: DeeplinkInteraction, +) { + logger.track('usage', 'deeplink', { + ...interaction, + query, + }); +} + const UNKNOWN = 'Unknown deeplink'; /** * Handle a flipper:// deeplink. Will throw if the URL pattern couldn't be recognised @@ -30,9 +46,21 @@ export async function handleDeeplink( logger: Logger, query: string, ): Promise { - const uri = new URL(query); - if (uri.protocol !== 'flipper:') { + const trackInteraction = track.bind(null, logger, query); + const unknownError = () => { + trackInteraction({ + state: 'ERROR', + errorMessage: UNKNOWN, + }); throw new Error(UNKNOWN); + }; + const uri = new URL(query); + + trackInteraction({ + state: 'INIT', + }); + if (uri.protocol !== 'flipper:') { + throw unknownError(); } if (uri.href.startsWith('flipper://open-plugin')) { return handleOpenPluginDeeplink(store, query); @@ -57,7 +85,7 @@ export async function handleDeeplink( handle.close(); }); } - throw new Error(UNKNOWN); + throw unknownError(); } else if (uri.pathname.match(/^\/*support-form\/*$/)) { const formParam = uri.searchParams.get('form'); const grp = deeplinkFormParamToGroups(formParam); @@ -65,7 +93,7 @@ export async function handleDeeplink( grp.handleSupportFormDeeplinks(store); return; } - throw new Error(UNKNOWN); + throw unknownError(); } else if (uri.pathname.match(/^\/*login\/*$/)) { const token = uri.searchParams.get('token'); store.dispatch(setPastedToken(token ?? undefined)); @@ -93,7 +121,7 @@ export async function handleDeeplink( ); return; } else { - throw new Error(UNKNOWN); + throw unknownError(); } }