spotlight.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import * as http from 'http';
  2. import { URL } from 'url';
  3. import { defineIntegration, convertIntegrationFnToClass } from '@sentry/core';
  4. import { logger, serializeEnvelope } from '@sentry/utils';
  5. const INTEGRATION_NAME = 'Spotlight';
  6. const _spotlightIntegration = ((options = {}) => {
  7. const _options = {
  8. sidecarUrl: options.sidecarUrl || 'http://localhost:8969/stream',
  9. };
  10. return {
  11. name: INTEGRATION_NAME,
  12. // TODO v8: Remove this
  13. setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function
  14. setup(client) {
  15. if (typeof process === 'object' && process.env && process.env.NODE_ENV !== 'development') {
  16. logger.warn("[Spotlight] It seems you're not in dev mode. Do you really want to have Spotlight enabled?");
  17. }
  18. connectToSpotlight(client, _options);
  19. },
  20. };
  21. }) ;
  22. const spotlightIntegration = defineIntegration(_spotlightIntegration);
  23. /**
  24. * Use this integration to send errors and transactions to Spotlight.
  25. *
  26. * Learn more about spotlight at https://spotlightjs.com
  27. *
  28. * Important: This integration only works with Node 18 or newer.
  29. *
  30. * @deprecated Use `spotlightIntegration()` instead.
  31. */
  32. // eslint-disable-next-line deprecation/deprecation
  33. const Spotlight = convertIntegrationFnToClass(INTEGRATION_NAME, spotlightIntegration)
  34. ;
  35. // eslint-disable-next-line deprecation/deprecation
  36. function connectToSpotlight(client, options) {
  37. const spotlightUrl = parseSidecarUrl(options.sidecarUrl);
  38. if (!spotlightUrl) {
  39. return;
  40. }
  41. let failedRequests = 0;
  42. if (typeof client.on !== 'function') {
  43. logger.warn('[Spotlight] Cannot connect to spotlight due to missing method on SDK client (`client.on`)');
  44. return;
  45. }
  46. client.on('beforeEnvelope', (envelope) => {
  47. if (failedRequests > 3) {
  48. logger.warn('[Spotlight] Disabled Sentry -> Spotlight integration due to too many failed requests');
  49. return;
  50. }
  51. const serializedEnvelope = serializeEnvelope(envelope);
  52. const request = getNativeHttpRequest();
  53. const req = request(
  54. {
  55. method: 'POST',
  56. path: spotlightUrl.pathname,
  57. hostname: spotlightUrl.hostname,
  58. port: spotlightUrl.port,
  59. headers: {
  60. 'Content-Type': 'application/x-sentry-envelope',
  61. },
  62. },
  63. res => {
  64. res.on('data', () => {
  65. // Drain socket
  66. });
  67. res.on('end', () => {
  68. // Drain socket
  69. });
  70. res.setEncoding('utf8');
  71. },
  72. );
  73. req.on('error', () => {
  74. failedRequests++;
  75. logger.warn('[Spotlight] Failed to send envelope to Spotlight Sidecar');
  76. });
  77. req.write(serializedEnvelope);
  78. req.end();
  79. });
  80. }
  81. function parseSidecarUrl(url) {
  82. try {
  83. return new URL(`${url}`);
  84. } catch (e) {
  85. logger.warn(`[Spotlight] Invalid sidecar URL: ${url}`);
  86. return undefined;
  87. }
  88. }
  89. /**
  90. * We want to get an unpatched http request implementation to avoid capturing our own calls.
  91. */
  92. function getNativeHttpRequest() {
  93. const { request } = http;
  94. if (isWrapped(request)) {
  95. return request.__sentry_original__;
  96. }
  97. return request;
  98. }
  99. function isWrapped(impl) {
  100. return '__sentry_original__' in impl;
  101. }
  102. export { Spotlight, getNativeHttpRequest, spotlightIntegration };
  103. //# sourceMappingURL=spotlight.js.map