AWS Builder Center

CloudWatch Application Signals Dynamic Instrumentation: capturar el estado de una aplicación viva sin redesplegar

Todo el que ha depurado un problema de producción conoce el ciclo lento. El error solo aparece en producción, no se reproduce en local, y la única pista sería ver el valor de una variable en cierto punto del código. Entonces empieza el ritual: agregar una línea de log, hacer commit, redesplegar, esperar a que el problema vuelva a ocurrir, leer el log, y muchas veces descubrir que faltó capturar otra variable, así que a repetir. Amazon CloudWatch Application Signals Dynamic Instrumentation, corta ese ciclo.

Esta serie insiste en una disciplina: elegir la señal correcta, fijar un objetivo, tener un runbook. Dynamic Instrumentation encaja en la primera parte de una forma nueva. La señal aquí no es una métrica agregada, es el estado en tiempo de ejecución en el punto exacto del código donde vive la duda: el valor de una variable, los argumentos de un método, el valor de retorno, la traza de pila. Y la disciplina es saber cuándo alcanzar esta herramienta en lugar del ritual de log y redespliegue. Este artículo explica qué es, cómo se configura, cómo leer lo que captura y dónde están los límites. Cierra con limitaciones, recursos y tags.

Qué captura y con qué vocabulario

Dynamic Instrumentation captura el estado en tiempo de ejecución de una aplicación viva sin reiniciarla ni redesplegarla. Se definen configuraciones de instrumentación que indican en qué parte del código capturar datos, y el agente en ejecución instrumenta la aplicación en caliente.
El vocabulario del servicio es pequeño y conviene manejarlo con precisión:
  • Breakpoint: instrumentación temporal que expira automáticamente. La expiración por defecto es de 24 horas, configurable desde 5 minutos hasta 24 horas. Es la herramienta para depuración e investigación puntual.
  • Probe: instrumentación permanente que persiste hasta que se elimina de forma explícita. Sirve para observabilidad continua.
  • Snapshot: una captura puntual del estado del programa, que incluye variables locales, argumentos, valor de retorno, excepciones y traza de pila. Dynamic Instrumentation emite los snapshots como registros de log en Amazon CloudWatch Logs.
  • Location: la ubicación de código donde se aplica la instrumentación. Los campos requeridos varían según el lenguaje.
La distinción breakpoint contra probe es la que ancla el uso. Un breakpoint es para la cacería activa de un bug y se apaga solo. Un probe es para dejar un punto de observación permanente sobre algo que quieres vigilar a largo plazo.

Lenguajes y requisitos previos

Los lenguajes soportados son Java, Python y JavaScript o TypeScript. Hay una limitación importante para el mundo de JavaScript y TypeScript: solo se admiten breakpoints a nivel de línea. No se admiten probes ni breakpoints a nivel de función, y TypeScript requiere que se provean source maps. En Java y Python el modelo es más rico, con ubicación por paquete o módulo, clase y método.
Para habilitarla hay que poner al día los componentes de instrumentación. Para clientes de Amazon EKS, se actualiza el complemento de observabilidad de CloudWatch para EKS a la última versión, que ya incluye el SDK de AWS Distro for OpenTelemetry (ADOT) y el CloudWatch Agent. Para el resto, se actualizan por separado el SDK de instrumentación de ADOT del lenguaje correspondiente y el CloudWatch Agent a la última versión.
Además, deben cumplirse estas condiciones:
  • Amazon CloudWatch Application Signals debe estar habilitado para la aplicación.
  • La variable de entorno OTEL_AWS_DYNAMIC_INSTRUMENTATION_ENABLED debe estar en true. La función viene desactivada por defecto en los SDK de ADOT.
  • La variable OTEL_SERVICE_NAME debe tener el nombre del servicio.
  • La variable OTEL_RESOURCE_ATTRIBUTES debe fijar deployment.environment.name con el nombre del entorno. Para usuarios existentes de Application Signals, ese valor debe coincidir con el nombre del entorno del servicio tal como aparece en la consola.
  • El CloudWatch Agent debe estar corriendo con la configuración de Application Signals.
Un límite que hay que tener claro de entrada: Dynamic Instrumentation no es compatible con entornos de AWS Lambda.

La señal correcta: dónde y qué capturar

Cada configuración define dos cosas: dónde en el código monitorear, y qué datos capturar cuando la ejecución llega a ese punto. Esa separación es la que convierte la herramienta en una señal quirúrgica en vez de un volcado masivo.
La ubicación depende del lenguaje. En Java se requieren el paquete, la clase, el método y la ruta de archivo, con el número de línea como opcional. En Python se requieren el módulo, el método y la ruta de archivo. En JavaScript o TypeScript se requieren la ruta de archivo y el número de línea, porque solo hay breakpoints de línea.
La captura se controla con opciones explícitas, y aquí está la parte que respeta el principio de elegir bien la señal:
  • CaptureArguments: lista de nombres de argumentos del método a capturar.
  • CaptureReturn: capturar el valor de retorno.
  • CaptureStackTrace: capturar la traza de pila.
  • CaptureLocals: lista de variables locales a capturar.
  • CaptureLimits: controla la profundidad y el tamaño de lo capturado.
Por defecto, Dynamic Instrumentation captura solo datos limitados. Para sacarle valor hay que ampliar de forma deliberada qué se recoge, y ahí es donde nombrar exactamente los argumentos y las variables que importan evita ahogarse en ruido.

Configurar por CLI o por el servidor MCP

