Skip to content

Commit 6807df6

Browse files
authored
feat: Logging cleanup in packages (web, node, attachments, react, vue) (#565)
1 parent f40ecf9 commit 6807df6

18 files changed

+136
-50
lines changed

.changeset/calm-roses-poke.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/node': patch
3+
---
4+
5+
Using logger types from @powersync/common.

.changeset/dirty-buttons-hunt.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@powersync/attachments': patch
3+
'@powersync/react': patch
4+
'@powersync/vue': patch
5+
---
6+
7+
Using newly exposed logger from AbstractPowerSyncDatabase to have controlled logging instead of using console based logging.

.changeset/fresh-jobs-explain.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/common': minor
3+
---
4+
5+
Exposing logger on AbstractPowerSyncDatabase.

.changeset/green-rings-judge.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/web': patch
3+
---
4+
5+
Updated db and sync workers to respect log levels.

packages/attachments/src/AbstractAttachmentQueue.ts

+23-19
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
9191
return this.options.powersync;
9292
}
9393

94+
get logger() {
95+
return this.powersync.logger ?? console;
96+
}
97+
9498
protected get storage() {
9599
return this.options.storage;
96100
}
@@ -123,7 +127,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
123127
async watchAttachmentIds() {
124128
this.onAttachmentIdsChange(async (ids) => {
125129
const _ids = `${ids.map((id) => `'${id}'`).join(',')}`;
126-
console.debug(`Queuing for sync, attachment IDs: [${_ids}]`);
130+
this.logger.debug(`Queuing for sync, attachment IDs: [${_ids}]`);
127131

128132
if (this.initialSync) {
129133
this.initialSync = false;
@@ -151,11 +155,11 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
151155
id: id,
152156
state: AttachmentState.QUEUED_SYNC
153157
});
154-
console.debug(`Attachment (${id}) not found in database, creating new record`);
158+
this.logger.debug(`Attachment (${id}) not found in database, creating new record`);
155159
await this.saveToQueue(newRecord);
156160
} else if (record.local_uri == null || !(await this.storage.fileExists(this.getLocalUri(record.local_uri)))) {
157161
// 2. Attachment in database but no local file, mark as queued download
158-
console.debug(`Attachment (${id}) found in database but no local file, marking as queued download`);
162+
this.logger.debug(`Attachment (${id}) found in database but no local file, marking as queued download`);
159163
await this.update({
160164
...record,
161165
state: AttachmentState.QUEUED_DOWNLOAD
@@ -241,7 +245,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
241245
filename: record.filename
242246
});
243247
} catch (e) {
244-
console.error(e);
248+
this.logger.error(e);
245249
}
246250
}
247251

