apitally 0.25.1 → 0.25.2
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.
- package/dist/adonisjs/index.cjs +0 -3
- package/dist/adonisjs/index.cjs.map +1 -1
- package/dist/adonisjs/index.d.cts +2 -2
- package/dist/adonisjs/index.d.ts +2 -2
- package/dist/adonisjs/index.js +0 -2
- package/dist/adonisjs/index.js.map +1 -1
- package/dist/common/client.cjs +1 -1
- package/dist/common/client.cjs.map +1 -1
- package/dist/common/client.js +1 -1
- package/dist/common/client.js.map +1 -1
- package/dist/common/requestLogger.d.cts +0 -2
- package/dist/common/requestLogger.d.ts +0 -2
- package/dist/common/spanCollector.cjs +20 -38
- package/dist/common/spanCollector.cjs.map +1 -1
- package/dist/common/spanCollector.d.cts +1 -6
- package/dist/common/spanCollector.d.ts +1 -6
- package/dist/common/spanCollector.js +20 -38
- package/dist/common/spanCollector.js.map +1 -1
- package/dist/elysia/index.cjs +0 -3
- package/dist/elysia/index.cjs.map +1 -1
- package/dist/elysia/index.d.cts +2 -2
- package/dist/elysia/index.d.ts +2 -2
- package/dist/elysia/index.js +0 -2
- package/dist/elysia/index.js.map +1 -1
- package/dist/elysia/plugin.d.cts +2 -2
- package/dist/elysia/plugin.d.ts +2 -2
- package/dist/express/index.cjs +0 -3
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +2 -2
- package/dist/express/index.d.ts +2 -2
- package/dist/express/index.js +0 -2
- package/dist/express/index.js.map +1 -1
- package/dist/express/middleware.d.cts +2 -2
- package/dist/express/middleware.d.ts +2 -2
- package/dist/fastify/index.cjs +0 -3
- package/dist/fastify/index.cjs.map +1 -1
- package/dist/fastify/index.d.cts +2 -2
- package/dist/fastify/index.d.ts +2 -2
- package/dist/fastify/index.js +0 -2
- package/dist/fastify/index.js.map +1 -1
- package/dist/fastify/plugin.d.cts +2 -2
- package/dist/fastify/plugin.d.ts +2 -2
- package/dist/h3/index.cjs +0 -3
- package/dist/h3/index.cjs.map +1 -1
- package/dist/h3/index.d.cts +2 -2
- package/dist/h3/index.d.ts +2 -2
- package/dist/h3/index.js +0 -2
- package/dist/h3/index.js.map +1 -1
- package/dist/h3/plugin.d.cts +2 -2
- package/dist/h3/plugin.d.ts +2 -2
- package/dist/hapi/index.cjs +0 -3
- package/dist/hapi/index.cjs.map +1 -1
- package/dist/hapi/index.d.cts +2 -2
- package/dist/hapi/index.d.ts +2 -2
- package/dist/hapi/index.js +0 -2
- package/dist/hapi/index.js.map +1 -1
- package/dist/hapi/plugin.d.cts +2 -2
- package/dist/hapi/plugin.d.ts +2 -2
- package/dist/hono/index.cjs +0 -3
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +2 -2
- package/dist/hono/index.d.ts +2 -2
- package/dist/hono/index.js +0 -2
- package/dist/hono/index.js.map +1 -1
- package/dist/hono/middleware.d.cts +2 -2
- package/dist/hono/middleware.d.ts +2 -2
- package/dist/hono/utils.d.cts +1 -1
- package/dist/hono/utils.d.ts +1 -1
- package/dist/koa/index.cjs +0 -3
- package/dist/koa/index.cjs.map +1 -1
- package/dist/koa/index.d.cts +2 -2
- package/dist/koa/index.d.ts +2 -2
- package/dist/koa/index.js +0 -2
- package/dist/koa/index.js.map +1 -1
- package/dist/koa/middleware.d.cts +2 -2
- package/dist/koa/middleware.d.ts +2 -2
- package/dist/loggers/console.d.cts +0 -2
- package/dist/loggers/console.d.ts +0 -2
- package/dist/loggers/hapi.d.cts +0 -2
- package/dist/loggers/hapi.d.ts +0 -2
- package/dist/loggers/index.d.cts +0 -2
- package/dist/loggers/index.d.ts +0 -2
- package/dist/loggers/nestjs.d.cts +0 -2
- package/dist/loggers/nestjs.d.ts +0 -2
- package/dist/loggers/pino.d.cts +0 -2
- package/dist/loggers/pino.d.ts +0 -2
- package/dist/loggers/winston.d.cts +0 -2
- package/dist/loggers/winston.d.ts +0 -2
- package/dist/nestjs/index.cjs +0 -3
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.d.cts +3 -3
- package/dist/nestjs/index.d.ts +3 -3
- package/dist/nestjs/index.js +0 -2
- package/dist/nestjs/index.js.map +1 -1
- package/dist/otel/index.cjs +29 -0
- package/dist/otel/index.cjs.map +1 -0
- package/dist/otel/index.d.cts +2 -0
- package/dist/otel/index.d.ts +2 -0
- package/dist/otel/index.js +5 -0
- package/dist/otel/index.js.map +1 -0
- package/package.json +15 -2
package/dist/adonisjs/index.cjs
CHANGED
|
@@ -19,14 +19,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
var adonisjs_exports = {};
|
|
21
21
|
__export(adonisjs_exports, {
|
|
22
|
-
ApitallySpanProcessor: () => import_spanCollector.ApitallySpanProcessor,
|
|
23
22
|
captureError: () => captureError,
|
|
24
23
|
configure: () => import_configure.configure,
|
|
25
24
|
defineConfig: () => defineConfig,
|
|
26
25
|
setConsumer: () => setConsumer
|
|
27
26
|
});
|
|
28
27
|
module.exports = __toCommonJS(adonisjs_exports);
|
|
29
|
-
var import_spanCollector = require('../common/spanCollector.cjs');
|
|
30
28
|
var import_configure = require('./configure.cjs');
|
|
31
29
|
function defineConfig(config) {
|
|
32
30
|
return config;
|
|
@@ -44,7 +42,6 @@ function setConsumer(ctx, consumer) {
|
|
|
44
42
|
__name(setConsumer, "setConsumer");
|
|
45
43
|
// Annotate the CommonJS export names for ESM import in node:
|
|
46
44
|
0 && (module.exports = {
|
|
47
|
-
ApitallySpanProcessor,
|
|
48
45
|
captureError,
|
|
49
46
|
configure,
|
|
50
47
|
defineConfig,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adonisjs/index.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\n\nimport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport
|
|
1
|
+
{"version":3,"sources":["../../src/adonisjs/index.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\n\nimport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { configure } from \"./configure.js\";\n\nexport function defineConfig(config: ApitallyConfig) {\n return config;\n}\n\nexport function captureError(error: unknown, ctx: HttpContext) {\n if (error instanceof Error) {\n ctx.apitallyError = error;\n }\n}\n\nexport function setConsumer(\n ctx: HttpContext,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n ctx.apitallyConsumer = consumer || undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAIA;;;;;;;;AAAA,uBAA0B;AAEnB,SAASA,aAAaC,QAAsB;AACjD,SAAOA;AACT;AAFgBD;AAIT,SAASE,aAAaC,OAAgBC,KAAgB;AAC3D,MAAID,iBAAiBE,OAAO;AAC1BD,QAAIE,gBAAgBH;EACtB;AACF;AAJgBD;AAMT,SAASK,YACdH,KACAI,UAAsD;AAEtDJ,MAAIK,mBAAmBD,YAAYE;AACrC;AALgBH;","names":["defineConfig","config","captureError","error","ctx","Error","apitallyError","setConsumer","consumer","apitallyConsumer","undefined"]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { HttpContext } from '@adonisjs/core/http';
|
|
2
2
|
import { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
|
|
3
|
-
export { ApitallySpanProcessor } from '../common/spanCollector.cjs';
|
|
4
3
|
export { configure } from './configure.cjs';
|
|
5
4
|
import '../common/logging.cjs';
|
|
6
5
|
import 'winston';
|
|
7
6
|
import '../common/requestLogger.cjs';
|
|
8
7
|
import 'node:buffer';
|
|
9
8
|
import 'node:http';
|
|
10
|
-
import '../common/
|
|
9
|
+
import '../common/spanCollector.cjs';
|
|
11
10
|
import '@opentelemetry/sdk-trace-base';
|
|
11
|
+
import '../common/tempGzipFile.cjs';
|
|
12
12
|
import '@adonisjs/core/commands/configure';
|
|
13
13
|
|
|
14
14
|
declare function defineConfig(config: ApitallyConfig): ApitallyConfig;
|
package/dist/adonisjs/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { HttpContext } from '@adonisjs/core/http';
|
|
2
2
|
import { ApitallyConfig, ApitallyConsumer } from '../common/types.js';
|
|
3
|
-
export { ApitallySpanProcessor } from '../common/spanCollector.js';
|
|
4
3
|
export { configure } from './configure.js';
|
|
5
4
|
import '../common/logging.js';
|
|
6
5
|
import 'winston';
|
|
7
6
|
import '../common/requestLogger.js';
|
|
8
7
|
import 'node:buffer';
|
|
9
8
|
import 'node:http';
|
|
10
|
-
import '../common/
|
|
9
|
+
import '../common/spanCollector.js';
|
|
11
10
|
import '@opentelemetry/sdk-trace-base';
|
|
11
|
+
import '../common/tempGzipFile.js';
|
|
12
12
|
import '@adonisjs/core/commands/configure';
|
|
13
13
|
|
|
14
14
|
declare function defineConfig(config: ApitallyConfig): ApitallyConfig;
|
package/dist/adonisjs/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
import { ApitallySpanProcessor } from "../common/spanCollector.js";
|
|
4
3
|
import { configure } from "./configure.js";
|
|
5
4
|
function defineConfig(config) {
|
|
6
5
|
return config;
|
|
@@ -17,7 +16,6 @@ function setConsumer(ctx, consumer) {
|
|
|
17
16
|
}
|
|
18
17
|
__name(setConsumer, "setConsumer");
|
|
19
18
|
export {
|
|
20
|
-
ApitallySpanProcessor,
|
|
21
19
|
captureError,
|
|
22
20
|
configure,
|
|
23
21
|
defineConfig,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adonisjs/index.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\n\nimport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport
|
|
1
|
+
{"version":3,"sources":["../../src/adonisjs/index.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\n\nimport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { configure } from \"./configure.js\";\n\nexport function defineConfig(config: ApitallyConfig) {\n return config;\n}\n\nexport function captureError(error: unknown, ctx: HttpContext) {\n if (error instanceof Error) {\n ctx.apitallyError = error;\n }\n}\n\nexport function setConsumer(\n ctx: HttpContext,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n ctx.apitallyConsumer = consumer || undefined;\n}\n"],"mappings":";;AAIA,SAASA,iBAAiB;AAEnB,SAASC,aAAaC,QAAsB;AACjD,SAAOA;AACT;AAFgBD;AAIT,SAASE,aAAaC,OAAgBC,KAAgB;AAC3D,MAAID,iBAAiBE,OAAO;AAC1BD,QAAIE,gBAAgBH;EACtB;AACF;AAJgBD;AAMT,SAASK,YACdH,KACAI,UAAsD;AAEtDJ,MAAIK,mBAAmBD,YAAYE;AACrC;AALgBH;","names":["configure","defineConfig","config","captureError","error","ctx","Error","apitallyError","setConsumer","consumer","apitallyConsumer","undefined"]}
|
package/dist/common/client.cjs
CHANGED
|
@@ -98,7 +98,7 @@ const _ApitallyClient = class _ApitallyClient {
|
|
|
98
98
|
this.syncDataQueue = [];
|
|
99
99
|
this.requestCounter = new import_requestCounter.default();
|
|
100
100
|
this.requestLogger = new import_requestLogger.default(requestLogging ?? requestLoggingConfig);
|
|
101
|
-
this.spanCollector = new import_spanCollector.default(this.enabled && this.requestLogger.enabled && this.requestLogger.config.captureTraces
|
|
101
|
+
this.spanCollector = new import_spanCollector.default(this.enabled && this.requestLogger.enabled && this.requestLogger.config.captureTraces);
|
|
102
102
|
this.validationErrorCounter = new import_validationErrorCounter.default();
|
|
103
103
|
this.serverErrorCounter = new import_serverErrorCounter.default();
|
|
104
104
|
this.consumerRegistry = new import_consumerRegistry.default();
|
|
@@ -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":["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","getLogger","isValidClientId","error","isValidEnv","console","warn","getOrCreateInstanceUuid","RequestCounter","RequestLogger","SpanCollector","config","captureTraces","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","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","randomUUID","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","resources","getCpuMemoryUsage","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":["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","getLogger","isValidClientId","error","isValidEnv","console","warn","getOrCreateInstanceUuid","RequestCounter","RequestLogger","SpanCollector","config","captureTraces","ValidationErrorCounter","ServerErrorCounter","ConsumerRegistry","handleShutdown","bind","getInstance","isEnabled","shutdown","stopSync","sendSyncData","sendLogData","close","undefined","getHubUrlPrefix","baseURL","process","APITALLY_HUB_BASE_URL","version","sendData","url","payload","fetchWithRetry","fetchRetry","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","randomUUID","handled","handleHubError","message","newPayload","timestamp","Date","now","requests","getAndResetRequests","validation_errors","getAndResetValidationErrors","server_errors","getAndResetServerErrors","consumers","getAndResetUpdatedConsumers","resources","getCpuMemoryUsage","i","length","shift","randomDelay","rotateFile","logFile","getFile","uuid","getContent","has","retryAfter","parseInt","get","suspendUntil","clear","delete","retryFileLater","delay","Math","random","resolve"]}
|
package/dist/common/client.js
CHANGED
|
@@ -66,7 +66,7 @@ const _ApitallyClient = class _ApitallyClient {
|
|
|
66
66
|
this.syncDataQueue = [];
|
|
67
67
|
this.requestCounter = new RequestCounter();
|
|
68
68
|
this.requestLogger = new RequestLogger(requestLogging ?? requestLoggingConfig);
|
|
69
|
-
this.spanCollector = new SpanCollector(this.enabled && this.requestLogger.enabled && this.requestLogger.config.captureTraces
|
|
69
|
+
this.spanCollector = new SpanCollector(this.enabled && this.requestLogger.enabled && this.requestLogger.config.captureTraces);
|
|
70
70
|
this.validationErrorCounter = new ValidationErrorCounter();
|
|
71
71
|
this.serverErrorCounter = new ServerErrorCounter();
|
|
72
72
|
this.consumerRegistry = new ConsumerRegistry();
|
|
@@ -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
|
-
|
|
46
|
-
constructor(enabled, logger) {
|
|
36
|
+
constructor(enabled) {
|
|
47
37
|
this.enabled = enabled;
|
|
48
|
-
this.logger = logger;
|
|
49
38
|
if (enabled) {
|
|
50
|
-
this.
|
|
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
|
|
98
|
-
|
|
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
|
|
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 = (
|
|
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
|
|
123
|
+
var _a;
|
|
142
124
|
const ctx = span.spanContext();
|
|
143
125
|
const data = {
|
|
144
126
|
spanId: ctx.spanId,
|
|
145
|
-
parentSpanId: ((
|
|
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
|
|
196
|
-
(
|
|
177
|
+
var _a;
|
|
178
|
+
(_a = this.getCollector()) == null ? void 0 : _a.onStart(span);
|
|
197
179
|
}
|
|
198
180
|
onEnd(span) {
|
|
199
|
-
var
|
|
200
|
-
(
|
|
181
|
+
var _a;
|
|
182
|
+
(_a = this.getCollector()) == null ? void 0 : _a.onEnd(span);
|
|
201
183
|
}
|
|
202
184
|
async shutdown() {
|
|
203
|
-
var
|
|
204
|
-
(
|
|
185
|
+
var _a;
|
|
186
|
+
(_a = this.getCollector()) == null ? void 0 : _a.shutdown();
|
|
205
187
|
}
|
|
206
188
|
async forceFlush() {
|
|
207
|
-
var
|
|
208
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
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;
|