node-sdk.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { ConfigSource } from '@growi/core/dist/interfaces';
  2. import type { NodeSDK } from '@opentelemetry/sdk-node';
  3. import { configManager } from '~/server/service/config-manager';
  4. import loggerFactory from '~/utils/logger';
  5. const logger = loggerFactory('growi:opentelemetry:server');
  6. let sdkInstance: NodeSDK;
  7. /**
  8. * Overwrite "OTEL_SDK_DISABLED" env var before sdk.start() is invoked if needed.
  9. * Since otel library sees it.
  10. */
  11. function overwriteSdkDisabled(): void {
  12. const instrumentationEnabled = configManager.getConfig('otel:enabled', ConfigSource.env);
  13. if (instrumentationEnabled && (
  14. process.env.OTEL_SDK_DISABLED === 'true'
  15. || process.env.OTEL_SDK_DISABLED === '1'
  16. )) {
  17. logger.warn("OTEL_SDK_DISABLED overwritten with 'false' since GROWI's 'otel:enabled' config is true.");
  18. process.env.OTEL_SDK_DISABLED = 'false';
  19. return;
  20. }
  21. if (!instrumentationEnabled && (
  22. process.env.OTEL_SDK_DISABLED === 'false'
  23. || process.env.OTEL_SDK_DISABLED === '0'
  24. )) {
  25. logger.warn("OTEL_SDK_DISABLED is overwritten with 'true' since GROWI's 'otel:enabled' config is false.");
  26. process.env.OTEL_SDK_DISABLED = 'true';
  27. return;
  28. }
  29. }
  30. export const startInstrumentation = async(): Promise<void> => {
  31. if (sdkInstance != null) {
  32. logger.warn('OpenTelemetry instrumentation already started');
  33. return;
  34. }
  35. // load configs from env
  36. await configManager.loadConfigs({ source: ConfigSource.env });
  37. overwriteSdkDisabled();
  38. const instrumentationEnabled = configManager.getConfig('otel:enabled', ConfigSource.env);
  39. if (instrumentationEnabled) {
  40. logger.info(`GROWI now collects anonymous telemetry.
  41. This data is used to help improve GROWI, but you can opt-out at any time.
  42. For more information, see https://docs.growi.org/en/admin-guide/telemetry.html.
  43. `);
  44. // initialize global logger for development
  45. const isDev = process.env.NODE_ENV === 'development';
  46. if (isDev) {
  47. const { initLogger } = await import('./logger');
  48. initLogger();
  49. }
  50. // instanciate NodeSDK
  51. const { NodeSDK } = await import('@opentelemetry/sdk-node');
  52. const { generateNodeSDKConfiguration } = await import('./node-sdk-configuration');
  53. sdkInstance = new NodeSDK(generateNodeSDKConfiguration());
  54. sdkInstance.start();
  55. }
  56. };
  57. export const initServiceInstanceId = async(): Promise<void> => {
  58. const instrumentationEnabled = configManager.getConfig('otel:enabled', ConfigSource.env);
  59. if (instrumentationEnabled) {
  60. const { generateNodeSDKConfiguration } = await import('./node-sdk-configuration');
  61. const serviceInstanceId = configManager.getConfig('otel:serviceInstanceId')
  62. ?? configManager.getConfig('app:serviceInstanceId');
  63. // overwrite resource
  64. const updatedResource = generateNodeSDKConfiguration(serviceInstanceId).resource;
  65. (sdkInstance as any).resource = updatedResource;
  66. }
  67. };
  68. // public async shutdownInstrumentation(): Promise<void> {
  69. // await this.sdkInstance.shutdown();
  70. // // メモ: 以下の restart コードは動かない
  71. // // span/metrics ともに何も出なくなる
  72. // // そもそも、restart するような使い方が出来なさそう?
  73. // // see: https://github.com/open-telemetry/opentelemetry-specification/issues/27/
  74. // // const sdk = new NodeSDK({...});
  75. // // sdk.start();
  76. // // await sdk.shutdown().catch(console.error);
  77. // // const newSdk = new NodeSDK({...});
  78. // // newSdk.start();
  79. // }