node-sdk-configuration.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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 type { Resource } from '@opentelemetry/resources';
  5. import { resourceFromAttributes } from '@opentelemetry/resources';
  6. import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
  7. import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
  8. import {
  9. ATTR_SERVICE_NAME,
  10. ATTR_SERVICE_VERSION,
  11. } from '@opentelemetry/semantic-conventions';
  12. import { configManager } from '~/server/service/config-manager';
  13. import { getGrowiVersion } from '~/utils/growi-version';
  14. import { httpInstrumentationConfig as httpInstrumentationConfigForAnonymize } from './anonymization';
  15. import { ATTR_SERVICE_INSTANCE_ID } from './semconv';
  16. type Option = {
  17. enableAnonymization?: boolean;
  18. };
  19. type Configuration = Partial<NodeSDKConfiguration> & {
  20. resource: Resource;
  21. };
  22. let resource: Resource;
  23. let configuration: Configuration;
  24. export const generateNodeSDKConfiguration = (opts?: Option): Configuration => {
  25. if (configuration == null) {
  26. const version = getGrowiVersion();
  27. resource = resourceFromAttributes({
  28. [ATTR_SERVICE_NAME]: 'growi',
  29. [ATTR_SERVICE_VERSION]: version,
  30. });
  31. // Data anonymization configuration
  32. const httpInstrumentationConfig = opts?.enableAnonymization
  33. ? httpInstrumentationConfigForAnonymize
  34. : {};
  35. configuration = {
  36. resource,
  37. traceExporter: new OTLPTraceExporter(),
  38. metricReader: new PeriodicExportingMetricReader({
  39. exporter: new OTLPMetricExporter(),
  40. exportIntervalMillis: 300000, // 5 minute
  41. }),
  42. instrumentations: [
  43. getNodeAutoInstrumentations({
  44. '@opentelemetry/instrumentation-bunyan': {
  45. enabled: false,
  46. },
  47. // disable fs instrumentation since this generates very large amount of traces
  48. // see: https://opentelemetry.io/docs/languages/js/libraries/#registration
  49. '@opentelemetry/instrumentation-fs': {
  50. enabled: false,
  51. },
  52. // HTTP instrumentation with anonymization
  53. '@opentelemetry/instrumentation-http': {
  54. enabled: true,
  55. ...httpInstrumentationConfig,
  56. },
  57. }),
  58. ],
  59. };
  60. }
  61. return configuration;
  62. };
  63. /**
  64. * Generate additional attributes after database initialization
  65. * This function should be called after database is available
  66. */
  67. export const generateAdditionalResourceAttributes = async (
  68. _opts?: Option,
  69. ): Promise<Resource> => {
  70. if (resource == null) {
  71. throw new Error(
  72. 'Resource is not initialized. Call generateNodeSDKConfiguration first.',
  73. );
  74. }
  75. const serviceInstanceId =
  76. configManager.getConfig('otel:serviceInstanceId') ??
  77. configManager.getConfig('app:serviceInstanceId');
  78. const { getApplicationResourceAttributes, getOsResourceAttributes } =
  79. await import('./custom-resource-attributes');
  80. return resource.merge(
  81. resourceFromAttributes({
  82. [ATTR_SERVICE_INSTANCE_ID]: serviceInstanceId,
  83. ...(await getApplicationResourceAttributes()),
  84. ...(await getOsResourceAttributes()),
  85. }),
  86. );
  87. };