Skip to content

Commit

Permalink
initialize service instance id after DB is initialized
Browse files Browse the repository at this point in the history
  • Loading branch information
yuki-takei committed Jan 15, 2025
1 parent 8b4cd95 commit 8b0af79
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -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> {
Expand Down
16 changes: 3 additions & 13 deletions apps/app/src/features/opentelemetry/server/node-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};
Expand Down
4 changes: 3 additions & 1 deletion apps/app/src/server/app.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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(() => {
Expand Down
7 changes: 0 additions & 7 deletions apps/app/src/server/crowi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -207,8 +206,6 @@ Crowi.prototype.init = async function() {
// depends on passport service
this.setupExternalAccountService(),
this.setupExternalUserGroupSyncService(),
// depends on aclService
this.setupOpentelemetry2ndPhase(),
]);

await normalizeData();
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 8b0af79

Please sign in to comment.