fg-tracker-sdk 0.4.0 → 0.5.0
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/CHANGELOG.md +10 -0
- package/README.md +91 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/infra/aggregator.d.ts +64 -0
- package/dist/infra/aggregator.d.ts.map +1 -0
- package/dist/infra/aggregator.js +122 -0
- package/dist/infra/aggregator.js.map +1 -0
- package/dist/infra/aws.d.ts +51 -0
- package/dist/infra/aws.d.ts.map +1 -0
- package/dist/infra/aws.js +456 -0
- package/dist/infra/aws.js.map +1 -0
- package/dist/infra/db-pool.d.ts +26 -0
- package/dist/infra/db-pool.d.ts.map +1 -0
- package/dist/infra/db-pool.js +68 -0
- package/dist/infra/db-pool.js.map +1 -0
- package/dist/infra/ecs.d.ts +17 -0
- package/dist/infra/ecs.d.ts.map +1 -0
- package/dist/infra/ecs.js +154 -0
- package/dist/infra/ecs.js.map +1 -0
- package/dist/infra/lambda.d.ts +27 -0
- package/dist/infra/lambda.d.ts.map +1 -0
- package/dist/infra/lambda.js +83 -0
- package/dist/infra/lambda.js.map +1 -0
- package/dist/tracker.d.ts +33 -1
- package/dist/tracker.d.ts.map +1 -1
- package/dist/tracker.js +143 -13
- package/dist/tracker.js.map +1 -1
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { als } from '../context.js';
|
|
2
|
+
import { detectArchitecture } from './aggregator.js';
|
|
3
|
+
const DEFAULT_INTERVAL_MS = 10_000;
|
|
4
|
+
const MB = 1024 * 1024;
|
|
5
|
+
async function getJson(url) {
|
|
6
|
+
try {
|
|
7
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
|
|
8
|
+
if (!res.ok)
|
|
9
|
+
return null;
|
|
10
|
+
return (await res.json());
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reporter de infraestrutura do processo. Em ECS/Fargate lê `/task` uma vez e `/task/stats`
|
|
18
|
+
* periodicamente → agregado `ecs_task` (CPU, memória, rede e heartbeat com o ARN da task).
|
|
19
|
+
*/
|
|
20
|
+
export function startInfraReporter(core, options = {}) {
|
|
21
|
+
const noop = { stop() { } };
|
|
22
|
+
const infra = core.infra;
|
|
23
|
+
const metadataUri = process.env.ECS_CONTAINER_METADATA_URI_V4?.trim();
|
|
24
|
+
if (!infra || !core.enabled || options.ecs === false || !metadataUri) {
|
|
25
|
+
if (core.options.debug && options.ecs !== false && !metadataUri) {
|
|
26
|
+
console.info('[fg-tracker] startInfraReporter: ECS_CONTAINER_METADATA_URI_V4 ausente; nada a reportar.');
|
|
27
|
+
}
|
|
28
|
+
return noop;
|
|
29
|
+
}
|
|
30
|
+
let stopped = false;
|
|
31
|
+
let ref = null;
|
|
32
|
+
let task = null;
|
|
33
|
+
let previousNet = null;
|
|
34
|
+
let previousCpu = null;
|
|
35
|
+
let running = false;
|
|
36
|
+
const loadTask = async () => {
|
|
37
|
+
if (ref)
|
|
38
|
+
return true;
|
|
39
|
+
task = await getJson(`${metadataUri}/task`);
|
|
40
|
+
if (!task?.TaskARN)
|
|
41
|
+
return false;
|
|
42
|
+
const region = task.TaskARN.split(':')[3] || process.env.AWS_REGION || undefined;
|
|
43
|
+
const family = task.Containers?.map((c) => c.Labels?.['com.amazonaws.ecs.task-definition-family']).find(Boolean);
|
|
44
|
+
const serviceName = process.env.ECS_SERVICE_NAME?.trim() || task.ServiceName || family || task.Family;
|
|
45
|
+
ref = { kind: 'ecs_task', resourceArn: task.TaskARN, resourceName: serviceName, region };
|
|
46
|
+
infra.learnAccount(task.TaskARN);
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
const tick = async () => {
|
|
50
|
+
if (stopped || running)
|
|
51
|
+
return;
|
|
52
|
+
running = true;
|
|
53
|
+
try {
|
|
54
|
+
if (!(await loadTask()) || !ref || !task)
|
|
55
|
+
return;
|
|
56
|
+
const stats = await getJson(`${metadataUri}/task/stats`);
|
|
57
|
+
const r = ref;
|
|
58
|
+
infra.last(r, 'taskArn', task.TaskARN);
|
|
59
|
+
if (task.Cluster)
|
|
60
|
+
infra.last(r, 'clusterArn', task.Cluster);
|
|
61
|
+
if (r.resourceName)
|
|
62
|
+
infra.last(r, 'serviceName', r.resourceName);
|
|
63
|
+
if (task.LaunchType)
|
|
64
|
+
infra.last(r, 'launchType', task.LaunchType);
|
|
65
|
+
infra.last(r, 'architecture', detectArchitecture());
|
|
66
|
+
const cpuLimit = typeof task.Limits?.CPU === 'number' && task.Limits.CPU > 0 ? task.Limits.CPU : undefined;
|
|
67
|
+
if (cpuLimit)
|
|
68
|
+
infra.last(r, 'cpuUnits', Math.round(cpuLimit * 1024));
|
|
69
|
+
if (typeof task.Limits?.Memory === 'number' && task.Limits.Memory > 0)
|
|
70
|
+
infra.last(r, 'memoryLimitMb', task.Limits.Memory);
|
|
71
|
+
if (!stats)
|
|
72
|
+
return;
|
|
73
|
+
let cores = 0;
|
|
74
|
+
let cpuMeasured = false;
|
|
75
|
+
let memoryBytes = 0;
|
|
76
|
+
const net = new Map();
|
|
77
|
+
let aggTotal = 0;
|
|
78
|
+
let aggSystem = 0;
|
|
79
|
+
let aggOnline = 0;
|
|
80
|
+
for (const container of Object.values(stats)) {
|
|
81
|
+
if (!container)
|
|
82
|
+
continue;
|
|
83
|
+
const cpu = container.cpu_stats;
|
|
84
|
+
const pre = container.precpu_stats;
|
|
85
|
+
const online = cpu?.online_cpus || 1;
|
|
86
|
+
const total = cpu?.cpu_usage?.total_usage ?? 0;
|
|
87
|
+
const system = cpu?.system_cpu_usage ?? 0;
|
|
88
|
+
aggTotal += total;
|
|
89
|
+
aggSystem = Math.max(aggSystem, system);
|
|
90
|
+
aggOnline = Math.max(aggOnline, online);
|
|
91
|
+
const cpuDelta = total - (pre?.cpu_usage?.total_usage ?? 0);
|
|
92
|
+
const systemDelta = system - (pre?.system_cpu_usage ?? 0);
|
|
93
|
+
if (pre?.system_cpu_usage && systemDelta > 0 && cpuDelta >= 0) {
|
|
94
|
+
cores += (cpuDelta / systemDelta) * online;
|
|
95
|
+
cpuMeasured = true;
|
|
96
|
+
}
|
|
97
|
+
const mem = container.memory_stats;
|
|
98
|
+
if (typeof mem?.usage === 'number') {
|
|
99
|
+
const cache = mem.stats?.cache ?? mem.stats?.inactive_file ?? mem.stats?.total_inactive_file ?? 0;
|
|
100
|
+
memoryBytes += Math.max(0, mem.usage - cache);
|
|
101
|
+
}
|
|
102
|
+
// Em awsvpc os containers compartilham a ENI: deduplica por interface.
|
|
103
|
+
for (const [iface, counters] of Object.entries(container.networks ?? {})) {
|
|
104
|
+
const current = net.get(iface) ?? { rx: 0, tx: 0 };
|
|
105
|
+
net.set(iface, { rx: Math.max(current.rx, counters.rx_bytes ?? 0), tx: Math.max(current.tx, counters.tx_bytes ?? 0) });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!cpuMeasured && previousCpu && aggSystem > previousCpu.system) {
|
|
109
|
+
// precpu_stats vazio: usa a leitura anterior deste reporter.
|
|
110
|
+
cores = ((aggTotal - previousCpu.total) / (aggSystem - previousCpu.system)) * aggOnline;
|
|
111
|
+
cpuMeasured = cores >= 0;
|
|
112
|
+
}
|
|
113
|
+
previousCpu = { total: aggTotal, system: aggSystem };
|
|
114
|
+
if (cpuMeasured) {
|
|
115
|
+
const percent = cpuLimit ? (cores / cpuLimit) * 100 : cores * 100;
|
|
116
|
+
infra.max(r, 'cpuPercent', Math.round(percent * 100) / 100);
|
|
117
|
+
}
|
|
118
|
+
if (memoryBytes > 0)
|
|
119
|
+
infra.max(r, 'memoryMb', Math.round((memoryBytes / MB) * 100) / 100);
|
|
120
|
+
let rx = 0;
|
|
121
|
+
let tx = 0;
|
|
122
|
+
for (const counters of net.values()) {
|
|
123
|
+
rx += counters.rx;
|
|
124
|
+
tx += counters.tx;
|
|
125
|
+
}
|
|
126
|
+
if (previousNet && rx >= previousNet.rx && tx >= previousNet.tx) {
|
|
127
|
+
infra.add(r, 'networkRxBytes', rx - previousNet.rx);
|
|
128
|
+
infra.add(r, 'networkTxBytes', tx - previousNet.tx);
|
|
129
|
+
}
|
|
130
|
+
if (net.size > 0)
|
|
131
|
+
previousNet = { rx, tx };
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (core.options.debug)
|
|
135
|
+
console.warn(`[fg-tracker] startInfraReporter: ${err?.message ?? err}`);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
running = false;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const timer = als.exit(() => setInterval(() => void tick(), Math.max(1000, options.intervalMs ?? DEFAULT_INTERVAL_MS)));
|
|
142
|
+
timer.unref?.();
|
|
143
|
+
als.exit(() => void tick());
|
|
144
|
+
const stop = () => {
|
|
145
|
+
if (stopped)
|
|
146
|
+
return;
|
|
147
|
+
stopped = true;
|
|
148
|
+
clearInterval(timer);
|
|
149
|
+
unregister();
|
|
150
|
+
};
|
|
151
|
+
const unregister = core.onShutdown(stop);
|
|
152
|
+
return { stop };
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=ecs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecs.js","sourceRoot":"","sources":["../../src/infra/ecs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TrackerCore } from '../tracker.js';
|
|
2
|
+
/** Contexto mínimo da Lambda (tipo estrutural; sem `@types/aws-lambda`). */
|
|
3
|
+
export interface LambdaContextLike {
|
|
4
|
+
awsRequestId?: string;
|
|
5
|
+
functionName?: string;
|
|
6
|
+
invokedFunctionArn?: string;
|
|
7
|
+
getRemainingTimeInMillis?: () => number;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export type LambdaHandler<E = unknown, R = unknown, C extends LambdaContextLike = LambdaContextLike> = (event: E, context: C) => R | Promise<R>;
|
|
11
|
+
export interface WrapLambdaOptions {
|
|
12
|
+
/** Tempo máximo esperando o `flush()` no fim da invocação. Default 1000 ms. */
|
|
13
|
+
flushTimeoutMs?: number;
|
|
14
|
+
/** Cria um span raiz `custom` por invocação (spans de AWS/db/fetch passam a formar um trace). Default `true`. */
|
|
15
|
+
span?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Caminho do executável da camada `fg-tracker-lambda-extension`. */
|
|
18
|
+
export declare const LAMBDA_EXTENSION_PATH = "/opt/extensions/fg-tracker-extension";
|
|
19
|
+
export declare function hasLambdaExtension(): boolean;
|
|
20
|
+
export declare function flushWithTimeout(core: TrackerCore, timeoutMs: number): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Envolve um handler async da Lambda. Sem a extensão do FG Tracker, aguarda o `flush()` (com timeout
|
|
23
|
+
* curto) ao fim de cada invocação para não perder spans no congelamento do ambiente; com a extensão,
|
|
24
|
+
* a fila sobrevive ao congelamento e é enviada no SIGTERM do encerramento.
|
|
25
|
+
*/
|
|
26
|
+
export declare function wrapLambdaHandler<E, R, C extends LambdaContextLike>(core: TrackerCore, handler: LambdaHandler<E, R, C>, options?: WrapLambdaOptions): LambdaHandler<E, R, C>;
|
|
27
|
+
//# sourceMappingURL=lambda.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda.d.ts","sourceRoot":"","sources":["../../src/infra/lambda.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,SAAS,iBAAiB,GAAG,iBAAiB,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhJ,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iHAAiH;IACjH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,yCAAyC,CAAC;AAI5E,wBAAgB,kBAAkB,IAAI,OAAO,CAS5C;AAgBD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW1F;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,iBAAiB,EACjE,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC/B,OAAO,GAAE,iBAAsB,GAC9B,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAiCxB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
/** Caminho do executável da camada `fg-tracker-lambda-extension`. */
|
|
3
|
+
export const LAMBDA_EXTENSION_PATH = '/opt/extensions/fg-tracker-extension';
|
|
4
|
+
let extensionDetected;
|
|
5
|
+
export function hasLambdaExtension() {
|
|
6
|
+
if (extensionDetected === undefined) {
|
|
7
|
+
try {
|
|
8
|
+
extensionDetected = existsSync(LAMBDA_EXTENSION_PATH);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
extensionDetected = false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return extensionDetected;
|
|
15
|
+
}
|
|
16
|
+
let sigtermInstalled = false;
|
|
17
|
+
/**
|
|
18
|
+
* Com a extensão registrada, a Lambda envia SIGTERM ao runtime no encerramento do ambiente:
|
|
19
|
+
* é a última chance de enviar a fila. Só instala quando ninguém mais trata SIGTERM.
|
|
20
|
+
*/
|
|
21
|
+
function installSigtermFlush(core, timeoutMs) {
|
|
22
|
+
if (sigtermInstalled || process.listenerCount('SIGTERM') > 0)
|
|
23
|
+
return;
|
|
24
|
+
sigtermInstalled = true;
|
|
25
|
+
process.once('SIGTERM', () => {
|
|
26
|
+
void flushWithTimeout(core, timeoutMs).finally(() => process.exit(0));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export async function flushWithTimeout(core, timeoutMs) {
|
|
30
|
+
let timer;
|
|
31
|
+
const timeout = new Promise((resolve) => {
|
|
32
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
33
|
+
timer.unref?.();
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
await Promise.race([core.flush(true).catch(() => undefined), timeout]);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
if (timer)
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
let coldStart = true;
|
|
44
|
+
/**
|
|
45
|
+
* Envolve um handler async da Lambda. Sem a extensão do FG Tracker, aguarda o `flush()` (com timeout
|
|
46
|
+
* curto) ao fim de cada invocação para não perder spans no congelamento do ambiente; com a extensão,
|
|
47
|
+
* a fila sobrevive ao congelamento e é enviada no SIGTERM do encerramento.
|
|
48
|
+
*/
|
|
49
|
+
export function wrapLambdaHandler(core, handler, options = {}) {
|
|
50
|
+
const flushTimeoutMs = Math.max(50, options.flushTimeoutMs ?? 1000);
|
|
51
|
+
const withSpan = options.span ?? true;
|
|
52
|
+
return async function fgTrackerLambda(event, context) {
|
|
53
|
+
if (!core.enabled)
|
|
54
|
+
return handler(event, context);
|
|
55
|
+
const extension = hasLambdaExtension();
|
|
56
|
+
if (extension)
|
|
57
|
+
installSigtermFlush(core, flushTimeoutMs);
|
|
58
|
+
const functionName = context?.functionName ?? process.env.AWS_LAMBDA_FUNCTION_NAME ?? 'lambda';
|
|
59
|
+
const span = withSpan
|
|
60
|
+
? core.startSpan('custom', `lambda ${functionName}`, {
|
|
61
|
+
'faas.name': functionName,
|
|
62
|
+
'faas.coldStart': coldStart,
|
|
63
|
+
...(context?.awsRequestId ? { 'faas.requestId': context.awsRequestId } : {}),
|
|
64
|
+
...(context?.invokedFunctionArn ? { 'aws.resourceArn': context.invokedFunctionArn } : {}),
|
|
65
|
+
...(process.env.AWS_REGION ? { 'aws.region': process.env.AWS_REGION } : {}),
|
|
66
|
+
}, null)
|
|
67
|
+
: null;
|
|
68
|
+
coldStart = false;
|
|
69
|
+
try {
|
|
70
|
+
return await (span ? core.runInSpan(span, () => handler(event, context)) : handler(event, context));
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
span?.setError(err);
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
span?.end();
|
|
78
|
+
if (!extension)
|
|
79
|
+
await flushWithTimeout(core, flushTimeoutMs);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=lambda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../src/infra/lambda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAqBrC,qEAAqE;AACrE,MAAM,CAAC,MAAM,qBAAqB,GAAG,sCAAsC,CAAC;AAE5E,IAAI,iBAAsC,CAAC;AAE3C,MAAM,UAAU,kBAAkB;IAChC,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,iBAAiB,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B;;;GAGG;AACH,SAAS,mBAAmB,CAAC,IAAiB,EAAE,SAAiB;IAC/D,IAAI,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO;IACrE,gBAAgB,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;QAC3B,KAAK,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAiB,EAAE,SAAiB;IACzE,IAAI,KAAgD,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC5C,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACzE,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,IAAI,SAAS,GAAG,IAAI,CAAC;AAErB;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAiB,EACjB,OAA+B,EAC/B,UAA6B,EAAE;IAE/B,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC;IACtC,OAAO,KAAK,UAAU,eAAe,CAAC,KAAQ,EAAE,OAAU;QACxD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;QACvC,IAAI,SAAS;YAAE,mBAAmB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,QAAQ,CAAC;QAC/F,MAAM,IAAI,GAAG,QAAQ;YACnB,CAAC,CAAC,IAAI,CAAC,SAAS,CACZ,QAAQ,EACR,UAAU,YAAY,EAAE,EACxB;gBACE,WAAW,EAAE,YAAY;gBACzB,gBAAgB,EAAE,SAAS;gBAC3B,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzF,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E,EACD,IAAI,CACL;YACH,CAAC,CAAC,IAAI,CAAC;QACT,SAAS,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QACtG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpB,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,IAAI,EAAE,GAAG,EAAE,CAAC;YACZ,IAAI,CAAC,SAAS;gBAAE,MAAM,gBAAgB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/tracker.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type SpanContext } from './context.js';
|
|
2
|
+
import { InfraAggregator } from './infra/aggregator.js';
|
|
2
3
|
import type { ActiveSpan, PropagationTargets, SamplingContext, Span, SpanError, SpanKind, TrackerOptions, UserRef } from './types.js';
|
|
3
4
|
export interface ResolvedOptions {
|
|
4
5
|
apiKey: string;
|
|
@@ -19,6 +20,8 @@ export interface ResolvedOptions {
|
|
|
19
20
|
enabled: boolean;
|
|
20
21
|
debug: boolean;
|
|
21
22
|
fetch: typeof globalThis.fetch;
|
|
23
|
+
infraEnabled: boolean;
|
|
24
|
+
infraIdleIntervalMs: number;
|
|
22
25
|
}
|
|
23
26
|
/** Release detectada do ambiente (CONTRATO.md §15): `${serviceName}@${sha}` para SHAs de CI/hosting. */
|
|
24
27
|
export declare function detectRelease(serviceName: string | undefined, env?: NodeJS.ProcessEnv): string | undefined;
|
|
@@ -40,6 +43,19 @@ export declare class TrackerCore {
|
|
|
40
43
|
private stopped;
|
|
41
44
|
/** Spans ainda abertos, por spanId — permite `currentSpan()` a partir do contexto assíncrono. */
|
|
42
45
|
private readonly active;
|
|
46
|
+
/** Agregados de infra (nunca amostrados); `null` quando `infra.enabled === false`. */
|
|
47
|
+
readonly infra: InfraAggregator | null;
|
|
48
|
+
/** Agregados já fechados aguardando envio (retentativa após falha). */
|
|
49
|
+
private infraPending;
|
|
50
|
+
/** A janela de infra venceu: o próximo flush fecha o agregador e envia junto dos spans. */
|
|
51
|
+
private infraDue;
|
|
52
|
+
private infraTimer;
|
|
53
|
+
private infraTimerMs;
|
|
54
|
+
/** Última resposta da ingestão: há sessão de observação ativa no painel (§27.4). */
|
|
55
|
+
live: boolean;
|
|
56
|
+
liveIntervalMs: number;
|
|
57
|
+
/** Callbacks de encerramento (reporters, timers de pool). */
|
|
58
|
+
private readonly disposers;
|
|
43
59
|
constructor(options: TrackerOptions);
|
|
44
60
|
get enabled(): boolean;
|
|
45
61
|
currentContext(): SpanContext | undefined;
|
|
@@ -65,8 +81,24 @@ export declare class TrackerCore {
|
|
|
65
81
|
/** Executa `fn` com `span` como contexto pai das operações internas. */
|
|
66
82
|
runInSpan<T>(span: ActiveSpanImpl, fn: () => T): T;
|
|
67
83
|
enqueue(span: Span): void;
|
|
68
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Envia a fila. `includeInfra` (default `true`) também fecha a janela de infra e envia os
|
|
86
|
+
* agregados no mesmo lote; o timer de spans chama com `false` para respeitar a janela de 60 s/5 s.
|
|
87
|
+
*/
|
|
88
|
+
flush(includeInfra?: boolean): Promise<void>;
|
|
89
|
+
private hasInfraToSend;
|
|
69
90
|
private doFlush;
|
|
91
|
+
private pushInfraPending;
|
|
92
|
+
/** Mesma política dos spans: acima do limite, descarta os agregados mais antigos. */
|
|
93
|
+
private trimInfraPending;
|
|
94
|
+
/** Intervalo atual da janela de infra: `liveIntervalMs` com o painel aberto, senão `idleIntervalMs`. */
|
|
95
|
+
infraIntervalMs(): number;
|
|
96
|
+
/** Arma (ou rearma, se o intervalo mudou) o timer que fecha a janela de infra. */
|
|
97
|
+
ensureInfraTimer(): void;
|
|
98
|
+
/** Lê `live`/`liveIntervalMs` da resposta da ingestão (piggyback, sem chamada extra). */
|
|
99
|
+
private readLiveFlag;
|
|
100
|
+
/** Registra uma função chamada no `shutdown()` (timers de reporters/pools). */
|
|
101
|
+
onShutdown(dispose: () => void): () => void;
|
|
70
102
|
/** POST autenticado na API (ingest, check-ins, releases). Devolve a resposta ou `null` em falha de rede. */
|
|
71
103
|
post(path: string, body: unknown, timeoutMs?: number): Promise<Response | null>;
|
|
72
104
|
private send;
|
package/dist/tracker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAqE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAInH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAqE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAInH,OAAO,EAAE,eAAe,EAAuB,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAatI,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,GAAG,OAAO,CAAC,GAAG,SAAS,CAAC;IAC5E,kBAAkB,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACxC,YAAY,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAClC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACtD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAaD,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAWvH;AAED,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAE1F;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAwBvE;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAU9E;AAED;;;;GAIG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,iGAAiG;IACjG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IACvC,uEAAuE;IACvE,OAAO,CAAC,YAAY,CAAwB;IAC5C,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,YAAY,CAAK;IACzB,oFAAoF;IACpF,IAAI,UAAS;IACb,cAAc,SAAkC;IAChD,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;gBAEvC,OAAO,EAAE,cAAc;IAiBnC,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,cAAc,IAAI,WAAW,GAAG,SAAS;IAIzC,0FAA0F;IAC1F,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,cAAc;IAY9H,OAAO,CAAC,QAAQ;IAQhB,gGAAgG;IAChG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO;IAgBjD;;;;OAIG;IACH,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,cAAc;IASvH,2EAA2E;IAC3E,WAAW,IAAI,cAAc,GAAG,SAAS;IAKzC,yEAAyE;IACzE,QAAQ,IAAI,cAAc,GAAG,SAAS;IAYtC,sDAAsD;IACtD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAKtC,0FAA0F;IAC1F,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,GAAG,IAAI;IAoBrD,wEAAwE;IACxE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAIlD,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAUzB;;;OAGG;IACG,KAAK,CAAC,YAAY,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB/C,OAAO,CAAC,cAAc;YAIR,OAAO;IAyBrB,OAAO,CAAC,gBAAgB;IAKxB,qFAAqF;IACrF,OAAO,CAAC,gBAAgB;IAMxB,wGAAwG;IACxG,eAAe,IAAI,MAAM;IAIzB,kFAAkF;IAClF,gBAAgB,IAAI,IAAI;IAgBxB,yFAAyF;YAC3E,YAAY;IAmB1B,+EAA+E;IAC/E,UAAU,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAK3C,4GAA4G;IACtG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;YAcvE,IAAI;IAyClB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAoBhC;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM5E;AAED,qBAAa,cAAe,YAAW,UAAU;IAY7C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IACpC,QAAQ,CAAC,IAAI,EAAE,QAAQ;IAGvB,QAAQ,CAAC,OAAO,EAAE,OAAO;IAlB3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAO;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,KAAK,CAAS;gBAGH,IAAI,EAAE,WAAW,EACzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,IAAI,EAAE,QAAQ,EACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1B,OAAO,GAAE,OAAc;IAQlC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAI/C,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAI5B,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI;IAOnC,GAAG,IAAI,IAAI;CAqBZ"}
|
package/dist/tracker.js
CHANGED
|
@@ -3,10 +3,17 @@ import { als, formatTraceparent, newSpanId, newTraceId, TRACEPARENT_HEADER } fro
|
|
|
3
3
|
import { toSpanError } from './normalize.js';
|
|
4
4
|
import { DEFAULT_SCRUB_FIELDS, matchesAny, scrubAttributes } from './scrub.js';
|
|
5
5
|
import { API_KEY_HEADER, DEFAULT_ENDPOINT, readEnv } from './constants.js';
|
|
6
|
+
import { InfraAggregator } from './infra/aggregator.js';
|
|
6
7
|
const DEFAULT_FLUSH_INTERVAL_MS = 2000;
|
|
7
8
|
const DEFAULT_MAX_BATCH = 200;
|
|
8
9
|
const DEFAULT_MAX_QUEUE = 5000;
|
|
9
10
|
const MAX_SPANS_PER_REQUEST = 1000;
|
|
11
|
+
/** Limites de agregados de infra (CONTRATO.md §27.4: ≤ 500 por requisição). */
|
|
12
|
+
const MAX_INFRA_PER_REQUEST = 500;
|
|
13
|
+
const MAX_INFRA_PENDING = 2000;
|
|
14
|
+
const DEFAULT_INFRA_IDLE_INTERVAL_MS = 60_000;
|
|
15
|
+
const DEFAULT_INFRA_LIVE_INTERVAL_MS = 5_000;
|
|
16
|
+
const MIN_INFRA_INTERVAL_MS = 1_000;
|
|
10
17
|
const RELEASE_ENV_VARS = [
|
|
11
18
|
'VERCEL_GIT_COMMIT_SHA',
|
|
12
19
|
'RAILWAY_GIT_COMMIT_SHA',
|
|
@@ -56,6 +63,8 @@ export function resolveOptions(options) {
|
|
|
56
63
|
enabled: (options.enabled ?? true) && Boolean(options.apiKey),
|
|
57
64
|
debug: options.debug ?? false,
|
|
58
65
|
fetch: options.fetch ?? globalThis.fetch,
|
|
66
|
+
infraEnabled: options.infra?.enabled ?? true,
|
|
67
|
+
infraIdleIntervalMs: Math.max(MIN_INFRA_INTERVAL_MS, options.infra?.idleIntervalMs ?? DEFAULT_INFRA_IDLE_INTERVAL_MS),
|
|
59
68
|
};
|
|
60
69
|
}
|
|
61
70
|
/** Decide se um destino recebe o `traceparent` (CONTRATO.md §16). */
|
|
@@ -89,8 +98,23 @@ export class TrackerCore {
|
|
|
89
98
|
stopped = false;
|
|
90
99
|
/** Spans ainda abertos, por spanId — permite `currentSpan()` a partir do contexto assíncrono. */
|
|
91
100
|
active = new Map();
|
|
101
|
+
/** Agregados de infra (nunca amostrados); `null` quando `infra.enabled === false`. */
|
|
102
|
+
infra;
|
|
103
|
+
/** Agregados já fechados aguardando envio (retentativa após falha). */
|
|
104
|
+
infraPending = [];
|
|
105
|
+
/** A janela de infra venceu: o próximo flush fecha o agregador e envia junto dos spans. */
|
|
106
|
+
infraDue = false;
|
|
107
|
+
infraTimer = null;
|
|
108
|
+
infraTimerMs = 0;
|
|
109
|
+
/** Última resposta da ingestão: há sessão de observação ativa no painel (§27.4). */
|
|
110
|
+
live = false;
|
|
111
|
+
liveIntervalMs = DEFAULT_INFRA_LIVE_INTERVAL_MS;
|
|
112
|
+
/** Callbacks de encerramento (reporters, timers de pool). */
|
|
113
|
+
disposers = new Set();
|
|
92
114
|
constructor(options) {
|
|
93
115
|
this.options = resolveOptions(options);
|
|
116
|
+
this.infra =
|
|
117
|
+
this.options.enabled && this.options.infraEnabled ? new InfraAggregator({ onRecord: () => this.ensureInfraTimer() }) : null;
|
|
94
118
|
if (!this.options.enabled) {
|
|
95
119
|
if (!options.apiKey && (options.enabled ?? true)) {
|
|
96
120
|
console.warn('[fg-tracker] apiKey ausente: tracker desabilitado.');
|
|
@@ -98,7 +122,7 @@ export class TrackerCore {
|
|
|
98
122
|
return;
|
|
99
123
|
}
|
|
100
124
|
this.timer = setInterval(() => {
|
|
101
|
-
void this.flush();
|
|
125
|
+
void this.flush(false);
|
|
102
126
|
}, this.options.flushIntervalMs);
|
|
103
127
|
// Não segura o processo vivo só por causa do timer.
|
|
104
128
|
if (typeof this.timer === 'object' && this.timer && 'unref' in this.timer)
|
|
@@ -226,34 +250,123 @@ export class TrackerCore {
|
|
|
226
250
|
this.queue.splice(0, this.queue.length - this.options.maxQueueSize);
|
|
227
251
|
}
|
|
228
252
|
if (this.queue.length >= this.options.maxBatchSize)
|
|
229
|
-
void this.flush();
|
|
253
|
+
void this.flush(false);
|
|
230
254
|
}
|
|
231
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Envia a fila. `includeInfra` (default `true`) também fecha a janela de infra e envia os
|
|
257
|
+
* agregados no mesmo lote; o timer de spans chama com `false` para respeitar a janela de 60 s/5 s.
|
|
258
|
+
*/
|
|
259
|
+
async flush(includeInfra = true) {
|
|
232
260
|
if (!this.options.enabled)
|
|
233
261
|
return;
|
|
234
|
-
if (this.
|
|
235
|
-
|
|
236
|
-
if (this.
|
|
262
|
+
if (includeInfra && this.infra)
|
|
263
|
+
this.infraDue = true;
|
|
264
|
+
if (this.flushing) {
|
|
265
|
+
// Um envio em andamento pode já ter passado da checagem de infra: encadeia outro.
|
|
266
|
+
return includeInfra ? this.flushing.then(() => (this.hasInfraToSend() ? this.flush(true) : undefined)) : this.flushing;
|
|
267
|
+
}
|
|
268
|
+
if (this.queue.length === 0 && !this.hasInfraToSend()) {
|
|
269
|
+
this.infraDue = false;
|
|
237
270
|
return;
|
|
271
|
+
}
|
|
238
272
|
this.flushing = this.doFlush().finally(() => {
|
|
239
273
|
this.flushing = null;
|
|
240
274
|
});
|
|
241
275
|
return this.flushing;
|
|
242
276
|
}
|
|
277
|
+
hasInfraToSend() {
|
|
278
|
+
return this.infraPending.length > 0 || (this.infraDue && Boolean(this.infra?.hasData()));
|
|
279
|
+
}
|
|
243
280
|
async doFlush() {
|
|
244
|
-
|
|
281
|
+
for (;;) {
|
|
282
|
+
if (this.infraDue && this.infra) {
|
|
283
|
+
this.infraDue = false;
|
|
284
|
+
if (this.infra.hasData())
|
|
285
|
+
this.pushInfraPending(this.infra.drain());
|
|
286
|
+
}
|
|
245
287
|
const batch = this.queue.splice(0, MAX_SPANS_PER_REQUEST);
|
|
246
|
-
const
|
|
288
|
+
const infra = this.infraPending.splice(0, MAX_INFRA_PER_REQUEST);
|
|
289
|
+
if (batch.length === 0 && infra.length === 0)
|
|
290
|
+
return;
|
|
291
|
+
const ok = await this.send(batch, infra);
|
|
247
292
|
if (!ok) {
|
|
248
293
|
// Devolve para a frente da fila e tenta no próximo flush.
|
|
249
294
|
this.queue.unshift(...batch);
|
|
250
295
|
if (this.queue.length > this.options.maxQueueSize) {
|
|
251
296
|
this.queue.splice(0, this.queue.length - this.options.maxQueueSize);
|
|
252
297
|
}
|
|
298
|
+
if (infra.length > 0) {
|
|
299
|
+
this.infraPending.unshift(...infra);
|
|
300
|
+
this.trimInfraPending();
|
|
301
|
+
}
|
|
253
302
|
return;
|
|
254
303
|
}
|
|
255
304
|
}
|
|
256
305
|
}
|
|
306
|
+
pushInfraPending(items) {
|
|
307
|
+
this.infraPending.push(...items);
|
|
308
|
+
this.trimInfraPending();
|
|
309
|
+
}
|
|
310
|
+
/** Mesma política dos spans: acima do limite, descarta os agregados mais antigos. */
|
|
311
|
+
trimInfraPending() {
|
|
312
|
+
if (this.infraPending.length > MAX_INFRA_PENDING) {
|
|
313
|
+
this.infraPending.splice(0, this.infraPending.length - MAX_INFRA_PENDING);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/** Intervalo atual da janela de infra: `liveIntervalMs` com o painel aberto, senão `idleIntervalMs`. */
|
|
317
|
+
infraIntervalMs() {
|
|
318
|
+
return this.live ? this.liveIntervalMs : this.options.infraIdleIntervalMs;
|
|
319
|
+
}
|
|
320
|
+
/** Arma (ou rearma, se o intervalo mudou) o timer que fecha a janela de infra. */
|
|
321
|
+
ensureInfraTimer() {
|
|
322
|
+
if (!this.infra || !this.enabled)
|
|
323
|
+
return;
|
|
324
|
+
const interval = this.infraIntervalMs();
|
|
325
|
+
if (this.infraTimer && this.infraTimerMs === interval)
|
|
326
|
+
return;
|
|
327
|
+
if (this.infraTimer)
|
|
328
|
+
clearTimeout(this.infraTimer);
|
|
329
|
+
this.infraTimerMs = interval;
|
|
330
|
+
this.infraTimer = setTimeout(() => {
|
|
331
|
+
this.infraTimer = null;
|
|
332
|
+
void this.flush(true).finally(() => {
|
|
333
|
+
// Com painel aberto mantém o ritmo mesmo sem dados; ocioso, só rearma quando houver algo.
|
|
334
|
+
if (this.enabled && (this.live || this.infra?.hasData() || this.infraPending.length > 0))
|
|
335
|
+
this.ensureInfraTimer();
|
|
336
|
+
});
|
|
337
|
+
}, interval);
|
|
338
|
+
if (typeof this.infraTimer === 'object' && this.infraTimer && 'unref' in this.infraTimer)
|
|
339
|
+
this.infraTimer.unref();
|
|
340
|
+
}
|
|
341
|
+
/** Lê `live`/`liveIntervalMs` da resposta da ingestão (piggyback, sem chamada extra). */
|
|
342
|
+
async readLiveFlag(res) {
|
|
343
|
+
if (!this.infra || res.status === 204 || typeof res.json !== 'function')
|
|
344
|
+
return;
|
|
345
|
+
let body;
|
|
346
|
+
try {
|
|
347
|
+
body = await res.json();
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (!body || typeof body !== 'object')
|
|
353
|
+
return;
|
|
354
|
+
const { live, liveIntervalMs } = body;
|
|
355
|
+
if (typeof live !== 'boolean')
|
|
356
|
+
return;
|
|
357
|
+
const previousInterval = this.infraIntervalMs();
|
|
358
|
+
this.live = live;
|
|
359
|
+
if (typeof liveIntervalMs === 'number' && Number.isFinite(liveIntervalMs)) {
|
|
360
|
+
this.liveIntervalMs = Math.max(MIN_INFRA_INTERVAL_MS, liveIntervalMs);
|
|
361
|
+
}
|
|
362
|
+
if (this.infraIntervalMs() !== previousInterval || (live && !this.infraTimer))
|
|
363
|
+
this.ensureInfraTimer();
|
|
364
|
+
}
|
|
365
|
+
/** Registra uma função chamada no `shutdown()` (timers de reporters/pools). */
|
|
366
|
+
onShutdown(dispose) {
|
|
367
|
+
this.disposers.add(dispose);
|
|
368
|
+
return () => this.disposers.delete(dispose);
|
|
369
|
+
}
|
|
257
370
|
/** POST autenticado na API (ingest, check-ins, releases). Devolve a resposta ou `null` em falha de rede. */
|
|
258
371
|
async post(path, body, timeoutMs = 10_000) {
|
|
259
372
|
try {
|
|
@@ -269,7 +382,7 @@ export class TrackerCore {
|
|
|
269
382
|
return null;
|
|
270
383
|
}
|
|
271
384
|
}
|
|
272
|
-
async send(spans) {
|
|
385
|
+
async send(spans, infra = []) {
|
|
273
386
|
const byTrace = new Map();
|
|
274
387
|
for (const span of spans) {
|
|
275
388
|
const { traceId, ...rest } = span;
|
|
@@ -280,7 +393,9 @@ export class TrackerCore {
|
|
|
280
393
|
}
|
|
281
394
|
list.push(rest);
|
|
282
395
|
}
|
|
283
|
-
const
|
|
396
|
+
const traces = [...byTrace].map(([traceId, s]) => ({ traceId, spans: s }));
|
|
397
|
+
// Sem agregados o body continua idêntico ao das versões anteriores.
|
|
398
|
+
const body = JSON.stringify(infra.length > 0 ? { traces, infra } : { traces });
|
|
284
399
|
try {
|
|
285
400
|
const res = await this.options.fetch(`${this.options.endpoint}/v1/ingest`, {
|
|
286
401
|
method: 'POST',
|
|
@@ -298,8 +413,10 @@ export class TrackerCore {
|
|
|
298
413
|
if (this.options.debug)
|
|
299
414
|
console.info('[fg-tracker] envio restabelecido.');
|
|
300
415
|
}
|
|
301
|
-
|
|
302
|
-
|
|
416
|
+
await this.readLiveFlag(res);
|
|
417
|
+
if (this.options.debug) {
|
|
418
|
+
console.info(`[fg-tracker] enviados ${spans.length} spans em ${byTrace.size} traces${infra.length > 0 ? ` e ${infra.length} agregados de infra` : ''}.`);
|
|
419
|
+
}
|
|
303
420
|
return true;
|
|
304
421
|
}
|
|
305
422
|
catch (err) {
|
|
@@ -318,7 +435,20 @@ export class TrackerCore {
|
|
|
318
435
|
clearInterval(this.timer);
|
|
319
436
|
this.timer = null;
|
|
320
437
|
}
|
|
321
|
-
|
|
438
|
+
if (this.infraTimer) {
|
|
439
|
+
clearTimeout(this.infraTimer);
|
|
440
|
+
this.infraTimer = null;
|
|
441
|
+
}
|
|
442
|
+
for (const dispose of this.disposers) {
|
|
443
|
+
try {
|
|
444
|
+
dispose();
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
/* encerramento nunca lança */
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
this.disposers.clear();
|
|
451
|
+
await this.flush(true);
|
|
322
452
|
this.stopped = true;
|
|
323
453
|
}
|
|
324
454
|
}
|