From 4e2f0405db7c2f4bb38507e82fdbf50925ce94db Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 21 Nov 2024 16:36:31 +0000 Subject: [PATCH] Additional instrumentation for DD around CouchDB. --- .../backend-core/src/db/couch/DatabaseImpl.ts | 4 +- .../backend-core/src/db/instrumentation.ts | 127 ++++++++++++------ packages/types/src/documents/pouch.ts | 2 +- packages/types/src/sdk/db.ts | 4 +- 4 files changed, 92 insertions(+), 45 deletions(-) diff --git a/packages/backend-core/src/db/couch/DatabaseImpl.ts b/packages/backend-core/src/db/couch/DatabaseImpl.ts index 83b9b69d0b..371f3dc997 100644 --- a/packages/backend-core/src/db/couch/DatabaseImpl.ts +++ b/packages/backend-core/src/db/couch/DatabaseImpl.ts @@ -190,7 +190,7 @@ export class DatabaseImpl implements Database { } } - private async performCall(call: DBCallback): Promise { + private async performCall(call: DBCallback): Promise { const db = this.getDb() const fnc = await call(db) try { @@ -467,7 +467,7 @@ export class DatabaseImpl implements Database { } catch (err: any) { // didn't exist, don't worry if (err.statusCode === 404) { - return + return { ok: true } } else { throw new CouchDBError(err.message, err) } diff --git a/packages/backend-core/src/db/instrumentation.ts b/packages/backend-core/src/db/instrumentation.ts index e08bfc0362..4c12e20443 100644 --- a/packages/backend-core/src/db/instrumentation.ts +++ b/packages/backend-core/src/db/instrumentation.ts @@ -27,7 +27,7 @@ export class DDInstrumentedDatabase implements Database { exists(docId?: string): Promise { return tracer.trace("db.exists", span => { - span?.addTags({ db_name: this.name, doc_id: docId }) + span.addTags({ db_name: this.name, doc_id: docId }) if (docId) { return this.db.exists(docId) } @@ -37,15 +37,17 @@ export class DDInstrumentedDatabase implements Database { get(id?: string | undefined): Promise { return tracer.trace("db.get", span => { - span?.addTags({ db_name: this.name, doc_id: id }) + span.addTags({ db_name: this.name, doc_id: id }) return this.db.get(id) }) } tryGet(id?: string | undefined): Promise { - return tracer.trace("db.tryGet", span => { - span?.addTags({ db_name: this.name, doc_id: id }) - return this.db.tryGet(id) + return tracer.trace("db.tryGet", async span => { + span.addTags({ db_name: this.name, doc_id: id }) + const doc = await this.db.tryGet(id) + span.addTags({ doc_found: doc !== undefined }) + return doc }) } @@ -53,13 +55,15 @@ export class DDInstrumentedDatabase implements Database { ids: string[], opts?: { allowMissing?: boolean | undefined } | undefined ): Promise { - return tracer.trace("db.getMultiple", span => { - span?.addTags({ + return tracer.trace("db.getMultiple", async span => { + span.addTags({ db_name: this.name, num_docs: ids.length, allow_missing: opts?.allowMissing, }) - return this.db.getMultiple(ids, opts) + const docs = await this.db.getMultiple(ids, opts) + span.addTags({ num_docs_found: docs.length }) + return docs }) } @@ -69,12 +73,14 @@ export class DDInstrumentedDatabase implements Database { idOrDoc: string | Document, rev?: string ): Promise { - return tracer.trace("db.remove", span => { - span?.addTags({ db_name: this.name, doc_id: idOrDoc }) + return tracer.trace("db.remove", async span => { + span.addTags({ db_name: this.name, doc_id: idOrDoc, rev }) const isDocument = typeof idOrDoc === "object" const id = isDocument ? idOrDoc._id! : idOrDoc rev = isDocument ? idOrDoc._rev : rev - return this.db.remove(id, rev) + const resp = await this.db.remove(id, rev) + span.addTags({ ok: resp.ok }) + return resp }) } @@ -83,7 +89,11 @@ export class DDInstrumentedDatabase implements Database { opts?: { silenceErrors?: boolean } ): Promise { return tracer.trace("db.bulkRemove", span => { - span?.addTags({ db_name: this.name, num_docs: documents.length }) + span.addTags({ + db_name: this.name, + num_docs: documents.length, + silence_errors: opts?.silenceErrors, + }) return this.db.bulkRemove(documents, opts) }) } @@ -92,15 +102,21 @@ export class DDInstrumentedDatabase implements Database { document: AnyDocument, opts?: DatabasePutOpts | undefined ): Promise { - return tracer.trace("db.put", span => { - span?.addTags({ db_name: this.name, doc_id: document._id }) - return this.db.put(document, opts) + return tracer.trace("db.put", async span => { + span.addTags({ + db_name: this.name, + doc_id: document._id, + force: opts?.force, + }) + const resp = await this.db.put(document, opts) + span.addTags({ ok: resp.ok }) + return resp }) } bulkDocs(documents: AnyDocument[]): Promise { return tracer.trace("db.bulkDocs", span => { - span?.addTags({ db_name: this.name, num_docs: documents.length }) + span.addTags({ db_name: this.name, num_docs: documents.length }) return this.db.bulkDocs(documents) }) } @@ -108,9 +124,15 @@ export class DDInstrumentedDatabase implements Database { allDocs( params: DatabaseQueryOpts ): Promise> { - return tracer.trace("db.allDocs", span => { - span?.addTags({ db_name: this.name }) - return this.db.allDocs(params) + return tracer.trace("db.allDocs", async span => { + span.addTags({ db_name: this.name, ...params }) + const resp = await this.db.allDocs(params) + span.addTags({ + total_rows: resp.total_rows, + rows_length: resp.rows.length, + offset: resp.offset, + }) + return resp }) } @@ -118,57 +140,77 @@ export class DDInstrumentedDatabase implements Database { viewName: string, params: DatabaseQueryOpts ): Promise> { - return tracer.trace("db.query", span => { - span?.addTags({ db_name: this.name, view_name: viewName }) - return this.db.query(viewName, params) + return tracer.trace("db.query", async span => { + span.addTags({ db_name: this.name, view_name: viewName, ...params }) + const resp = await this.db.query(viewName, params) + span.addTags({ + total_rows: resp.total_rows, + rows_length: resp.rows.length, + offset: resp.offset, + }) + return resp }) } - destroy(): Promise { - return tracer.trace("db.destroy", span => { - span?.addTags({ db_name: this.name }) - return this.db.destroy() + destroy(): Promise { + return tracer.trace("db.destroy", async span => { + span.addTags({ db_name: this.name }) + const resp = await this.db.destroy() + span.addTags({ ok: resp.ok }) + return resp }) } - compact(): Promise { - return tracer.trace("db.compact", span => { - span?.addTags({ db_name: this.name }) - return this.db.compact() + compact(): Promise { + return tracer.trace("db.compact", async span => { + span.addTags({ db_name: this.name }) + const resp = await this.db.compact() + span.addTags({ ok: resp.ok }) + return resp }) } dump(stream: Writable, opts?: DatabaseDumpOpts | undefined): Promise { return tracer.trace("db.dump", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ + db_name: this.name, + batch_limit: opts?.batch_limit, + batch_size: opts?.batch_size, + style: opts?.style, + timeout: opts?.timeout, + num_doc_ids: opts?.doc_ids?.length, + query_params: opts?.query_params, + view: opts?.view, + selector: opts?.selector, + }) return this.db.dump(stream, opts) }) } load(...args: any[]): Promise { return tracer.trace("db.load", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ db_name: this.name, num_args: args.length }) return this.db.load(...args) }) } createIndex(...args: any[]): Promise { return tracer.trace("db.createIndex", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ db_name: this.name, num_args: args.length }) return this.db.createIndex(...args) }) } deleteIndex(...args: any[]): Promise { return tracer.trace("db.deleteIndex", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ db_name: this.name, num_args: args.length }) return this.db.deleteIndex(...args) }) } getIndexes(...args: any[]): Promise { return tracer.trace("db.getIndexes", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ db_name: this.name, num_args: args.length }) return this.db.getIndexes(...args) }) } @@ -177,22 +219,27 @@ export class DDInstrumentedDatabase implements Database { sql: string, parameters?: SqlQueryBinding ): Promise { - return tracer.trace("db.sql", span => { - span?.addTags({ db_name: this.name }) - return this.db.sql(sql, parameters) + return tracer.trace("db.sql", async span => { + span.addTags({ db_name: this.name, num_bindings: parameters?.length }) + const resp = await this.db.sql(sql, parameters) + span.addTags({ num_rows: resp.length }) + return resp }) } sqlPurgeDocument(docIds: string[] | string): Promise { return tracer.trace("db.sqlPurgeDocument", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ + db_name: this.name, + num_docs: Array.isArray(docIds) ? docIds.length : 1, + }) return this.db.sqlPurgeDocument(docIds) }) } sqlDiskCleanup(): Promise { return tracer.trace("db.sqlDiskCleanup", span => { - span?.addTags({ db_name: this.name }) + span.addTags({ db_name: this.name }) return this.db.sqlDiskCleanup() }) } diff --git a/packages/types/src/documents/pouch.ts b/packages/types/src/documents/pouch.ts index 6ff851a515..c2ac1599ee 100644 --- a/packages/types/src/documents/pouch.ts +++ b/packages/types/src/documents/pouch.ts @@ -8,7 +8,7 @@ export interface RowValue { export interface RowResponse { id: string key: string - error: string + error?: string value: T doc?: T } diff --git a/packages/types/src/sdk/db.ts b/packages/types/src/sdk/db.ts index 9797715329..9feecbdb2b 100644 --- a/packages/types/src/sdk/db.ts +++ b/packages/types/src/sdk/db.ts @@ -163,8 +163,8 @@ export interface Database { viewName: string, params: DatabaseQueryOpts ): Promise> - destroy(): Promise - compact(): Promise + destroy(): Promise + compact(): Promise // these are all PouchDB related functions that are rarely used - in future // should be replaced by better typed/non-pouch implemented methods dump(stream: Writable, opts?: DatabaseDumpOpts): Promise