Become a member!

ExeWatch 1.30: SDKs para C++Builder, MSVC e Delphi anteriores ao XE8, Global Tags e Alertas por Cliente

ExeWatch Logo
🌐
Este artigo também está disponível em outros idiomas:
🇮🇹 Italiano  •  🇬🇧 English  •  🇩🇪 Deutsch  •  🇪🇸 Español

TL;DR: O ExeWatch 1.30 adiciona suporte nativo para C++Builder, Microsoft Visual C++ e as versões de Delphi 4 até XE7 por meio de um novo SDK baseado em DLL. Introduz as global tags herdadas automaticamente em todo log e o filtro de alertas por cliente individual. Acrescenta WaitForSending para aguardar explicitamente o envio dos logs em fila, timings thread-local, isolamento do file queue por aplicação e notificações por e-mail ao atingir 80% e 100% da cota mensal de eventos. Tudo incluído em cada plano. Experimente em exewatch.com

Destaques da release

  • 🆕 Novo SDK baseado em DLL para C++Builder, Microsoft Visual C++ (MSVC), MinGW, Clang e Delphi 4–XE7
  • 🏷️ Global Tags: pares chave/valor herdados automaticamente em todo log da sessão (Delphi nativo + JavaScript)
  • 🎯 Filtro de alertas por Customer ID: regras de alerta log-level e timing restringíveis a um único cliente
  • ⏱️ WaitForSending em todos os SDKs: API para aguardar o esvaziamento explícito da fila de logs
  • 🧵 Timings thread-local em Delphi, .NET e Python: cada thread mantém seu próprio stack de timing
  • 📁 Isolamento do file queue por aplicação: subpasta dedicada identificada pela API key
  • 📧 Notificações por e-mail sobre a cota mensal: alerta aos 80%, bloqueio aos 100%
  • 🚀 DLL ABI elevada para a versão 3 para refletir o WaitForSending

Uma release que amplia o perímetro

Desde que o ExeWatch foi apresentado, a resposta da comunidade superou qualquer previsão. Toda semana recebemos pedidos de integração, relatos de cenários de uso que não imaginávamos e, sobretudo, perguntas do tipo “o SDK de vocês também está disponível para …?”. É a confirmação mais direta de que um produto como o ExeWatch era necessário e demandado pelos desenvolvedores de aplicações que rodam “fora do navegador”: Delphi e C++Builder em primeiro lugar, mas no geral todos os que desenvolvem software desktop, serviços Windows, aplicações industriais e tooling técnico, aquele mundo em que os logs de produção historicamente são difíceis de obter e em que os APMs cloud-native pensados para microserviços não se encaixam bem.

As releases do ExeWatch seguiram um caminho preciso: primeiro a consolidação do core (logging, timing, breadcrumbs, device info), depois a extensão para novas linguagens (Delphi, então .NET, JavaScript, Python) e, por fim, o amadurecimento das funcionalidades “de produto” (custom metrics, health monitoring, usage analytics).

Com a 1.30 damos mais um passo importante em duas direções que se entrelaçam:

  1. Mais linguagens e ambientes suportados: chega o suporte para C++Builder e Microsoft Visual C++ por meio do novo SDK baseado em DLL. O mesmo mecanismo abre o ExeWatch também para as versões de Delphi da 4 até a XE7 (o SDK Delphi nativo ExeWatchSDKv1.pas ainda requer Delphi XE8 ou posterior).
  2. Mais controle fino sobre as funcionalidades existentes: global tags herdadas em todo log, filtro de alertas por cliente individual, tratamento explícito do encerramento, isolamento por aplicação.

São novidades que chegam, em grande parte, do feedback de clientes enterprise que usam o ExeWatch em produção em parques de máquinas importantes. Uma vez integradas, porém, ficam disponíveis em todos os planos, do gratuito Hobby ao Business.

SDK baseado em DLL: Delphi legado, C++Builder e Microsoft Visual C++

