Become a member!

ExeWatch 1.30: SDKs para C++Builder, MSVC y Delphi anteriores a XE8, Tags Globales y Alertas por Cliente

ExeWatch Logo
🌐
Este artículo también está disponible en otros idiomas:
🇮🇹 Italiano  •  🇬🇧 English  •  🇩🇪 Deutsch  •  🇧🇷 Português
📣 Webinar ExeWatch en español, miércoles 20 de mayo de 2026, organizado en colaboración con Delphi Studio. Inscripción a través de este formulario.

TL;DR: ExeWatch 1.30 incorpora soporte nativo para C++Builder, Microsoft Visual C++ y las versiones de Delphi de la 4 a la XE7 mediante un nuevo SDK basado en DLL. Introduce los tags globales heredados automáticamente en cada log y el filtro de alertas por cliente individual. Se añaden WaitForSending para esperar de forma explícita el envío de los logs en cola, timings thread-local, aislamiento del file queue por aplicación y notificaciones por correo electrónico al 80% y al 100% de la cuota mensual de eventos. Todo incluido en cada plan. Pruébalo en exewatch.com

Puntos clave de la release

  • 🆕 Nuevo SDK basado en DLL para C++Builder, Microsoft Visual C++ (MSVC), MinGW, Clang y Delphi 4–XE7
  • 🏷️ Global Tags: pares clave/valor heredados automáticamente en cada log de la sesión (Delphi nativo + JavaScript)
  • 🎯 Filtro de alertas por Customer ID: reglas de alerta log-level y timing limitables a un único cliente
  • ⏱️ WaitForSending en todos los SDKs: API para esperar el vaciado explícito de la cola de logs
  • 🧵 Timings thread-local en Delphi, .NET y Python: cada thread mantiene su propio stack de timing
  • 📁 Aislamiento del file queue por aplicación: subcarpeta dedicada identificada por la API key
  • 📧 Notificaciones por correo electrónico sobre la cuota mensual: aviso al 80%, bloqueo al 100%
  • 🚀 ABI de la DLL elevada a la versión 3 para reflejar WaitForSending

Una release que amplía el perímetro

Desde la presentación de ExeWatch, la respuesta de la comunidad ha superado cualquier previsión. Cada semana recibimos solicitudes de integración, descripciones de escenarios de uso que no habíamos imaginado y, sobre todo, preguntas del tipo "¿vuestro SDK también está disponible para …?". Es la confirmación más directa de que un producto como ExeWatch era necesario y demandado por los desarrolladores de aplicaciones que viven “fuera del navegador”: en primer lugar Delphi y C++Builder, pero en general cualquiera que desarrolle software desktop, servicios Windows, aplicaciones industriales y herramientas técnicas, ese mundo donde los logs de producción son históricamente difíciles de obtener y donde los APMs cloud-native pensados para microservicios sencillamente no encajan.

Las releases de ExeWatch han seguido un recorrido preciso: primero la consolidación del core (logging, timing, breadcrumbs, device info), luego la extensión a nuevos lenguajes (Delphi, después .NET, JavaScript, Python) y por último la maduración de las funcionalidades “de producto” (custom metrics, health monitoring, usage analytics).

Con la 1.30 damos otro paso importante en dos direcciones que se entrelazan:

  1. Más lenguajes y entornos soportados: llega el soporte para C++Builder y Microsoft Visual C++ mediante el nuevo SDK basado en DLL. El mismo mecanismo abre ExeWatch también a las versiones de Delphi desde la 4 hasta la XE7 (el SDK Delphi nativo ExeWatchSDKv1.pas sigue requiriendo Delphi XE8 o posterior).
  2. Más control fino sobre las funcionalidades existentes: tags globales heredados en cada log, filtro de alertas por cliente individual, gestión explícita del cierre, aislamiento por aplicación.

Son novedades que llegan en gran parte de feedback de clientes enterprise que están usando ExeWatch en producción sobre parques de máquinas importantes. Una vez integradas, sin embargo, están disponibles en todos los planes, desde el gratuito Hobby hasta el Business.

SDK basado en DLL: Delphi legacy, C++Builder y Microsoft Visual C++

