Become a member!

Roube este código: monitoramento ExeWatch para Delphi, .NET, C++ e mais

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

ExeWatch: monitoramento de aplicações em tempo real para Delphi, C++Builder, .NET, JavaScript e Python, com motor de IA integrado e plano Hobby gratuito.

TL;DR: O repositório ExeWatch Samples é um conjunto de projetos prontos para executar que mostram como integrar o ExeWatch em aplicações reais: Delphi (VCL, FMX, Android, WebBroker, DMVCFramework, runtime packages, webhooks), .NET (Console, Windows Forms, Windows Service), JavaScript no navegador, e C++Builder / MSVC / Python através da DLL nativa. Cada exemplo exercita uma parte do SDK, então você copia o padrão que combina com a sua app. Uma API key, plano Hobby gratuito, e seus eventos aparecem no dashboard em poucos segundos.

O ExeWatch está crescendo, e a comunidade está construindo em cima dele

O ExeWatch continua crescendo, rápido. Em poucos meses chegou a centenas de desenvolvedores registrados que agora monitoram em produção software escrito em Delphi, C++Builder, .NET, JavaScript e Python: de apps desktop e serviços do Windows a APIs REST e aplicações web completas.

O que eles usam primeiro diz muito sobre por que depois ficam:

  • Captura automática de exceções - erros não tratados são interceptados e reportados, com classe, mensagem e stack.
  • Trilhas de breadcrumbs - a sequência exata de ações que levou a um erro, anexada automaticamente à falha.
  • Timings de desempenho com Avg / Min / Max / P95 - meça qualquer operação e acompanhe a tendência no dashboard.
  • Nested timing traces - waterfalls estilo profiler e uma Calling-Context-Tree agregada, para ver para onde o tempo realmente vai.
  • Contadores e gauges - métricas de negócio e de runtime ao lado dos seus logs.
  • Inteligência de hardware e dispositivo - CPU, RAM, disco, SO, monitores, detalhes de dispositivos móveis.
  • Rastreamento multi-cliente - filtre cada log por id de cliente.
  • Alertas por e-mail e de timing mais webhooks - seja notificado, ou acione sua própria automação, quando algo dá errado ou fica lento.
  • Um motor de IA integrado que ajuda a dar sentido a tudo isso.

Uma funcionalidade merece menção especial: os Nested Timing Traces, uma das adições mais pedidas e a que mais recebe comentários positivos. Ela transforma uma lista plana de timings num waterfall estilo profiler que mostra exatamente para onde o tempo vai, com loops mesclados e avg/min/max/p95 por nó. Cada SDK do repositório inclui uma demo de nested trace pronta para executar (GenerateInvoiceReport), então você pode produzir uma árvore como esta a partir da sua própria app em poucos minutos:

Waterfall de um Nested Timing Trace do ExeWatch para GenerateInvoiceReport: operações aninhadas (LoadCustomers, Transform com RenderRow x5, WriteFile, Flush) cada uma com uma barra proporcional ao tempo total, porcentagem e duração, e estatísticas avg/min/max/p95 dos loops mesclados

Se quiser a história completa de como os traces são construídos e visualizados, leia o artigo dedicado: ExeWatch 1.35: Nested Timing Traces.

A forma mais rápida de entender como isso se traduz no seu próprio código é o repositório de exemplos. Vamos percorrê-lo.

Por que estes exemplos importam: versões reais, linguagens reais

Este repositório não é só uma vitrine de marketing. Ele existe porque as perguntas são reais. Só nas últimas semanas, um cliente me pediu para adicionar o ExeWatch a uma aplicação Delphi 6, outro a um projeto C++Builder 10, e outro queria pilotá-lo a partir de uma linguagem que não está nem um pouco na lista habitual.

