Observabilidad en TypeScript: de la caja negra al sistema transparente
\n\nImagina que tu aplicación TypeScript es un mecanismo complejo de miles de engranajes. Todo funciona perfectamente hasta que se rompe. Y entonces recibes un mensaje: «El sitio va lento». ¿Dónde buscar el problema? ¿Base de datos? ¿API? ¿O simplemente cayó uno de los microservicios?
\n\nSin observabilidad, estarás adivinando como un chamán con su tambor. Con observabilidad, ves el panorama completo: dónde cayó el rendimiento, qué solicitud causó el error y por qué hubo una fuga de memoria.
\n\nEn este artículo, analizaremos los tres pilares de la observabilidad — trazabilidad, métricas y registros — y aprenderemos a implementarlos en aplicaciones TypeScript con ejemplos reales. Descubrirás cómo transformar tu aplicación de una caja negra a un sistema transparente que se puede diagnosticar en minutos.
\n\n¿Por qué la observabilidad es crítica para las aplicaciones TypeScript?
\n\nTypeScript no es solo una extensión de JavaScript. Es un lenguaje con el que se escribe backend para sistemas de alta carga, microservicios e incluso herramientas CLI. Y cuanto más complejo es el sistema, más importante es entender lo que sucede en él.
\n\nEl registro tradicional está bien, pero no es suficiente. Cuando tienes 50 microservicios, los registros se convierten en ruido blanco. Necesitas:
\n\n- \n
- Trazabilidad — para rastrear la ruta de una sola solicitud a través de todos los servicios. \n
- Métricas — para ver que la RAM crece como la espuma. \n
- Registros estructurados — para no buscar una aguja en un pajar. \n
Implementemos esto en una aplicación real.
\n\nTrazabilidad en TypeScript: OpenTelemetry en la práctica
\n\nLa trazabilidad es la historia de vida de una sola solicitud. Ves cuánto tiempo tomó cada paso: desde la solicitud HTTP hasta la consulta a la base de datos. En TypeScript, el estándar de facto es OpenTelemetry.
\n\nInstalación y configuración de OpenTelemetry
\n\nnpm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-jaeger\n\nCreemos un archivo tracing.ts para inicializar la trazabilidad:
import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { JaegerExporter } from '@opentelemetry/exporter-jaeger';\nimport { Resource } from '@opentelemetry/resources';\nimport { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';\n\nconst jaegerExporter = new JaegerExporter({\n endpoint: 'http://localhost:14268/api/traces',\n serviceName: 'my-typescript-app',\n});\n\nconst sdk = new NodeSDK({\n resource: new Resource({\n [SemanticResourceAttributes.SERVICE_NAME]: 'my-typescript-app',\n [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',\n }),\n traceExporter: jaegerExporter,\n instrumentations: [getNodeAutoInstrumentations()],\n});\n\nsdk.start();\n\n\nAhora, cada solicitud HTTP, cada llamada a la base de datos se rastreará automáticamente. Verás en Jaeger UI (o Grafana Tempo) el mapa completo de llamadas.
\n\nCreación manual de spans
\n\nLa autoinstrumentación es genial, pero a veces necesitas agregar tus propias etiquetas. Por ejemplo, medir el tiempo de ejecución de una lógica de negocio compleja:
\n\nimport { trace } from '@opentelemetry/api';\n\nconst tracer = trace.getTracer('business-logic');\n\nasync function processOrder(orderId: string): Promise<void> {\n const span = tracer.startSpan('process-order', {\n attributes: { 'order.id': orderId },\n });\n\n try {\n // Tu lógica de procesamiento de pedidos\n await validateOrder(orderId);\n await chargePayment(orderId);\n await sendConfirmation(orderId);\n\n span.setStatus({ code: 1 }); // OK\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus