fg-tracker-sdk 0.6.0 → 0.8.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 +17 -0
- package/README.md +98 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +2 -2
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +13 -3
- package/dist/database.js.map +1 -1
- package/dist/event-loop.d.ts +61 -0
- package/dist/event-loop.d.ts.map +1 -0
- package/dist/event-loop.js +115 -0
- package/dist/event-loop.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/measure.d.ts +32 -0
- package/dist/measure.d.ts.map +1 -0
- package/dist/measure.js +57 -0
- package/dist/measure.js.map +1 -0
- package/dist/monitors.d.ts.map +1 -1
- package/dist/monitors.js +10 -4
- package/dist/monitors.js.map +1 -1
- package/dist/nest.d.ts +53 -0
- package/dist/nest.d.ts.map +1 -0
- package/dist/nest.js +128 -0
- package/dist/nest.js.map +1 -0
- package/dist/node-http.d.ts +7 -0
- package/dist/node-http.d.ts.map +1 -0
- package/dist/node-http.js +115 -0
- package/dist/node-http.js.map +1 -0
- package/dist/pool-wait.d.ts +25 -0
- package/dist/pool-wait.d.ts.map +1 -0
- package/dist/pool-wait.js +58 -0
- package/dist/pool-wait.js.map +1 -0
- package/dist/tracker.d.ts +36 -0
- package/dist/tracker.d.ts.map +1 -1
- package/dist/tracker.js +74 -1
- package/dist/tracker.js.map +1 -1
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog — fg-tracker-sdk
|
|
2
2
|
|
|
3
|
+
## 0.8.0 — 2026-09-18
|
|
4
|
+
|
|
5
|
+
A 0.7.0 foi publicada antes destes itens entrarem na `main`. O workflow de
|
|
6
|
+
publicação dispara em mudança de versão, e a versão já estava em 0.7.0 quando
|
|
7
|
+
eles foram mergeados, então ficaram sem chegar ao npm. Esta versão os leva.
|
|
8
|
+
|
|
9
|
+
- **Espera de conexão separada do tempo de execução** (`db.poolWaitMs` nos spans `db.query` do `postgres`/porsager). O span envolve a chamada ao driver, e a chamada inclui a fila do pool: uma query trivial que aparece com 2 s não dizia se o SQL é lento ou se o pool encheu — causas com soluções opostas. O driver marca `query.active = true` quando a conexão assume a query; interceptar essa atribuição dá o instante exato da aquisição, sem polling nem estimativa. Só é gravado acima de 1 ms. Num pool frio a espera inclui estabelecer a conexão (TCP, TLS, autenticação), que também é esperar por conexão. Se uma versão futura do driver mudar o campo, perde-se a medida e nunca a query.
|
|
10
|
+
- **Check-in de job carrega o trace e a release da execução.** Quando o job roda dentro de um span (por exemplo sob `wrapLambda`), o `traceId` vai junto: no histórico do cron, uma falha deixa de ser um quadradinho vermelho e vira o mesmo caminho de investigação de um endpoint — waterfall, spans e logs daquela rodada. Fora de um trace, nenhum `traceId` é inventado.
|
|
11
|
+
|
|
12
|
+
## 0.7.0 — 2026-09-18
|
|
13
|
+
|
|
14
|
+
- **Saída HTTP de `node:http`/`node:https` vira span `http.client`** (`instrumentNodeHttp`, default `true`). O `fetch` instrumentado só cobre quem chama `fetch`; o resto do ecossistema fala pelo módulo `http` — AWS SDK v3 (`@smithy/node-http-handler`), axios, got, node-fetch 2, gaxios (`google-auth-library`) e web-push. Sem isso, essas chamadas viravam tempo sem span nenhum, indistinguível de CPU travada. Usa `diagnostics_channel` em vez de monkeypatch: nada é substituído, outra biblioteca instrumentando o mesmo módulo não conflita e a ordem de import não importa. Mesmas regras do fetch (span só dentro de um trace, `propagateTraceTo`, header já definido preservado, endpoint do coletor ignorado). `shutdown()` cancela as inscrições. Chamadas feitas direto pela API do `undici` não são cobertas.
|
|
15
|
+
- **Atraso do event loop por requisição** (`measureEventLoopLag`, default `true`): grava `eventLoop.maxLagMs` e `eventLoop.blockedMs` no span raiz quando o loop trava acima de `eventLoopLagThresholdMs` (default 50 ms). É o que separa "o processo parou" de "estávamos esperando alguém lá fora" num trecho sem span. A amostragem só roda enquanto há requisição aberta: não gasta nada com processo ocioso e o congelamento do Lambda entre invocações não vira falso positivo.
|
|
16
|
+
- **`tracker.measure(name, fn, options?)`**: mede um trecho e só cria o span acima de `autoSpanMinDurationMs` (default 5 ms) ou em erro. Preserva função síncrona como síncrona. O span nasce depois do trecho terminar, então não é pai dos spans criados dentro dele — use `tracker.span()` onde o aninhamento importa.
|
|
17
|
+
- **`tracker.instrumentNest(container, options?)`**: envolve os métodos de providers e controllers de uma aplicação NestJS a partir de `app.get(ModulesContainer)`, sem decorar nada. Lê o container estruturalmente, então o SDK não importa `@nestjs/core` nem ganha peer dependency. Pula providers do próprio framework (que o Nest re-registra em todo módulo) e hooks de ciclo de vida.
|
|
18
|
+
- Novas opções: `instrumentNodeHttp`, `measureEventLoopLag`, `eventLoopLagThresholdMs`, `autoSpanMinDurationMs`. Novos exports de tipo: `MeasureOptions`, `NestContainerLike`, `NestInstrumentationOptions`. Sem novas dependências de runtime.
|
|
19
|
+
|
|
3
20
|
## 0.5.0 — 2026-09-15
|
|
4
21
|
|
|
5
22
|
- **Agregados de infraestrutura** (CONTRATO.md §27.4): o tracker agrega em processo por recurso e envia `infra[]` no mesmo `POST /v1/ingest` dos spans. Contadores nunca são amostrados (independem de `tracesSampleRate`, `tracesSampler` e `beforeSend`). Janela de 60 s (`infra.idleIntervalMs`) ou `liveIntervalMs` enquanto a resposta da ingestão trouxer `live: true`. Processo só com infra envia `{ traces: [], infra }`; sem agregados o body é idêntico ao da 0.4.
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ pnpm add fg-tracker-sdk # publicado no npm
|
|
|
14
14
|
|
|
15
15
|
## Endpoint
|
|
16
16
|
|
|
17
|
-
O default de `endpoint` é `http://localhost:4050` (constante `DEFAULT_ENDPOINT`, API local do monorepo). Em produção passe a URL da API mostrada no painel em **Conectar** (por exemplo via `FG_TRACKER_URL`). O
|
|
17
|
+
O default de `endpoint` é `http://localhost:4050` (constante `DEFAULT_ENDPOINT`, API local do monorepo). Em produção passe a URL da API mostrada no painel em **Conectar** (por exemplo via `FG_TRACKER_URL`). O endereço de produção da API é `https://tracker-api.fortground.com.br` (o antigo `track-api.fortground.com.br` continua respondendo).
|
|
18
18
|
|
|
19
19
|
## API
|
|
20
20
|
|
|
@@ -50,6 +50,13 @@ await tracker.flush(); await tracker.shutdown();
|
|
|
50
50
|
| `environment` | detectado | `FG_TRACKER_ENV`, `APP_ENV` ou `NODE_ENV`; `false` desliga |
|
|
51
51
|
| `propagateTraceTo` | `true` | destinos que recebem `traceparent` no fetch instrumentado (`true`, lista de hosts/prefixos/RegExp ou `false`) |
|
|
52
52
|
| `instrumentGlobalFetch` | `false` | substitui `globalThis.fetch` pelo fetch instrumentado (provedores externos viram spans) |
|
|
53
|
+
| `instrumentNodeHttp` | `true` | spans `http.client` para a saída de `node:http`/`node:https` (AWS SDK, axios, got, node-fetch 2, gaxios, web-push) |
|
|
54
|
+
<<<<<<< HEAD
|
|
55
|
+
| `autoSpanMinDurationMs` | `5` | duração mínima para um trecho medido com `measure`/`instrumentNest` virar span |
|
|
56
|
+
=======
|
|
57
|
+
| `measureEventLoopLag` | `true` | mede o atraso do event loop na requisição e grava `eventLoop.maxLagMs`/`eventLoop.blockedMs` no span raiz quando o loop trava |
|
|
58
|
+
| `eventLoopLagThresholdMs` | `50` | atraso mínimo para virar atributo |
|
|
59
|
+
>>>>>>> origin/main
|
|
53
60
|
| `captureGlobalErrors` | `false` | `uncaughtExceptionMonitor` + `unhandledRejection` viram spans com erro |
|
|
54
61
|
| `tracesSampleRate` | `1` | fração de traces enviados (decidida na raiz; filhos seguem; `traceparent` sai com `-00` quando não amostrado) |
|
|
55
62
|
| `tracesSampler` | — | `(ctx: { kind, name, attributes, parentSampled? }) => taxa` por operação (ex.: `0` para `GET /health`) |
|
|
@@ -152,6 +159,16 @@ tracker.instrumentPg(pool);
|
|
|
152
159
|
|
|
153
160
|
Se você usa drizzle/kysely/knex sobre `pg.Pool`, instrumente o pool antes de passá-lo ao ORM.
|
|
154
161
|
|
|
162
|
+
### Espera de conexão
|
|
163
|
+
|
|
164
|
+
Num span `db.query` do `postgres` (porsager), o atributo **`db.poolWaitMs`** diz quanto daquele tempo foi esperando uma conexão, e não executando SQL.
|
|
165
|
+
|
|
166
|
+
Isso importa porque as duas causas têm soluções opostas: uma query de 2 s pode ser SQL ruim (falta índice) ou pool saturado (falta conexão). Sem separar, a duração sozinha não distingue — e otimizar o SQL não resolve pool cheio.
|
|
167
|
+
|
|
168
|
+
A medida é exata, não estimada: o driver marca a query como ativa no instante em que a conexão a assume, e é esse instante que é capturado. Só aparece acima de 1 ms; abaixo disso é ruído de agendamento.
|
|
169
|
+
|
|
170
|
+
> Num pool frio a espera inclui **estabelecer** a conexão (TCP, TLS, autenticação). Esperar por uma conexão que ainda não existe é esperar por conexão do mesmo jeito, então isso é proposital.
|
|
171
|
+
|
|
155
172
|
## fetch
|
|
156
173
|
|
|
157
174
|
```ts
|
|
@@ -164,6 +181,86 @@ globalThis.fetch = tracker.wrapFetch(globalThis.fetch);
|
|
|
164
181
|
|
|
165
182
|
Cada chamada vira um span `http.client` nomeado `${method} ${origin}${pathname normalizado}` (ex.: `GET https://api.github.com/repos/:id`). É isso que alimenta a detecção de **LOOP**: a mesma chamada repetida ≥ `loop_threshold` vezes sob o mesmo pai. Chamadas ao próprio endpoint do FG Tracker são ignoradas.
|
|
166
183
|
|
|
184
|
+
## node:http e node:https (automático)
|
|
185
|
+
|
|
186
|
+
O `fetch` cobre quem chama `fetch`. Todo o resto do ecossistema Node continua falando pelo módulo `http`, e por isso o SDK também instrumenta a saída de `node:http`/`node:https` — **ligado por default, sem nenhuma linha de código**:
|
|
187
|
+
|
|
188
|
+
| biblioteca | transporte |
|
|
189
|
+
|---|---|
|
|
190
|
+
| AWS SDK v3 (S3, DynamoDB, Lambda, SQS…) | `@smithy/node-http-handler` → `node:https` |
|
|
191
|
+
| `google-auth-library`, `googleapis` | gaxios → node-fetch 2 → `node:https` |
|
|
192
|
+
| `axios`, `got`, `node-fetch` 2, `request` | `node:http`/`node:https` |
|
|
193
|
+
| `web-push`, `@apple/app-store-server-library` | `node:https` |
|
|
194
|
+
|
|
195
|
+
Vale para qualquer cliente, inclusive um que você nem sabe que existe dentro de uma dependência — e não depende de lembrar de envolver cada cliente. A implementação usa [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html), o ponto de observação que o próprio Node publica: nada é substituído por monkeypatch, nada quebra se outra biblioteca instrumentar o mesmo módulo, e a ordem de import não importa.
|
|
196
|
+
|
|
197
|
+
As regras são as mesmas do `fetch`: span `http.client` com o mesmo nome e `attributes.host`, só dentro de um trace em andamento (um poller de background não vira trace órfão), `traceparent` propagado conforme `propagateTraceTo` e sem tocar num header que o chamador já definiu, 5xx marcando erro no span, e chamadas ao próprio endpoint do FG Tracker ignoradas.
|
|
198
|
+
|
|
199
|
+
Para desligar:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
createTracker({ apiKey, serviceName: 'minha-app', instrumentNodeHttp: false });
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
> Chamadas feitas direto pela API do `undici` (e não por `fetch`) não passam por `node:http` e não são cobertas; use `tracker.wrapFetch()` nesse caso.
|
|
206
|
+
|
|
207
|
+
<<<<<<< HEAD
|
|
208
|
+
## Spans por método, automáticos (NestJS)
|
|
209
|
+
|
|
210
|
+
Instrumentar à mão só cobre o que alguém já suspeitava. O trecho que some do waterfall é justamente aquele em que ninguém pensou. Uma linha no bootstrap envolve **todos** os providers e controllers:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { ModulesContainer } from '@nestjs/core';
|
|
214
|
+
|
|
215
|
+
const app = await NestFactory.create(AppModule);
|
|
216
|
+
tracker.instrumentNest(app.get(ModulesContainer)); // devolve quantos métodos envolveu
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Cada método vira `Classe.metodo`, e **só aparece no trace se passar de `autoSpanMinDurationMs`** (default 5 ms). Método trivial chamado mil vezes por requisição não deixa rastro; o método que segurou 1,6 s aparece com nome e duração. Erro sempre vira span, mesmo rápido.
|
|
220
|
+
|
|
221
|
+
O container é lido estruturalmente: o SDK **não importa `@nestjs/core`**, não ganha peer dependency e não fica preso a uma versão do Nest. Providers do próprio framework (`Reflector`, `ApplicationConfig`, …) são pulados — o Nest os re-registra em todo módulo, e medir o framework não diz nada sobre a latência de uma rota. Hooks de ciclo de vida (`onModuleInit` e companhia) também ficam de fora, porque rodam no boot.
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
tracker.instrumentNest(container, {
|
|
225
|
+
minDurationMs: 20,
|
|
226
|
+
includeClass: (className, moduleName) => moduleName !== 'BillingModule',
|
|
227
|
+
includeMethod: (className, methodName) => !methodName.startsWith('_'),
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Em qualquer framework
|
|
232
|
+
|
|
233
|
+
`measure` é o primitivo por trás disso e funciona sozinho:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
const artists = await tracker.measure('resolveAvatars', () => Promise.all(rows.map(resolveAvatar)));
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Diferença para `tracker.span()`: `span` cria o span sempre — é o certo para um trecho escolhido a dedo. `measure` guarda só dois números na chamada e descarta o que foi rápido, que é o que torna viável instrumentar tudo. Preserva função síncrona como síncrona.
|
|
240
|
+
|
|
241
|
+
> O preço da troca: o span de `measure` é criado depois que o trecho terminou, então ele não é o **pai** dos spans criados lá dentro. Uma query feita dentro de um método medido aparece como irmã dele, não aninhada. Para aninhar, use `tracker.span()`.
|
|
242
|
+
|
|
243
|
+
=======
|
|
244
|
+
## Atraso do event loop (automático)
|
|
245
|
+
|
|
246
|
+
Um trecho do request sem span nenhum tem duas causas possíveis e opostas: o processo **parou** (laço em memória, JSON gigante, cripto síncrona) ou o processo estava **esperando** alguém lá fora que ninguém instrumentou. As duas produzem exatamente o mesmo espaço em branco no waterfall.
|
|
247
|
+
|
|
248
|
+
O SDK mede o atraso do event loop durante cada requisição e, quando o loop realmente travou, grava no span raiz:
|
|
249
|
+
|
|
250
|
+
| atributo | significado |
|
|
251
|
+
|---|---|
|
|
252
|
+
| `eventLoop.maxLagMs` | pior travada isolada durante a requisição |
|
|
253
|
+
| `eventLoop.blockedMs` | quanto do request o processo passou parado |
|
|
254
|
+
|
|
255
|
+
Abaixo do limiar (`eventLoopLagThresholdMs`, default 50 ms) nada é gravado — um atributo em todo span raiz só engordaria o payload. Então a presença do atributo já é o sinal.
|
|
256
|
+
|
|
257
|
+
A amostragem roda **apenas enquanto há requisição aberta**: processo ocioso não gasta nada, e o congelamento do Lambda entre invocações não vira falso positivo (um timer armado antes do congelamento dispararia segundos depois parecendo uma travada gigante).
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
createTracker({ apiKey, serviceName: 'minha-app', measureEventLoopLag: false }); // desliga
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
>>>>>>> origin/main
|
|
167
264
|
## Spans manuais
|
|
168
265
|
|
|
169
266
|
```ts
|
package/dist/constants.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ export declare const API_KEY_HEADER = "x-fg-tracker-key";
|
|
|
7
7
|
/**
|
|
8
8
|
* Endpoint usado quando `endpoint` não é informado (API local do monorepo).
|
|
9
9
|
* Em produção passe o endpoint explicitamente (ex.: `FG_TRACKER_URL`). O domínio
|
|
10
|
-
* `https://
|
|
11
|
-
*
|
|
10
|
+
* A API de produção é `https://tracker-api.fortground.com.br` (o antigo
|
|
11
|
+
* `track-api.fortground.com.br` continua respondendo).
|
|
12
12
|
*/
|
|
13
13
|
export declare const DEFAULT_ENDPOINT = "http://localhost:4050";
|
|
14
14
|
/** Prefixo das variáveis de ambiente lidas pelo SDK e pelos CLIs. */
|
package/dist/constants.js
CHANGED
|
@@ -7,8 +7,8 @@ export const API_KEY_HEADER = 'x-fg-tracker-key';
|
|
|
7
7
|
/**
|
|
8
8
|
* Endpoint usado quando `endpoint` não é informado (API local do monorepo).
|
|
9
9
|
* Em produção passe o endpoint explicitamente (ex.: `FG_TRACKER_URL`). O domínio
|
|
10
|
-
* `https://
|
|
11
|
-
*
|
|
10
|
+
* A API de produção é `https://tracker-api.fortground.com.br` (o antigo
|
|
11
|
+
* `track-api.fortground.com.br` continua respondendo).
|
|
12
12
|
*/
|
|
13
13
|
export const DEFAULT_ENDPOINT = 'http://localhost:4050';
|
|
14
14
|
/** Prefixo das variáveis de ambiente lidas pelo SDK e pelos CLIs. */
|
package/dist/database.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,QAKzE;AAED,MAAM,WAAW,8BAA8B;IAC7C,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC;IACxD,mFAAmF;IACnF,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,SAAS,CAAC;IACpE,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4GAA4G;IAC5G,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAW/D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,qDAIhF;AAED,iGAAiG;AACjG,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,8BAA8B,GAAG,CAAC,CAsCnI;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IACtB,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;CACjC;AAED,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAuEhG"}
|
package/dist/database.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeSql } from './normalize.js';
|
|
2
|
+
import { watchPoolWait } from './pool-wait.js';
|
|
2
3
|
const genericClients = new WeakMap();
|
|
3
4
|
const postgresClients = new WeakMap();
|
|
4
5
|
export function databaseError(span, error) {
|
|
@@ -100,16 +101,25 @@ export function instrumentPostgresClient(core, sql) {
|
|
|
100
101
|
const execute = () => {
|
|
101
102
|
if (!execution) {
|
|
102
103
|
const span = startDatabaseSpan(core, { system: 'postgresql', operation: 'query', statement, host });
|
|
104
|
+
// Espera na fila do pool, separada do tempo de execução: sem isso uma
|
|
105
|
+
// query trivial de 2 s não diz se o SQL é lento ou se o pool encheu.
|
|
106
|
+
const poolWait = span ? watchPoolWait(query) : undefined;
|
|
107
|
+
const finish = () => {
|
|
108
|
+
const waitMs = poolWait?.();
|
|
109
|
+
if (waitMs !== undefined)
|
|
110
|
+
span?.setAttribute('db.poolWaitMs', waitMs);
|
|
111
|
+
span?.end();
|
|
112
|
+
};
|
|
103
113
|
try {
|
|
104
|
-
execution = query.then((value) => {
|
|
114
|
+
execution = query.then((value) => { finish(); return value; }, (error) => {
|
|
105
115
|
databaseError(span, error);
|
|
106
|
-
|
|
116
|
+
finish();
|
|
107
117
|
throw error;
|
|
108
118
|
});
|
|
109
119
|
}
|
|
110
120
|
catch (error) {
|
|
111
121
|
databaseError(span, error);
|
|
112
|
-
|
|
122
|
+
finish();
|
|
113
123
|
throw error;
|
|
114
124
|
}
|
|
115
125
|
}
|
package/dist/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atraso do event loop durante uma requisição.
|
|
3
|
+
*
|
|
4
|
+
* Um span diz onde o tempo foi quando alguém instrumentou aquele trecho. Não
|
|
5
|
+
* diz nada quando o tempo foi embora **sem** ninguém estar esperando I/O: um
|
|
6
|
+
* laço em memória, um JSON gigante, uma criptografia síncrona. Nesse caso o
|
|
7
|
+
* processo inteiro para, e o trace mostra só espaço em branco — idêntico ao
|
|
8
|
+
* espaço em branco de uma chamada externa não instrumentada.
|
|
9
|
+
*
|
|
10
|
+
* Medir o atraso do loop separa os dois casos: se o loop travou junto com o
|
|
11
|
+
* buraco, foi CPU deste processo; se o loop estava livre, o request estava
|
|
12
|
+
* esperando alguém lá fora.
|
|
13
|
+
*
|
|
14
|
+
* A amostragem roda **apenas enquanto há requisição aberta**. Além de não
|
|
15
|
+
* gastar nada com o processo ocioso, isso evita o falso positivo do Lambda:
|
|
16
|
+
* entre invocações o processo é congelado, e um timer armado antes do
|
|
17
|
+
* congelamento dispararia segundos depois parecendo um travamento gigantesco.
|
|
18
|
+
*/
|
|
19
|
+
export interface EventLoopWindow {
|
|
20
|
+
/** Pior atraso observado numa única amostra da janela. */
|
|
21
|
+
maxLagMs: number;
|
|
22
|
+
/** Soma dos atrasos na janela: quanto do request o processo passou parado. */
|
|
23
|
+
blockedMs: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const DEFAULT_RESOLUTION_MS = 20;
|
|
26
|
+
export declare class EventLoopMonitor {
|
|
27
|
+
private readonly resolutionMs;
|
|
28
|
+
private readonly retention;
|
|
29
|
+
private readonly samples;
|
|
30
|
+
private cursor;
|
|
31
|
+
private timer;
|
|
32
|
+
private lastTick;
|
|
33
|
+
/** Requisições abertas: a amostragem liga na primeira e desliga na última. */
|
|
34
|
+
private refs;
|
|
35
|
+
constructor(resolutionMs?: number, retention?: number);
|
|
36
|
+
/** A amostragem está ligada (há requisição aberta). */
|
|
37
|
+
get sampling(): boolean;
|
|
38
|
+
/** Uma requisição abriu. */
|
|
39
|
+
acquire(): void;
|
|
40
|
+
/** Uma requisição fechou. */
|
|
41
|
+
release(): void;
|
|
42
|
+
private start;
|
|
43
|
+
private stop;
|
|
44
|
+
/**
|
|
45
|
+
* O atraso é o quanto o tick passou do horário previsto. Um loop livre
|
|
46
|
+
* acorda a cada `resolutionMs`; um loop bloqueado por 1,6 s produz um tick
|
|
47
|
+
* 1,6 s atrasado.
|
|
48
|
+
*/
|
|
49
|
+
private tick;
|
|
50
|
+
/**
|
|
51
|
+
* Atraso observado entre dois instantes de `performance.now()`.
|
|
52
|
+
*
|
|
53
|
+
* Cada amostra é contabilizada pela parte do seu intervalo que cai dentro da
|
|
54
|
+
* janela, e não pelo instante do tick: um bloqueio que começou antes da
|
|
55
|
+
* requisição não conta inteiro para ela.
|
|
56
|
+
*/
|
|
57
|
+
window(fromPerf: number, toPerf: number): EventLoopWindow;
|
|
58
|
+
/** Só para encerramento do tracker: para o timer independente do refcount. */
|
|
59
|
+
dispose(): void;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=event-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-loop.d.ts","sourceRoot":"","sources":["../src/event-loop.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB;AASD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAIxC,qBAAa,gBAAgB;IASzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAT5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAAK;IACrB,8EAA8E;IAC9E,OAAO,CAAC,IAAI,CAAK;gBAGE,YAAY,GAAE,MAA8B,EAC5C,SAAS,GAAE,MAA0B;IAGxD,uDAAuD;IACvD,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,4BAA4B;IAC5B,OAAO,IAAI,IAAI;IAKf,6BAA6B;IAC7B,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,IAAI;IAMZ;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAiBZ;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe;IAyBzD,8EAA8E;IAC9E,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { performance } from 'node:perf_hooks';
|
|
2
|
+
export const DEFAULT_RESOLUTION_MS = 20;
|
|
3
|
+
/** 60 s de histórico a 20 ms; o suficiente para qualquer request que valha investigar. */
|
|
4
|
+
const DEFAULT_RETENTION = 3_000;
|
|
5
|
+
export class EventLoopMonitor {
|
|
6
|
+
resolutionMs;
|
|
7
|
+
retention;
|
|
8
|
+
samples = [];
|
|
9
|
+
cursor = 0;
|
|
10
|
+
timer = null;
|
|
11
|
+
lastTick = 0;
|
|
12
|
+
/** Requisições abertas: a amostragem liga na primeira e desliga na última. */
|
|
13
|
+
refs = 0;
|
|
14
|
+
constructor(resolutionMs = DEFAULT_RESOLUTION_MS, retention = DEFAULT_RETENTION) {
|
|
15
|
+
this.resolutionMs = resolutionMs;
|
|
16
|
+
this.retention = retention;
|
|
17
|
+
}
|
|
18
|
+
/** A amostragem está ligada (há requisição aberta). */
|
|
19
|
+
get sampling() {
|
|
20
|
+
return this.timer !== null;
|
|
21
|
+
}
|
|
22
|
+
/** Uma requisição abriu. */
|
|
23
|
+
acquire() {
|
|
24
|
+
this.refs += 1;
|
|
25
|
+
if (this.refs === 1)
|
|
26
|
+
this.start();
|
|
27
|
+
}
|
|
28
|
+
/** Uma requisição fechou. */
|
|
29
|
+
release() {
|
|
30
|
+
this.refs = Math.max(0, this.refs - 1);
|
|
31
|
+
if (this.refs === 0)
|
|
32
|
+
this.stop();
|
|
33
|
+
}
|
|
34
|
+
start() {
|
|
35
|
+
if (this.timer)
|
|
36
|
+
return;
|
|
37
|
+
this.lastTick = performance.now();
|
|
38
|
+
this.timer = setInterval(() => this.tick(), this.resolutionMs);
|
|
39
|
+
// Telemetria nunca segura o processo vivo.
|
|
40
|
+
if (typeof this.timer === 'object' && this.timer && 'unref' in this.timer)
|
|
41
|
+
this.timer.unref();
|
|
42
|
+
}
|
|
43
|
+
stop() {
|
|
44
|
+
if (!this.timer)
|
|
45
|
+
return;
|
|
46
|
+
clearInterval(this.timer);
|
|
47
|
+
this.timer = null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* O atraso é o quanto o tick passou do horário previsto. Um loop livre
|
|
51
|
+
* acorda a cada `resolutionMs`; um loop bloqueado por 1,6 s produz um tick
|
|
52
|
+
* 1,6 s atrasado.
|
|
53
|
+
*/
|
|
54
|
+
tick() {
|
|
55
|
+
const now = performance.now();
|
|
56
|
+
const from = this.lastTick;
|
|
57
|
+
const lagMs = Math.max(0, now - from - this.resolutionMs);
|
|
58
|
+
this.lastTick = now;
|
|
59
|
+
// Buffer circular: memória constante, sem alocar a cada amostra.
|
|
60
|
+
const sample = this.samples[this.cursor];
|
|
61
|
+
if (sample) {
|
|
62
|
+
sample.from = from;
|
|
63
|
+
sample.to = now;
|
|
64
|
+
sample.lagMs = lagMs;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.samples[this.cursor] = { from, to: now, lagMs };
|
|
68
|
+
}
|
|
69
|
+
this.cursor = (this.cursor + 1) % this.retention;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Atraso observado entre dois instantes de `performance.now()`.
|
|
73
|
+
*
|
|
74
|
+
* Cada amostra é contabilizada pela parte do seu intervalo que cai dentro da
|
|
75
|
+
* janela, e não pelo instante do tick: um bloqueio que começou antes da
|
|
76
|
+
* requisição não conta inteiro para ela.
|
|
77
|
+
*/
|
|
78
|
+
window(fromPerf, toPerf) {
|
|
79
|
+
let maxLagMs = 0;
|
|
80
|
+
let blockedMs = 0;
|
|
81
|
+
const consider = (from, to, lagMs) => {
|
|
82
|
+
if (lagMs <= 0)
|
|
83
|
+
return;
|
|
84
|
+
const overlap = Math.min(to, toPerf) - Math.max(from, fromPerf);
|
|
85
|
+
if (overlap <= 0)
|
|
86
|
+
return;
|
|
87
|
+
const share = Math.min(lagMs, overlap);
|
|
88
|
+
if (share > maxLagMs)
|
|
89
|
+
maxLagMs = share;
|
|
90
|
+
blockedMs += share;
|
|
91
|
+
};
|
|
92
|
+
for (const sample of this.samples) {
|
|
93
|
+
if (sample)
|
|
94
|
+
consider(sample.from, sample.to, sample.lagMs);
|
|
95
|
+
}
|
|
96
|
+
// Bloqueio ainda não observado: se o loop travou até agora, o tick não teve
|
|
97
|
+
// chance de rodar e não existe amostra nenhuma — é justamente o caso de um
|
|
98
|
+
// request que termina logo depois de travar o processo.
|
|
99
|
+
// Limitado a agora: uma janela no futuro não pode inventar bloqueio.
|
|
100
|
+
if (this.timer) {
|
|
101
|
+
const until = Math.min(toPerf, performance.now());
|
|
102
|
+
consider(this.lastTick, until, until - this.lastTick - this.resolutionMs);
|
|
103
|
+
}
|
|
104
|
+
return { maxLagMs: round(maxLagMs), blockedMs: round(blockedMs) };
|
|
105
|
+
}
|
|
106
|
+
/** Só para encerramento do tracker: para o timer independente do refcount. */
|
|
107
|
+
dispose() {
|
|
108
|
+
this.refs = 0;
|
|
109
|
+
this.stop();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function round(value) {
|
|
113
|
+
return Math.round(value * 10) / 10;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=event-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-loop.js","sourceRoot":"","sources":["../src/event-loop.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export type { DatabaseInstrumentationOptions, DatabaseOperation, PostgresSqlLike } from "./database.js";
|
|
2
2
|
import type { Tracker, TrackerOptions } from './types.js';
|
|
3
3
|
export type { ActiveSpan, CheckInHandle, CheckInOptions, ExpressErrorMiddleware, ExpressLikeRequest, ExpressLikeResponse, ExpressMiddleware, ExpressOptions, InfraOptions, NextRouteHandler, PgPoolLike, PropagationTargets, RegisterReleaseInput, ReleaseCommitInput, SamplingContext, Span, SpanError, SpanKind, Tracker, TrackerOptions, UserRef, } from './types.js';
|
|
4
|
+
export type { MeasureOptions } from './measure.js';
|
|
5
|
+
export type { NestContainerLike, NestInstrumentationOptions } from './nest.js';
|
|
6
|
+
export { MIN_POOL_WAIT_MS } from './pool-wait.js';
|
|
4
7
|
export { normalizePath, normalizeSql } from './normalize.js';
|
|
5
8
|
export { detectEnvironment, detectRelease, shouldPropagate } from './tracker.js';
|
|
6
9
|
export { formatTraceparent, parseTraceparent, TRACEPARENT_HEADER } from './context.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAiBxG,OAAO,KAAK,EAAsE,OAAO,EAAE,cAAc,EAAW,MAAM,YAAY,CAAC;AAEvI,YAAY,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,OAAO,EACP,cAAc,EACd,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtF,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACjH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7F;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAwH9D;AAyBD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC5I,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtH,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,9 @@ import { createExpressErrorHandler, createExpressMiddleware } from './express.js
|
|
|
3
3
|
import { createInstrumentedFetch } from './fetch.js';
|
|
4
4
|
import { installGlobalErrorCapture } from './global-errors.js';
|
|
5
5
|
import { createMonitor, runCheckIn } from './monitors.js';
|
|
6
|
+
import { measure } from './measure.js';
|
|
7
|
+
import { instrumentNestContainer } from './nest.js';
|
|
8
|
+
import { instrumentNodeHttp } from './node-http.js';
|
|
6
9
|
import { wrapNextRouteHandler } from './next.js';
|
|
7
10
|
import { instrumentPgPool } from './pg.js';
|
|
8
11
|
import { registerRelease } from './releases.js';
|
|
@@ -11,6 +14,7 @@ import { instrumentAwsClient, trackQueueMessage } from './infra/aws.js';
|
|
|
11
14
|
import { monitorPgPool } from './infra/db-pool.js';
|
|
12
15
|
import { startInfraReporter } from './infra/ecs.js';
|
|
13
16
|
import { wrapLambdaHandler } from './infra/lambda.js';
|
|
17
|
+
export { MIN_POOL_WAIT_MS } from './pool-wait.js';
|
|
14
18
|
export { normalizePath, normalizeSql } from './normalize.js';
|
|
15
19
|
export { detectEnvironment, detectRelease, shouldPropagate } from './tracker.js';
|
|
16
20
|
export { formatTraceparent, parseTraceparent, TRACEPARENT_HEADER } from './context.js';
|
|
@@ -40,6 +44,9 @@ export function createTracker(options) {
|
|
|
40
44
|
};
|
|
41
45
|
if (options.instrumentGlobalFetch && core.enabled)
|
|
42
46
|
instrumentGlobalFetch();
|
|
47
|
+
// Ligado por default: a saída HTTP que não passa pelo `fetch` (AWS SDK, axios,
|
|
48
|
+
// got, node-fetch 2, gaxios, web-push) é invisível sem isto.
|
|
49
|
+
const uninstrumentNodeHttp = options.instrumentNodeHttp !== false && core.enabled ? instrumentNodeHttp(core) : undefined;
|
|
43
50
|
if (options.captureGlobalErrors && core.enabled)
|
|
44
51
|
installGlobalErrorCapture(core);
|
|
45
52
|
const tracker = {
|
|
@@ -91,6 +98,8 @@ export function createTracker(options) {
|
|
|
91
98
|
span.end();
|
|
92
99
|
}
|
|
93
100
|
},
|
|
101
|
+
measure: (name, fn, measureOptions) => measure(core, name, fn, measureOptions),
|
|
102
|
+
instrumentNest: (container, nestOptions) => instrumentNestContainer(core, container, nestOptions),
|
|
94
103
|
wrapNextRoute: (handler) => wrapNextRouteHandler(core, handler),
|
|
95
104
|
wrapFetch: (fetchImpl) => createInstrumentedFetch(core, fetchImpl),
|
|
96
105
|
instrumentGlobalFetch,
|
|
@@ -132,7 +141,12 @@ export function createTracker(options) {
|
|
|
132
141
|
return core.options.environment;
|
|
133
142
|
},
|
|
134
143
|
flush: () => core.flush(),
|
|
135
|
-
|
|
144
|
+
// As inscrições em `diagnostics_channel` são do processo, não do tracker:
|
|
145
|
+
// sem cancelar, um tracker desligado continuaria instrumentando requisições.
|
|
146
|
+
shutdown: async () => {
|
|
147
|
+
uninstrumentNodeHttp?.();
|
|
148
|
+
await core.shutdown();
|
|
149
|
+
},
|
|
136
150
|
};
|
|
137
151
|
return tracker;
|
|
138
152
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAErH,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TrackerCore } from './tracker.js';
|
|
2
|
+
import type { SpanKind } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Span que só existe se o trecho tiver sido lento.
|
|
5
|
+
*
|
|
6
|
+
* `tracker.span()` cria o span sempre: é o certo para um trecho que você
|
|
7
|
+
* escolheu a dedo. Não serve para instrumentar *tudo*, porque um método
|
|
8
|
+
* chamado milhares de vezes por requisição pagaria alocação e id aleatório em
|
|
9
|
+
* toda chamada, e encheria o trace de barras de 0 ms.
|
|
10
|
+
*
|
|
11
|
+
* `measure` inverte isso: na chamada guarda só dois números (o instante e o
|
|
12
|
+
* contexto) e, no fim, descarta o que foi rápido. O que sobra no waterfall é
|
|
13
|
+
* exatamente o que merece atenção — mais um erro, que sempre vira span mesmo
|
|
14
|
+
* quando rápido, porque aí a duração não é o ponto.
|
|
15
|
+
*
|
|
16
|
+
* O preço dessa troca: o span é criado depois que o trecho terminou, então ele
|
|
17
|
+
* não é o pai dos spans criados lá dentro. Uma query feita dentro de um método
|
|
18
|
+
* medido aparece como irmã dele, não aninhada.
|
|
19
|
+
*/
|
|
20
|
+
export interface MeasureOptions {
|
|
21
|
+
kind?: SpanKind;
|
|
22
|
+
/** Abaixo disto o trecho não vira span. Default: `autoSpanMinDurationMs` do tracker. */
|
|
23
|
+
minDurationMs?: number;
|
|
24
|
+
attributes?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Executa `fn` medindo o tempo. Preserva a natureza da função: o que é
|
|
28
|
+
* síncrono continua síncrono (envolver um método qualquer não pode
|
|
29
|
+
* transformá-lo em Promise).
|
|
30
|
+
*/
|
|
31
|
+
export declare function measure<T>(core: TrackerCore, name: string, fn: () => T, options?: MeasureOptions): T;
|
|
32
|
+
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAMD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAE,cAAmB,GAAG,CAAC,CAgDxG"}
|