Skip to content

Commit 78d0a1c

Browse files
authored
Merge pull request #10020 from LedgerHQ/chore/LIVE-18146
2 parents d12b0e5 + 20a73cb commit 78d0a1c

File tree

12 files changed

+519
-52
lines changed

12 files changed

+519
-52
lines changed

.changeset/silver-crews-relate.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"live-mobile": minor
3+
---
4+
5+
Storage perfomance debug tool. Enhance sentry error and analytics

apps/ledger-live-mobile/src/index.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ import {
7979
} from "@ledgerhq/live-common/exchange/swap/hooks/index";
8080
import useAccountsWithFundsListener from "@ledgerhq/live-common/hooks/useAccountsWithFundsListener";
8181
import { updateIdentify } from "./analytics";
82-
import { getFeature, useFeature } from "@ledgerhq/live-common/featureFlags/index";
82+
import { FeatureToggle, getFeature, useFeature } from "@ledgerhq/live-common/featureFlags/index";
8383
import { StorylyProvider } from "./components/StorylyStories/StorylyProvider";
8484
import { useSettings } from "~/hooks";
8585
import AppProviders from "./AppProviders";
@@ -91,6 +91,7 @@ import { walletSelector } from "~/reducers/wallet";
9191
import { exportWalletState, walletStateExportShouldDiffer } from "@ledgerhq/live-wallet/store";
9292
import { registerTransports } from "~/services/registerTransports";
9393
import { useDeviceManagementKitEnabled } from "@ledgerhq/live-dmk-mobile";
94+
import { StoragePerformanceOverlay } from "./newArch/storage/screens/PerformanceMonitor";
9495

9596
if (Config.DISABLE_YELLOW_BOX) {
9697
LogBox.ignoreAllLogs();
@@ -249,6 +250,9 @@ function App() {
249250
<PerformanceConsole />
250251
<DebugTheme />
251252
<Modals />
253+
<FeatureToggle featureId="llmMmkvMigration">
254+
<StoragePerformanceOverlay />
255+
</FeatureToggle>
252256
</GestureHandlerRootView>
253257
);
254258
}

apps/ledger-live-mobile/src/newArch/storage/__tests__/storage.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ describe("storage", () => {
757757
});
758758