Disparado, o pedido mais frequente que recebemos desde o lançamento do ExeWatch é “posso usá-lo também com versões de Delphi anteriores ao XE8?”. O SDK nativo ExeWatchSDKv1.pas usa recursos de linguagem (generics, anonymous methods, namespaces com pontos) não disponíveis nos compiladores mais antigos, e Delphi 4, 5, 6, 7, 2007, 2009, 2010 ainda estão hoje em produção em parques de máquinas importantes, especialmente nas áreas industrial, de gestão e científica.

A resposta da 1.30 é um novo SDK baseado em DLL que desacopla totalmente a compilação do cliente do compilador do projeto do usuário. A lógica vive dentro de ExeWatchSDKv1DLL.dll (distribuída em duas variantes, 32 e 64 bits) e o projeto do usuário se conecta a ela por meio de uma unit de importação dedicada, ExeWatchSDKv1Imports.pas, que funciona a partir do Delphi 5. A unit de importação resolve internamente as diferenças entre AnsiString e WideString, entre namespaces antigos e modernos, entre IInterface e IUnknown.

// Delphi 5, 6, 7, 2007 e 2009: mesmo código, mesma API
uses
  ExeWatchSDKv1Imports;

procedure InitMyApp;
begin
  ew_Initialize('ew_win_your_key', 'ACME-Corp', '1.0.0');
  ew_Info('App started', 'startup');
end;

Tendo o mecanismo da DLL em casa, expô-lo para um segundo mundo foi um passo natural: C++Builder e Microsoft Visual C++ (MSVC). A DLL é um binário Windows padrão, chamável a partir de qualquer linguagem capaz de invocar funções C. Junto dela disponibilizamos um header C utilizável tanto em link estático quanto com carga dinâmica via LoadLibrary, e um loader pronto para incluir no projeto:

// ExeWatchSDKv1.h: link estático ou carga dinâmica
#include "ExeWatchSDKv1.h"

int main(int argc, char** argv) {
    EWConfig cfg = {0};
    cfg.api_key      = "ew_win_your_key";
    cfg.customer_id  = "ACME-Corp";
    cfg.app_version  = "1.0.0";

    if (ew_Initialize(&cfg) != EW_OK) {
        fprintf(stderr, "ExeWatch init failed\n");
        return 1;
    }

    ew_Info("MSVC console starting", "startup");

    ew_StartTiming("invoice.generate", "pdf");
    // ... trabalho real ...
    ew_EndTiming("invoice.generate");

    ew_WaitForSending(5);  // aguarda o flush antes de sair (máx 5s)
    ew_Shutdown();
    return 0;
}

O mesmo header com o mesmo loader funciona indistintamente com C++Builder, MSVC, MinGW e Clang no Windows. Não são necessários build systems especiais nem dependências externas: a DLL é autossuficiente e, do lado do projeto, basta um único arquivo .c (o header ExeWatchSDKv1.h e a implementação do loader, já incluída).

Operacionalmente, a ABI da DLL foi elevada para a versão 3, alinhada com a nova API WaitForSending. Quem usava a 2 precisa apenas atualizar DLL e unit de importação juntas: o esquema das chamadas existentes não muda.

Global Tags: dimensões transversais em todo log

As tags clássicas do ExeWatch (tag no log, tag no timing) são, por definição, contextuais: descrevem o evento individual. Mas muitos cenários exigem dimensões transversais que valem para toda a sessão de uma aplicação: o tenant para o qual ela está rodando, a região, o build flavor, o ambiente, a variante de produto.

Até agora a solução padrão era incluir essas informações em customer_id ou em extra_data. Funcionava, mas era repetitivo e, sobretudo, não permitia filtragem estruturada a partir do dashboard.

Com a 1.30 chegam as Global Tags, suportadas no SDK Delphi nativo e no SDK JavaScript. São declaradas uma única vez na inicialização e são automaticamente anexadas a cada log:

// Delphi
InitializeExeWatch(
  EXEWATCH_API_KEY,
  ACustomerId    := 'ACME-Corp',
  AGlobalTags    := [
    TPair<string, string>.Create('tenant',     'EU-North'),
    TPair<string, string>.Create('flavor',     'Pro-Edition'),
    TPair<string, string>.Create('deployment', 'kiosk')
  ]
);
// JavaScript
ExeWatch.init({
  apiKey: 'ew_web_your_key',
  customerId: 'ACME-Corp',
  globalTags: {
    tenant: 'EU-North',
    flavor: 'Pro-Edition',
    deployment: 'kiosk'
  }
});