@@ -267,7 +271,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
267271
const localFilePathUri = this.getLocalUri(record.local_uri);
268272
try {
269273
if (!(await this.storage.fileExists(localFilePathUri))) {
270-
console.warn(`File for ${record.id} does not exist, skipping upload`);
274+
this.logger.warn(`File for ${record.id} does not exist, skipping upload`);
271275
await this.update({
272276
...record,
273277
state: AttachmentState.QUEUED_DOWNLOAD
@@ -285,11 +289,11 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
285289
});
286290
// Mark as uploaded
287291
await this.update({ ...record, state: AttachmentState.SYNCED });
288-
console.debug(`Uploaded attachment "${record.id}" to Cloud Storage`);
292+
this.logger.debug(`Uploaded attachment "${record.id}" to Cloud Storage`);
289293
return true;
290294
} catch (e: any) {
291295
if (e.error == 'Duplicate') {
292-
console.debug(`File already uploaded, marking ${record.id} as synced`);
296+
this.logger.debug(`File already uploaded, marking ${record.id} as synced`);
293297
await this.update({ ...record, state: AttachmentState.SYNCED });
294298
return false;
295299
}
@@ -300,7 +304,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
300304
return true;
301305
}
302306
}
303-
console.error(`UploadAttachment error for record ${JSON.stringify(record, null, 2)}`);
307+
this.logger.error(`UploadAttachment error for record ${JSON.stringify(record, null, 2)}`);
304308
return false;
305309
}
306310
}
@@ -314,7 +318,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
314318
}
315319
const localFilePathUri = this.getLocalUri(record.local_uri);
316320
if (await this.storage.fileExists(localFilePathUri)) {
317-
console.debug(`Local file already downloaded, marking "${record.id}" as synced`);
321+
this.logger.debug(`Local file already downloaded, marking "${record.id}" as synced`);
318322
await this.update({ ...record, state: AttachmentState.SYNCED });
319323
return true;
320324
}
@@ -345,7 +349,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
345349
media_type: fileBlob.type,
346350
state: AttachmentState.SYNCED
347351
});
348-
console.debug(`Downloaded attachment "${record.id}"`);
352+
this.logger.debug(`Downloaded attachment "${record.id}"`);
349353
return true;
350354
} catch (e) {
351355
if (this.options.onDownloadError) {
@@ -355,7 +359,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
355359
return true;
356360
}
357361
}
358-
console.error(`Download attachment error for record ${JSON.stringify(record, null, 2)}`, e);
362+
this.logger.error(`Download attachment error for record ${JSON.stringify(record, null, 2)}`, e);
359363
}
360364
return false;
361365
}
@@ -396,7 +400,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
396400
if (!record) {
397401
return;
398402
}
399-
console.debug(`Uploading attachments...`);
403+
this.logger.debug(`Uploading attachments...`);
400404
while (record) {
401405
const uploaded = await this.uploadAttachment(record);
402406
if (!uploaded) {
@@ -405,9 +409,9 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
405409
}
406410
record = await this.getNextUploadRecord();
407411
}
408-
console.debug('Finished uploading attachments');
412+
this.logger.debug('Finished uploading attachments');
409413
} catch (error) {
410-
console.error('Upload failed:', error);
414+
this.logger.error('Upload failed:', error);
411415
} finally {
412416
this.uploading = false;
413417
}
@@ -464,7 +468,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
464468

465469
this.downloading = true;
466470
try {
467-
console.debug(`Downloading ${this.downloadQueue.size} attachments...`);
471+
this.logger.debug(`Downloading ${this.downloadQueue.size} attachments...`);
468472
while (this.downloadQueue.size > 0) {
469473
const id = this.downloadQueue.values().next().value;
470474
this.downloadQueue.delete(id);
@@ -474,9 +478,9 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
474478
}
475479
await this.downloadRecord(record);
476480
}
477-
console.debug('Finished downloading attachments');
481+
this.logger.debug('Finished downloading attachments');
478482
} catch (e) {
479-
console.error('Downloads failed:', e);
483+
this.logger.error('Downloads failed:', e);
480484
} finally {
481485
this.downloading = false;
482486
}
@@ -518,7 +522,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
518522
return;
519523
}
520524

