apitally 0.25.1 → 0.25.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +131 -88
  2. package/dist/adonisjs/index.cjs +0 -3
  3. package/dist/adonisjs/index.cjs.map +1 -1
  4. package/dist/adonisjs/index.d.cts +2 -2
  5. package/dist/adonisjs/index.d.ts +2 -2
  6. package/dist/adonisjs/index.js +0 -2
  7. package/dist/adonisjs/index.js.map +1 -1
  8. package/dist/common/client.cjs +1 -1
  9. package/dist/common/client.cjs.map +1 -1
  10. package/dist/common/client.js +1 -1
  11. package/dist/common/client.js.map +1 -1
  12. package/dist/common/requestLogger.d.cts +0 -2
  13. package/dist/common/requestLogger.d.ts +0 -2
  14. package/dist/common/spanCollector.cjs +20 -38
  15. package/dist/common/spanCollector.cjs.map +1 -1
  16. package/dist/common/spanCollector.d.cts +1 -6
  17. package/dist/common/spanCollector.d.ts +1 -6
  18. package/dist/common/spanCollector.js +20 -38
  19. package/dist/common/spanCollector.js.map +1 -1
  20. package/dist/elysia/index.cjs +0 -3
  21. package/dist/elysia/index.cjs.map +1 -1
  22. package/dist/elysia/index.d.cts +2 -2
  23. package/dist/elysia/index.d.ts +2 -2
  24. package/dist/elysia/index.js +0 -2
  25. package/dist/elysia/index.js.map +1 -1
  26. package/dist/elysia/plugin.d.cts +2 -2
  27. package/dist/elysia/plugin.d.ts +2 -2
  28. package/dist/express/index.cjs +0 -3
  29. package/dist/express/index.cjs.map +1 -1
  30. package/dist/express/index.d.cts +2 -2
  31. package/dist/express/index.d.ts +2 -2
  32. package/dist/express/index.js +0 -2
  33. package/dist/express/index.js.map +1 -1
  34. package/dist/express/middleware.d.cts +2 -2
  35. package/dist/express/middleware.d.ts +2 -2
  36. package/dist/fastify/index.cjs +0 -3
  37. package/dist/fastify/index.cjs.map +1 -1
  38. package/dist/fastify/index.d.cts +2 -2
  39. package/dist/fastify/index.d.ts +2 -2
  40. package/dist/fastify/index.js +0 -2
  41. package/dist/fastify/index.js.map +1 -1
  42. package/dist/fastify/plugin.d.cts +2 -2
  43. package/dist/fastify/plugin.d.ts +2 -2
  44. package/dist/h3/index.cjs +0 -3
  45. package/dist/h3/index.cjs.map +1 -1
  46. package/dist/h3/index.d.cts +2 -2
  47. package/dist/h3/index.d.ts +2 -2
  48. package/dist/h3/index.js +0 -2
  49. package/dist/h3/index.js.map +1 -1
  50. package/dist/h3/plugin.d.cts +2 -2
  51. package/dist/h3/plugin.d.ts +2 -2
  52. package/dist/hapi/index.cjs +0 -3
  53. package/dist/hapi/index.cjs.map +1 -1
  54. package/dist/hapi/index.d.cts +2 -2
  55. package/dist/hapi/index.d.ts +2 -2
  56. package/dist/hapi/index.js +0 -2
  57. package/dist/hapi/index.js.map +1 -1
  58. package/dist/hapi/plugin.d.cts +2 -2
  59. package/dist/hapi/plugin.d.ts +2 -2
  60. package/dist/hono/index.cjs +0 -3
  61. package/dist/hono/index.cjs.map +1 -1
  62. package/dist/hono/index.d.cts +2 -2
  63. package/dist/hono/index.d.ts +2 -2
  64. package/dist/hono/index.js +0 -2
  65. package/dist/hono/index.js.map +1 -1
  66. package/dist/hono/middleware.d.cts +2 -2
  67. package/dist/hono/middleware.d.ts +2 -2
  68. package/dist/hono/utils.d.cts +1 -1
  69. package/dist/hono/utils.d.ts +1 -1
  70. package/dist/koa/index.cjs +0 -3
  71. package/dist/koa/index.cjs.map +1 -1
  72. package/dist/koa/index.d.cts +2 -2
  73. package/dist/koa/index.d.ts +2 -2
  74. package/dist/koa/index.js +0 -2
  75. package/dist/koa/index.js.map +1 -1
  76. package/dist/koa/middleware.d.cts +2 -2
  77. package/dist/koa/middleware.d.ts +2 -2
  78. package/dist/loggers/console.d.cts +0 -2
  79. package/dist/loggers/console.d.ts +0 -2
  80. package/dist/loggers/hapi.d.cts +0 -2
  81. package/dist/loggers/hapi.d.ts +0 -2
  82. package/dist/loggers/index.d.cts +0 -2
  83. package/dist/loggers/index.d.ts +0 -2
  84. package/dist/loggers/nestjs.d.cts +0 -2
  85. package/dist/loggers/nestjs.d.ts +0 -2
  86. package/dist/loggers/pino.d.cts +0 -2
  87. package/dist/loggers/pino.d.ts +0 -2
  88. package/dist/loggers/winston.d.cts +0 -2
  89. package/dist/loggers/winston.d.ts +0 -2
  90. package/dist/nestjs/index.cjs +0 -3
  91. package/dist/nestjs/index.cjs.map +1 -1
  92. package/dist/nestjs/index.d.cts +3 -3
  93. package/dist/nestjs/index.d.ts +3 -3
  94. package/dist/nestjs/index.js +0 -2
  95. package/dist/nestjs/index.js.map +1 -1
  96. package/dist/otel/index.cjs +29 -0
  97. package/dist/otel/index.cjs.map +1 -0
  98. package/dist/otel/index.d.cts +2 -0
  99. package/dist/otel/index.d.ts +2 -0
  100. package/dist/otel/index.js +5 -0
  101. package/dist/otel/index.js.map +1 -0
  102. package/package.json +15 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/client.ts"],"sourcesContent":["import fetchRetry from \"fetch-retry\";\nimport { randomUUID } from \"node:crypto\";\n\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { getOrCreateInstanceUuid } from \"./instance.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport RequestLogger from \"./requestLogger.js\";\nimport { getCpuMemoryUsage } from \"./resources.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport SpanCollector from \"./spanCollector.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: SyncPayload[];\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n private enabled: boolean = true;\n\n public requestCounter: RequestCounter;\n public requestLogger: RequestLogger;\n public spanCollector: SpanCollector;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({\n clientId,\n env = \"dev\",\n requestLogging,\n requestLoggingConfig,\n logger,\n }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n\n this.logger = logger ?? getLogger();\n\n if (!isValidClientId(clientId)) {\n this.logger.error(\n `Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`,\n );\n this.enabled = false;\n }\n if (!isValidEnv(env)) {\n this.logger.error(\n `Invalid Apitally env '${env}' (expecting 1-32 alphanumeric characters and hyphens only)`,\n );\n this.enabled = false;\n }\n if (requestLoggingConfig && !requestLogging) {\n console.warn(\n \"requestLoggingConfig is deprecated, use requestLogging instead.\",\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = getOrCreateInstanceUuid(clientId, env);\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.requestLogger = new RequestLogger(\n requestLogging ?? requestLoggingConfig,\n );\n this.spanCollector = new SpanCollector(\n this.enabled &&\n this.requestLogger.enabled &&\n this.requestLogger.config.captureTraces,\n this.logger,\n );\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public isEnabled() {\n return this.enabled;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.enabled = false;\n this.stopSync();\n await this.sendSyncData();\n await this.sendLogData();\n await this.spanCollector.shutdown();\n await this.requestLogger.close();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n public startSync() {\n if (!this.enabled) {\n return;\n }\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData(), this.sendLogData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n timestamp: Date.now() / 1000,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n resources: getCpuMemoryUsage(),\n };\n this.syncDataQueue.push(newPayload);\n\n let i = 0;\n while (this.syncDataQueue.length > 0) {\n const payload = this.syncDataQueue.shift();\n if (payload) {\n try {\n if (Date.now() - payload.timestamp * 1000 <= MAX_QUEUE_TIME) {\n if (i > 0) {\n await this.randomDelay();\n }\n await this.sendData(\"sync\", payload);\n i += 1;\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n this.syncDataQueue.push(payload);\n break;\n }\n }\n }\n }\n }\n\n private async sendLogData() {\n this.logger.debug(\"Sending request log data to Apitally Hub\");\n await this.requestLogger.rotateFile();\n\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n\n let i = 0;\n let logFile;\n while ((logFile = this.requestLogger.getFile())) {\n if (i > 0) {\n await this.randomDelay();\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`,\n {\n method: \"POST\",\n body: (await logFile.getContent()) as any,\n },\n );\n\n if (response.status === 402 && response.headers.has(\"Retry-After\")) {\n const retryAfter = parseInt(\n response.headers.get(\"Retry-After\") ?? \"0\",\n );\n if (retryAfter > 0) {\n this.requestLogger.suspendUntil = Date.now() + retryAfter * 1000;\n this.requestLogger.clear();\n return;\n }\n }\n\n if (!response.ok) {\n throw new HTTPError(response);\n }\n\n logFile.delete();\n } catch (error) {\n this.requestLogger.retryFileLater(logFile);\n break;\n }\n\n i++;\n if (i >= 10) break;\n }\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.enabled = false;\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n\n private async randomDelay() {\n const delay = 100 + Math.random() * 400;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n"],"mappings":"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","names":["fetchRetry","randomUUID","ConsumerRegistry","getOrCreateInstanceUuid","getLogger","isValidClientId","isValidEnv","RequestCounter","RequestLogger","getCpuMemoryUsage","ServerErrorCounter","SpanCollector","ValidationErrorCounter","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","enabled","requestCounter","requestLogger","spanCollector","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","requestLogging","requestLoggingConfig","instance","error","console","warn","config","captureTraces","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","startSync","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","resources","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve"]}