Con diferencia, la petición más frecuente que recibimos desde el lanzamiento de ExeWatch es “¿puedo usarlo también con versiones de Delphi anteriores a XE8?”. El SDK nativo ExeWatchSDKv1.pas utiliza características del lenguaje (generics, anonymous methods, namespaces con puntos) no disponibles en los compiladores más antiguos, y Delphi 4, 5, 6, 7, 2007, 2009, 2010 siguen estando hoy en producción en parques de máquinas importantes, especialmente en el ámbito industrial, de gestión y científico.

La respuesta de la 1.30 es un nuevo SDK basado en DLL que desacopla por completo la compilación del cliente del compilador del proyecto del usuario. La lógica vive dentro de ExeWatchSDKv1DLL.dll (distribuida en dos variantes, 32 y 64 bits) y el proyecto del usuario se enlaza a ella mediante una unit de importación dedicada, ExeWatchSDKv1Imports.pas, que funciona desde Delphi 5 en adelante. La unit de importación resuelve internamente las diferencias entre AnsiString y WideString, entre namespaces antiguos y modernos, entre IInterface y IUnknown.

// Delphi 5, 6, 7, 2007 y 2009: el mismo código, la misma API
uses
  ExeWatchSDKv1Imports;

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

Una vez tenido en casa el mecanismo de la DLL, exponerlo a un segundo mundo fue un paso natural: C++Builder y Microsoft Visual C++ (MSVC). La DLL es un binario Windows estándar, invocable desde cualquier lenguaje capaz de llamar a funciones C. La acompañamos con un header C utilizable tanto en link estático como con carga dinámica vía LoadLibrary, y un loader ya listo para incluir en el proyecto:

// ExeWatchSDKv1.h: link estático o 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");
    // ... trabajo real ...
    ew_EndTiming("invoice.generate");

    ew_WaitForSending(5);  // esperar el flush antes de salir (máx 5s)
    ew_Shutdown();
    return 0;
}

El mismo header con el mismo loader funciona indistintamente con C++Builder, MSVC, MinGW y Clang en Windows. No se necesitan build systems especiales ni dependencias externas: la DLL es autosuficiente y, desde el lado del proyecto, basta un único fichero .c (el header ExeWatchSDKv1.h y la implementación del loader, ya provista).

En lo operativo, la ABI de la DLL ha pasado a la versión 3, alineada con la nueva API WaitForSending. Quien usaba la 2 solo necesita actualizar la DLL y la unit de importación juntas: el esquema de las llamadas existentes no cambia.

Global Tags: dimensiones transversales en cada log

Los tags clásicos de ExeWatch (tag del log, tag del timing) son por definición contextuales: describen el evento individual. Pero muchos escenarios requieren dimensiones transversales que valen para toda la sesión de una aplicación: el tenant para el que se ejecuta, la región, el build flavor, el entorno, la variante de producto.

Hasta ahora la solución habitual era incluir esta información en el customer_id o en extra_data. Funcionaba, pero era repetitivo y, sobre todo, no se podía filtrar de forma estructurada desde el dashboard.

Con la 1.30 llegan los Global Tags, soportados en el SDK Delphi nativo y el SDK JavaScript. Se declaran una vez al inicializar el SDK y se añaden automáticamente 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 de ese momento, cada log enviado por la aplicación lleva consigo los tres tags. En la página Logs del dashboard encontrarás un filtro Global Tags que te permite ver, por ejemplo, solo los logs del tenant EU-North con flavor Pro-Edition:

Filtro Global Tags en la página Logs de ExeWatch: el desplegable muestra los pares clave/valor recogidos por las aplicaciones (environment: abi-test, environment: staging, feature_flag: new_checkout) listos para usarse como filtro

El desplegable "Global Tags" en la página Logs de ExeWatch enumera todos los pares clave/valor recibidos del SDK y permite filtrar la timeline de un vistazo.

Es exactamente la dimensión que faltaba para quien gestiona instalaciones multi-tenant o releases diferenciadas.

Alertas con filtro por Customer ID

Siguiendo en la línea del “control fino”, hemos añadido un filtro opcional por Customer ID tanto a las alertas de tipo log-level como a las de tipo timing.