A partir daí, todo log enviado pela aplicação leva consigo as três tags. Na página Logs do dashboard você encontra um filtro Global Tags que permite ver, por exemplo, apenas os logs do tenant EU-North com flavor Pro-Edition:

Filtro Global Tags na página Logs do ExeWatch: o dropdown mostra os pares chave/valor coletados pelas aplicações (environment: abi-test, environment: staging, feature_flag: new_checkout) prontos para serem usados como filtro

O dropdown "Global Tags" na página Logs do ExeWatch lista todos os pares chave/valor recebidos do SDK e permite filtrar a timeline em um piscar de olhos.

É exatamente a dimensão que faltava para quem gerencia instalações multi-tenant ou releases diferenciadas.

Alertas com filtro por Customer ID

Ainda no mesmo espírito de “controle fino”, adicionamos um filtro opcional por Customer ID tanto aos alertas do tipo log-level quanto aos do tipo timing.

O cenário é familiar: você tem uma frota de 500 instalações e uma delas (talvez um cliente novo com um setup particular) gera erros recorrentes. Se baixar o limiar global, recebe 20 notificações por dia do restante do parque. Se mantiver alto, perde o problema do cliente específico.

Com o filtro por cliente você tem ambas as coisas: uma regra “global” tolerante e uma regra específica para aquele cliente com limiar baixo e cooldown curto. Ao criar ou alterar um alerta você verá um novo campo opcional Filter by Customer: deixando-o na opção padrão All Customers a regra vale para toda a frota, ao escolher um Customer ID específico a regra dispara apenas para aquele cliente.

Diálogo de criação de um Log Level Alert no ExeWatch: o campo opcional Filter by Customer mostra uma lista suspensa com todos os Customer IDs recebidos da aplicação, entre eles SampleCustomer, MsvcSmokeText, BreadcrumbsSample, madExceptSample, Sample C++ Customer e DEMO-CUSTOMER

O novo campo "Filter by Customer" no diálogo de criação de um Log Level Alert. O mesmo campo está disponível também para os Timing Alerts, com o mesmo comportamento.

O filtro está disponível tanto nos Log Level Alerts quanto nos Timing Alerts, com a mesma lógica: se preenchido com um Customer ID, a regra dispara apenas quando o evento (erro ou timing lento) vem desse cliente; se deixado na opção padrão All Customers, a regra vale para toda a frota. É útil também para o padrão oposto: receber notificações somente dos clientes piloto durante uma fase de rollout gradual de uma nova versão.

WaitForSending: espera explícita pelo flush

O log shipping do ExeWatch é assíncrono por design: o logging nunca bloqueia o chamador, e uma thread dedicada cuida de enviar os batches ao servidor em background. Para aplicações VCL, FMX, WPF, WinForms ou para serviços de longa duração essa escolha é ideal: o esvaziamento final da fila é gerenciado automaticamente no Shutdown, quando a main loop termina de forma controlada.

Existem, porém, cenários em que o chamador quer saber que a fila foi esvaziada antes de prosseguir: scripts CLI que terminam logo após registrar um erro, jobs batch noturnos, sessões de testes E2E que precisam propagar os logs antes de fechar o navegador, finalização de um serviço Windows em resposta a um stop request. Em todos esses casos, a 1.30 introduz uma API uniforme em todos os SDKs chamada WaitForSending:

// Delphi, no final de uma console app
EW.Fatal('Unrecoverable error: ' + E.Message, 'startup');
EW.WaitForSending(5);  // aguarda no máximo 5 segundos
ExitCode := 1;
// C#, no final de um Windows Service
EW.Fatal("Service stopping due to fatal error", "lifecycle");
EW.WaitForSending(5);
ExeWatchSdk.Shutdown();
// JS, antes de fechar/recarregar a página
ew.fatal("Unrecoverable client error", "ui");
await ew.waitForSending(5);
# Python, fim de script CLI
ew.fatal("Job failed", "batch")
ew.wait_for_sending(5)