Cada um desses pedidos tem resposta aqui dentro, e é exatamente esse o ponto: os exemplos são a forma mais rápida de ver qual SDK usar para qual ambiente, e como.

  • Delphi moderno (XE8 e posteriores) usa o SDK Pascal nativo (ExeWatchSDKv1.pas + o hook VCL ou FMX): os exemplos VCL, FMX, Android, WebBroker e DMVCFramework seguem todos esse caminho.
  • Delphi legado (até o Delphi 6/7) e qualquer versão anterior ao XE8 não conseguem compilar a unit moderna, então falam com a DLL nativa através da unit de importação Pascal ExeWatchSDKv1Imports.pas em DLLSDKCommons/. Mesmas chamadas, mesmo dashboard, apenas ligadas à DLL em vez de compiladas dentro.
  • C++Builder (antigo e novo) carrega a mesma DLL dinamicamente: o exemplo CPPBuilderWithDLLSDK/ compila sem alterações sob bcc32, bcc64 e bcc64x, então um projeto C++Builder 10 e um 13 usam código idêntico.
  • Outras linguagens consomem a DLL através da sua ABI do Windows padrão: os exemplos MSVC e Python ctypes provam o padrão, que então se aplica a Rust, Go, MinGW, Clang e além.

Então, quando alguém pergunta “consigo colocar o ExeWatch neste compilador antigo / naquela linguagem incomum?”, a resposta honesta normalmente é “sim, e aqui está o exemplo que mostra como”.

Antes de começar: uma API key, sem cartão de crédito

Cada exemplo precisa de uma API key válida. Cadastre-se em exewatch.com, crie uma aplicação no dashboard e copie a key dela (o prefixo depende da plataforma de destino: ew_win_ Windows, ew_lin_ Linux, ew_mac_ macOS, ew_and_ Android, ew_ios_ iOS, ew_web_ navegador). O plano Hobby gratuito não pede cartão de crédito e te dá uma aplicação, 10.000 eventos por mês, 7 dias de retenção e dois alertas: mais que suficiente para executar tudo.

Depois o ciclo é sempre o mesmo: abra o projeto, cole sua key onde está o placeholder, compile, execute e veja os eventos chegarem ao dashboard em tempo real.

Clientes desktop e mobile

São os exemplos “cliente na máquina de outra pessoa”: apps com interface gráfica onde a captura de exceções e os breadcrumbs importam mais, porque normalmente você não consegue reproduzir o crash localmente.

Delphi VCL (DelphiVCL/) é o ponto de partida canônico. Um formulário desktop Windows com um botão por funcionalidade: os cinco níveis de log, timing, breadcrumbs-depois-erro, identidade de usuário, tags, contadores e gauges, além da captura automática de exceções VCL via ExeWatchSDKv1.VCL. Os logs são persistidos em disco antes do envio, então nada se perde se a app travar. Use quando você desenvolve software desktop Windows clássico em Delphi e quer o caminho mais curto de zero a dados.

uses ExeWatchSDKv1, ExeWatchSDKv1.VCL;   // hook VCL = captura automática de exceções da GUI

InitializeExeWatch(EXEWATCH_API_KEY, 'SampleCustomer');
EW.Info('User logged in', 'auth');
Exemplo ExeWatch Delphi VCL: um botão por funcionalidade do SDK (logging, timing, breadcrumbs, identidade de usuário, tags, métricas, nested trace) e um activity log em tempo real

Delphi FMX (DelphiFMX/) espelha o exemplo VCL funcionalidade por funcionalidade, mas sobre FireMonkey, então pode mirar em Windows, macOS, Linux, iOS e Android. A única diferença real é a cláusula uses: ExeWatchSDKv1.FMX em vez do hook VCL. Use quando você distribui um app FireMonkey multiplataforma.

uses ExeWatchSDKv1, ExeWatchSDKv1.FMX;   // hook FMX em vez do de VCL

InitializeExeWatch(EXEWATCH_API_KEY, 'SampleCustomer');
EW.Info('User logged in', 'auth');

Delphi Android (DelphiAndroid/) é o SDK FMX apontado diretamente para um celular. Uma UI estreita e rolável construída por código exercita cada ponto de entrada, incluindo o uso a partir de uma thread em segundo plano e o flush, e foca em preocupações específicas de mobile: device info no estilo Android, captura de uma exceção não tratada antes de o processo ser destruído, e prova de thread-safety fora da thread de UI. Use quando você desenvolve para Android e quer percorrer toda a API num dispositivo real ou emulador.

