Background logger prints flush retries straight to the console, with no way to route or rate-limit them
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 52/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- node.js, typescript
Línea de trabajo
Start at HTTPBackgroundLogger in dist/index.js, especially submitLogsRequest, unwrapLazyValues, registerDroppedItemCount, logFailedPayloadsDir, and dumpDroppedEvents, then trace how initLogger constructs it. Done means the listed retry and dropped-event messages can be routed through the requested injectable logger while preserving console as the default; verify the existing onFlushError and environment options remain unaffected.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Retry / flush failures in HTTPBackgroundLogger dump unstructured console spam and page us
Setup
We run law-server on Kubernetes: long-lived API + Temporal workers, plus 20–30 short-lived agent Job pods at a time. Every pod calls initLogger on start and flushes on exit. Node 22, [email protected]. Logging is off the request path, so a failed ingest write is never user-facing for us.
What happened
Aug 31–Sep 5 we hit nine bursts of /logs3 500s (support ticket 21586 — two separate issues on your side, both since fixed). Biggest one was ~3k failed attempts in 10 minutes.
The dropped spans were fine. The log volume was not. Every pod printed its whole retry chain to stderr as unstructured text. Our alerting is log-based, so each burst paged on-call.
Why we can’t just fix this ourselves
In HTTPBackgroundLogger the failure path writes straight to the console:
submitLogsRequest—console.warn(errMsg)on each failed attempt,console.info("Sleeping for Ns")between attempts, thenconsole.warn("log request failed after N retries. Dropping batch")(dist/index.js~L6011–6030)unwrapLazyValuesretry loop —console.warn(errmsg),console.warn(e),console.info(...)(~L5954)registerDroppedItemCount,logFailedPayloadsDir,dumpDroppedEvents—console.warn/console.error(~L6034, L6066, L6118)
Default numTries = 3 → ~5 console lines per failing batch per pod, with payload size and elapsed time interpolated into the message, so there’s no structured field to filter on. 20–30 pods retrying a saturated endpoint = the 3k-line burst.
Everything around this is configurable. The logging isn’t: BRAINTRUST_NUM_RETRIES, BRAINTRUST_MAX_REQUEST_SIZE, BRAINTRUST_QUEUE_DROP_LOGGING_PERIOD, BRAINTRUST_FAILED_PUBLISH_PAYLOADS_DIR. onFlushError is the closest hook, but it doesn’t cover this — it’s only wired through the login params that construct the background logger, and it fires once on the final flush error, after every per-attempt line has already been printed. That leaves monkey-patching console.warn, which we’d rather not ship.
What would help
Either of these works:
- An injectable sink:
initLogger({ logger }), or a globalsetBraintrustLogger({ debug, info, warn, error }), defaulting toconsole. We’d point it at our structured logger and emit these at debug with pod/request id attached. - Rate-limit the retry lines the same way you already rate-limit the dropped-item counter: one line per failure kind per N seconds, env-configurable. Also have per-attempt errors reach
onFlushError(or a sibling callback) so the host app can count failures without parsing strings.
We’d use option 1.
Same shape in the Python SDK
braintrust==0.6.0, _HTTPBackgroundLogger: self.outfile = sys.stderr (logger.py:980). The flush path uses print(..., file=self.outfile) and traceback.print_exc(file=self.outfile) (L1232, L1369–1375, L1392, L1421). That object already has self.logger = logging.getLogger("braintrust") (L1032) but only uses it for one debug line. Routing those prints through that logger would be enough for us — stdlib logging config can take it from there. Happy to open a matching issue on braintrust-sdk-python if you’d rather track it separately.
Context
Ticket 21586, thread with Evan Keith — he suggested filing this here. Following his other rec we now pass projectId alongside projectName at every init site, which killed the project-register calls on pod start. That’s solved and separate from this.
Timestamps and trace IDs
All times UTC, 2026. Pulled from our log store — these are the InternalTraceId values your API returned to the SDK. Two namespaces: law-server (JS SDK) and law-pipelines (Python SDK).
Counts with a + hit our query’s 200-line cap, so they’re floors, not totals.
| Window | JS SDK lines | Python SDK lines |
|---|---|---|
| Aug 31 19:19–19:53 | 200+ | 111 |
| Sep 1 15:19–15:56 | 21 | 8 |
| Sep 1 16:42–17:00 | 4 | 0 |
| Sep 1 18:01–21:09 | 66 | 16 |
| Sep 4 14:41–14:53 | 2 | 0 |
| Sep 4 23:50 – Sep 5 01:11 | 200+ | 200+ |
Three other windows we flagged at the time (Aug 31 18:12–18:29, Aug 31 20:17–20:39, Sep 3 17:37–17:54) have no matching lines left in these namespaces, so I left them out.
The error line the SDK prints looks like this:
Error: 500 (Internal Server Error): {"Code":"InternalServerError","InternalTraceId":"c2cc1334d06819049ec0eb183dc622e6","Path":"/logs3","Service":"api"}
log request failed. Elapsed time: 5.077 seconds. Payload size: 3566.
Trace IDs by window:
Sep 1 15:19–15:56
c2cc1334d06819049ec0eb183dc622e6
fbda42fa048688bc006e7bfe04f32400
8b1287c886e03854baf4776e8e636f64
2066defe6c4c5dac3ca1bae19a7e9195
ce353438d1b5e4a097fedf10ce10f910
6a96ef05000000003a6671d73997e54a
6a96ef7d000000002412292dc31ba80a
6a96ef7a00000000614fdcef848738ea
6a96f159000000004919ac781bb38628
Sep 1 16:42–17:00
6a97005b0000000044c223fc902d06ab
6a97005b000000001f4f119eff437961
Sep 1 18:01–21:09
6a9719ac0000000063ca30a5bf5db3dd
3711f5af2f17314aeb6511e6ae9baed5
20d15bc207422036930eb7694fc723b7
c758588ce0d9d7ce9e88a972ae19e9a0
8fc3af82e8c32722145cd748672ae337
6a971627000000001442a38cf7d1a189
6a9716ae000000004ad33535548d0626
6a971771000000007cdc27af335d1c4c
6a9720b3000000005e3235c709ee1b60
6a9732a30000000062330d8e234cd634
Sep 4 23:50 – Sep 5 01:11 (99+ distinct on JS, 96+ on Python)
6a9b5b7f00000000778340d959e03db3
6a9b5b80000000004aa757fac4c721fa
6a9b5b82000000001bbb0dbd2bfee6e2
6a9b5b86000000006701ca1eecf19798
c457ad77f132a16a0a8cf67f2082bfb6
6a9b5b56000000003875e99a0f8f3fb2
6a9b5b57000000006487ced2db512ca5
6a9b5b5a0000000011a1701214f4c907
6a9b5b5e0000000033806e4e6819b65b
6a9b5b660000000057a35ad813a90f56
6a9b5d9b000000004da37a8ec2ee9d70
A different failure shape showed up twice — Sep 1 15:19 (Python SDK) and Sep 4 14:41 (JS SDK, trace id 806e65102cddf74929d6110a3b3e267c): a 400 Failed to decode API key, with connect ETIMEDOUT to a host on port 6543 in the message. One Braintrust request id from the Sep 1 occurrence, if it helps: iad1::rzjs9-1788276485217-bc3e8c663175. Same API key worked immediately before and after both windows.
Can pull the full ID list for any window if that’s useful.
- Lenguaje dominante
- TypeScript
- Estrellas
- 28
- Forks
- 14
- Merge medio
- 2 d 16 h
- PR fusionados (30 d)
- 70
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de braintrustdata/braintrust-sdk-javascript
-
Dificultad 4/5 3-5 días Aptitud para principiantes 55/100
braintrustdata/braintrust-sdk-javascript#2527 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 65/100
braintrustdata/braintrust-sdk-javascript#2526 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 3/5 1-2 días Aptitud para principiantes 65/100
braintrustdata/braintrust-sdk-javascript#2511 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 56/100
braintrustdata/braintrust-sdk-javascript#2482 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 68/100
braintrustdata/braintrust-sdk-javascript#2481 ·
Los mantenedores suelen responder en 2 días
Todos los issues de braintrustdata/braintrust-sdk-javascript
Issues similares
-
priority: P2
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
prime-radiant-inc/evener#3291 ·
Los mantenedores suelen responder en 1 día
-
accessibility bug revealjs
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
quarto-dev/quarto-cli#14961 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
supabase/agent-skills#614 ·
-
Content
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
RunestoneInteractive/rs#1559 · 1 comentario ·
Los mantenedores suelen responder en 2 días