O valor de retorno é o número de itens ainda na fila quando o timeout expirou: zero significa “tudo enviado com sucesso”.

Timings thread-local

As medições de timing (StartTiming / EndTiming) estão entre as funcionalidades mais usadas do SDK, porque permitem profilar código em produção com custo praticamente zero. Até a 1.30, em aplicações fortemente multi-thread, dois workers que utilizavam o mesmo timing id em threads diferentes compartilhavam o mesmo “slot” interno. Em casos extremos isso podia produzir medições menos precisas do que você esperaria.

Com esta release o SDK gerencia um stack de timing por thread. Cada thread tem seu próprio mapa independente de timers pendentes, e timers com o mesmo id em threads diferentes ficam totalmente isolados. O comportamento interno muda; a API não. A mudança está disponível em Delphi, .NET e Python (o JavaScript-browser é single-thread por natureza, e os Web Workers já têm um contexto isolado):

// Delphi: agora cada thread mantém seu próprio stack de timing
// Nota: envolver sempre StartTiming/EndTiming em um try..finally,
// para que o timer seja encerrado mesmo se DoHeavyWork levantar uma exceção.
TThread.CreateAnonymousThread(
  procedure
  begin
    EW.StartTiming('worker.process', 'background');
    try
      DoHeavyWork;
    finally
      EW.EndTiming('worker.process');  // encerra o timer DESTA thread
    end;
  end).Start;

TThread.CreateAnonymousThread(
  procedure
  begin
    EW.StartTiming('worker.process', 'background');  // OK, não colide
    try
      DoHeavyWork;
    finally
      EW.EndTiming('worker.process');
    end;
  end).Start;

O id lógico do timing permanece idêntico: no dashboard worker.process continua agregando corretamente as execuções de ambas as threads. Mas internamente cada thread mantém seu próprio “slot” e os timers não atrapalham um ao outro.

SDK JavaScript: captura completa dos erros HTTP

No SDK JavaScript há duas adições que mudam a qualidade das informações sobre erros em produção.

A primeira: toda vez que um fetch ou um XMLHttpRequest retorna um status >= 400, o SDK captura automaticamente o body da resposta e o anexa como extra_data. Significa que junto com o status code chega também a mensagem de erro devolvida pelo backend, que é quase sempre a chave para entender o que aconteceu.

A segunda: um novo callback httpErrorExtractor que permite personalizar o que é anexado:

ExeWatch.init({
  apiKey: 'ew_web_your_key',
  httpErrorExtractor: (body, contentType, status, url) => {
    if (contentType?.includes('json')) {
      try {
        const parsed = JSON.parse(body);
        return {
          message: parsed.detail || parsed.error || `HTTP ${status}`,
          extra: { trace_id: parsed.trace_id }
        };
      } catch (_) { /* fall through */ }
    }
    return null;  // usa o body raw como padrão
  }
});

Útil quando seu backend expõe um payload de erro estruturado (por exemplo FastAPI com {"detail": "...", "trace_id": "..."}) e você quer que o ExeWatch o registre no mesmo formato que usaria no seu dashboard de observabilidade do lado servidor.

Isolamento do file queue por aplicação

Detalhe invisível, consequência importante. Numa máquina em que rodam várias aplicações ExeWatch (tipicamente uma aplicação principal para o usuário mais um serviço Windows auxiliar, ou duas variantes de produto no mesmo workstation), até agora o diretório de armazenamento offline era único por padrão e o isolamento exigia passar paths diferentes manualmente na configuração de cada SDK.

A partir da 1.30 cada aplicação que inicializa o SDK cria automaticamente uma subpasta dedicada identificada pela API key. Várias aplicações podem coexistir no mesmo diretório de armazenamento com total segurança, sem precisar de configuração adicional.

Notificações por e-mail sobre a cota de eventos

O plano gratuito Hobby inclui 5.000 eventos por mês, o Pro 100.000, o Business 1.000.000. A partir da 1.30, o owner e os membros do time recebem um e-mail ao atingir dois limiares:

  • 80% da cota mensal (aviso): ainda há tempo para agir antes do bloqueio
  • 100% da cota mensal (limit reached): os logs adicionais não são aceitos até o reset mensal