uses ExeWatchSDKv1, ExeWatchSDKv1.FMX;

InitializeExeWatch(EXEWATCH_API_KEY, 'AndroidSample');   // key Android: ew_and_
EW.Info('Info message from Android', 'test');

.NET Windows Forms (DotNetWindowsForms/) é a contraparte C#: uma GUI com abas onde você cola a API key em tempo de execução (sem recompilar) e explora logging, timings aninhados e paralelos, device info, métricas e upgrades de versão simulados. Ele instala ExeWatch.WinForms para capturar Application.ThreadException automaticamente. Use quando seu app desktop é WinForms.

ExeWatchWinForms.Install();   // captura Application.ThreadException, antes de Application.Run()

ExeWatchSdk.Initialize(new ExeWatchConfig(apiKey, customerId));
EW.Info("User logged in", "auth");
Exemplo ExeWatch .NET Windows Forms: API key inserida em tempo de execução, abas para Logging, Timing, Device Info, User/Tags, Metrics e Updates, e um painel de saída mostrando o SDK conectando e inicializando

Servidores, serviços e apps web

Código de longa execução, headless ou de servidor, onde timings, contadores e contexto estruturado de erros viram visibilidade operacional.

Delphi WebBroker (DelphiWebBroker/) é um pequeno servidor REST que envolve cada requisição num único helper HandleRequest: incrementa um contador de requisições, adiciona um breadcrumb, inicia um timing, executa o handler e então registra sucesso ou falha (e em caso de erro, conta, registra a exceção e devolve HTTP 500). Seis endpoints de demo, incluindo um delay ?ms= para gerar respostas lentas. Use quando você tem um serviço WebBroker e quer monitoramento no nível de requisição com um único wrapper.

InitializeExeWatch(TExeWatchConfig.Create(EXEWATCH_API_KEY, 'demo_customer'));
EW.SetTag('app', 'WebBrokerSample');

// dentro do wrapper por requisição:
EW.IncrementCounter('http.requests', 1);
EW.StartTiming(Endpoint);
try
  Handler;
  EW.EndTiming(Endpoint, nil, True);    // sucesso
except
  on E: Exception do
    EW.EndTiming(Endpoint, nil, False); // falha
end;

Delphi DMVCFramework (DelphiDMVCFramework/) é o exemplo de servidor mais completo: uma app web de verdade com TemplatePro e HTMX, CRUD de pessoas com busca ao vivo e importação em lote, relatórios pesados com timings aninhados, serviços externos simulados com modos de falha realistas (timeouts de pagamento, rate limit 429, erros 502), extra data estruturada, breadcrumbs, contadores e gauges periódicos. O destaque é o quão pouco custa: três linhas no .dpr e nenhuma alteração nos controllers. Você roteia a saída do LoggerPro do DMVCFramework para o ExeWatch com um appender de callback, chama InitializeExeWatch e aponta o Profiler embutido do framework para o logger. A partir daí cada requisição é registrada e cronometrada de graça. Use quando você desenvolve APIs ou apps web com DMVCFramework e quer visibilidade profunda com quase zero código.

// 1. roteia a saída do LoggerPro do DMVCFramework para o ExeWatch
SetDefaultLogger(CreateLogBuilderWithDefaultConfiguration.WriteToCallback
  .WithCallback(procedure(const ALogItem: TLogItem; const AFormattedMessage: string)
  begin
    if ExeWatchIsInitialized and (ALogItem.LogType > TLogType.Debug) then
      EW.Log(TEWLogLevel(Ord(ALogItem.LogType)), ALogItem.LogMessage,
        ALogItem.LogTag, ALogItem.TimeStamp, ALogItem.ThreadID);
  end).Done.Build);

// 2. inicializa, depois 3. aponta o profiler embutido para o logger
InitializeExeWatch(TExeWatchConfig.Create(EXEWATCH_API_KEY, 'dmvc_sample_customer'));
Profiler.ProfileLogger := Log;        // cada action cronometrada, sem mexer nos controllers
Profiler.WarningThreshold := 500;     // avisa se uma action passar de 500 ms

