From 47a71ca1538ba9e2d7dfa01bf048a2db897bdf5f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 1 Oct 2022 19:24:28 -0700 Subject: [PATCH] feat: enhance debug logging abilities (#8201) --- README.md | 7 ++- packages/-ember-data/addon/index.js | 5 +- packages/-ember-data/ember-cli-build.js | 3 ++ .../node-tests/fixtures/expected.js | 3 ++ .../private-build-infra/addon/debugging.ts | 26 +++++++++++ .../addon-build-config-for-data-package.js | 3 ++ .../record-data/addon/-private/record-data.ts | 46 ++++++++++++++++++- .../store/addon/-private/store-service.ts | 21 +++++++++ 8 files changed, 109 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f97c822cce9..6fe966e199a 100644 --- a/README.md +++ b/README.md @@ -113,11 +113,14 @@ that has not explicitly activated it. To activate it set the appropriate flag to let app = new EmberApp(defaults, { emberData: { debug: { + LOG_PAYLOADS: false, // data store received to update cache with + LOG_OPERATIONS: false, // updates to cache remote state + LOG_MUTATIONS: false, // updates to cache local state LOG_NOTIFICATIONS: false, LOG_REQUEST_STATUS: false, LOG_IDENTIFIERS: false, - LOG_GRAPH: false, - LOG_INSTANCE_CACHE: false, + LOG_GRAPH: false, // relationship storage + LOG_INSTANCE_CACHE: false, // instance creation/deletion } } }); diff --git a/packages/-ember-data/addon/index.js b/packages/-ember-data/addon/index.js index 1ef63fb505a..d8e1d8d225a 100644 --- a/packages/-ember-data/addon/index.js +++ b/packages/-ember-data/addon/index.js @@ -9,7 +9,7 @@ It provides many of the facilities you'd find in server-side `ORM`s like `Active EmberData is organized into primitives that compose together via public APIs. -- [@ember-data/store](/ember-data/release/modules/@ember-data%2Fstore is the core and handles coordination +- [@ember-data/store](/ember-data/release/modules/@ember-data%2Fstore) is the core and handles coordination - [@ember-data/record-data](/ember-data/release/modules/@ember-data%2Frecord-data) is a resource cache for JSON:API structured data. It integrates with the store via the hook `createRecordDataFor` - [@ember-data/model](/ember-data/release/modules/@ember-data%2Fmodel) is a presentation layer, it integrates with the store via the hooks `instantiateRecord` and `teardownRecord`. - [@ember-data/adapter](/ember-data/release/modules/@ember-data%2Fadapter) provides various network API integrations for APIS built over specific REST or JSON:API conventions. @@ -82,6 +82,9 @@ that has not explicitly activated it. To activate it set the appropriate flag to let app = new EmberApp(defaults, { emberData: { debug: { + LOG_PAYLOADS: false, // data store received to update cache with + LOG_OPERATIONS: false, // updates to cache remote state + LOG_MUTATIONS: false, // updates to cache local state LOG_NOTIFICATIONS: false, LOG_REQUEST_STATUS: false, LOG_IDENTIFIERS: false, diff --git a/packages/-ember-data/ember-cli-build.js b/packages/-ember-data/ember-cli-build.js index e61ea3e5e16..64b3eeb9541 100644 --- a/packages/-ember-data/ember-cli-build.js +++ b/packages/-ember-data/ember-cli-build.js @@ -40,6 +40,9 @@ module.exports = function (defaults) { let config = { compatWith, debug: { + LOG_PAYLOADS: process.env.DEBUG_DATA ? true : false, + LOG_OPERATIONS: process.env.DEBUG_DATA ? true : false, + LOG_MUTATIONS: process.env.DEBUG_DATA ? true : false, LOG_NOTIFICATIONS: process.env.DEBUG_DATA ? true : false, LOG_REQUEST_STATUS: process.env.DEBUG_DATA ? true : false, LOG_IDENTIFIERS: process.env.DEBUG_DATA ? true : false, diff --git a/packages/-ember-data/node-tests/fixtures/expected.js b/packages/-ember-data/node-tests/fixtures/expected.js index a7a3ad7e663..5b50f9e3f1e 100644 --- a/packages/-ember-data/node-tests/fixtures/expected.js +++ b/packages/-ember-data/node-tests/fixtures/expected.js @@ -148,6 +148,9 @@ module.exports = { '(public) @ember-data/adapter/rest RESTAdapter#sortQueryParams', '(public) @ember-data/adapter/rest RESTAdapter#updateRecord', '(public) @ember-data/adapter/rest RESTAdapter#useFetch', + "(public) @ember-data/debug DebugLogging#LOG_PAYLOADS", + "(public) @ember-data/debug DebugLogging#LOG_OPERATIONS", + "(public) @ember-data/debug DebugLogging#LOG_MUTATIONS", "(public) @ember-data/debug DebugLogging#LOG_GRAPH", "(public) @ember-data/debug DebugLogging#LOG_IDENTIFIERS", "(public) @ember-data/debug DebugLogging#LOG_INSTANCE_CACHE", diff --git a/packages/private-build-infra/addon/debugging.ts b/packages/private-build-infra/addon/debugging.ts index 4d165538588..1bbb2bf719e 100644 --- a/packages/private-build-infra/addon/debugging.ts +++ b/packages/private-build-infra/addon/debugging.ts @@ -11,6 +11,9 @@ that has not explicitly activated it. To activate it set the appropriate flag to let app = new EmberApp(defaults, { emberData: { debug: { + LOG_PAYLOADS: false, // data store received to update cache with + LOG_OPERATIONS: false, // updates to cache remote state + LOG_MUTATIONS: false, // updates to cache local state LOG_NOTIFICATIONS: false, LOG_REQUEST_STATUS: false, LOG_IDENTIFIERS: false, @@ -24,6 +27,29 @@ that has not explicitly activated it. To activate it set the appropriate flag to @class DebugLogging @public */ +/** + * log payloads received by the store + * via `push` or returned from a delete/update/create + * operation. + * + * @property {boolean} LOG_PAYLOADS + * @public + */ +export const LOG_PAYLOADS = false; +/** + * log remote-state updates to the cache + * + * @property {boolean} LOG_OPERATIONS + * @public + */ +export const LOG_OPERATIONS = false; +/** + * log local-state updates to the cache + * + * @property {boolean} LOG_MUTATIONS + * @public + */ +export const LOG_MUTATIONS = false; /** * log notifications received by the RecordNotificationManager * diff --git a/packages/private-build-infra/src/addon-build-config-for-data-package.js b/packages/private-build-infra/src/addon-build-config-for-data-package.js index 2475c817185..da73ca293e0 100644 --- a/packages/private-build-infra/src/addon-build-config-for-data-package.js +++ b/packages/private-build-infra/src/addon-build-config-for-data-package.js @@ -227,6 +227,9 @@ function addonBuildConfigForDataPackage(PackageName) { options.emberData.debug = options.emberData.debug || {}; const debugOptions = Object.assign( { + LOG_PAYLOADS: false, + LOG_OPERATIONS: false, + LOG_MUTATIONS: false, LOG_NOTIFICATIONS: false, LOG_REQUEST_STATUS: false, LOG_IDENTIFIERS: false, diff --git a/packages/record-data/addon/-private/record-data.ts b/packages/record-data/addon/-private/record-data.ts index 4805ae1608e..bb41420dac4 100644 --- a/packages/record-data/addon/-private/record-data.ts +++ b/packages/record-data/addon/-private/record-data.ts @@ -5,6 +5,7 @@ import { assert } from '@ember/debug'; import { schedule } from '@ember/runloop'; import { isEqual } from '@ember/utils'; +import { LOG_MUTATIONS, LOG_OPERATIONS } from '@ember-data/private-build-infra/debugging'; import type { CollectionResourceRelationship, SingleResourceRelationship, @@ -108,6 +109,17 @@ export default class SingletonRecordData implements RecordData { let changedKeys: string[] | undefined; const cached = this.__peek(identifier); + if (LOG_OPERATIONS) { + try { + let _data = JSON.parse(JSON.stringify(data)); + // eslint-disable-next-line no-console + console.log('EmberData | Operation - pushData (upsert)', _data); + } catch (e) { + // eslint-disable-next-line no-console + console.log('EmberData | Operation - pushData (upsert)', data); + } + } + if (cached.isNew) { cached.isNew = false; this.__storeWrapper.notifyChange(identifier, 'state'); @@ -136,6 +148,16 @@ export default class SingletonRecordData implements RecordData { } sync(op: MergeOperation): void { + if (LOG_OPERATIONS) { + try { + let _data = JSON.parse(JSON.stringify(op)); + // eslint-disable-next-line no-console + console.log(`EmberData | Operation - sync ${op.op}`, _data); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`EmberData | Operation - sync ${op.op}`, op); + } + } if (op.op === 'mergeIdentifiers') { const cache = this.__cache.get(op.record); if (cache) { @@ -146,11 +168,31 @@ export default class SingletonRecordData implements RecordData { } } - update(operation: LocalRelationshipOperation): void { - graphFor(this.__storeWrapper).update(operation, false); + update(op: LocalRelationshipOperation): void { + if (LOG_MUTATIONS) { + try { + let _data = JSON.parse(JSON.stringify(op)); + // eslint-disable-next-line no-console + console.log(`EmberData | Mutation - update ${op.op}`, _data); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`EmberData | Mutation - update ${op.op}`, op); + } + } + graphFor(this.__storeWrapper).update(op, false); } clientDidCreate(identifier: StableRecordIdentifier, options?: Dict | undefined): Dict { + if (LOG_MUTATIONS) { + try { + let _data = options ? JSON.parse(JSON.stringify(options)) : options; + // eslint-disable-next-line no-console + console.log(`EmberData | Mutation - clientDidCreate ${identifier.lid}`, _data); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`EmberData | Mutation - clientDidCreate ${identifier.lid}`, options); + } + } const cached = this.__peek(identifier); cached.isNew = true; let createOptions = {}; diff --git a/packages/store/addon/-private/store-service.ts b/packages/store/addon/-private/store-service.ts index 7169c619965..f2d445ee0ce 100644 --- a/packages/store/addon/-private/store-service.ts +++ b/packages/store/addon/-private/store-service.ts @@ -13,6 +13,7 @@ import { reject, resolve } from 'rsvp'; import type DSModelClass from '@ember-data/model'; import { HAS_MODEL_PACKAGE, HAS_RECORD_DATA_PACKAGE } from '@ember-data/private-build-infra'; +import { LOG_PAYLOADS } from '@ember-data/private-build-infra/debugging'; import { DEPRECATE_HAS_RECORD, DEPRECATE_JSON_API_FALLBACK, @@ -2119,6 +2120,16 @@ class Store extends Service { if (DEBUG) { assertDestroyingStore(this, '_push'); } + if (LOG_PAYLOADS) { + try { + let data = JSON.parse(JSON.stringify(jsonApiDoc)); + // eslint-disable-next-line no-console + console.log('EmberData | Payload - push', data); + } catch (e) { + // eslint-disable-next-line no-console + console.log('EmberData | Payload - push', jsonApiDoc); + } + } let ret; this._join(() => { let included = jsonApiDoc.included; @@ -2300,6 +2311,16 @@ class Store extends Service { let fetchManagerPromise = this._fetchManager.scheduleSave(identifier, saveOptions); return fetchManagerPromise.then( (payload) => { + if (LOG_PAYLOADS) { + try { + let data = payload ? JSON.parse(JSON.stringify(payload)) : payload; + // eslint-disable-next-line no-console + console.log(`EmberData | Payload - ${operation}`, data); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`EmberData | Payload - ${operation}`, payload); + } + } /* // TODO @runspired re-evaluate the below claim now that // the save request pipeline is more streamlined.