El escenario es familiar: tienes una flota de 500 instalaciones y una de ellas (quizá un cliente nuevo con una configuración particular) genera errores recurrentes. Si bajas el umbral global recibes 20 notificaciones al día desde el resto del parque. Si lo dejas alto, pierdes el problema en el cliente específico.

Con el filtro por cliente puedes tener ambas cosas: una regla “global” tolerante y una regla específica para ese cliente con umbral bajo y cooldown corto. Cuando creas o modificas una alerta verás un nuevo campo opcional Filter by Customer: dejándolo en la opción por defecto All Customers la regla se aplica a toda la flota, mientras que eligiendo un Customer ID específico la regla solo se activa para ese cliente.

Diálogo de creación de un Log Level Alert en ExeWatch: el campo opcional Filter by Customer muestra una lista desplegable con todos los Customer ID recibidos de la aplicación, entre ellos SampleCustomer, MsvcSmokeText, BreadcrumbsSample, madExceptSample, Sample C++ Customer y DEMO-CUSTOMER

El nuevo campo "Filter by Customer" en el diálogo de creación de un Log Level Alert. El mismo campo está disponible también para los Timing Alert, con el mismo comportamiento.

El filtro está disponible tanto en los Log Level Alert como en los Timing Alert, con la misma lógica: si se rellena con un Customer ID, la regla se activa únicamente cuando el evento (error o timing lento) proviene de ese cliente; si se deja en la opción por defecto All Customers, la regla se aplica a toda la flota. Es útil también para el patrón opuesto: recibir notificaciones solo de los clientes piloto durante una fase de despliegue gradual de una nueva versión.

WaitForSending: espera explícita del flush

El log shipping de ExeWatch es asíncrono por diseño: el logging nunca bloquea al que llama y un thread dedicado se ocupa de enviar los batches al servidor en segundo plano. Para las aplicaciones VCL, FMX, WPF, WinForms o para los servicios de larga ejecución esta decisión es ideal: el vaciado final de la cola se gestiona automáticamente en Shutdown cuando el main loop termina de forma controlada.

Sin embargo, existen escenarios en los que el que llama quiere saber que la cola se ha vaciado antes de proseguir: scripts CLI que terminan justo después de loguear un error, jobs batch nocturnos, sesiones de tests E2E que deben propagar los logs antes de cerrar el navegador, finalización de un servicio Windows en respuesta a un stop request. En todos estos casos la 1.30 introduce una API uniforme en todos los SDKs llamada WaitForSending:

// Delphi, al final de una console app
EW.Fatal('Unrecoverable error: ' + E.Message, 'startup');
EW.WaitForSending(5);  // espera como máximo 5 segundos
ExitCode := 1;
// C#, al final de un Windows Service
EW.Fatal("Service stopping due to fatal error", "lifecycle");
EW.WaitForSending(5);
ExeWatchSdk.Shutdown();
// JS, antes de cerrar/recargar la página
ew.fatal("Unrecoverable client error", "ui");
await ew.waitForSending(5);
# Python, al final de un script CLI
ew.fatal("Job failed", "batch")
ew.wait_for_sending(5)

El valor devuelto es el número de items que aún quedan en la cola cuando el timeout ha expirado: cero significa “todo enviado correctamente”.

Timings thread-local

Las mediciones de timing (StartTiming / EndTiming) están entre las funcionalidades más usadas del SDK porque permiten perfilar código en producción con coste cero. Hasta la 1.30, en aplicaciones fuertemente multi-thread, dos workers que utilizaban el mismo timing id en threads distintos compartían el mismo “slot” interno. En casos límite esto podía producir mediciones menos precisas de lo que cabría esperar.

Con esta release el SDK gestiona un stack de timing por thread. Cada thread tiene su propio mapa independiente de timers pendientes, y los timers con el mismo id en threads distintos están completamente aislados. Cambia el comportamiento interno; la API no cambia. La modificación está disponible en Delphi, .NET y Python (el JavaScript-browser es single-thread por naturaleza, y los Web Workers ya tienen un contexto aislado):