Receptor de WebHook Delphi (DelphiWebHookSample/) inverte a relação: em vez de enviar dados ao ExeWatch, ele recebe os webhooks de alerta do ExeWatch. Um controller DMVCFramework valida o token do webhook e processa o payload do alerta, e um endpoint trace-demo complementar emite um nested timing trace sob demanda. Use quando você quer que os alertas acionem a sua própria automação (notificações em chat, ticketing, auto-remediação) e não só o e-mail.

// valida o secret compartilhado, depois age sobre o payload do alerta
if Context.Request.Headers['X-ExeWatch-Token'] <> EXEWATCH_WEBHOOK_TOKEN then
  Exit(UnauthorizedResponse('Invalid token'));

AlertType := Payload.S['alert_type'];   // 'log_level', 'timing', 'health_critical'...
LogI('ExeWatch [%s] %s: %s', [AlertType, Payload.S['app_name'], Payload.S['message']]);
Result := OKResponse('Webhook received');

.NET Windows Service (DotNetWindowsService/) é um Worker Service com um ciclo de processamento a cada 10 segundos. Ele mostra o padrão recomendado para serviços de longa execução: inicialize em StartAsync, envolva cada ciclo num timing externo com sub-timings aninhados, use a convenção de timing com try/catch para que ciclos com falha sejam marcados como falhos sem derrubar o serviço, emita contadores e gauges, e faça flush em StopAsync. Pode rodar como app de console ou ser instalado com sc create. Use quando você opera serviços em segundo plano ou daemons.

// StartAsync - uma única vez na inicialização do serviço
ExeWatchSdk.Initialize(new ExeWatchConfig(ApiKey, CustomerId) { AppVersion = "1.0.0-service-demo" });
EW.SetTag("service_name", "ExeWatchDemoService");
EW.Info("Service started", "lifecycle");

// cada ciclo - cronometrado, falhas marcadas sem derrubar o serviço
EW.StartTiming("process_cycle", "worker");
try { /* ... trabalho ... */ EW.EndTiming("process_cycle"); }
catch (Exception ex) {
    EW.EndTiming("process_cycle", new Dictionary<string, object> { ["error"] = ex.Message }, false);
}

.NET Console (DotNetConsole/) percorre toda a superfície do SDK sequencialmente, incluindo 20 iterações cronometradas com falhas aleatórias para que o dashboard mostre de imediato Avg / Min / Max / P95 e uma taxa de sucesso realistas. Use quando você quer um smoke test de 60 segundos do SDK .NET, ou um job CLI/batch para instrumentar.

var config = new ExeWatchConfig(ApiKey, CustomerId) { AppVersion = "1.0.0-console-demo" };
ExeWatchSdk.Initialize(config);
EW.SetTag("environment", "development");
EW.Info("Configuration loaded successfully", "config");

No navegador

JavaScript (JS/) é um único index.html: sem npm, sem etapa de build. Defina window.ewConfig com a sua key ew_web_, carregue o SDK do CDN, e clique nos botões de logging, timing, breadcrumbs-depois-erro, identidade de usuário, tags e métricas. Use quando você quer rastreamento de erros e desempenho de front-end numa página web simples ou dentro de um site existente.

<script>
  window.ewConfig = { apiKey: 'ew_web_...', customerId: 'SampleCustomer', appVersion: '1.0.0' };
</script>
<script src="https://exewatch.com/static/js/exewatch.v1.min.js"></script>
<script>
  ew.info('User signed in', 'auth');   // o global 'ew' fica pronto assim que o SDK carrega
</script>

C, C++ e qualquer linguagem capaz de chamar uma DLL

O ExeWatch inclui uma DLL nativa que expõe uma ABI do Windows deliberadamente sem graça: extern "C" + __stdcall + wchar_t* + #pragma pack(1). Isso a torna consumível a partir de quase qualquer coisa. Todos estes exemplos a carregam dinamicamente com LoadLibrary + GetProcAddress, o que evita o clássico desencontro entre import library .lib e .a e permite que a app inicie limpa mesmo quando a DLL está ausente.

