start.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
  2. import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
  3. import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
  4. import { Resource } from '@opentelemetry/resources';
  5. import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
  6. import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
  7. import { NodeSDK } from '@opentelemetry/sdk-node';
  8. import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, SEMRESATTRS_SERVICE_INSTANCE_ID } from '@opentelemetry/semantic-conventions';
  9. import { configManager } from '~/server/service/config-manager';
  10. import loggerFactory from '~/utils/logger';
  11. import { initLogger } from './logger';
  12. const logger = loggerFactory('growi:opentelemetry');
  13. let sdkInstance: NodeSDK;
  14. function generateNodeSDKConfiguration(instanceId: string, version: string): Partial<NodeSDKConfiguration> {
  15. return {
  16. resource: new Resource({
  17. [ATTR_SERVICE_NAME]: 'growi',
  18. [ATTR_SERVICE_VERSION]: version,
  19. [SEMRESATTRS_SERVICE_INSTANCE_ID]: instanceId,
  20. }),
  21. traceExporter: new OTLPTraceExporter(),
  22. metricReader: new PeriodicExportingMetricReader({
  23. exporter: new OTLPMetricExporter(),
  24. exportIntervalMillis: 10000,
  25. }),
  26. instrumentations: [getNodeAutoInstrumentations({
  27. '@opentelemetry/instrumentation-bunyan': {
  28. enabled: false,
  29. },
  30. // disable fs instrumentation since this generates very large amount of traces
  31. // see: https://opentelemetry.io/docs/languages/js/libraries/#registration
  32. '@opentelemetry/instrumentation-fs': {
  33. enabled: false,
  34. },
  35. })],
  36. };
  37. }
  38. /**
  39. * Overwrite "OTEL_SDK_DISABLED" env var before sdk.start() is invoked if needed.
  40. * Since otel library sees it.
  41. */
  42. function overwriteSdkDisabled(): void {
  43. const instrumentationEnabled = configManager.getConfig('crowi', 'otel:enabled');
  44. if (instrumentationEnabled && (
  45. process.env.OTEL_SDK_DISABLED === 'true'
  46. || process.env.OTEL_SDK_DISABLED === '1'
  47. )) {
  48. logger.warn("OTEL_SDK_DISABLED will be set 'false' since GROWI's 'otel:enabled' config is true.");
  49. process.env.OTEL_SDK_DISABLED = 'false';
  50. return;
  51. }
  52. if (!instrumentationEnabled && (
  53. process.env.OTEL_SDK_DISABLED == null
  54. || process.env.OTEL_SDK_DISABLED === 'false'
  55. || process.env.OTEL_SDK_DISABLED === '0'
  56. )) {
  57. logger.warn("OTEL_SDK_DISABLED will be set 'true' since GROWI's 'otel:enabled' config is false.");
  58. process.env.OTEL_SDK_DISABLED = 'true';
  59. return;
  60. }
  61. }
  62. export const startInstrumentation = (version: string): void => {
  63. if (sdkInstance != null) {
  64. logger.warn('OpenTelemetry instrumentation already started');
  65. return;
  66. }
  67. overwriteSdkDisabled();
  68. const instrumentationEnabled = configManager.getConfig('crowi', 'otel:enabled');
  69. if (instrumentationEnabled) {
  70. initLogger();
  71. logger.info(`GROWI now collects anonymous telemetry.
  72. This data is used to help improve GROWI, but you can opt-out at any time.
  73. For more information, see https://docs.growi.org/en/admin-guide/telemetry.html.
  74. `);
  75. const serviceInstanceId = configManager.getConfig('crowi', 'otel:serviceInstanceId');
  76. sdkInstance = new NodeSDK(generateNodeSDKConfiguration(serviceInstanceId, version));
  77. sdkInstance.start();
  78. }
  79. };
  80. // public async shutdownInstrumentation(): Promise<void> {
  81. // await this.sdkInstance.shutdown();
  82. // // メモ: 以下の restart コードは動かない
  83. // // span/metrics ともに何も出なくなる
  84. // // そもそも、restart するような使い方が出来なさそう?
  85. // // see: https://github.com/open-telemetry/opentelemetry-specification/issues/27/
  86. // // const sdk = new NodeSDK({...});
  87. // // sdk.start();
  88. // // await sdk.shutdown().catch(console.error);
  89. // // const newSdk = new NodeSDK({...});
  90. // // newSdk.start();
  91. // }