Hay dos caminos para crear configuraciones. El primero es programático, con la AWS CLI o el SDK. El siguiente ejemplo, tomado de la documentación, crea un breakpoint en un método de Java y captura dos argumentos, el valor de retorno y la traza de pila, con límites explícitos de captura:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
aws application-signals create-instrumentation-configuration \
--instrumentation-type BREAKPOINT \
--service "my-service" \
--environment "production" \
--signal-type SNAPSHOT \
--location '{
"CodeLocation": {
"Language": "Java",
"CodeUnit": "com.example.service",
"ClassName": "OrderController",
"MethodName": "processOrder",
"FilePath": "OrderController.java"
}
}' \
--capture-configuration '{
"CodeCapture": {
"CaptureArguments": ["orderId", "user"],
"CaptureReturn": true,
"CaptureStackTrace": true,
"CaptureLimits": {
"MaxHits": 100,
"MaxStringLength": 255,
"MaxCollectionWidth": 20,
"MaxObjectDepth": 3,
"MaxFieldsPerObject": 20,
"MaxStackFrames": 20
}
}
}'
El segundo camino, que la documentación recomienda, es el servidor MCP (Model Context Protocol) de Application Signals. Con él, un asistente de codificación con IA dentro del IDE puede crear breakpoints y probes sin salir del editor, consultar los snapshots capturados para inspeccionar valores de variables y rutas de llamada, correlacionar esos datos con el código en el que se está trabajando para sugerir arreglos, y administrar el ciclo de vida de las configuraciones. Este puente entre el editor y la telemetría de producción es el que conecta la feature con el mundo de developer experience.

Leer lo capturado y su ciclo de vida

Cuando un breakpoint o un probe se dispara, Dynamic Instrumentation crea un grupo de logs en CloudWatch Logs con el prefijo /aws/application-signals/service-name, donde service-name es el valor de la variable OTEL_SERVICE_NAME, y escribe los snapshots como registros de log en ese grupo. Si el grupo no existe, se crea de forma automática la primera vez que se emite un snapshot.
En la consola de CloudWatch, en la página de detalle del servicio, la pestaña de instrumentación permite alternar entre breakpoints y probes, ver el detalle de cada configuración (descripción, configuración de captura, ubicación, ARN y tiempo de expiración), seguir el historial de estados y eliminar lo que ya no se necesita.
El estado de cada configuración cuenta una historia clara: READY cuando el agente recibió la configuración, ACTIVE cuando la aplicó a la aplicación en ejecución, ERROR cuando falló, y DISABLED cuando expiró o se eliminó. Cuando algo entra en ERROR, la causa suele ser precisa y accionable: archivo no encontrado, método no encontrado, línea no ejecutable, métodos sobrecargados que exigen más detalle de ubicación, desajuste de lenguaje, o un error de tiempo de ejecución.

Un runbook para no capturar a ciegas

La misma disciplina de la serie aplica aquí, con un flujo repetible cuando cae un problema difícil de reproducir:
  1. Confirmar los prerequisitos una sola vez: Application Signals habilitado, componentes de ADOT y CloudWatch Agent al día, y las variables de entorno en su sitio, recordando que Lambda queda fuera.
  2. Elegir la ubicación exacta. En lugar de instrumentar medio servicio, apuntar al método o la línea donde vive la duda. La precisión de la ubicación es la mitad del valor.
  3. Elegir qué capturar. Nombrar solo los argumentos y las variables locales pertinentes, y decidir si hacen falta el valor de retorno y la traza de pila. Ajustar los límites de captura al caso.
  4. Usar un breakpoint, no un probe, para una investigación puntual. Expira solo, así que no deja instrumentación olvidada en producción.
  5. Leer los snapshots en el grupo de logs del servicio, correlacionados con la traza activa, y confirmar la hipótesis.
  6. Si es una condición que conviene vigilar a largo plazo, convertirla en probe de forma consciente. Si no, dejar que el breakpoint expire y documentar el hallazgo.

Limitaciones

  • No es compatible con AWS Lambda. Para funciones serverless hay que seguir con otras técnicas de observabilidad.
  • El soporte de JavaScript y TypeScript es más restringido: solo breakpoints a nivel de línea, sin probes ni breakpoints de función, y TypeScript exige source maps.
  • Los snapshots se almacenan como logs y se facturan a las tarifas estándar de CloudWatch Logs de ingesta y almacenamiento. Capturar mucho, muy seguido, tiene costo.
  • La captura está limitada por diseño. Cada punto de instrumentación está limitado a 5 capturas por segundo, y hay topes configurables: por defecto 255 caracteres por cadena, 20 elementos por colección, profundidad de objeto 3 (hasta 5), 20 campos por objeto, 20 marcos de pila, y para breakpoints un máximo de 100 capturas antes de autodesactivarse (hasta 1000). Son límites sanos, pero pueden truncar estructuras grandes.
  • La captura por defecto es mínima. Sin ampliar la configuración, el valor es escaso, así que exige decisión explícita sobre qué recoger.
  • Los breakpoints expiran (24 horas por defecto). Es una ventaja para investigación, pero si alguien esperaba una captura permanente sin darse cuenta, se le apagará sola; para permanencia se usa un probe.

Conclusion

Dynamic Instrumentation reemplaza el ciclo de agregar un log, redesplegar y esperar por algo mucho más cercano a la disciplina de esta serie: elegir con precisión la señal (el estado en el punto de código exacto), acotarla (qué capturar y con qué límites) y tener un flujo claro para investigar sin dejar instrumentación olvidada. Para un problema que solo aparece en producción y se resiste a reproducirse, la señal correcta ya no exige un despliegue nuevo. Se captura en caliente, se lee en CloudWatch Logs, y se apaga sola.

Recursos

Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article