759759
it("should log the #stringify error", () => {
760-
expect(console.error).toHaveBeenCalledWith("Error pushing value to storage", {
760+
expect(console.error).toHaveBeenCalledWith("Error stringifying storage", {
761761
error: error,
762762
state: {
763763
migrationStatus: MIGRATION_STATUS.NOT_STARTED,

apps/ledger-live-mobile/src/newArch/storage/index.ts

+82-41
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "./utils/migrations/constants";
1313
import { track } from "~/analytics";
1414
import type { Feature_LlmMmkvMigration } from "@ledgerhq/types-live";
15+
import { trackStorageOperation } from "./utils/performance";
1516

1617
/** Singleton reference to the global application storage object. */
1718
export default createStorage();
@@ -35,145 +36,185 @@ export function createStorage(init: StorageInitializer = initStorageState): Stor
3536

3637
incrementNumberOfErrorsDebug,
3738

38-
keys() {
39+
async keys() {
3940
try {
4041
return state.storageType === STORAGE_TYPE.MMKV
41-
? Promise.resolve(mmkvStorageWrapper.keys())
42-
: asyncStorageWrapper.keys();
42+
? await trackStorageOperation("keys", STORAGE_TYPE.MMKV, "all", () =>
43+
Promise.resolve(mmkvStorageWrapper.keys()),
44+
)
45+
: await trackStorageOperation("keys", STORAGE_TYPE.ASYNC_STORAGE, "all", () =>
46+
asyncStorageWrapper.keys(),
47+
);
4348
} catch (e) {
4449
console.error("Error getting keys from storage", {
4550
error: e,
4651
state: state,
4752
});
48-
return rejectWithError(e);
53+
return rejectWithError({ e, extraData: { op: "keys" } });
4954
}
5055
},
5156

5257
async get(key) {
5358
try {
5459
return state.storageType === STORAGE_TYPE.MMKV
55-
? Promise.resolve(mmkvStorageWrapper.get(key))
56-
: asyncStorageWrapper.get(key);
60+
? await trackStorageOperation("get", STORAGE_TYPE.MMKV, key, () =>
61+
Promise.resolve(mmkvStorageWrapper.get(key)),
62+
)
63+
: await trackStorageOperation("get", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
64+
asyncStorageWrapper.get(key),
65+
);
5766
} catch (e) {
5867
console.error("Error getting key from storage", {
5968
error: e,
6069
state: state,
6170
});
6271
await incrementNumberOfErrors(state, e);
63-
return rejectWithError(e);
72+
return rejectWithError({ e, extraData: { op: "get", key } });
6473
}
6574
},
6675

6776
async getString(key) {
6877
try {
6978
return state.storageType === STORAGE_TYPE.MMKV
70-
? Promise.resolve(mmkvStorageWrapper.getString(key))
71-
: asyncStorageWrapper.getString(key);
79+
? await trackStorageOperation("getString", STORAGE_TYPE.MMKV, key, () =>
80+
Promise.resolve(mmkvStorageWrapper.getString(key)),
81+
)
82+
: await trackStorageOperation("getString", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
83+
asyncStorageWrapper.getString(key),
84+
);
7285
} catch (e) {
7386
console.error("Error getting key from storage", {
7487
error: e,
7588
state: state,
7689
});
7790
await incrementNumberOfErrors(state, e);
78-
return rejectWithError(e);
91+
return rejectWithError({ e, extraData: { op: "getString", key } });
7992
}
8093
},
8194

82-
save(key, value) {
95+
async save(key, value) {
8396
try {
8497
return state.storageType === STORAGE_TYPE.MMKV
85-
? Promise.resolve(mmkvStorageWrapper.save(key, value))
86-
: asyncStorageWrapper.save(key, value);
98+
? await trackStorageOperation("save", STORAGE_TYPE.MMKV, key as string, () =>
99+
Promise.resolve(mmkvStorageWrapper.save(key, value)),
100+
)
101+
: await trackStorageOperation("save", STORAGE_TYPE.ASYNC_STORAGE, key as string, () =>
102+
asyncStorageWrapper.save(key, value),
103+
);
87104
} catch (e) {
88105
console.error("Error saving key to storage", {
89106
error: e,
90107
state: state,
91108
});
92-
return rejectWithError(e);
109+
return rejectWithError({ e, extraData: { op: "save", key, value } });
93110
}
94111
},
95112

96-
saveString(key, value) {
113+
async saveString(key, value) {
97114
try {
98115
return state.storageType === STORAGE_TYPE.MMKV
99-
? Promise.resolve(mmkvStorageWrapper.saveString(key, value))
100-
: asyncStorageWrapper.saveString(key, value);
116+
? await trackStorageOperation("saveString", STORAGE_TYPE.MMKV, key, () =>
117+
Promise.resolve(mmkvStorageWrapper.saveString(key, value)),
118+
)
119+
: await trackStorageOperation("saveString", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
120+
asyncStorageWrapper.saveString(key, value),
121+
);
101122
} catch (e) {
102123
console.error("Error saving key to storage", {
103124
error: e,
104125
state: state,
105126
});
106-
return rejectWithError(e);
127+
return rejectWithError({ e, extraData: { op: "saveString", key } });
107128
}
108129
},
109130

110-
update(key, value) {
131+
async update(key, value) {
111132
try {
112133
return state.storageType === STORAGE_TYPE.MMKV
113-
? Promise.resolve(mmkvStorageWrapper.update(key, value))
114-
: asyncStorageWrapper.update(key, value);
134+
? await trackStorageOperation("update", STORAGE_TYPE.MMKV, key, () =>
135+
Promise.resolve(mmkvStorageWrapper.update(key, value)),
136+
)
137+
: await trackStorageOperation("update", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
138+
asyncStorageWrapper.update(key, value),
139+
);
115140
} catch (e) {
116141
console.error("Error updating key in storage", {
117142
error: e,
118143
state: state,
119144
});
120-
return rejectWithError(e);
145+
return rejectWithError({ e, extraData: { op: "update", key } });
121146
}
122147
},
123148

124149
async delete(key) {
125150
try {
126151
return state.storageType === STORAGE_TYPE.MMKV
127-
? await mmkvStorageWrapper.delete(key)
128-
: await asyncStorageWrapper.delete(key);
152+
? await trackStorageOperation("delete", STORAGE_TYPE.MMKV, key, () =>
153+
mmkvStorageWrapper.delete(key),
154+
)
155+
: await trackStorageOperation("delete", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
156+
asyncStorageWrapper.delete(key),
157+
);
129158
} catch (e) {
130159
console.error("Error deleting key from storage", {
131160
error: e,
132161
state: state,
133162
});
134-
return rejectWithError(e);
163+
return rejectWithError({ e, extraData: { op: "delete", key } });
135164
}
136165
},
137166

138167
async deleteAll() {
139168
try {
140169
return state.storageType === STORAGE_TYPE.MMKV
141-
? await mmkvStorageWrapper.deleteAll()
142-
: await asyncStorageWrapper.deleteAll();
170+
? await trackStorageOperation("deleteAll", STORAGE_TYPE.MMKV, "all", () =>
171+
mmkvStorageWrapper.deleteAll(),
172+
)
173+
: await trackStorageOperation("deleteAll", STORAGE_TYPE.ASYNC_STORAGE, "all", () =>
174+
asyncStorageWrapper.deleteAll(),
175+
);
143176
} catch (e) {
144177
console.error("Error deleting all keys from storage", {
145178
error: e,
146179
state: state,
147180
});
148-
return rejectWithError(e);
181+
return rejectWithError({ e, extraData: { op: "deleteAll" } });
149182
}
150183
},
151184

152-
push(key, value) {
185+
async push(key, value) {
153186
try {
154187
return state.storageType === STORAGE_TYPE.MMKV
155-
? Promise.resolve(mmkvStorageWrapper.push(key, value))
156-
: asyncStorageWrapper.push(key, value);
188+
? await trackStorageOperation("push", STORAGE_TYPE.MMKV, key, () =>
189+
Promise.resolve(mmkvStorageWrapper.push(key, value)),
190+
)
191+
: await trackStorageOperation("push", STORAGE_TYPE.ASYNC_STORAGE, key, () =>
192+
asyncStorageWrapper.push(key, value),
193+
);
157194
} catch (e) {
158195
console.error("Error pushing value to storage", {
159196
error: e,
160197
state: state,
161198
});
162-
return rejectWithError(e);
199+
return rejectWithError({ e, extraData: { op: "push", key, value } });
163200
}
164201
},
165202

166-
stringify() {
203+
async stringify() {
167204
try {
168205
return state.storageType === STORAGE_TYPE.MMKV
169-
? Promise.resolve(mmkvStorageWrapper.stringify())
170-
: asyncStorageWrapper.stringify();
206+
? await trackStorageOperation("stringify", STORAGE_TYPE.MMKV, "all", () =>
207+
Promise.resolve(mmkvStorageWrapper.stringify()),
208+
)
209+
: await trackStorageOperation("stringify", STORAGE_TYPE.ASYNC_STORAGE, "all", () =>
210+
asyncStorageWrapper.stringify(),
211+
);
171212
} catch (e) {
172-
console.error("Error pushing value to storage", {
213+
console.error("Error stringifying storage", {
173214
error: e,
174215
state: state,
175216
});
176-
return rejectWithError(e);
217+
return rejectWithError({ e, extraData: { op: "stringify" } });
177218
}
178219
},
179220

@@ -185,7 +226,7 @@ export function createStorage(init: StorageInitializer = initStorageState): Stor
185226
error: e,
186227
state: state,
187228
});
188-
return rejectWithError(e);
229+
return rejectWithError({ e, extraData: { op: "migrate" } });
189230
}
190231
},
191232

@@ -197,7 +238,7 @@ export function createStorage(init: StorageInitializer = initStorageState): Stor
197238
error: e,
198239
state: state,
199240
});
200-
return rejectWithError(e);
241+
return rejectWithError({ e, extraData: { op: "resetMigration" } });
201242
}
202243
},
203244

@@ -209,7 +250,7 @@ export function createStorage(init: StorageInitializer = initStorageState): Stor
209250
error: e,
210251
state: state,
211252
});
212-
return rejectWithError(e);
253+
return rejectWithError({ e, extraData: { op: "rollbackMigration" } });
213254
}
214255
},
215256

@@ -221,7 +262,7 @@ export function createStorage(init: StorageInitializer = initStorageState): Stor
221262
error: e,
222263
state: state,
223264
});
224-
return rejectWithError(e);
265+
return rejectWithError({ e, extraData: { op: "handleMigration", featureFlag } });
225266
}
226267
},
227268
} satisfies Storage;

0 commit comments

Comments
 (0)