From 0dbc01c330a5419e3d4c5b0ef10ffa6d51efd1da Mon Sep 17 00:00:00 2001 From: YANG QIA <2013xile@gmail.com> Date: Tue, 2 Jan 2024 12:17:46 +0800 Subject: [PATCH] feat: telemetry (#3279) * feat: telemetry * fix: build * chore: update * refactor: improve api * fix: test * fix: version * fix: build * feat: support for adding views * fix: typo * fix: version * chore: update * chore(env): `true` -> `on` * fix: metric version --- packages/core/app/src/config/index.ts | 2 + packages/core/app/src/config/telemetry.ts | 11 + packages/core/server/package.json | 109 +++++----- packages/core/server/src/application.ts | 46 ++++- packages/core/telemetry/.npmignore | 2 + packages/core/telemetry/LICENSE | 201 +++++++++++++++++++ packages/core/telemetry/package.json | 23 +++ packages/core/telemetry/src/index.ts | 1 + packages/core/telemetry/src/metric.ts | 77 +++++++ packages/core/telemetry/src/telemetry.ts | 62 ++++++ packages/core/telemetry/src/trace.ts | 62 ++++++ packages/core/test/vitest.mjs | 136 +++++++------ yarn.lock | 233 ++++++++++++++++++++-- 13 files changed, 829 insertions(+), 136 deletions(-) create mode 100644 packages/core/app/src/config/telemetry.ts create mode 100644 packages/core/telemetry/.npmignore create mode 100644 packages/core/telemetry/LICENSE create mode 100644 packages/core/telemetry/package.json create mode 100644 packages/core/telemetry/src/index.ts create mode 100644 packages/core/telemetry/src/metric.ts create mode 100644 packages/core/telemetry/src/telemetry.ts create mode 100644 packages/core/telemetry/src/trace.ts diff --git a/packages/core/app/src/config/index.ts b/packages/core/app/src/config/index.ts index d30f72a7e..f1aa7d72b 100644 --- a/packages/core/app/src/config/index.ts +++ b/packages/core/app/src/config/index.ts @@ -3,6 +3,7 @@ import { parseDatabaseOptions } from './database'; import logger from './logger'; import plugins from './plugins'; import resourcer from './resourcer'; +import { telemetry } from './telemetry'; export async function getConfig() { return { @@ -11,6 +12,7 @@ export async function getConfig() { plugins, cacheManager, logger, + telemetry, perfHooks: process.env.ENABLE_PERF_HOOKS ? true : false, }; } diff --git a/packages/core/app/src/config/telemetry.ts b/packages/core/app/src/config/telemetry.ts new file mode 100644 index 000000000..3c946f26f --- /dev/null +++ b/packages/core/app/src/config/telemetry.ts @@ -0,0 +1,11 @@ +import { AppTelemetryOptions } from '@nocobase/server'; + +export const telemetry: AppTelemetryOptions = { + enabled: process.env.TELEMETRY_ENABLED === 'on', + metric: { + readerName: process.env.TELEMETRY_METRIC_READER, + }, + trace: { + processorName: process.env.TELEMETRY_TRACE_PROCESSOR, + }, +}; diff --git a/packages/core/server/package.json b/packages/core/server/package.json index 35f9710fb..591c27798 100644 --- a/packages/core/server/package.json +++ b/packages/core/server/package.json @@ -1,56 +1,57 @@ { - "name": "@nocobase/server", - "version": "0.18.0-alpha.8", - "main": "lib/index.js", - "types": "./lib/index.d.ts", - "license": "Apache-2.0", - "dependencies": { - "@formily/json-schema": "2.2.27", - "@hapi/topo": "^6.0.0", - "@koa/cors": "^3.1.0", - "@koa/multer": "^3.0.2", - "@koa/router": "^9.4.0", - "@nocobase/acl": "0.18.0-alpha.8", - "@nocobase/actions": "0.18.0-alpha.8", - "@nocobase/auth": "0.18.0-alpha.8", - "@nocobase/cache": "0.18.0-alpha.8", - "@nocobase/database": "0.18.0-alpha.8", - "@nocobase/evaluators": "0.18.0-alpha.8", - "@nocobase/logger": "0.18.0-alpha.8", - "@nocobase/resourcer": "0.18.0-alpha.8", - "@nocobase/sdk": "0.18.0-alpha.8", - "@nocobase/utils": "0.18.0-alpha.8", - "@types/decompress": "4.2.4", - "@types/ini": "^1.3.31", - "@types/koa-send": "^4.1.3", - "@types/multer": "^1.4.5", - "axios": "^0.26.1", - "chalk": "^4.1.1", - "commander": "^9.2.0", - "cron": "^2.4.4", - "cronstrue": "^2.11.0", - "dayjs": "^1.11.8", - "decompress": "4.2.1", - "find-package-json": "^1.2.0", - "fs-extra": "^11.1.1", - "i18next": "^22.4.9", - "ini": "^4.1.1", - "koa": "^2.13.4", - "koa-bodyparser": "^4.3.0", - "koa-send": "^5.0.1", - "koa-static": "^5.0.0", - "lodash": "^4.17.21", - "multer": "^1.4.2", - "nanoid": "3.3.4", - "semver": "^7.3.7", - "serve-handler": "^6.1.5", - "ws": "^8.13.0", - "xpipe": "^1.0.5" - }, - "devDependencies": { - "@types/semver": "^7.3.9", - "@types/serve-handler": "^6.1.1", - "@types/ws": "^8.5.5" - }, - "gitHead": "979a9c59a98c61a2287dd847580746a9b597cbde" + "name": "@nocobase/server", + "version": "0.18.0-alpha.8", + "main": "lib/index.js", + "types": "./lib/index.d.ts", + "license": "Apache-2.0", + "dependencies": { + "@formily/json-schema": "2.2.27", + "@hapi/topo": "^6.0.0", + "@koa/cors": "^3.1.0", + "@koa/multer": "^3.0.2", + "@koa/router": "^9.4.0", + "@nocobase/acl": "0.18.0-alpha.8", + "@nocobase/actions": "0.18.0-alpha.8", + "@nocobase/auth": "0.18.0-alpha.8", + "@nocobase/cache": "0.18.0-alpha.8", + "@nocobase/database": "0.18.0-alpha.8", + "@nocobase/evaluators": "0.18.0-alpha.8", + "@nocobase/logger": "0.18.0-alpha.8", + "@nocobase/resourcer": "0.18.0-alpha.8", + "@nocobase/sdk": "0.18.0-alpha.8", + "@nocobase/utils": "0.18.0-alpha.8", + "@nocobase/telemetry": "0.18.0-alpha.8", + "@types/decompress": "4.2.4", + "@types/ini": "^1.3.31", + "@types/koa-send": "^4.1.3", + "@types/multer": "^1.4.5", + "axios": "^0.26.1", + "chalk": "^4.1.1", + "commander": "^9.2.0", + "cron": "^2.4.4", + "cronstrue": "^2.11.0", + "dayjs": "^1.11.8", + "decompress": "4.2.1", + "find-package-json": "^1.2.0", + "fs-extra": "^11.1.1", + "i18next": "^22.4.9", + "ini": "^4.1.1", + "koa": "^2.13.4", + "koa-bodyparser": "^4.3.0", + "koa-send": "^5.0.1", + "koa-static": "^5.0.0", + "lodash": "^4.17.21", + "multer": "^1.4.2", + "nanoid": "3.3.4", + "semver": "^7.3.7", + "serve-handler": "^6.1.5", + "ws": "^8.13.0", + "xpipe": "^1.0.5" + }, + "devDependencies": { + "@types/semver": "^7.3.9", + "@types/serve-handler": "^6.1.1", + "@types/ws": "^8.5.5" + }, + "gitHead": "979a9c59a98c61a2287dd847580746a9b597cbde" } diff --git a/packages/core/server/src/application.ts b/packages/core/server/src/application.ts index 4912062f6..5ee9fe481 100644 --- a/packages/core/server/src/application.ts +++ b/packages/core/server/src/application.ts @@ -42,6 +42,7 @@ import { ApplicationVersion } from './helpers/application-version'; import { Locale } from './locale'; import { Plugin } from './plugin'; import { InstallOptions, PluginManager } from './plugin-manager'; +import { TelemetryOptions, Telemetry } from '@nocobase/telemetry'; import packageJson from '../package.json'; @@ -57,6 +58,10 @@ export interface AppLoggerOptions { system: SystemLoggerOptions; } +export interface AppTelemetryOptions extends TelemetryOptions { + enabled?: boolean; +} + export interface ApplicationOptions { database?: IDatabaseOptions | Database; cacheManager?: CacheManagerOptions; @@ -73,6 +78,7 @@ export interface ApplicationOptions { name?: string; authManager?: AuthManagerOptions; perfHooks?: boolean; + telemetry?: AppTelemetryOptions; } export interface DefaultState extends KoaDefaultState { @@ -249,6 +255,12 @@ export class Application exten return this._locales; } + protected _telemetry: Telemetry; + + get telemetry() { + return this._telemetry; + } + protected _version: ApplicationVersion; get version() { @@ -352,14 +364,20 @@ export class Application exten if (options?.reload) { this.setMaintainingMessage('app reload'); this.log.info(`app.reload()`, { method: 'load' }); + + if (this.cacheManager) { + await this.cacheManager.close(); + } + + if (this.telemetry.started) { + await this.telemetry.shutdown(); + } + const oldDb = this._db; this.init(); if (!oldDb.closed()) { await oldDb.close(); } - if (this._cacheManager) { - await this._cacheManager.close(); - } } this._cacheManager = await createCacheManager(this, this.options.cacheManager); @@ -372,6 +390,14 @@ export class Application exten this.setMaintainingMessage('emit beforeLoad'); await this.emitAsync('beforeLoad', this, options); + // Telemetry is initialized after beforeLoad hook + // since some configuration may be registered in beforeLoad hook + this.telemetry.init(); + if (this.options.telemetry?.enabled) { + // Start collecting telemetry data if enabled + this.telemetry.start(); + } + await this.pm.load(options); this.setMaintainingMessage('emit afterLoad'); @@ -588,8 +614,12 @@ export class Application exten this.log.error(e.message, { method: 'stop', err: e.stack }); } - if (this._cacheManager) { - await this._cacheManager.close(); + if (this.cacheManager) { + await this.cacheManager.close(); + } + + if (this.telemetry.started) { + await this.telemetry.shutdown(); } await this.emitAsync('afterStop', this, options); @@ -750,6 +780,12 @@ export class Application exten plugins: plugins || [], }); + this._telemetry = new Telemetry({ + serviceName: `nocobase-${this.name}`, + version: this.getVersion(), + ...options.telemetry, + }); + this._authManager = new AuthManager({ authKey: 'X-Authenticator', default: 'basic', diff --git a/packages/core/telemetry/.npmignore b/packages/core/telemetry/.npmignore new file mode 100644 index 000000000..c593fe9df --- /dev/null +++ b/packages/core/telemetry/.npmignore @@ -0,0 +1,2 @@ +/node_modules +/src \ No newline at end of file diff --git a/packages/core/telemetry/LICENSE b/packages/core/telemetry/LICENSE new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/packages/core/telemetry/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/core/telemetry/package.json b/packages/core/telemetry/package.json new file mode 100644 index 000000000..7840677f4 --- /dev/null +++ b/packages/core/telemetry/package.json @@ -0,0 +1,23 @@ +{ + "name": "@nocobase/telemetry", + "version": "0.18.0-alpha.8", + "description": "nocobase telemetry library", + "license": "Apache-2.0", + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/nocobase/nocobase.git", + "directory": "packages/telemetry" + }, + "dependencies": { + "@nocobase/utils": "0.18.0-alpha.8", + "@opentelemetry/api": "^1.7.0", + "@opentelemetry/instrumentation": "^0.46.0", + "@opentelemetry/resources": "^1.19.0", + "@opentelemetry/sdk-metrics": "^1.19.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", + "@opentelemetry/sdk-trace-node": "^1.19.0", + "@opentelemetry/semantic-conventions": "^1.19.0" + } +} diff --git a/packages/core/telemetry/src/index.ts b/packages/core/telemetry/src/index.ts new file mode 100644 index 000000000..2e9d35da7 --- /dev/null +++ b/packages/core/telemetry/src/index.ts @@ -0,0 +1 @@ +export * from './telemetry'; diff --git a/packages/core/telemetry/src/metric.ts b/packages/core/telemetry/src/metric.ts new file mode 100644 index 000000000..e29cce23e --- /dev/null +++ b/packages/core/telemetry/src/metric.ts @@ -0,0 +1,77 @@ +import { Registry } from '@nocobase/utils'; +import { + MetricReader, + PeriodicExportingMetricReader, + ConsoleMetricExporter, + MeterProvider, + View, +} from '@opentelemetry/sdk-metrics'; +import { Resource } from '@opentelemetry/resources'; +import opentelemetry from '@opentelemetry/api'; + +export type MetricOptions = { + meterName?: string; + version?: string; + readerName?: string | string[]; +}; + +type GetMetricReader = () => MetricReader; + +export class Metric { + meterName: string; + version: string; + readerName: string | string[]; + readers = new Registry(); + provider: MeterProvider; + views: View[] = []; + + constructor(options?: MetricOptions) { + const { meterName, readerName, version } = options || {}; + this.readerName = readerName || 'console'; + this.meterName = meterName || 'nocobase-meter'; + this.version = version || ''; + this.registerReader( + 'console', + () => + new PeriodicExportingMetricReader({ + exporter: new ConsoleMetricExporter(), + }), + ); + } + + init(resource: Resource) { + this.provider = new MeterProvider({ resource, views: this.views }); + opentelemetry.metrics.setGlobalMeterProvider(this.provider); + } + + registerReader(name: string, reader: GetMetricReader) { + this.readers.register(name, reader); + } + + getReader(name: string) { + return this.readers.get(name); + } + + addView(...view: View[]) { + this.views.push(...view); + } + + getMeter(name?: string, version?: string) { + return this.provider.getMeter(name || this.meterName, version || this.version); + } + + start() { + let readerName = this.readerName; + if (typeof readerName === 'string') { + readerName = readerName.split(','); + } + readerName.forEach((name) => { + const reader = this.getReader(name)(); + this.provider.addMetricReader(reader); + }); + } + + shutdown() { + return this.provider.shutdown(); + } +} diff --git a/packages/core/telemetry/src/telemetry.ts b/packages/core/telemetry/src/telemetry.ts new file mode 100644 index 000000000..fd74b93a8 --- /dev/null +++ b/packages/core/telemetry/src/telemetry.ts @@ -0,0 +1,62 @@ +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { Resource } from '@opentelemetry/resources'; +import { InstrumentationOption, registerInstrumentations } from '@opentelemetry/instrumentation'; +import { Metric, MetricOptions } from './metric'; +import { Trace, TraceOptions } from './trace'; + +export interface TelemetryOptions { + serviceName?: string; + version?: string; + trace?: TraceOptions; + metric?: MetricOptions; +} + +export class Telemetry { + serviceName: string; + version: string; + instrumentations: InstrumentationOption[] = []; + trace: Trace; + metric: Metric; + started = false; + + constructor(options?: TelemetryOptions) { + const { trace, metric, serviceName, version } = options || {}; + this.trace = new Trace({ tracerName: `${serviceName}-trace`, version, ...trace }); + this.metric = new Metric({ meterName: `${serviceName}-meter`, version, ...metric }); + this.serviceName = serviceName || 'nocobase'; + this.version = version || ''; + } + + init() { + registerInstrumentations({ + instrumentations: this.instrumentations, + }); + + const resource = Resource.default().merge( + new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: this.serviceName, + [SemanticResourceAttributes.SERVICE_VERSION]: this.version, + }), + ); + + this.trace.init(resource); + this.metric.init(resource); + } + + start() { + if (!this.started) { + this.trace.start(); + this.metric.start(); + } + this.started = true; + } + + async shutdown() { + await Promise.all([this.trace.shutdown(), this.metric.shutdown()]); + this.started = false; + } + + addInstrumentation(...instrumentation: InstrumentationOption[]) { + this.instrumentations.push(...instrumentation); + } +} diff --git a/packages/core/telemetry/src/trace.ts b/packages/core/telemetry/src/trace.ts new file mode 100644 index 000000000..9e38e96e6 --- /dev/null +++ b/packages/core/telemetry/src/trace.ts @@ -0,0 +1,62 @@ +import { Registry } from '@nocobase/utils'; +import { BatchSpanProcessor, ConsoleSpanExporter, SpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { Resource } from '@opentelemetry/resources'; + +export type TraceOptions = { + tracerName?: string; + version?: string; + processorName?: string | string[]; +}; + +type GetSpanProcessor = () => SpanProcessor; + +export class Trace { + processorName: string | string[]; + processors = new Registry(); + tracerName: string; + version: string; + provider: NodeTracerProvider; + + constructor(options?: TraceOptions) { + const { processorName, tracerName, version } = options || {}; + this.processorName = processorName || 'console'; + this.tracerName = tracerName || 'nocobase-trace'; + this.version = version || ''; + this.registerProcessor('console', () => new BatchSpanProcessor(new ConsoleSpanExporter())); + } + + init(resource: Resource) { + this.provider = new NodeTracerProvider({ + resource, + }); + this.provider.register(); + } + + registerProcessor(name: string, processor: GetSpanProcessor) { + this.processors.register(name, processor); + } + + getProcessor(name: string) { + return this.processors.get(name); + } + + getTracer(name?: string, version?: string) { + return this.provider.getTracer(name || this.tracerName, version || this.version); + } + + start() { + let processorName = this.processorName; + if (typeof processorName === 'string') { + processorName = processorName.split(','); + } + processorName.forEach((name) => { + const processor = this.getProcessor(name)(); + this.provider.addSpanProcessor(processor); + }); + } + + shutdown() { + return this.provider.shutdown(); + } +} diff --git a/packages/core/test/vitest.mjs b/packages/core/test/vitest.mjs index a37d4aa25..015917a87 100644 --- a/packages/core/test/vitest.mjs +++ b/packages/core/test/vitest.mjs @@ -23,10 +23,16 @@ function tsConfigPathsToAlias() { } return acc; }, []); - alias.unshift({ - find: '@nocobase/utils/plugin-symlink', - replacement: 'node_modules/@nocobase/utils/plugin-symlink.js', - }); + alias.unshift( + { + find: '@nocobase/utils/plugin-symlink', + replacement: 'node_modules/@nocobase/utils/plugin-symlink.js', + }, + { + find: '@opentelemetry/resources', + replacement: 'node_modules/@opentelemetry/resources/build/src/index.js', + }, + ); return [ { find: /^~antd\/(.*)/, replacement: 'antd/$1' }, ...alias.map((item) => { @@ -42,70 +48,70 @@ export const defineConfig = (config = {}) => { return vitestConfig( process.env.TEST_ENV === 'server-side' ? { - root: process.cwd(), - resolve: { - mainFields: ['module'], - }, - test: { - globals: true, - setupFiles: resolve(__dirname, './setup/server.ts'), - alias: tsConfigPathsToAlias(), - include: ['packages/**/__tests__/**/*.test.ts'], - exclude: [ - '**/node_modules/**', - '**/dist/**', - '**/lib/**', - '**/es/**', - '**/e2e/**', - '**/__e2e__/**', - '**/{vitest,commitlint}.config.*', - 'packages/**/{dumi-theme-nocobase,sdk,client}/**/__tests__/**/*.{test,spec}.{ts,tsx}', - ], - testTimeout: 300000, - bail: 1, - // 在 GitHub Actions 中不输出日志 - silent: !!process.env.GITHUB_ACTIONS, - // poolOptions: { - // threads: { - // singleThread: process.env.SINGLE_THREAD == 'false' ? false : true, - // }, - // }, - }, - } + root: process.cwd(), + resolve: { + mainFields: ['module'], + }, + test: { + globals: true, + setupFiles: resolve(__dirname, './setup/server.ts'), + alias: tsConfigPathsToAlias(), + include: ['packages/**/__tests__/**/*.test.ts'], + exclude: [ + '**/node_modules/**', + '**/dist/**', + '**/lib/**', + '**/es/**', + '**/e2e/**', + '**/__e2e__/**', + '**/{vitest,commitlint}.config.*', + 'packages/**/{dumi-theme-nocobase,sdk,client}/**/__tests__/**/*.{test,spec}.{ts,tsx}', + ], + testTimeout: 300000, + bail: 1, + // 在 GitHub Actions 中不输出日志 + silent: !!process.env.GITHUB_ACTIONS, + // poolOptions: { + // threads: { + // singleThread: process.env.SINGLE_THREAD == 'false' ? false : true, + // }, + // }, + }, + } : { - plugins: [react()], - resolve: { - mainFields: ['module'], - }, - define: { - 'process.env.__TEST__': true, - 'process.env.__E2E__': false, - }, - test: { - globals: true, - setupFiles: resolve(__dirname, './setup/client.ts'), - environment: 'jsdom', - css: false, - alias: tsConfigPathsToAlias(), - include: ['packages/**/{dumi-theme-nocobase,sdk,client}/**/__tests__/**/*.{test,spec}.{ts,tsx}'], - exclude: [ - '**/node_modules/**', - '**/dist/**', - '**/lib/**', - '**/es/**', - '**/e2e/**', - '**/__e2e__/**', - '**/{vitest,commitlint}.config.*', - ], - testTimeout: 300000, - // 在 GitHub Actions 中不输出日志 - silent: !!process.env.GITHUB_ACTIONS, - server: { - deps: { - inline: ['@juggle/resize-observer', 'clsx'], - }, + plugins: [react()], + resolve: { + mainFields: ['module'], + }, + define: { + 'process.env.__TEST__': true, + 'process.env.__E2E__': false, + }, + test: { + globals: true, + setupFiles: resolve(__dirname, './setup/client.ts'), + environment: 'jsdom', + css: false, + alias: tsConfigPathsToAlias(), + include: ['packages/**/{dumi-theme-nocobase,sdk,client}/**/__tests__/**/*.{test,spec}.{ts,tsx}'], + exclude: [ + '**/node_modules/**', + '**/dist/**', + '**/lib/**', + '**/es/**', + '**/e2e/**', + '**/__e2e__/**', + '**/{vitest,commitlint}.config.*', + ], + testTimeout: 300000, + // 在 GitHub Actions 中不输出日志 + silent: !!process.env.GITHUB_ACTIONS, + server: { + deps: { + inline: ['@juggle/resize-observer', 'clsx'], }, }, }, + }, ); }; diff --git a/yarn.lock b/yarn.lock index bed847086..c0a324949 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4454,6 +4454,100 @@ "@opencensus/core" "^0.0.8" uuid "^3.2.1" +"@opentelemetry/api@^1.7.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz#b139c81999c23e3c8d3c0a7234480e945920fc40" + integrity sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw== + +"@opentelemetry/context-async-hooks@1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.19.0.tgz#86406105280d428f99afccd65b092ad4a3540347" + integrity sha512-0i1ECOc9daKK3rjUgDDXf0GDD5XfCou5lXnt2DALIc2qKoruPPcesobNKE54laSVUWnC3jX26RzuOa31g0V32A== + +"@opentelemetry/core@1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/core/-/core-1.19.0.tgz#6563bb65465bf232d8435553b9a122d9351c0fbb" + integrity sha512-w42AukJh3TP8R0IZZOVJVM/kMWu8g+lm4LzT70WtuKqhwq7KVhcDzZZuZinWZa6TtQCl7Smt2wolEYzpHabOgw== + dependencies: + "@opentelemetry/semantic-conventions" "1.19.0" + +"@opentelemetry/exporter-prometheus@^0.46.0": + version "0.46.0" + resolved "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.46.0.tgz#c411a1e8a5266f9f3ddc44a088a538c3c1ee4830" + integrity sha512-AXcoCHG31K2PLGizlJJWcfQqZsGfUZkT7ik6C8VJu7U2Cenk0Xhvd3rO+vVNSSjP1+LHkP4MQtqEXpIZttw5cw== + dependencies: + "@opentelemetry/core" "1.19.0" + "@opentelemetry/resources" "1.19.0" + "@opentelemetry/sdk-metrics" "1.19.0" + +"@opentelemetry/instrumentation@^0.46.0": + version "0.46.0" + resolved "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.46.0.tgz#a8a252306f82e2eace489312798592a14eb9830e" + integrity sha512-a9TijXZZbk0vI5TGLZl+0kxyFfrXHhX6Svtz7Pp2/VBlCSKrazuULEyoJQrOknJyFWNMEmbbJgOciHCCpQcisw== + dependencies: + "@types/shimmer" "^1.0.2" + import-in-the-middle "1.7.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/propagator-b3@1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.19.0.tgz#9fbf15922aca1e09a599272ba7edb766732f848f" + integrity sha512-v7y5IBOKBm0vP3yf0DHzlw4L2gL6tZ0KeeMTaxfO5IuomMffDbrGWcvYFp0Dt4LdZctTSK523rVLBB9FBHBciQ== + dependencies: + "@opentelemetry/core" "1.19.0" + +"@opentelemetry/propagator-jaeger@1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.19.0.tgz#e30913b4ba75b734c7269602902d5a205c802624" + integrity sha512-dedkOoTzKg+nYoLWCMp0Im+wo+XkTRW6aXhi8VQRtMW/9SNJGOllCJSu8llToLxMDF0+6zu7OCrKkevAof2tew== + dependencies: + "@opentelemetry/core" "1.19.0" + +"@opentelemetry/resources@1.19.0", "@opentelemetry/resources@^1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.19.0.tgz#2df9e0e8623cd390569243e2c9c15d7cce063c2f" + integrity sha512-RgxvKuuMOf7nctOeOvpDjt2BpZvZGr9Y0vf7eGtY5XYZPkh2p7e2qub1S2IArdBMf9kEbz0SfycqCviOu9isqg== + dependencies: + "@opentelemetry/core" "1.19.0" + "@opentelemetry/semantic-conventions" "1.19.0" + +"@opentelemetry/sdk-metrics@1.19.0", "@opentelemetry/sdk-metrics@^1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.19.0.tgz#fe8029af29402563eb8dba75a85fc02006ea92c4" + integrity sha512-FiMii40zr0Fmys4F1i8gmuCvbinBnBsDeGBr4FQemOf0iPCLytYQm5AZJ/nn4xSc71IgKBQwTFQRAGJI7JvZ4Q== + dependencies: + "@opentelemetry/core" "1.19.0" + "@opentelemetry/resources" "1.19.0" + lodash.merge "^4.6.2" + +"@opentelemetry/sdk-trace-base@1.19.0", "@opentelemetry/sdk-trace-base@^1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.19.0.tgz#87e629e7080945d955d53c2c12352915f5797cd3" + integrity sha512-+IRvUm+huJn2KqfFW3yW/cjvRwJ8Q7FzYHoUNx5Fr0Lws0LxjMJG1uVB8HDpLwm7mg5XXH2M5MF+0jj5cM8BpQ== + dependencies: + "@opentelemetry/core" "1.19.0" + "@opentelemetry/resources" "1.19.0" + "@opentelemetry/semantic-conventions" "1.19.0" + +"@opentelemetry/sdk-trace-node@^1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.19.0.tgz#9dc6306d9f935a7cf132fce162e7bda28d0ecca5" + integrity sha512-TCiEq/cUjM15RFqBRwWomTVbOqzndWL4ILa7ZCu0zbjU1/XY6AgHkgrgAc7vGP6TjRqH4Xryuglol8tcIfbBUQ== + dependencies: + "@opentelemetry/context-async-hooks" "1.19.0" + "@opentelemetry/core" "1.19.0" + "@opentelemetry/propagator-b3" "1.19.0" + "@opentelemetry/propagator-jaeger" "1.19.0" + "@opentelemetry/sdk-trace-base" "1.19.0" + semver "^7.5.2" + +"@opentelemetry/semantic-conventions@1.19.0", "@opentelemetry/semantic-conventions@^1.19.0": + version "1.19.0" + resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.19.0.tgz#0c17f80b45de1c8778dfdf17acb1e9d4c4aa4ba8" + integrity sha512-14jRpC8f5c0gPSwoZ7SbEJni1PqI+AhAE8m1bMz6v+RPM4OlP1PT2UHBJj5Qh/ALLPjhVU/aZUK3YyjTUqqQVg== + "@pkgr/utils@^2.3.1", "@pkgr/utils@^2.4.2": version "2.4.2" resolved "https://registry.npmmirror.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" @@ -4748,6 +4842,11 @@ resolved "https://registry.npmmirror.com/@remix-run/router/-/router-1.14.0.tgz#9bc39a5a3a71b81bdb310eba6def5bc3966695b7" integrity sha512-WOHih+ClN7N8oHk9N4JUiMxQJmRVaOxcg8w7F/oHUXzJt920ekASLI/7cYX8XkntDWRhLZtsk6LbGrkgOAvi5A== +"@remix-run/router@1.14.1": + version "1.14.1" + resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.14.1.tgz#6d2dd03d52e604279c38911afc1079d58c50a755" + integrity sha512-Qg4DMQsfPNAs88rb2xkdk03N3bjK4jgX5fR24eHCTR9q6PrhZQZ4UJBPzCHJkIpTRN1UKxx2DzjZmnC+7Lj0Ow== + "@restart/hooks@^0.4.7": version "0.4.15" resolved "https://registry.npmmirror.com/@restart/hooks/-/hooks-0.4.15.tgz#70990085c9b79d1f3e140db824b29218bdc2b5bb" @@ -6304,6 +6403,15 @@ dependencies: "@types/express" "*" +"@types/pg@^8.10.9": + version "8.10.9" + resolved "https://registry.npmjs.org/@types/pg/-/pg-8.10.9.tgz#d20bb948c6268c5bd847e2bf968f1194c5a2355a" + integrity sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + "@types/picomatch@*": version "2.3.3" resolved "https://registry.npmmirror.com/@types/picomatch/-/picomatch-2.3.3.tgz#be60498568c19e989e43fb39aa84be1ed3655e92" @@ -6426,6 +6534,11 @@ "@types/mime" "*" "@types/node" "*" +"@types/shimmer@^1.0.2": + version "1.0.5" + resolved "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz#491d8984d4510e550bfeb02d518791d7f59d2b88" + integrity sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww== + "@types/streamx@*": version "2.9.5" resolved "https://registry.npmmirror.com/@types/streamx/-/streamx-2.9.5.tgz#2a4a28d73e521c6799e06e7faa4dabc2139c5733" @@ -7221,6 +7334,11 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -8439,7 +8557,7 @@ bessel@^1.0.2: resolved "https://registry.npmmirror.com/bessel/-/bessel-1.0.2.tgz#828812291e0b62e94959cdea43fac186e8a7202d" integrity sha512-Al3nHGQGqDYqqinXhQzmwmcRToe/3WyBv4N8aZc5Pef8xw2neZlR9VPi84Sa23JtgWcucu18HxVZrnI0fn2etw== -big-integer@^1.6.44: +big-integer@^1.6.44, big-integer@^1.6.48: version "1.6.52" resolved "https://registry.npmmirror.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== @@ -9284,6 +9402,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +cjs-module-lexer@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.npmmirror.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -14808,6 +14931,16 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-in-the-middle@1.7.1: + version "1.7.1" + resolved "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz#3e111ff79c639d0bde459bd7ba29dd9fdf357364" + integrity sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg== + dependencies: + acorn "^8.8.2" + acorn-import-assertions "^1.9.0" + cjs-module-lexer "^1.2.2" + module-details-from-path "^1.0.3" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.npmmirror.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -15782,6 +15915,11 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" +jmespath@^0.16.0: + version "0.16.0" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" + integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== + jose@^4.15.1: version "4.15.4" resolved "https://registry.npmmirror.com/jose/-/jose-4.15.4.tgz#02a9a763803e3872cf55f29ecef0dfdcc218cc03" @@ -15971,6 +16109,11 @@ json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: resolved "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonata@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/jsonata/-/jsonata-2.0.3.tgz#f8971c2891cb1d6ebfeecbfe657ecc38c1b843a5" + integrity sha512-Up2H81MUtjqI/dWwWX7p4+bUMfMrQJVMN/jW6clFMTiYP528fBOBNtRu944QhKTs3+IsVWbgMeUTny5fw2VMUA== + jsonc-parser@^3.2.0: version "3.2.0" resolved "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -16004,6 +16147,11 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.npmmirror.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +jsonpath-plus@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.2.0.tgz#7ad94e147b3ed42f7939c315d2b9ce490c5a3899" + integrity sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA== + jsonwebtoken@^8.5.1: version "8.5.1" resolved "https://registry.npmmirror.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" @@ -18445,6 +18593,13 @@ node-releases@^2.0.14: resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-sql-parser@^4.11.0: + version "4.17.0" + resolved "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-4.17.0.tgz#00d31b9943edd93f5a33cd2db2691df41a1e2225" + integrity sha512-3IhovpmUBpcETnoKK/KBdkz2mz53kVG5E1dnqz1QuYvtzdxYZW5xaGGEvW9u6Yyy2ivwR3eUZrn9inmEVef02w== + dependencies: + big-integer "^1.6.48" + node-xlsx@^0.16.1: version "0.16.2" resolved "https://registry.npmmirror.com/node-xlsx/-/node-xlsx-0.16.2.tgz#40f580187eae0e032cac96e958e97cb6ceca09f6" @@ -18737,7 +18892,7 @@ number-is-nan@^1.0.0: nwsapi@2.2.7, nwsapi@^2.2.0: version "2.2.7" - resolved "https://registry.npmmirror.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== oauth-sign@~0.9.0: @@ -18913,7 +19068,7 @@ object.values@^1.1.6, object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -obuf@^1.0.0, obuf@^1.1.2: +obuf@^1.0.0, obuf@^1.1.2, obuf@~1.1.2: version "1.1.2" resolved "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== @@ -19742,12 +19897,17 @@ pg-int8@1.0.1: resolved "https://registry.npmmirror.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + pg-pool@^3.6.1: version "3.6.1" resolved "https://registry.npmmirror.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7" integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og== -pg-protocol@^1.6.0: +pg-protocol@*, pg-protocol@^1.6.0: version "1.6.0" resolved "https://registry.npmmirror.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833" integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q== @@ -19763,7 +19923,20 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@^8.7.3: +pg-types@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz#31857e89d00a6c66b06a14e907c3deec03889542" + integrity sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.0.1" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + +pg@^8.11.3, pg@^8.7.3: version "8.11.3" resolved "https://registry.npmmirror.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb" integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g== @@ -20361,16 +20534,33 @@ postgres-array@~2.0.0: resolved "https://registry.npmmirror.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + postgres-bytea@~1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + postgres-date@~1.0.4: version "1.0.7" resolved "https://registry.npmmirror.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== +postgres-date@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz#638b62e5c33764c292d37b08f5257ecb09231457" + integrity sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw== + postgres-interval@^1.1.0: version "1.2.0" resolved "https://registry.npmmirror.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" @@ -20378,6 +20568,16 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.3" + resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz#9ccd7b01ca2789eb3c2e0888b3184225fa859f76" + integrity sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -21494,11 +21694,11 @@ react-router-dom@6.3.0, react-router-dom@6.x, react-router-dom@^6.11.2: react-router "6.21.0" react-router@6.21.0, react-router@6.3.0, react-router@^6.11.2: - version "6.21.0" - resolved "https://registry.npmmirror.com/react-router/-/react-router-6.21.0.tgz#6fe3e59877aca3dccceec1801d26991ddf42d12b" - integrity sha512-hGZ0HXbwz3zw52pLZV3j3+ec+m/PQ9cTpBvqjFQmy2XVUWGn5MD+31oXHb6dVTxYzmAeaiUBYjkoNz66n3RGCg== + version "6.21.1" + resolved "https://registry.npmjs.org/react-router/-/react-router-6.21.1.tgz#8db7ee8d7cfc36513c9a66b44e0897208c33be34" + integrity sha512-W0l13YlMTm1YrpVIOpjCADJqEUpz1vm+CMo47RuFX4Ftegwm6KOYsL5G3eiE52jnJpKvzm6uB/vTKTPKM8dmkA== dependencies: - "@remix-run/router" "1.14.0" + "@remix-run/router" "1.14.1" react-side-effect@^2.1.0: version "2.1.2" @@ -22113,6 +22313,15 @@ require-in-the-middle@^5.0.0: module-details-from-path "^1.0.3" resolve "^1.22.1" +require-in-the-middle@^7.1.1: + version "7.2.0" + resolved "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz#b539de8f00955444dc8aed95e17c69b0a4f10fcf" + integrity sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw== + dependencies: + debug "^4.1.1" + module-details-from-path "^1.0.3" + resolve "^1.22.1" + require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" @@ -22598,7 +22807,7 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.1.1, semver@^7.1.3, semver@^7.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.4, semver@~7.5.0, semver@~7.5.4: +semver@^7.1.1, semver@^7.1.3, semver@^7.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4, semver@~7.5.0, semver@~7.5.4: version "7.5.4" resolved "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -22615,7 +22824,7 @@ sequelize-pool@^7.1.0: resolved "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz#210b391af4002762f823188fd6ecfc7413020768" integrity sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg== -sequelize@^6.26.0: +sequelize@^6.26.0, sequelize@^6.35.0: version "6.35.2" resolved "https://registry.npmmirror.com/sequelize/-/sequelize-6.35.2.tgz#9276d24055a9a07bd6812c89ab402659f5853e70" integrity sha512-EdzLaw2kK4/aOnWQ7ed/qh3B6/g+1DvmeXr66RwbcqSm/+QRS9X0LDI5INBibsy4eNJHWIRPo3+QK0zL+IPBHg== @@ -22778,7 +22987,7 @@ shell-quote@^1.7.3: resolved "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -shimmer@^1.1.0, shimmer@^1.2.0: +shimmer@^1.1.0, shimmer@^1.2.0, shimmer@^1.2.1: version "1.2.1" resolved "https://registry.npmmirror.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==