Skip to content

Commit e9e8e76

Browse files
Merge pull request #18 from journeyapps/better-logs
[Feature] Better Error Logging
2 parents b612362 + 413a4d0 commit e9e8e76

File tree

6 files changed

+52
-4
lines changed

6 files changed

+52
-4
lines changed

.changeset/strong-moose-applaud.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@journeyapps/powersync-sdk-react-native': patch
3+
'@journeyapps/powersync-sdk-common': patch
4+
---
5+
6+
Added better logging of streaming errors. Added warnings if Polyfills are not correctly configured.

packages/powersync-sdk-common/src/client/sync/stream/AbstractRemote.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
1+
import Logger, { ILogger } from 'js-logger';
12
import { PowerSyncCredentials } from '../../connection/PowerSyncCredentials';
23

3-
export type RemoteOptions = {
4+
export type RemoteConnector = {
45
fetchCredentials: () => Promise<PowerSyncCredentials>;
56
};
67

78
//Refresh at least 30 sec before it expires
89
const REFRESH_CREDENTIALS_SAFETY_PERIOD_MS = 30_000;
910

11+
export const DEFAULT_REMOTE_LOGGER = Logger.get('PowerSyncRemote');
12+
1013
export abstract class AbstractRemote {
1114
protected credentials?: PowerSyncCredentials;
1215

13-
constructor(protected options: RemoteOptions) {}
16+
constructor(protected connector: RemoteConnector, protected logger: ILogger = DEFAULT_REMOTE_LOGGER) {}
1417

1518
async getCredentials(): Promise<PowerSyncCredentials> {
1619
const { expiresAt } = this.credentials ?? {};
1720
if (expiresAt && expiresAt > new Date(new Date().valueOf() + REFRESH_CREDENTIALS_SAFETY_PERIOD_MS)) {
1821
return this.credentials!;
1922
}
20-
this.credentials = await this.options.fetchCredentials();
23+
this.credentials = await this.connector.fetchCredentials();
2124
return this.credentials;
2225
}
2326

packages/powersync-sdk-common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export abstract class AbstractStreamingSyncImplementation extends BaseObserver<S
123123
await this.streamingSyncIteration(signal);
124124
// Continue immediately
125125
} catch (ex) {
126+
this.logger.error(ex);
126127
this.updateSyncStatus(false);
127128
// On error, wait a little before retrying
128129
await new Promise((resolve) => setTimeout(resolve, this.options.retryDelayMs));

packages/powersync-sdk-react-native/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,15 @@ export const TodoListDisplay = () => {
491491
}
492492
```
493493

494+
### Logging
495+
The default logger uses js-logger. Debug logs can be displayed with:
496+
497+
```JavaScript
498+
import Logger from 'js-logger';
499+
Logger.useDefaults();
500+
Logger.setLevel(Logger.DEBUG);
501+
```
502+
494503

495504
# Known Issues
496505

packages/powersync-sdk-react-native/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@journeyapps/react-native-quick-sqlite": "0.0.2",
2828
"base-64": "^1.0.0",
2929
"react": "*",
30+
"react-native": "*",
3031
"react-native-fetch-api": "^3.0.0",
3132
"react-native-get-random-values": "^1.9.0",
3233
"react-native-polyfill-globals": "^3.1.0",
@@ -42,6 +43,7 @@
4243
"devDependencies": {
4344
"@journeyapps/react-native-quick-sqlite": "0.0.2",
4445
"@types/async-lock": "^1.4.0",
46+
"react-native": "0.72.4",
4547
"react": "18.2.0",
4648
"typescript": "^4.1.3"
4749
},

packages/powersync-sdk-react-native/src/sync/stream/ReactNativeRemote.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { AbstractRemote } from '@journeyapps/powersync-sdk-common';
2+
import { Platform } from 'react-native';
3+
4+
export const STREAMING_POST_TIMEOUT_MS = 30_000;
25

36
export class ReactNativeRemote extends AbstractRemote {
47
async post(path: string, data: any, headers: Record<string, string> = {}): Promise<any> {
@@ -43,8 +46,30 @@ export class ReactNativeRemote extends AbstractRemote {
4346
headers: Record<string, string> = {},
4447
signal?: AbortSignal
4548
): Promise<any> {
49+
// Ensure polyfills are present
50+
if (
51+
typeof ReadableStream == 'undefined' ||
52+
typeof TextEncoder == 'undefined' ||
53+
typeof TextDecoder == 'undefined'
54+
) {
55+
const errorMessage = `Polyfills are undefined. Please ensure React Native polyfills are installed and imported in the app entrypoint.
56+
"import 'react-native-polyfill-globals/auto';"
57+
`;
58+
this.logger.error(errorMessage);
59+
throw new Error(errorMessage);
60+
}
61+
4662
const credentials = await this.getCredentials();
4763

64+
let timeout =
65+
Platform.OS == 'android'
66+
? setTimeout(() => {
67+
this.logger.warn(
68+
`HTTP Streaming POST is taking longer than 30 seconds to resolve. If using a debug build, please ensure Flipper Network plugin is disabled.`
69+
);
70+
}, STREAMING_POST_TIMEOUT_MS)
71+
: null;
72+
4873
const res = await fetch(credentials.endpoint + path, {
4974
method: 'POST',
5075
headers: { ...headers, ...(await this.getHeaders()) },
@@ -63,9 +88,11 @@ export class ReactNativeRemote extends AbstractRemote {
6388
throw ex;
6489
});
6590

91+
clearTimeout(timeout);
92+
6693
if (!res.ok) {
6794
const text = await res.text();
68-
console.error(`Could not POST streaming to ${path} - ${res.status} - ${res.statusText}: ${text}`);
95+
this.logger.error(`Could not POST streaming to ${path} - ${res.status} - ${res.statusText}: ${text}`);
6996
const error: any = new Error(`HTTP ${res.statusText}: ${text}`);
7097
error.status = res.status;
7198
throw error;

0 commit comments

Comments
 (0)