1
+ {"version":3,"sources":["../../src/common/client.ts"],"sourcesContent":["import fetchRetry from \"fetch-retry\";\nimport { randomUUID } from \"node:crypto\";\n\nimport ConsumerRegistry from \"./consumerRegistry.js\";\nimport { getOrCreateInstanceUuid } from \"./instance.js\";\nimport { Logger, getLogger } from \"./logging.js\";\nimport { isValidClientId, isValidEnv } from \"./paramValidation.js\";\nimport RequestCounter from \"./requestCounter.js\";\nimport RequestLogger from \"./requestLogger.js\";\nimport { getCpuMemoryUsage } from \"./resources.js\";\nimport ServerErrorCounter from \"./serverErrorCounter.js\";\nimport SpanCollector from \"./spanCollector.js\";\nimport {\n ApitallyConfig,\n StartupData,\n StartupPayload,\n SyncPayload,\n} from \"./types.js\";\nimport ValidationErrorCounter from \"./validationErrorCounter.js\";\n\nconst SYNC_INTERVAL = 60000; // 60 seconds\nconst INITIAL_SYNC_INTERVAL = 10000; // 10 seconds\nconst INITIAL_SYNC_INTERVAL_DURATION = 3600000; // 1 hour\nconst MAX_QUEUE_TIME = 3.6e6; // 1 hour\n\nclass HTTPError extends Error {\n public response: Response;\n\n constructor(response: Response) {\n const reason = response.status\n ? `status code ${response.status}`\n : \"an unknown error\";\n super(`Request failed with ${reason}`);\n this.response = response;\n }\n}\n\nexport class ApitallyClient {\n private clientId: string;\n private env: string;\n\n private static instance?: ApitallyClient;\n private instanceUuid: string;\n private syncDataQueue: SyncPayload[];\n private syncIntervalId?: NodeJS.Timeout;\n public startupData?: StartupData;\n private startupDataSent: boolean = false;\n private enabled: boolean = true;\n\n public requestCounter: RequestCounter;\n public requestLogger: RequestLogger;\n public spanCollector: SpanCollector;\n public validationErrorCounter: ValidationErrorCounter;\n public serverErrorCounter: ServerErrorCounter;\n public consumerRegistry: ConsumerRegistry;\n public logger: Logger;\n\n constructor({\n clientId,\n env = \"dev\",\n requestLogging,\n requestLoggingConfig,\n logger,\n }: ApitallyConfig) {\n if (ApitallyClient.instance) {\n throw new Error(\"Apitally client is already initialized\");\n }\n\n this.logger = logger ?? getLogger();\n\n if (!isValidClientId(clientId)) {\n this.logger.error(\n `Invalid Apitally client ID '${clientId}' (expecting hexadecimal UUID format)`,\n );\n this.enabled = false;\n }\n if (!isValidEnv(env)) {\n this.logger.error(\n `Invalid Apitally env '${env}' (expecting 1-32 alphanumeric characters and hyphens only)`,\n );\n this.enabled = false;\n }\n if (requestLoggingConfig && !requestLogging) {\n console.warn(\n \"requestLoggingConfig is deprecated, use requestLogging instead.\",\n );\n }\n\n ApitallyClient.instance = this;\n this.clientId = clientId;\n this.env = env;\n this.instanceUuid = getOrCreateInstanceUuid(clientId, env);\n this.syncDataQueue = [];\n this.requestCounter = new RequestCounter();\n this.requestLogger = new RequestLogger(\n requestLogging ?? requestLoggingConfig,\n );\n this.spanCollector = new SpanCollector(\n this.enabled &&\n this.requestLogger.enabled &&\n this.requestLogger.config.captureTraces,\n );\n this.validationErrorCounter = new ValidationErrorCounter();\n this.serverErrorCounter = new ServerErrorCounter();\n this.consumerRegistry = new ConsumerRegistry();\n this.handleShutdown = this.handleShutdown.bind(this);\n }\n\n public static getInstance() {\n if (!ApitallyClient.instance) {\n throw new Error(\"Apitally client is not initialized\");\n }\n return ApitallyClient.instance;\n }\n\n public isEnabled() {\n return this.enabled;\n }\n\n public static async shutdown() {\n if (ApitallyClient.instance) {\n await ApitallyClient.instance.handleShutdown();\n }\n }\n\n public async handleShutdown() {\n this.enabled = false;\n this.stopSync();\n await this.sendSyncData();\n await this.sendLogData();\n await this.spanCollector.shutdown();\n await this.requestLogger.close();\n ApitallyClient.instance = undefined;\n }\n\n private getHubUrlPrefix() {\n const baseURL =\n process.env.APITALLY_HUB_BASE_URL || \"https://hub.apitally.io\";\n const version = \"v2\";\n return `${baseURL}/${version}/${this.clientId}/${this.env}/`;\n }\n\n private async sendData(url: string, payload: any) {\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {\n method: \"POST\",\n body: JSON.stringify(payload),\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!response.ok) {\n throw new HTTPError(response);\n }\n }\n\n public startSync() {\n if (!this.enabled) {\n return;\n }\n this.sync();\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, INITIAL_SYNC_INTERVAL);\n setTimeout(() => {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = setInterval(() => {\n this.sync();\n }, SYNC_INTERVAL);\n }\n }, INITIAL_SYNC_INTERVAL_DURATION);\n }\n\n private async sync() {\n try {\n const promises = [this.sendSyncData(), this.sendLogData()];\n if (!this.startupDataSent) {\n promises.push(this.sendStartupData());\n }\n await Promise.all(promises);\n } catch (error) {\n this.logger.error(\"Error while syncing with Apitally Hub\", {\n error,\n });\n }\n }\n\n private stopSync() {\n if (this.syncIntervalId) {\n clearInterval(this.syncIntervalId);\n this.syncIntervalId = undefined;\n }\n }\n\n public setStartupData(data: StartupData) {\n this.startupData = data;\n this.startupDataSent = false;\n }\n\n private async sendStartupData() {\n if (this.startupData) {\n this.logger.debug(\"Sending startup data to Apitally Hub\");\n const payload: StartupPayload = {\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n ...this.startupData,\n };\n try {\n await this.sendData(\"startup\", payload);\n this.startupDataSent = true;\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.error((error as Error).message);\n this.logger.debug(\n \"Error while sending startup data to Apitally Hub (will retry)\",\n { error },\n );\n }\n }\n }\n }\n\n private async sendSyncData() {\n this.logger.debug(\"Synchronizing data with Apitally Hub\");\n const newPayload: SyncPayload = {\n timestamp: Date.now() / 1000,\n instance_uuid: this.instanceUuid,\n message_uuid: randomUUID(),\n requests: this.requestCounter.getAndResetRequests(),\n validation_errors:\n this.validationErrorCounter.getAndResetValidationErrors(),\n server_errors: this.serverErrorCounter.getAndResetServerErrors(),\n consumers: this.consumerRegistry.getAndResetUpdatedConsumers(),\n resources: getCpuMemoryUsage(),\n };\n this.syncDataQueue.push(newPayload);\n\n let i = 0;\n while (this.syncDataQueue.length > 0) {\n const payload = this.syncDataQueue.shift();\n if (payload) {\n try {\n if (Date.now() - payload.timestamp * 1000 <= MAX_QUEUE_TIME) {\n if (i > 0) {\n await this.randomDelay();\n }\n await this.sendData(\"sync\", payload);\n i += 1;\n }\n } catch (error) {\n const handled = this.handleHubError(error);\n if (!handled) {\n this.logger.debug(\n \"Error while synchronizing data with Apitally Hub (will retry)\",\n { error },\n );\n this.syncDataQueue.push(payload);\n break;\n }\n }\n }\n }\n }\n\n private async sendLogData() {\n this.logger.debug(\"Sending request log data to Apitally Hub\");\n await this.requestLogger.rotateFile();\n\n const fetchWithRetry = fetchRetry(fetch, {\n retries: 3,\n retryDelay: 1000,\n retryOn: [408, 429, 500, 502, 503, 504],\n });\n\n let i = 0;\n let logFile;\n while ((logFile = this.requestLogger.getFile())) {\n if (i > 0) {\n await this.randomDelay();\n }\n\n try {\n const response = await fetchWithRetry(\n `${this.getHubUrlPrefix()}log?uuid=${logFile.uuid}`,\n {\n method: \"POST\",\n body: (await logFile.getContent()) as any,\n },\n );\n\n if (response.status === 402 && response.headers.has(\"Retry-After\")) {\n const retryAfter = parseInt(\n response.headers.get(\"Retry-After\") ?? \"0\",\n );\n if (retryAfter > 0) {\n this.requestLogger.suspendUntil = Date.now() + retryAfter * 1000;\n this.requestLogger.clear();\n return;\n }\n }\n\n if (!response.ok) {\n throw new HTTPError(response);\n }\n\n logFile.delete();\n } catch (error) {\n this.requestLogger.retryFileLater(logFile);\n break;\n }\n\n i++;\n if (i >= 10) break;\n }\n }\n\n private handleHubError(error: unknown) {\n if (error instanceof HTTPError) {\n if (error.response.status === 404) {\n this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);\n this.enabled = false;\n this.stopSync();\n return true;\n }\n if (error.response.status === 422) {\n this.logger.error(\"Received validation error from Apitally Hub\");\n return true;\n }\n }\n return false;\n }\n\n private async randomDelay() {\n const delay = 100 + Math.random() * 400;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n"],"mappings":"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","names":["fetchRetry","randomUUID","ConsumerRegistry","getOrCreateInstanceUuid","getLogger","isValidClientId","isValidEnv","RequestCounter","RequestLogger","getCpuMemoryUsage","ServerErrorCounter","SpanCollector","ValidationErrorCounter","SYNC_INTERVAL","INITIAL_SYNC_INTERVAL","INITIAL_SYNC_INTERVAL_DURATION","MAX_QUEUE_TIME","HTTPError","Error","response","reason","status","ApitallyClient","clientId","env","instanceUuid","syncDataQueue","syncIntervalId","startupData","startupDataSent","enabled","requestCounter","requestLogger","spanCollector","validationErrorCounter","serverErrorCounter","consumerRegistry","logger","requestLogging","requestLoggingConfig","instance","error","console","warn","config","captureTraces","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetch","retries","retryDelay","retryOn","method","body","JSON","stringify","headers","ok","startSync","sync","setInterval","setTimeout","clearInterval","promises","push","sendStartupData","Promise","all","setStartupData","data","debug","instance_uuid","message_uuid","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","resources","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve"]}
@@ -3,8 +3,6 @@ import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http';
3
3
  import { SpanData } from './spanCollector.cjs';