// Delphi: ahora cada thread mantiene su propio stack de timing
// Nota: envolver siempre StartTiming/EndTiming en un try..finally,
// para que el timer se cierre incluso si DoHeavyWork lanza una excepción.
TThread.CreateAnonymousThread(
  procedure
  begin
    EW.StartTiming('worker.process', 'background');
    try
      DoHeavyWork;
    finally
      EW.EndTiming('worker.process');  // cierra el timer de ESTE thread
    end;
  end).Start;

TThread.CreateAnonymousThread(
  procedure
  begin
    EW.StartTiming('worker.process', 'background');  // OK, no colisiona
    try
      DoHeavyWork;
    finally
      EW.EndTiming('worker.process');
    end;
  end).Start;

El id lógico del timing se mantiene idéntico: en el dashboard worker.process sigue agregando correctamente las ejecuciones de ambos threads. Pero internamente cada thread tiene su propio “slot” y los timers no se pisan entre sí.

SDK JavaScript: captura completa de los errores HTTP

En el SDK JavaScript hay dos novedades que cambian la calidad de la información sobre los errores en producción.

La primera: cada vez que un fetch o un XMLHttpRequest devuelve un estado >= 400, el SDK captura automáticamente el body de la respuesta y lo adjunta como extra_data. Significa que junto al status code te llega también el mensaje de error devuelto por el backend, que es casi siempre la clave para entender lo que ha pasado.

La segunda: un nuevo callback httpErrorExtractor que te permite personalizar lo que se adjunta:

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 el body raw por defecto
  }
});

Útil si tu backend expone un payload de error estructurado (p. ej. FastAPI con {"detail": "...", "trace_id": "..."}) y quieres que ExeWatch lo logue en el mismo formato que usarías en tu dashboard de observabilidad del lado servidor.

Aislamiento del file queue por aplicación

Detalle invisible, consecuencia importante. En una máquina donde se ejecutan varias aplicaciones ExeWatch (típicamente una aplicación principal de usuario más un servicio Windows auxiliar, o dos variantes de producto en el mismo workstation), hasta ahora el directorio de almacenamiento offline era único por defecto y el aislamiento requería pasar paths distintos manualmente en la configuración de cada SDK.

Desde la 1.30, cada aplicación que inicializa el SDK crea automáticamente una subcarpeta dedicada identificada por la API key. Varias aplicaciones pueden coexistir en el mismo directorio de almacenamiento con total seguridad, sin necesidad de configuración adicional.

Notificaciones por correo electrónico sobre la cuota de eventos

El plan gratuito Hobby incluye 5.000 eventos al mes, el Pro 100.000, el Business 1.000.000. Desde la 1.30, el owner y los miembros del equipo reciben un correo al alcanzar dos umbrales:

  • 80% de la cuota mensual (aviso): hay tiempo para actuar antes del bloqueo
  • 100% de la cuota mensual (limit reached): los logs adicionales no se aceptan hasta el reset mensual

La cuota sigue siendo visible en el dashboard, pero el correo es la señal que muchos usuarios estaban esperando: te llega donde miras todos los días y te permite intervenir (bajando el nivel mínimo de log del SDK, aplicando filtros o planificando el upgrade) antes de que el problema se convierta en un bloqueo.

Pricing y On Premise

La página de pricing se ha enriquecido con un cuarto plan junto a Hobby, Pro y Business: On Premise. No es un plan self-service y nunca lo será: cada instalación on-premise de ExeWatch tiene necesidades específicas de sizing, backup, retención y soporte. Por eso mantenemos una conversación directa con quien lo necesita.

Los casos de uso más comunes son los previsibles: empresas que por política interna no pueden enviar datos de telemetría a un servicio gestionado, contextos regulatorios (GxP, healthcare, defense) o simples necesidades de latencia cuando la aplicación está geográficamente lejos de nuestro datacenter europeo.

La oferta on-premise incluye todas las funcionalidades del Business (incluido el AI Engine Full) más aplicaciones, eventos, retención, alertas y miembros de equipo ilimitados, integraciones personalizadas, onboarding dedicado y SLA negociado. Para detalles: exewatch@bittime.it.

Vídeos y webinars