C++Builder (CPPBuilderWithDLLSDK/) é uma app VCL que pilota a DLL através do par compartilhado ExeWatchSDKv1.h + ExeWatchSDKv1.dynload.c. Um único #define EW_DYNAMIC_LOAD transforma cada ew_* num ponteiro de função, e o mesmo código compila sob bcc32, bcc64 e bcc64x. Use quando você trabalha em C++Builder e quer evitar brigas com o linker.

#define EW_DYNAMIC_LOAD          // cada ew_* vira um ponteiro de função
#include "ExeWatchSDKv1.h"

if (ew_LoadSDK() != EW_OK) { /* DLL ausente: mostra uma mensagem clara */ }
ew_Initialize(EXEWATCH_API_KEY, L"Sample C++ Customer", L"");
ew_Info(L"This is an INFO message", L"sample");
Exemplo ExeWatch C++Builder VCL usando o DLL SDK: o mesmo layout de um botão por funcionalidade do exemplo Delphi, com o activity log mostrando o SDK inicializado via DLL e os breadcrumbs se acumulando antes de um erro

Microsoft Visual C++ (MSVCWithDLLSDK/) prova que o DLL SDK não tem limites nem dependências e pode ser usado em qualquer lugar e por qualquer um, sem nada do ecossistema Embarcadero à vista: uma app de console em cl.exe puro, com um run_msvc.cmd que localiza o vcvars64.bat, compila e executa. Ela percorre a superfície comum (init, usuário, tags, breadcrumbs, timing, contador, gauge, erro com breadcrumbs anexados automaticamente, flush, shutdown). Use quando sua base de código é MSVC, ou você simplesmente quer um quickstart autônomo.

#define EW_DYNAMIC_LOAD
#include "ExeWatchSDKv1.h"

ew_LoadSDK();
ew_Initialize(EXEWATCH_API_KEY, CUSTOMER_ID, APP_VERSION);
ew_SetTag(L"environment", L"dev");
ew_Info(L"Sample app started", L"startup");

A DLL a partir de outras linguagens (SpecificScenarios/DllFromOtherLanguages/) é o canto da portabilidade comprovada. Um smoke test em Python ctypes puro valida os cinco eixos da ABI (convenção de chamada, nomes sem decoração, marshalling UTF-16, empacotamento de structs e ABI de callbacks) sem nenhum vestígio da Embarcadero. O README é explícito: para uma app Python de verdade você deve usar o módulo do SDK Python nativo, que você baixa da página Integration do dashboard exatamente como baixa as units do Delphi (ainda não está no PyPI, então não há pip install); este exemplo existe como referência de portabilidade para Rust, Go, MinGW, Clang e outros runtimes capazes de FFI. Use quando você precisa chamar o ExeWatch a partir de um toolchain incomum e quer um template confiável.

dll = ctypes.WinDLL(dll_path)                 # ABI stdcall, nomes sem decoração
cfg = TEWDLLConfig(); cfg.StructSize = sizeof(TEWDLLConfig)
cfg.ApiKey = EXEWATCH_API_KEY; cfg.CustomerId = CUSTOMER_ID; cfg.SampleRate = 1.0
dll.ew_InitializeEx(byref(cfg))
dll.ew_Info('Hello from Python ctypes', 'smoke')

Arquitetura e cenários how-to específicos

O último grupo responde perguntas específicas que surgem quando o básico já funciona.

Runtime packages (DelphiVCLWithPackages/) demonstra que o ExeWatch funciona com BPLs do Delphi carregadas dinamicamente via LoadPackage. O truque é compilar o SDK no seu próprio package (ExeWatchSDKPkg.bpl) para que a instância global EW, os breadcrumbs, as tags e a identidade de usuário sejam de fato compartilhadas entre o EXE host e cada BPL de módulo. Dois módulos de demo (Customers, Orders) registram, cronometram e capturam erros usando exatamente a mesma API de uma app normal. Use quando você tem uma aplicação Delphi modular, no estilo plugin.

// HostApp: inicializa uma vez; o SDK vive em ExeWatchSDKPkg.bpl, compartilhado com cada módulo
InitializeExeWatch(TExeWatchConfig.Create(APP_API_KEY, APP_CUSTOMER_ID));
EW.SetTag('app_type', 'runtime_packages');