4
4
  import TempGzipFile from './tempGzipFile.cjs';
5
5
  import '@opentelemetry/sdk-trace-base';
6
- import './logging.cjs';
7
- import 'winston';
8
6
 
9
7
  type Request = {
10
8
  timestamp: number;
@@ -3,8 +3,6 @@ import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http';
3
3
  import { SpanData } from './spanCollector.js';
4
4
  import TempGzipFile from './tempGzipFile.js';
5
5
  import '@opentelemetry/sdk-trace-base';
6
- import './logging.js';
7
- import 'winston';
8
6
 
9
7
  type Request = {
10
8
  timestamp: number;
@@ -24,15 +24,7 @@ __export(spanCollector_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(spanCollector_exports);
26
26
  var import_api = require("@opentelemetry/api");
27
- var import_context_async_hooks = require("@opentelemetry/context-async-hooks");
28
- var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
29
27
  var import_client = require('./client.cjs');
30
- var _a;
31
- let AsyncLocalStorageContextManager = (_a = class extends import_context_async_hooks.AsyncLocalStorageContextManager {
32
- enterWith(ctx) {
33
- this._asyncLocalStorage.enterWith(ctx);
34
- }
35
- }, __name(_a, "AsyncLocalStorageContextManager"), _a);
36
28
  const TRACE_MAX_AGE = 5 * 60 * 1e3;
37
29
  const _SpanCollector = class _SpanCollector {
38
30
  enabled;
@@ -40,30 +32,16 @@ const _SpanCollector = class _SpanCollector {
40
32
  collectedSpans = /* @__PURE__ */ new Map();
41
33
  traceStartTimes = /* @__PURE__ */ new Map();
42
34
  maintainIntervalId;
43
- contextManager;
44
35
  tracer;
45
- logger;
46
- constructor(enabled, logger) {
36
+ constructor(enabled) {
47
37
  this.enabled = enabled;
48
- this.logger = logger;
49
38
  if (enabled) {
50
- this.setupTracerProvider();
39
+ this.tracer = import_api.trace.getTracer("apitally");
51
40
  this.maintainIntervalId = setInterval(() => {
52
41
  this.maintain();
53
42
  }, 6e4);
54
43
  }
55
44
  }
56
- setupTracerProvider() {
57
- this.contextManager = new AsyncLocalStorageContextManager();
58
- import_api.context.setGlobalContextManager(this.contextManager);
59
- const provider = new import_sdk_trace_base.BasicTracerProvider({
60
- spanProcessors: [
61
- this
62
- ]
63
- });
64
- import_api.trace.setGlobalTracerProvider(provider);
65
- this.tracer = import_api.trace.getTracer("apitally");
66
- }
67
45
  startSpan() {
68
46
  if (!this.enabled || !this.tracer) {
69
47
  return {
@@ -94,8 +72,12 @@ const _SpanCollector = class _SpanCollector {
94
72
  return import_api.context.with(ctx, fn);
95
73
  }, "runInContext"),
96
74
  enterContext: /* @__PURE__ */ __name(() => {
97
- var _a2;
98
- (_a2 = this.contextManager) == null ? void 0 : _a2.enterWith(ctx);
75
+ var _a, _b, _c;
76
+ try {
77
+ const contextManager = (_b = (_a = import_api.context)._getContextManager) == null ? void 0 : _b.call(_a);
78
+ (_c = contextManager == null ? void 0 : contextManager._asyncLocalStorage) == null ? void 0 : _c.enterWith(ctx);
79
+ } catch {
80
+ }
99
81
  }, "enterContext"),
100
82
  end: /* @__PURE__ */ __name(() => {
101
83
  if (ended) return;
@@ -113,14 +95,14 @@ const _SpanCollector = class _SpanCollector {
113
95
  return spans;
114
96
  }
115
97
  onStart(span) {
116
- var _a2;
98
+ var _a;
117
99
  if (!this.enabled) return;
118
100
  const ctx = span.spanContext();
119
101
  const traceId = ctx.traceId;
120
102
  const spanId = ctx.spanId;
121
103
  const includedSpans = this.includedSpanIds.get(traceId);
122
104
  if (!includedSpans) return;
123
- const parentSpanId = (_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId;
105
+ const parentSpanId = (_a = span.parentSpanContext) == null ? void 0 : _a.spanId;
124
106
  if (parentSpanId && includedSpans.has(parentSpanId)) {
125
107
  includedSpans.add(spanId);
126
108
  }
@@ -138,11 +120,11 @@ const _SpanCollector = class _SpanCollector {
138
120
  }
139
121
  }
140
122
  serializeSpan(span) {
141
- var _a2;
123
+ var _a;
142
124
  const ctx = span.spanContext();
143
125
  const data = {
144
126
  spanId: ctx.spanId,
145
- parentSpanId: ((_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId) || null,
127
+ parentSpanId: ((_a = span.parentSpanContext) == null ? void 0 : _a.spanId) || null,
146
128
  name: span.name,
147
129
  kind: import_api.SpanKind[span.kind] ?? "INTERNAL",
148
130
  // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss
@@ -192,20 +174,20 @@ const _ApitallySpanProcessor = class _ApitallySpanProcessor {
192
174
  }
193
175
  }
194
176
  onStart(span) {
195
- var _a2;
196
- (_a2 = this.getCollector()) == null ? void 0 : _a2.onStart(span);
177
+ var _a;
178
+ (_a = this.getCollector()) == null ? void 0 : _a.onStart(span);
197
179
  }
198
180
  onEnd(span) {
199
- var _a2;
200
- (_a2 = this.getCollector()) == null ? void 0 : _a2.onEnd(span);
181
+ var _a;
182
+ (_a = this.getCollector()) == null ? void 0 : _a.onEnd(span);
201
183
  }
202
184
  async shutdown() {
203
- var _a2;
204
- (_a2 = this.getCollector()) == null ? void 0 : _a2.shutdown();
185
+ var _a;
186
+ (_a = this.getCollector()) == null ? void 0 : _a.shutdown();
205
187
  }
206
188
  async forceFlush() {
207
- var _a2;
208
- (_a2 = this.getCollector()) == null ? void 0 : _a2.forceFlush();
189
+ var _a;
190
+ (_a = this.getCollector()) == null ? void 0 : _a.forceFlush();
209
191
  }
210
192
  };
211
193
  __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n type Context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n BasicTracerProvider,\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\nimport { Logger } from \"./logging.js\";\n\n/**\n * Extends the official AsyncLocalStorageContextManager to add enterWith support\n * for frameworks that need to persist context across hook boundaries (e.g. Elysia).\n */\nclass AsyncLocalStorageContextManager extends _AsyncLocalStorageContextManager {\n enterWith(ctx: Context): void {\n // @ts-expect-error: _asyncLocalStorage is private\n this._asyncLocalStorage.enterWith(ctx);\n }\n}\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private contextManager?: AsyncLocalStorageContextManager;\n private tracer?: Tracer;\n private logger?: Logger;\n\n constructor(enabled: boolean, logger?: Logger) {\n this.enabled = enabled;\n this.logger = logger;\n\n if (enabled) {\n this.setupTracerProvider();\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n private setupTracerProvider() {\n this.contextManager = new AsyncLocalStorageContextManager();\n context.setGlobalContextManager(this.contextManager);\n\n const provider = new BasicTracerProvider({\n spanProcessors: [this],\n });\n trace.setGlobalTracerProvider(provider);\n this.tracer = trace.getTracer(\"apitally\");\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n this.contextManager?.enterWith(ctx);\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["AsyncLocalStorageContextManager","_AsyncLocalStorageContextManager","enterWith","ctx","_asyncLocalStorage","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","contextManager","tracer","logger","setupTracerProvider","setInterval","maintain","context","setGlobalContextManager","provider","BasicTracerProvider","spanProcessors","trace","setGlobalTracerProvider","getTracer","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","_a","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","SpanKind","startTime","BigInt","toString","endTime","status","code","SpanStatusCode","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","ApitallyClient","getInstance","spanCollector"]}
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","trace","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","context","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","SpanKind","startTime","BigInt","toString","endTime","status","code","SpanStatusCode","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","ApitallyClient","getInstance","spanCollector"]}
@@ -1,6 +1,4 @@
1
1
  import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
2
- import { Logger } from './logging.cjs';
3
- import 'winston';
4
2
 
5
3
  type SpanData = {
6
4
  spanId: string;
@@ -25,11 +23,8 @@ declare class SpanCollector implements SpanProcessor {
25
23
  private collectedSpans;
26
24
  private traceStartTimes;
27
25
  private maintainIntervalId?;
28
- private contextManager?;
29
26
  private tracer?;
30
- private logger?;
31
- constructor(enabled: boolean, logger?: Logger);
32
- private setupTracerProvider;
27
+ constructor(enabled: boolean);
33
28
  startSpan(): SpanHandle;
34
29
  private getAndClearSpans;
35
30
  onStart(span: Span): void;
@@ -1,6 +1,4 @@
1
1
  import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
2
- import { Logger } from './logging.js';
3
- import 'winston';
4
2
 
5
3
  type SpanData = {
6
4
  spanId: string;
@@ -25,11 +23,8 @@ declare class SpanCollector implements SpanProcessor {
25
23
  private collectedSpans;
26
24
  private traceStartTimes;
27
25
  private maintainIntervalId?;
28
- private contextManager?;
29
26
  private tracer?;
30
- private logger?;
31
- constructor(enabled: boolean, logger?: Logger);
32
- private setupTracerProvider;
27
+ constructor(enabled: boolean);
33
28
  startSpan(): SpanHandle;
34
29
  private getAndClearSpans;
35
30
  onStart(span: Span): void;
@@ -1,15 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
- var _a;
4
3
  import { context, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
5
- import { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
6
- import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
7
4
  import { ApitallyClient } from "./client.js";
8
- let AsyncLocalStorageContextManager = (_a = class extends _AsyncLocalStorageContextManager {
9
- enterWith(ctx) {
10
- this._asyncLocalStorage.enterWith(ctx);
11
- }
12
- }, __name(_a, "AsyncLocalStorageContextManager"), _a);
13
5
  const TRACE_MAX_AGE = 5 * 60 * 1e3;
14
6
  const _SpanCollector = class _SpanCollector {
15
7
  enabled;
@@ -17,30 +9,16 @@ const _SpanCollector = class _SpanCollector {
17
9
  collectedSpans = /* @__PURE__ */ new Map();
18
10
  traceStartTimes = /* @__PURE__ */ new Map();
19
11
  maintainIntervalId;
20
- contextManager;
21
12
  tracer;
22
- logger;
23
- constructor(enabled, logger) {
13
+ constructor(enabled) {
24
14
  this.enabled = enabled;
25
- this.logger = logger;
26
15
  if (enabled) {
27
- this.setupTracerProvider();
16
+ this.tracer = trace.getTracer("apitally");
28
17
  this.maintainIntervalId = setInterval(() => {
29
18
  this.maintain();
30
19
  }, 6e4);
31
20
  }
32
21
  }
33
- setupTracerProvider() {
34
- this.contextManager = new AsyncLocalStorageContextManager();
35
- context.setGlobalContextManager(this.contextManager);
36
- const provider = new BasicTracerProvider({
37
- spanProcessors: [
38
- this
39
- ]
40
- });
41
- trace.setGlobalTracerProvider(provider);
42
- this.tracer = trace.getTracer("apitally");
43
- }
44
22
  startSpan() {
45
23
  if (!this.enabled || !this.tracer) {
46
24
  return {
@@ -71,8 +49,12 @@ const _SpanCollector = class _SpanCollector {
71
49
  return context.with(ctx, fn);
72
50
  }, "runInContext"),
73
51
  enterContext: /* @__PURE__ */ __name(() => {
74
- var _a2;
75
- (_a2 = this.contextManager) == null ? void 0 : _a2.enterWith(ctx);
52
+ var _a, _b, _c;
53
+ try {
54
+ const contextManager = (_b = (_a = context)._getContextManager) == null ? void 0 : _b.call(_a);
55
+ (_c = contextManager == null ? void 0 : contextManager._asyncLocalStorage) == null ? void 0 : _c.enterWith(ctx);
56
+ } catch {
57
+ }
76
58
  }, "enterContext"),
77
59
  end: /* @__PURE__ */ __name(() => {
78
60
  if (ended) return;
@@ -90,14 +72,14 @@ const _SpanCollector = class _SpanCollector {
90
72
  return spans;
91
73
  }
92
74
  onStart(span) {
93
- var _a2;
75
+ var _a;
94
76
  if (!this.enabled) return;
95
77
  const ctx = span.spanContext();
96
78
  const traceId = ctx.traceId;
97
79
  const spanId = ctx.spanId;
98
80
  const includedSpans = this.includedSpanIds.get(traceId);
99
81
  if (!includedSpans) return;
100
- const parentSpanId = (_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId;
82
+ const parentSpanId = (_a = span.parentSpanContext) == null ? void 0 : _a.spanId;
101
83
  if (parentSpanId && includedSpans.has(parentSpanId)) {
102
84
  includedSpans.add(spanId);
103
85
  }
@@ -115,11 +97,11 @@ const _SpanCollector = class _SpanCollector {
115
97
  }
116
98
  }
117
99
  serializeSpan(span) {
118
- var _a2;
100
+ var _a;
119
101
  const ctx = span.spanContext();
120
102
  const data = {
121
103
  spanId: ctx.spanId,
122
- parentSpanId: ((_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId) || null,
104
+ parentSpanId: ((_a = span.parentSpanContext) == null ? void 0 : _a.spanId) || null,
123
105
  name: span.name,
124
106
  kind: SpanKind[span.kind] ?? "INTERNAL",
125
107
  // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss
@@ -169,20 +151,20 @@ const _ApitallySpanProcessor = class _ApitallySpanProcessor {
169
151
  }
170
152
  }
171
153
  onStart(span) {
172
- var _a2;
173
- (_a2 = this.getCollector()) == null ? void 0 : _a2.onStart(span);
154
+ var _a;
155
+ (_a = this.getCollector()) == null ? void 0 : _a.onStart(span);
174
156
  }
175
157
  onEnd(span) {
176
- var _a2;
177
- (_a2 = this.getCollector()) == null ? void 0 : _a2.onEnd(span);
158
+ var _a;
159
+ (_a = this.getCollector()) == null ? void 0 : _a.onEnd(span);
178
160
  }
179
161
  async shutdown() {
180
- var _a2;
181
- (_a2 = this.getCollector()) == null ? void 0 : _a2.shutdown();
162
+ var _a;
163
+ (_a = this.getCollector()) == null ? void 0 : _a.shutdown();
182
164
  }
183
165
  async forceFlush() {
184
- var _a2;
185
- (_a2 = this.getCollector()) == null ? void 0 : _a2.forceFlush();
166
+ var _a;
167
+ (_a = this.getCollector()) == null ? void 0 : _a.forceFlush();
186
168
  }
187
169
  };
188
170
  __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n type Context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n BasicTracerProvider,\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\nimport { Logger } from \"./logging.js\";\n\n/**\n * Extends the official AsyncLocalStorageContextManager to add enterWith support\n * for frameworks that need to persist context across hook boundaries (e.g. Elysia).\n */\nclass AsyncLocalStorageContextManager extends _AsyncLocalStorageContextManager {\n enterWith(ctx: Context): void {\n // @ts-expect-error: _asyncLocalStorage is private\n this._asyncLocalStorage.enterWith(ctx);\n }\n}\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private contextManager?: AsyncLocalStorageContextManager;\n private tracer?: Tracer;\n private logger?: Logger;\n\n constructor(enabled: boolean, logger?: Logger) {\n this.enabled = enabled;\n this.logger = logger;\n\n if (enabled) {\n this.setupTracerProvider();\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n private setupTracerProvider() {\n this.contextManager = new AsyncLocalStorageContextManager();\n context.setGlobalContextManager(this.contextManager);\n\n const provider = new BasicTracerProvider({\n spanProcessors: [this],\n });\n trace.setGlobalTracerProvider(provider);\n this.tracer = trace.getTracer(\"apitally\");\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n this.contextManager?.enterWith(ctx);\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["context","SpanKind","SpanStatusCode","trace","AsyncLocalStorageContextManager","_AsyncLocalStorageContextManager","BasicTracerProvider","ApitallyClient","enterWith","ctx","_asyncLocalStorage","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","contextManager","tracer","logger","setupTracerProvider","setInterval","maintain","setGlobalContextManager","provider","spanProcessors","setGlobalTracerProvider","getTracer","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","_a","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","startTime","BigInt","toString","endTime","status","code","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","getInstance","spanCollector"]}
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport {\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private tracer?: Tracer;\n\n constructor(enabled: boolean) {\n this.enabled = enabled;\n\n if (enabled) {\n this.tracer = trace.getTracer(\"apitally\");\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n try {\n // Access the global context manager's internal AsyncLocalStorage\n const contextManager = (context as any)._getContextManager?.();\n contextManager?._asyncLocalStorage?.enterWith(ctx);\n } catch {\n // Ignore errors accessing internals\n }\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["context","SpanKind","SpanStatusCode","trace","ApitallyClient","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","tracer","getTracer","setInterval","maintain","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","ctx","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","contextManager","_getContextManager","_asyncLocalStorage","enterWith","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","startTime","BigInt","toString","endTime","status","code","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","getInstance","spanCollector"]}
@@ -28,15 +28,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var elysia_exports = {};
30
30
  __export(elysia_exports, {
31
- ApitallySpanProcessor: () => import_spanCollector.ApitallySpanProcessor,
32
31
  apitallyPlugin: () => import_plugin.default
33
32
  });
34
33
  module.exports = __toCommonJS(elysia_exports);
35
- var import_spanCollector = require('../common/spanCollector.cjs');
36
34
  var import_plugin = __toESM(require('./plugin.cjs'), 1);
37
35
  // Annotate the CommonJS export names for ESM import in node:
38
36
  0 && (module.exports = {
39
- ApitallySpanProcessor,
40
37
  apitallyPlugin
41
38
  });
42
39
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export { ApitallySpanProcessor } from \"../common/spanCollector.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;2BAAsC;AAEtC,oBAA0C;","names":[]}
1
+ {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA;;;;;oBAA0C;","names":[]}
@@ -1,12 +1,12 @@
1
- export { ApitallySpanProcessor } from '../common/spanCollector.cjs';
2
1
  export { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
3
2
  export { default as apitallyPlugin } from './plugin.cjs';
4
- import '@opentelemetry/sdk-trace-base';
5
3
  import '../common/logging.cjs';
6
4
  import 'winston';
7
5
  import '../common/requestLogger.cjs';
8
6
  import 'node:buffer';
9
7
  import 'node:http';
8
+ import '../common/spanCollector.cjs';
9
+ import '@opentelemetry/sdk-trace-base';
10
10
  import '../common/tempGzipFile.cjs';
11
11
  import 'elysia';
12
12
  import '../common/client.cjs';
@@ -1,12 +1,12 @@
1
- export { ApitallySpanProcessor } from '../common/spanCollector.js';
2
1
  export { ApitallyConfig, ApitallyConsumer } from '../common/types.js';
3
2
  export { default as apitallyPlugin } from './plugin.js';
4
- import '@opentelemetry/sdk-trace-base';
5
3
  import '../common/logging.js';
6
4
  import 'winston';
7
5
  import '../common/requestLogger.js';
8
6
  import 'node:buffer';
9
7
  import 'node:http';
8
+ import '../common/spanCollector.js';
9
+ import '@opentelemetry/sdk-trace-base';
10
10
  import '../common/tempGzipFile.js';
11
11
  import 'elysia';
12
12
  import '../common/client.js';
@@ -1,7 +1,5 @@
1
- import { ApitallySpanProcessor } from "../common/spanCollector.js";
2
1
  import { default as default2 } from "./plugin.js";
3
2
  export {
4
- ApitallySpanProcessor,
5
3
  default2 as apitallyPlugin
6
4
  };
7
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export { ApitallySpanProcessor } from \"../common/spanCollector.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":"AAAA,SAASA,6BAA6B;AAEtC,SAAoBC,WAAXC,gBAAiC;","names":["ApitallySpanProcessor","apitallyPlugin","default"]}
1
+ {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":"AACA,SAAoBA,WAAXC,gBAAiC;","names":["apitallyPlugin","default"]}
@@ -1,15 +1,15 @@
1
- import { SpanHandle } from '../common/spanCollector.cjs';
2
1
  import { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
3
2
  import { Elysia } from 'elysia';
4
3
  import { ApitallyClient } from '../common/client.cjs';
5
4
  import { CapturedResponse } from '../common/response.cjs';
6
- import '@opentelemetry/sdk-trace-base';
5
+ import { SpanHandle } from '../common/spanCollector.cjs';
7
6
  import '../common/logging.cjs';
8
7
  import 'winston';
9
8
  import '../common/requestLogger.cjs';
10
9
  import 'node:buffer';
11
10
  import 'node:http';
12
11
  import '../common/tempGzipFile.cjs';
12
+ import '@opentelemetry/sdk-trace-base';
13
13
  import '../common/consumerRegistry.cjs';
14
14
  import '../common/requestCounter.cjs';
15
15
  import '../common/serverErrorCounter.cjs';
@@ -1,15 +1,15 @@
1
- import { SpanHandle } from '../common/spanCollector.js';
2
1
  import { ApitallyConfig, ApitallyConsumer } from '../common/types.js';
3
2
  import { Elysia } from 'elysia';
4
3
  import { ApitallyClient } from '../common/client.js';
5
4
  import { CapturedResponse } from '../common/response.js';
6
- import '@opentelemetry/sdk-trace-base';
5
+ import { SpanHandle } from '../common/spanCollector.js';
7
6
  import '../common/logging.js';
8
7
  import 'winston';
9
8
  import '../common/requestLogger.js';
10
9
  import 'node:buffer';
11
10
  import 'node:http';
12
11
  import '../common/tempGzipFile.js';
12
+ import '@opentelemetry/sdk-trace-base';
13
13
  import '../common/consumerRegistry.js';
14
14
  import '../common/requestCounter.js';
15
15
  import '../common/serverErrorCounter.js';