📣 Webinar ExeWatch en español: miércoles 20 de mayo de 2026, organizado en colaboración con Delphi Studio. Para inscribirte solo tienes que rellenar este formulario de inscripción. Es el evento de referencia para la comunidad hispanohablante interesada en la integración de ExeWatch en proyectos Delphi y C++Builder.

Si quieres ver ExeWatch “en movimiento” antes de probarlo, en YouTube encontrarás tres vídeos útiles según el idioma y el stack que te interese:

  • 🇮🇹 ExeWatch: Proactive Software Monitoring (en italiano): diálogo entre Daniele Teti y Fabrizio Bitti que cuenta la génesis del producto, las decisiones de diseño y los escenarios de uso típicos. Es la presentación “humana” del proyecto, útil antes de empezar a mancharte las manos.

  • 🇬🇧 ExeWatch: Stop Waiting for Crash Reports and Start Solving Problems (en inglés): versión internacional, pensada para quien busca una visión concisa en inglés de las ventajas del monitoring proactivo frente al modelo tradicional de “esperar a que el cliente llame”.

  • 🇮🇹 Cosa succede alla tua app .NET in produzione? Scoprilo con ExeWatch! (Live Coding) (en italiano), live de Marco Breveglieri dedicada expresamente a los desarrolladores .NET / C#: integración paso a paso de ExeWatch en una solución C# directamente desde Visual Studio, con código en directo. Es la vía más rápida para empezar si tu stack es Windows + .NET.

Por qué ExeWatch sigue creciendo así

Algo que me sigue impresionando cada vez que sacamos una release con tantas novedades: ninguna de estas funcionalidades nació “en solitario” delante de una hoja en blanco. Cada una es el resultado de una conversación concreta con alguien que está usando ExeWatch en producción.

El soporte a C++Builder y MSVC viene de clientes del mundo industrial con código C++ legacy crítico en producción. Los tags globales vienen de un cliente con instalaciones multi-tenant. El filtro de alertas por cliente llegó tras una llamada en la que un cliente me decía “tengo un gran usuario que me inunda de alertas pero no puedo subir el umbral para los demás”. WaitForSending es una necesidad emergida hablando con quien gestiona jobs batch nocturnos en CLI.

Esta es también la razón por la que todas estas funcionalidades (incluidas las “patrocinadas” por clientes enterprise) están disponibles también en el plan gratuito Hobby. Los patrones que emergen a escala llegan tarde o temprano también a proyectos más pequeños: mejor tenerlos listos para cuando hagan falta.

Qué viene después

Vale la pena recordar que el SDK Delphi nativo ya compila y funciona en Delphi para Windows, Delphi para Linux y Delphi para Android: quien desarrolla aplicaciones FireMonkey para el mundo mobile tiene ExeWatch disponible desde ya, sin tener que esperar un SDK separado. El siguiente paso en esta dirección es cerrar el círculo con SDKs nativos independientes del toolchain Delphi para quien desarrolla mobile con stacks distintos (Kotlin/Java para Android nativo, Swift para iOS).

En el backend estamos trabajando para extender el AI Engine a un tercer nivel de análisis: no solo errores y timings, sino también patrones de uso (sesiones, oleadas de tráfico, picos de utilización). El objetivo es que el dashboard te diga “algo ha cambiado” incluso cuando el cambio no es un error, sino una variación anómala en la forma en que tus clientes utilizan el producto.

Si ya usas ExeWatch, todas las novedades de la 1.30 ya están activas en tu cuenta: no tienes que hacer nada del lado servidor. Para beneficiarte de WaitForSending, de los Global Tags y del nuevo SDK C/C++ basta con actualizar el SDK en el lado aplicación desde la página Integration del dashboard.

Si todavía no lo has probado, el plan Hobby es gratuito y no requiere tarjeta de crédito: bastan cinco minutos para la primera integración y normalmente los primeros logs llegan al dashboard antes incluso de que termines de leer la guía.


Enlaces y Recursos


ExeWatch: Application Performance Monitoring para aplicaciones server, desktop y web, con Artificial Intelligence Engine integrado. Creado por bit Time Professionals.

Comments

comments powered by Disqus