Просмотр исходного кода

initialize service instance id after DB is initialized

Yuki Takei 1 год назад
Родитель
Сommit
8b0af798b0

+ 39 - 22
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<NodeSDKConfiguration> & {
+  resource: IResource;
+};
+
+let resource: Resource;
+let configuration: Configuration;
 
-export const generateNodeSDKConfiguration = (serviceInstanceId?: string): Partial<NodeSDKConfiguration> => {
-  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<void> {

+ 3 - 13
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<void> => {
-  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;
   }
 };

+ 3 - 1
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(() => {

+ 0 - 7
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();