Alexa skills monitoring: añadiendo interceptores al lambda para tener logs

Una cosa que no conté en mi serie de post sobre crear una skill de Alexa era el tema del monitoring de la parte back. Es básico poder visualizar de alguna forma cómo se está comportando nuestro sistema ante las interacciones de los usuarios. Sobre todo si tenemos cosas fallando y no estamos cubiertos ante esos errores.

Yo voy considerar dos patas en este tema del monitoring: por un lado, la creación de logs de requests y responses; por otro lado, apoyándonos en lo anterior, tendremos la creación de métricas y alarmas. En este post os voy a hablar de lo primero.

Vamos a ver cómo crear logs en el lambda y con qué herramientas de AWS visualizarlos.

Añadiendo logs al lambda

Añadir logs al lambda de la skill no es diferente de añadir logs a cualquier servicio backend que podemos tener en aplicaciones mobile o web. Depende de la tecnología hay unas librerías u otras. En el caso  Java/Kotlin lo habitual es usar Apache Log4j2 y con AWS Lambda se puede integrar en nuestro back tal y como indica en su documentación oficial.

Pero, si no queremos liarnos la manta a la cabeza y queremos algo simple, como era mi caso, no es necesario añadir nada de eso. Ya en AWS tenemos CloudWatch Logs que, al usar lambda, nos permitirá visualizar todo aquello que escribamos en la consola normal.

De esta forma no tenemos que añadir ni dependencias ni ficheros de configuración. En el caso de Kotlin, con usar println ya vamos a ver esos mensajes en la consola de CloudWatch. Ya sé que eso no es lo habitual y que solemos integrar librerías de logs para temas como el nivel del mensaje (info, debug, warning, error, etc) pero yo no iba a usarlo.

Usando interceptores para la request/response

El SDK de Alexa te permite añadir interceptores, de request y de response a la hora de construir la skill. Usaremos esos interceptores para tener uno que nos saque el contenido de la request y otro para el contenido de la response.

Aquí vemos:

  • Hay que extender de la clase RequestInterceptor y hacer override del método process. Este método nos permite tener acceso al HandlerInput.
  • Serializo el contenido de la request a JSON para sacarlo por la consola. Luego veréis en una captura qué bien queda la salida de esta forma. Uso una clase que ya tiene el SDK de JacksonSerializer que aplica una config básica al mapper.

Aquí vemos:

  • Hay que extender de la clase ResponseInterceptor que nos dará acceso al método process con el HandlerInput y la response.
  • En este caso sólo nos interesa la response, en el caso de que exista. Si la tenemos podemos serializar su contenido al igual que antes con la request.
  • Usamos igualmente la clase de utils de JacksonSerializer.

Una vez tenemos ambos interceptores creados solo nos queda añadirlos a la skill en el momento de su construcción.

  • La factory de Skills nos ofrece acceso a un par de métodos para añadir los interceptores que creamos antes.
  • Aquí es importante destacar que estamos creando una skill de tipo standar. Esto hace que haya ciertas cosas predefinidas y configuradas por el SDK, como por ejemplo Jackson, la apiClient para acceso a APIs de Amazon, un adaptador de persistencia para DynamoDb, etc. Hablar de la opción custom vs standard da para otro post. Puedes usar cualquier librería, como Gson y construir el skill con custom.

Usando CloudWatch Logs

Una vez hemos preparado el código y desplegado esa versión del lambda ya vamos a poder ver resultados usando AWS.

Si lanzamos un test event desde la consola de AWS, podemos ver una salida como la de la imagen anterior. Aquí ya podemos apreciar, en la parte inferior del cuadro verde, la salida por consola de nuestros interceptores. Con esto sabemos que lo que hemos hecho está funcionando.

Desde la pestaña monitoring podemos acceder a la consola de CloudWatch para esta función lambda directamente.

Aquí vemos entradas de logs por cada inicio de sesión del lambda. Cada entrada está identificada con la fecha, la versión de lambda que se inicia y el id de sesión. En cada sesión puede haber varios eventos y podemos ver, en la columna siguiente, la fecha del último evento en esa sesión.

Vamos a ver la forma de esos eventos en la siguiente captura.

  • Tenemos un mensaje de error porque no estamos configurando el tema de Log4j2, tal y como os dije al principio. Podemos pasar de ese error ya que no va a afectar a la salida de lo que nos interesa.
  • Vemos cómo se registra un evento de inicio de una request.
  • Lo siguiente es el resultado de nuestros interceptores. En este caso van seguidos porque no ha habido ninguna otra salida por consola durante la request en el lambda. Podemos ver cómo la salida JSON está bien formateada y es bastante fácil de leer.
  • Y, por último, tenemos el evento de final de sesión y un reporte de profiling.

Otros errores

¿Y qué pasa con otros mensajes de error como las excepciones? Pues que van a aparecer también como eventos dentro de una sesión de CloudWatch. Aquí os adjunto una captura de una excepción que ocurre dentro del lambda de la skill.


Llegado a este punto ya vamos a poder saber qué está pasando dentro de nuestro sistema cuando los usuarios interactúen con la skill. Además, estos mensajes nos van a servir como base para meter métricas y alarmas. De esta forma vamos a estar informados de si están ocurriendo errores en nuestro lambda sin tener que estar mirando continuamente CloudWatch.

Esto lo veremos en el siguiente post sobre monitoring :)