A cota em si continua visível no dashboard, mas o e-mail é o sinal que muitos usuários esperavam: chega onde você olha todo dia e permite intervir (baixando o nível mínimo de log do SDK, aplicando filtros ou planejando o upgrade) antes que o problema vire um bloqueio.

Pricing e On Premise

A página de pricing ganhou um quarto plano ao lado de Hobby, Pro e Business: On Premise. Não é um plano self-service e nunca será: cada instalação on-premise do ExeWatch tem necessidades específicas de sizing, backup, retenção e suporte. Por isso mantemos uma conversa direta com quem precisa dele.

Os casos mais comuns são os esperados: empresas que, por política interna, não podem enviar dados de telemetria a um serviço gerenciado, contextos regulatórios (GxP, healthcare, defense) ou simples necessidades de latência quando a aplicação está geograficamente longe do nosso datacenter europeu.

A oferta on-premise inclui todas as funcionalidades do Business (incluindo o AI Engine Full) mais aplicações, eventos, retenção, alertas e team members ilimitados, integrações personalizadas, onboarding dedicado e SLA negociado. Para detalhes: exewatch@bittime.it.

Vídeos e webinars

Se você quer ver o ExeWatch “em movimento” antes de testar, no YouTube há três vídeos úteis conforme o idioma e o stack de interesse:

Para o público de língua espanhola já está marcado o webinar do ExeWatch em espanhol para quarta-feira, 20 de maio de 2026, organizado em colaboração com Delphi Studio. Para se inscrever, basta preencher este formulário de inscrição.

Por que o ExeWatch continua crescendo assim

Algo que sempre me impressiona toda vez que sai uma release com tantas funcionalidades: nenhuma dessas novidades nasceu “no isolamento” diante de uma folha em branco. Cada uma é o resultado de uma conversa concreta com alguém que está usando o ExeWatch em produção.

O suporte a C++Builder e MSVC veio de clientes do mundo industrial com código C++ legado crítico em produção. As global tags vieram de um cliente com instalações multi-tenant. O filtro de alertas por cliente chegou após uma ligação em que um cliente me disse “tenho um usuário pesado que me inunda com alertas, mas não posso subir o limiar para os outros”. O WaitForSending é uma necessidade que emergiu conversando com quem gerencia jobs batch noturnos no CLI.

Esse é também o motivo pelo qual todas essas funcionalidades (inclusive as “patrocinadas” por clientes enterprise) estão disponíveis também no plano gratuito Hobby. Os padrões que emergem em larga escala chegam mais cedo ou mais tarde também aos projetos menores: melhor tê-los prontos quando forem necessários.

O que vem a seguir

Vale lembrar que o SDK Delphi nativo já compila e funciona em Delphi para Windows, Delphi para Linux e Delphi para Android: quem desenvolve aplicações FireMonkey para o mundo mobile tem o ExeWatch disponível desde já, sem precisar esperar um SDK separado. O próximo passo nessa direção é fechar o ciclo com SDKs nativos independentes da toolchain Delphi para quem desenvolve mobile com stacks diferentes (Kotlin/Java para Android nativo, Swift para iOS).

No backend estamos trabalhando para estender a AI Engine a um terceiro nível de análise: não apenas erros e timings, mas também padrões de uso (sessões, ondas de tráfego, picos de utilização). O objetivo é que o dashboard diga “algo mudou” mesmo quando a mudança não é um erro, mas uma variação anômala na forma como seus clientes usam o produto.

Se você já usa o ExeWatch, todas as novidades da 1.30 já estão ativas na sua conta: não há nada a fazer do lado servidor. Para aproveitar WaitForSending, das Global Tags e do novo SDK C/C++ basta atualizar o SDK no lado da aplicação na página Integration do dashboard.

Se você ainda não experimentou, o plano Hobby é gratuito e não exige cartão de crédito: bastam cinco minutos para a primeira integração e, geralmente, os primeiros logs chegam ao dashboard antes mesmo de você terminar de ler o guia.



ExeWatch: Application Performance Monitoring para aplicações server, desktop e web, com Artificial Intelligence Engine integrada. Criado pela bit Time Professionals.

Comments

comments powered by Disqus