From 8b0af798b06a22ca16c6f7b4f0e81f8c8aabe171 Mon Sep 17 00:00:00 2001 From: Yuki Takei Date: Wed, 15 Jan 2025 13:31:58 +0000 Subject: [PATCH] initialize service instance id after DB is initialized --- .../server/node-sdk-configuration.ts | 61 ++++++++++++------- .../features/opentelemetry/server/node-sdk.ts | 16 +---- apps/app/src/server/app.ts | 4 +- apps/app/src/server/crowi/index.js | 7 --- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/apps/app/src/features/opentelemetry/server/node-sdk-configuration.ts b/apps/app/src/features/opentelemetry/server/node-sdk-configuration.ts index 53065567ba3..a2fea14ce97 100644 --- a/apps/app/src/features/opentelemetry/server/node-sdk-configuration.ts +++ b/apps/app/src/features/opentelemetry/server/node-sdk-configuration.ts @@ -1,39 +1,56 @@ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; -import { Resource } from '@opentelemetry/resources'; +import { Resource, type IResource } from '@opentelemetry/resources'; import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node'; import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, SEMRESATTRS_SERVICE_INSTANCE_ID } from '@opentelemetry/semantic-conventions'; import { getGrowiVersion } from '~/utils/growi-version'; +type Configuration = Partial & { + resource: IResource; +}; + +let resource: Resource; +let configuration: Configuration; -export const generateNodeSDKConfiguration = (serviceInstanceId?: string): Partial => { - const version = getGrowiVersion(); +export const generateNodeSDKConfiguration = (serviceInstanceId?: string): Configuration => { + if (configuration == null) { + const version = getGrowiVersion(); - return { - resource: new Resource({ + resource = new Resource({ [ATTR_SERVICE_NAME]: 'growi', [ATTR_SERVICE_VERSION]: version, + }); + + configuration = { + resource, + traceExporter: new OTLPTraceExporter(), + metricReader: new PeriodicExportingMetricReader({ + exporter: new OTLPMetricExporter(), + exportIntervalMillis: 10000, + }), + instrumentations: [getNodeAutoInstrumentations({ + '@opentelemetry/instrumentation-bunyan': { + enabled: false, + }, + // disable fs instrumentation since this generates very large amount of traces + // see: https://opentelemetry.io/docs/languages/js/libraries/#registration + '@opentelemetry/instrumentation-fs': { + enabled: false, + }, + })], + }; + } + + if (serviceInstanceId != null) { + configuration.resource = resource.merge(new Resource({ [SEMRESATTRS_SERVICE_INSTANCE_ID]: serviceInstanceId, - }), - traceExporter: new OTLPTraceExporter(), - metricReader: new PeriodicExportingMetricReader({ - exporter: new OTLPMetricExporter(), - exportIntervalMillis: 10000, - }), - instrumentations: [getNodeAutoInstrumentations({ - '@opentelemetry/instrumentation-bunyan': { - enabled: false, - }, - // disable fs instrumentation since this generates very large amount of traces - // see: https://opentelemetry.io/docs/languages/js/libraries/#registration - '@opentelemetry/instrumentation-fs': { - enabled: false, - }, - })], - }; + })); + } + + return configuration; }; // public async shutdownInstrumentation(): Promise { diff --git a/apps/app/src/features/opentelemetry/server/node-sdk.ts b/apps/app/src/features/opentelemetry/server/node-sdk.ts index 317bb152792..9121de2e34c 100644 --- a/apps/app/src/features/opentelemetry/server/node-sdk.ts +++ b/apps/app/src/features/opentelemetry/server/node-sdk.ts @@ -74,26 +74,16 @@ For more information, see https://docs.growi.org/en/admin-guide/telemetry.html. }; export const initServiceInstanceId = async(): Promise => { - if (sdkInstance != null) { - logger.warn('OpenTelemetry instrumentation already started'); - return; - } - const instrumentationEnabled = configManager.getConfig('otel:enabled', ConfigSource.env); + if (instrumentationEnabled) { const { generateNodeSDKConfiguration } = await import('./node-sdk-configuration'); - const { growiInfoService } = await import('~/server/service/growi-info'); - - // get GrowiInfo with additional info - const growiInfo = await growiInfoService.getGrowiInfo(); const serviceInstanceId = configManager.getConfig('otel:serviceInstanceId') - ?? growiInfo.serviceInstanceId; - - const updatedResource = generateNodeSDKConfiguration(serviceInstanceId); + ?? configManager.getConfig('app:serviceInstanceId'); // overwrite resource - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const updatedResource = generateNodeSDKConfiguration(serviceInstanceId).resource; (sdkInstance as any).resource = updatedResource; } }; diff --git a/apps/app/src/server/app.ts b/apps/app/src/server/app.ts index ce52367767e..a43640cb445 100644 --- a/apps/app/src/server/app.ts +++ b/apps/app/src/server/app.ts @@ -1,6 +1,6 @@ import type Logger from 'bunyan'; -import { startInstrumentation } from '~/features/opentelemetry/server'; +import { initServiceInstanceId, startInstrumentation } from '~/features/opentelemetry/server'; import loggerFactory from '~/utils/logger'; import { hasProcessFlag } from '~/utils/process-utils'; @@ -27,6 +27,8 @@ async function main() { const growi = new Crowi(); const server = await growi.start(); + await initServiceInstanceId(); + if (hasProcessFlag('ci')) { logger.info('"--ci" flag is detected. Exit process.'); server.close(() => { diff --git a/apps/app/src/server/crowi/index.js b/apps/app/src/server/crowi/index.js index a867ca17b6b..4a519349d49 100644 --- a/apps/app/src/server/crowi/index.js +++ b/apps/app/src/server/crowi/index.js @@ -11,7 +11,6 @@ import next from 'next'; import { KeycloakUserGroupSyncService } from '~/features/external-user-group/server/service/keycloak-user-group-sync'; import { LdapUserGroupSyncService } from '~/features/external-user-group/server/service/ldap-user-group-sync'; import { startCronIfEnabled as startOpenaiCronIfEnabled } from '~/features/openai/server/services/cron'; -import { initServiceInstanceId } from '~/features/opentelemetry/server'; import QuestionnaireService from '~/features/questionnaire/server/service/questionnaire'; import QuestionnaireCronService from '~/features/questionnaire/server/service/questionnaire-cron'; import { getGrowiVersion } from '~/utils/growi-version'; @@ -207,8 +206,6 @@ Crowi.prototype.init = async function() { // depends on passport service this.setupExternalAccountService(), this.setupExternalUserGroupSyncService(), - // depends on aclService - this.setupOpentelemetry2ndPhase(), ]); await normalizeData(); @@ -342,10 +339,6 @@ Crowi.prototype.setupSocketIoService = async function() { this.socketIoService = new SocketIoService(this); }; -Crowi.prototype.setupOpentelemetry2ndPhase = async function() { - initServiceInstanceId(); -}; - Crowi.prototype.setupCron = function() { this.questionnaireCronService = new QuestionnaireCronService(this); this.questionnaireCronService.startCron();