521-
console.debug(`Deleting ${res.length} attachments from cache...`);
525+
this.logger.debug(`Deleting ${res.length} attachments from cache...`);
522526
await this.powersync.writeTransaction(async (tx) => {
523527
for (const record of res) {
524528
await this.delete(record, tx);
@@ -527,7 +531,7 @@ export abstract class AbstractAttachmentQueue<T extends AttachmentQueueOptions =
527531
}
528532

529533
async clearQueue(): Promise<void> {
530-
console.debug(`Clearing attachment queue...`);
534+
this.logger.debug(`Clearing attachment queue...`);
531535
await this.powersync.writeTransaction(async (tx) => {
532536
await tx.execute(`DELETE FROM ${this.table}`);
533537
});

packages/common/src/client/AbstractPowerSyncDatabase.ts

+4
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
406406
this.iterateListeners(async (cb) => cb.schemaChanged?.(schema));
407407
}
408408

409+
get logger() {
410+
return this.options.logger!;
411+
}
412+
409413
/**
410414
* Wait for initialization to complete.
411415
* While initializing is automatic, this helps to catch and report initialization errors.

packages/node/src/sync/stream/NodeRemote.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import * as os from 'node:os';
22

3-
import { ILogger } from 'js-logger';
4-
53
import {
4+
type ILogger,
65
AbstractRemote,
76
AbstractRemoteOptions,
87
BSONImplementation,

packages/react/src/WatchedQuery.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export class WatchedQuery extends BaseObserver<WatchedQueryListener> implements
4646
});
4747
}
4848

49+
get logger() {
50+
return this.db.logger ?? console;
51+
}
52+
4953
addTemporaryHold() {
5054
const ref = new Object();
5155
this.temporaryHolds.add(ref);
@@ -88,7 +92,7 @@ export class WatchedQuery extends BaseObserver<WatchedQueryListener> implements
8892
try {
8993
this.tables = await this.db.resolveTables(this.query.sqlStatement, this.query.queryParameters, this.options);
9094
} catch (e) {
91-
console.error('Failed to fetch tables:', e);
95+
this.logger.error('Failed to fetch tables:', e);
9296
this.setError(e);
9397
}
9498
}
@@ -103,7 +107,7 @@ export class WatchedQuery extends BaseObserver<WatchedQueryListener> implements
103107
const data = result ?? [];
104108
this.setData(data);
105109
} catch (e) {
106-
console.error('Failed to fetch data:', e);
110+
this.logger.error('Failed to fetch data:', e);
107111
this.setError(e);
108112
}
109113
}

packages/react/src/hooks/useQuery.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export const useQuery = <T = any>(
4242
options: AdditionalOptions = { runQueryOnce: false }
4343
): QueryResult<T> => {
4444
const powerSync = usePowerSync();
45+
const logger = powerSync?.logger ?? console;
4546
if (!powerSync) {
4647
return { isLoading: false, isFetching: false, data: [], error: new Error('PowerSync not configured.') };
4748
}
@@ -50,7 +51,7 @@ export const useQuery = <T = any>(
5051
try {
5152
parsedQuery = parseQuery(query, parameters);
5253
} catch (error) {
53-
console.error('Failed to parse query:', error);
54+
logger.error('Failed to parse query:', error);
5455
return { isLoading: false, isFetching: false, data: [], error };
5556
}
5657

@@ -107,7 +108,7 @@ export const useQuery = <T = any>(
107108

108109
handleResult(result);
109110
} catch (e) {
110-
console.error('Failed to fetch data:', e);
111+
logger.error('Failed to fetch data:', e);
111112
handleError(e);
112113
}
113114
};
@@ -122,7 +123,7 @@ export const useQuery = <T = any>(
122123

123124
setTables(tables);
124125
} catch (e) {
125-
console.error('Failed to fetch tables:', e);
126+
logger.error('Failed to fetch tables:', e);
126127
handleError(e);
127128
}
128129
};

packages/vue/src/composables/useQuery.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export const useQuery = <T = any>(
6565
let fetchData: () => Promise<void> | undefined;
6666

6767
const powerSync = usePowerSync();
68+
const logger = powerSync?.value?.logger ?? console;
6869

6970
const finishLoading = () => {
7071
isLoading.value = false;
@@ -99,7 +100,7 @@ export const useQuery = <T = any>(
99100
const result = await executor();
100101
handleResult(result);
101102
} catch (e) {
102-
console.error('Failed to fetch data:', e);
103+
logger.error('Failed to fetch data:', e);
103104
handleError(e);
104105
}
105106
};
@@ -114,7 +115,7 @@ export const useQuery = <T = any>(
114115
try {
115116
parsedQuery = parseQuery(queryValue, toValue(sqlParameters).map(toValue));
116117
} catch (e) {
117-
console.error('Failed to parse query:', e);
118+
logger.error('Failed to parse query:', e);
118119
handleError(e);
119120
return;
120121
}
@@ -125,7 +126,7 @@ export const useQuery = <T = any>(
125126
try {
126127
resolvedTables = await powerSync.value.resolveTables(sql, parameters, options);
127128
} catch (e) {
128-
console.error('Failed to fetch tables:', e);
129+
logger.error('Failed to fetch tables:', e);
129130
handleError(e);
130131
return;
131132
}

packages/web/src/db/adapters/AbstractWebSQLOpenFactory.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export abstract class AbstractWebSQLOpenFactory implements SQLOpenFactory {
2525
resolvedFlags: { disableSSRWarning, enableMultiTabs, ssrMode = isServerSide() }
2626
} = this;
2727
if (ssrMode && !disableSSRWarning) {
28-
console.warn(
28+
this.logger.warn(
2929
`
3030
Running PowerSync in SSR mode.
3131
Only empty query results will be returned.
@@ -34,7 +34,7 @@ export abstract class AbstractWebSQLOpenFactory implements SQLOpenFactory {
3434
}
3535

3636
if (!enableMultiTabs) {
37-
console.warn(
37+
this.logger.warn(
3838
'Multiple tab support is not enabled. Using this site across multiple tabs may not function correctly.'
3939
);
4040
}

packages/web/src/db/adapters/wa-sqlite/WASQLiteOpenFactory.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DBAdapter } from '@powersync/common';
1+
import { type ILogLevel, DBAdapter } from '@powersync/common';
22
import * as Comlink from 'comlink';
33
import { openWorkerDatabasePort, resolveWorkerDatabasePortFactory } from '../../../worker/db/open-worker-database';
44
import { AbstractWebSQLOpenFactory } from '../AbstractWebSQLOpenFactory';
@@ -20,6 +20,11 @@ export interface WASQLiteOpenFactoryOptions extends WebSQLOpenFactoryOptions {
2020
export interface ResolvedWASQLiteOpenFactoryOptions extends ResolvedWebSQLOpenOptions {
2121
vfs: WASQLiteVFS;
2222
}
23+
24+
export interface WorkerDBOpenerOptions extends ResolvedWASQLiteOpenFactoryOptions {
25+
logLevel: ILogLevel;
26+
}
27+
2328
/**
2429
* Opens a SQLite connection using WA-SQLite.
2530
*/
@@ -73,7 +78,7 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
7378
)
7479
: openWorkerDatabasePort(this.options.dbFilename, enableMultiTabs, optionsDbWorker, this.waOptions.vfs);
7580

76-
const workerDBOpener = Comlink.wrap<OpenAsyncDatabaseConnection<ResolvedWASQLiteOpenFactoryOptions>>(workerPort);
81+
const workerDBOpener = Comlink.wrap<OpenAsyncDatabaseConnection<WorkerDBOpenerOptions>>(workerPort);
7782

7883
return new WorkerWrappedAsyncDatabaseConnection({
7984
remote: workerDBOpener,
@@ -83,7 +88,8 @@ export class WASQLiteOpenFactory extends AbstractWebSQLOpenFactory {
8388
temporaryStorage,
8489
cacheSizeKb,
8590
flags: this.resolvedFlags,
86-
encryptionKey: encryptionKey
91+
encryptionKey: encryptionKey,
92+
logLevel: this.logger.getLevel()
8793
}),
8894
identifier: this.options.dbFilename,
8995
onClose: () => {

packages/web/src/db/sync/SharedWebStreamingSyncImplementation.ts

+2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ export class SharedWebStreamingSyncImplementation extends WebStreamingSyncImplem
135135
}
136136

137137
this.syncManager = Comlink.wrap<SharedSyncImplementation>(this.messagePort);
138+
this.syncManager.setLogLevel(this.logger.getLevel());
139+
138140
this.triggerCrudUpload = this.syncManager.triggerCrudUpload;
139141

140142
/**

packages/web/src/db/sync/WebStreamingSyncImplementation.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
AbstractStreamingSyncImplementation,
33
AbstractStreamingSyncImplementationOptions,
4+
createLogger,
45
LockOptions,
56
LockType
67
} from '@powersync/common';
@@ -26,7 +27,9 @@ export class WebStreamingSyncImplementation extends AbstractStreamingSyncImpleme
2627

2728
obtainLock<T>(lockOptions: LockOptions<T>): Promise<T> {
2829
const identifier = `streaming-sync-${lockOptions.type}-${this.webOptions.identifier}`;
29-
lockOptions.type == LockType.SYNC && console.debug('requesting lock for ', identifier);
30+
if (lockOptions.type == LockType.SYNC) {
31+
this.logger.debug('requesting lock for ', identifier);
32+
}
3033
return getNavigatorLocks().request(identifier, { signal: lockOptions.signal }, lockOptions.callback);
3134
}
3235
}

0 commit comments

Comments
 (0)