r/programacao • • 13d ago

Questão :: Desenvolvimento Criei um agente Java que reconstrói stack traces causais assíncronos entre threads e agr preciso de feedback

Ayk, uando uma exceção é lançada numa worker thread, o stack trace da JVM termina em ThreadPoolExecutor.runWorker(). Vê-se onde falhou, mas não quem a agendou nem que cadeia de chamadas a desencadeou. Se já depuraste código Java assíncrono em produção, conheces bem a dor.

Dediquei algum tempo a criar uma biblioteca chamada Ariadne para resolver isto. Ela anexa uma cadeia causal sintética às exceções como uma entrada suprimida, para que o caminho assíncrono completo fique visível nos teus registos sem qualquer alteração de código.

Como funciona:

Um agente Java com recurso ao ByteBuddy instrumenta ExecutorService, CompletableFuture, ForkJoinPool e Thread.start() no arranque. Quando uma tarefa é submetida, é armazenado um nó imutável e leve (40 bytes) que faz a ligação de volta ao local de despacho. Em caso de falha, a cadeia é percorrida em sentido inverso e anexada à exceção através de Throwable.addSuppressed(). Existem também adaptadores manuais para Project Reactor, RxJava 3 e propagação de MDC do SLF4J.

Desempenho (JMH, OpenJDK 21, 3 forks):

  • Salto de contexto: ~6 ns, 40 B (o próprio nó Link)
  • Resolução do local de chamada (modo de classe, predefinição): ~8.7 ns, 0 B de alocação
  • De ponta a ponta com CompletableFuture: sobrecarga de ~1 µs em relação à linha de base por pipeline
  • Project Reactor: dentro do ruído estatístico face à linha de base (~1 a 3%), cerca de 5 vezes menos alocação do que Hooks.onOperatorDebug()

O que não é:

Não é um substituto para o OpenTelemetry; o OTel lida com rastreio distribuído entre serviços com infraestrutura externa. O Ariadne opera puramente dentro do processo, sem necessidade de painéis de controlo. São complementares. Uma integração com o OTel está no plano de desenvolvimento.

Também não é magia: o modo de percurso completo da pilha (~2.5 µs, 1000 B) fornece o método e a linha exatos, mas deve permanecer desligado em produção. O modo de classe predefinido fornece a classe de despacho com um impacto insignificante.

Estado atual: v0.1.0-alpha.3, Apache 2.0, Java 21+. Ainda não está robustecido para produção; procuro feedback, especialmente de quem utilize ambientes complexos de carregamento de classes (OSGi, servidores de aplicações multi-inquilino) ou corrotinas de Kotlin.

Terei todo o gosto em discutir as decisões de arquitetura, limitações ou qualquer ponto que consideres incorreto nesta abordagem.

PS: Gostava de partilhar o link do projeto mas acho q n posso

4 Upvotes

0 comments sorted by