// dentro de uma BPL de módulo carregada dinamicamente - mesma EW global, sem setup extra
EW.Info('Customer added: ' + CustomerName, 'customers');

Uso de breadcrumbs (SpecificScenarios/BreadcrumbsUsage/) resolve num único projeto as três perguntas mais comuns sobre breadcrumbs: espalhe os breadcrumbs onde as ações acontecem (não os agrupe), exceções não tratadas os anexam automaticamente enquanto as capturadas exigem a sua chamada a EW.Error, e só logs Error e Fatal carregam breadcrumbs (Info / Warning / Debug não). Quatro botões tornam cada regra visível no dashboard. Use quando você quer acertar nos breadcrumbs de primeira.

EW.AddBreadcrumb(btClick, 'ui', 'Clicked "Save" button');
try
  FakeSaveToDatabase;   // lança uma exceção
except
  on E: Exception do
    EW.ErrorWithException(E, 'settings');  // os breadcrumbs se anexam a este Error
end;

Device info personalizada inicial (SpecificScenarios/InitialCustomDeviceInfo/) responde a um problema sutil de inicialização: como anexar tags e metadados de ambiente (sessão RDP, Terminal Server, modo desktop) ao primeiro evento, aquele emitido durante a inicialização? A resposta são dois campos de configuração, GlobalTags para os dados pelos quais você filtra os logs e InitialCustomDeviceInfo para os detalhes que descrevem o dispositivo. Use quando você precisa do contexto presente desde a primeira linha de log.

Config := TExeWatchConfig.Create(EXEWATCH_API_KEY, 'SampleCustomer');
Config.GlobalTags := [TPair<string, string>.Create('session_type', SessionType)];
Config.InitialCustomDeviceInfo := [
  TPair<string, string>.Create('screen_res',  DetectScreenResolution),
  TPair<string, string>.Create('color_depth', DetectColorDepth)];
InitializeExeWatch(Config);   // as tags presentes já desde o primeiro evento

Integração com madExcept (SpecificScenarios/madExceptIntegration/) é para quem já usa madExcept. Uma única unit ponte registra um callback do madExcept e encaminha cada exceção ao ExeWatch com o stack já simbolizado do madExcept (nomes de unit e números de linha) em vez dos endereços crus que o SDK capturaria num build de release. Ela também mostra o equivalente para EurekaLog. Use quando você quer stacks legíveis e pesquisáveis no dashboard e já paga a simbolização em tempo de link.

procedure ExeWatchMadExceptHandler(const ExceptIntf: IMEException; var Handled: Boolean);
var ExtraData: TJSONObject;
begin
  ExtraData := TJSONObject.Create;
  ExtraData.AddPair('stack_trace', ExceptIntf.BugReport);  // stack resolvido pelo madExcept
  EW.Log(llError, ExceptIntf.ExceptMessage, 'exception', ExtraData);
end;

initialization
  RegisterExceptionHandler(ExeWatchMadExceptHandler, stDontSync);
ExeWatch e madExcept convivendo: o diálogo de bug report do madExcept continua aparecendo para a exceção interceptada
A mesma exceção no dashboard do ExeWatch, com o stack trace resolvido pelo madExcept (nomes de unit e números de linha) em vez de endereços crus

Uma API, muitos runtimes

A razão pela qual um tour como este se mantém curto é que a API é intencionalmente a mesma em todos os lugares. Initialize, Info / Warning / Error, AddBreadcrumb, StartTiming / EndTiming, SetUser, SetTag, IncrementCounter / RecordGauge, e a captura automática de exceções: a grafia muda um pouco entre Delphi, C#, JavaScript e a DLL C, mas os conceitos e o dashboard são idênticos. Aprenda num exemplo e você conhece em todos.

Clone o repo, escolha o projeto mais próximo do seu stack, coloque a sua key, e você terá dados reais na sua frente em alguns minutos.



ExeWatch: Application Performance Monitoring para aplicações de servidor, desktop e web, com um motor de Inteligência Artificial integrado. Criado pela bit Time Professionals.

Comments

comments powered by Disqus