node-sdk-configuration.ts 3.1 KB

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