Registro de funciones de AWS Lambda en Java - AWS Lambda

Registro de funciones de AWS Lambda en Java

AWS Lambda supervisa automáticamente funciones de Lambda en su nombre y envía registros a Amazon CloudWatch. Su función de Lambda viene con un grupo de registros de CloudWatch Logs y con un flujo de registro para cada instancia de su función. El entorno de tiempo de ejecución de Lambda envía detalles sobre cada invocación al flujo de registro y retransmite los registros y otras salidas desde el código de la función. Para obtener más información, consulte Acceso a los registros de Amazon CloudWatch para AWS Lambda.

Esta página describe cómo producir resultados de registro a partir del código de la función de Lambda o registros de acceso mediante AWS Command Line Interface, la consola de Lambda o la consola CloudWatch.

Crear una función que devuelve registros

Para generar registros desde el código de función, puede utilizar los métodos de java.lang.System o cualquier módulo de registro que escriba en stdout o en stderr. La biblioteca aws-lambda-java-core tiene una clase de registrador llamada LambdaLogger a la que se puede acceder desde el objeto contextual. La clase de registrador admite registros multilínea.

En el ejemplo siguiente se utiliza el registrador LambdaLogger proporcionado por el objeto contextual.

ejemplo Handler.java
// Handler value: example.Handler public class Handler implements RequestHandler<Object, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Object event, Context context) { LambdaLogger logger = context.getLogger(); String response = new String("SUCCESS"); // log execution details logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); logger.log("CONTEXT: " + gson.toJson(context)); // process event logger.log("EVENT: " + gson.toJson(event)); return response; } }
ejemplo formato de registro
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... } EVENT: { "records": [ { "messageId": "19dd0b57-xmpl-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", "body": "Hello from SQS!", ... } ] } END RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 REPORT RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Duration: 198.50 ms Billed Duration: 200 ms Memory Size: 512 MB Max Memory Used: 90 MB Init Duration: 524.75 ms

El tiempo de ejecución de Java registra las líneas START, END y REPORT de cada invocación. La línea del informe proporciona los siguientes detalles:

Registro de informes
  • RequestId: el ID de solicitud único para la invocación.

  • Duración: la cantidad de tiempo que el método de controlador de función pasó procesando el evento.

  • Duración facturada: la cantidad de tiempo facturado por la invocación.

  • Tamaño de memoria: la cantidad de memoria asignada a la función.

  • Máximo de memoria usada: la cantidad de memoria utilizada por la función.

  • Duración de inicio: para la primera solicitud servida, la cantidad de tiempo que tardó el tiempo de ejecución en cargar la función y ejecutar código fuera del método del controlador.

  • TraceId de XRAY: para las solicitudes rastreadas, el ID de seguimientode AWS X-Ray.

  • SegmentId: para solicitudes rastreadas, el ID del segmento de X-Ray.

  • Muestras: para solicitudes rastreadas, el resultado del muestreo.

Uso de la consola de Lambda

Puede utilizar la consola de Lambda para ver la salida del registro después de invocar una función de Lambda. Para obtener más información, consulte Acceso a los registros de Amazon CloudWatch para AWS Lambda.

Uso de la consola de CloudWatch

Puede utilizar la consola Amazon CloudWatch para ver los registros de todas las invocaciones de funciones de Lambda.

Para ver los registros en la consola CloudWatch
  1. En la consola de CloudWatch, abra la página de grupos de registro.

  2. Seleccione el grupo de registros para su función (/aws/lambda/your-function-name).

  3. Elija una secuencia de registro.

Cada flujo de registro se corresponde con una instancia de su función. Aparece un flujo de registro cuando actualiza la función de Lambda y cuando se crean instancias adicionales para manejar varias invocaciones simultáneas. Para encontrar registros para una invocación específica, le recomendamos que interfiera su función con AWS X-Ray. X-Ray registra los detalles sobre la solicitud y el flujo de registro en el seguimiento.

Para utilizar una aplicación de ejemplo que correlacione registros y trazas con X-Ray, consulte Aplicación de ejemplo de procesamiento de errores para AWS Lambda.

Uso de AWS Command Line Interface (AWS CLI)

La AWS CLI es una herramienta de código abierto que le permite interactuar con los servicios de AWS mediante el uso de comandos en el shell de la línea de comandos. Para completar los pasos en esta sección, debe disponer de lo siguiente:

Puede utilizar la CLI de AWS CLI para recuperar registros de una invocación mediante la opción de comando --log-type. La respuesta contiene un campo LogResult que contiene hasta 4 KB de registros con codificación base64 a partir de la invocación.

ejemplo recuperar un ID de registro

En el ejemplo siguiente se muestra cómo recuperar un ID de registro del campo LogResult para una función denominada my-function.

aws lambda invoke --function-name my-function out --log-type Tail

Debería ver los siguientes datos de salida:

{ "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }
ejemplo decodificar los registros

En el mismo símbolo del sistema, utilice la utilidad base64 para decodificar los registros. En el ejemplo siguiente se muestra cómo recuperar registros codificados en base64 para my-function.

aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text | base64 -d

Debería ver los siguientes datos de salida:

START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST "AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib", END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Duration: 79.67 ms Billed Duration: 80 ms Memory Size: 128 MB Max Memory Used: 73 MB

La utilidad base64 está disponible en Linux, macOS y Ubuntu en Windows. Es posible que los usuarios de macOS necesiten usar base64 -D.

ejemplo get-logs.sh script

En el mismo símbolo del sistema, utilice el siguiente script para descargar los últimos cinco eventos de registro. El script utiliza sed para eliminar las comillas del archivo de salida y permanece inactivo durante 15 segundos para dar tiempo a que los registros estén disponibles. La salida incluye la respuesta de Lambda y la salida del comando get-log-events.

Copie el contenido de la siguiente muestra de código y guárdelo en su directorio de proyecto Lambda como get-logs.sh.

La opción cli-binary-format es obligatoria si va a usar la versión 2 de AWS CLI. Para que esta sea la configuración predeterminada, ejecute aws configure set cli-binary-format raw-in-base64-out. Para obtener más información, consulte las opciones globales de la línea de comandos admitidas de AWS CLI.

#!/bin/bash aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out sed -i'' -e 's/"//g' out sleep 15 aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
ejemplo macOS y Linux (solamente)

En el mismo símbolo del sistema, es posible que los usuarios de macOS y Linux necesiten ejecutar el siguiente comando para asegurarse de que el script es ejecutable.

chmod -R 755 get-logs.sh
ejemplo recuperar los últimos cinco eventos de registro

En el mismo símbolo del sistema, ejecute el siguiente script para obtener los últimos cinco eventos de registro.

./get-logs.sh

Debería ver los siguientes datos de salida:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" } { "events": [ { "timestamp": 1559763003171, "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n", "ingestionTime": 1559763003309 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r \"key\": \"value\"\r}\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

Eliminación de registros

Los grupos de registro no se eliminan automáticamente cuando se elimina una función. Para evitar almacenar registros indefinidamente, elimine el grupo de registros o configure un periodo de retención después de lo cual los registros se eliminan automáticamente.

Registro avanzado con Log4j 2 y SLF4J

nota

AWS Lambda no incluye Log4j2 en los tiempos de ejecución administrados ni en las imágenes de contenedores base. Por lo tanto, no se ven afectados por los problemas descritos en CVE-2021-44228, CVE-2021-45046 y CVE-2021-45105.

En los casos en los que una función de cliente incluya una versión de Log4j2 afectada, hemos aplicado cambios a los tiempos de ejecución administrados de Java y las imágenes de contenedores base de Lambda para poder mitigar los problemas de CVE-2021-44228, CVE-2021-45046 y CVE-2021-45105. Como resultado de este cambio, los clientes que utilizan Log4J2 pueden ver una entrada de registro adicional, similar a “Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)”. Cualquier cadena de registro que haga referencia al asignador jndi en la salida de Log4J2 se reemplazará por “Patched JndiLookup::lookup()”.

Independientemente de este cambio, recomendamos encarecidamente a todos los clientes cuyas funciones incluyan Log4j2 que actualicen a la última versión. En concreto, los clientes que utilicen la biblioteca aws-lambda-java-log4j2 en sus funciones deben actualizar a la versión 1.5.0 (o posterior) y volver a implementarlas. Esta versión actualiza las dependencias de la utilidad Log4j2 subyacentes a la versión 2.17.0 (o posterior). El binario aws-lambda-java-log4j2 actualizado está disponible en el repositorio de Maven y su código fuente está disponible en GitHub.

Para personalizar la salida del registro, posibilitar el registro durante las pruebas unitarias y registrar las llamadas del SDK de AWS, utilice Apache Log4j 2 con SLF4J. Log4j es una biblioteca de registros para programas Java que permite configurar diversos niveles de registro y utilizar bibliotecas de appender. SLF4J es una biblioteca de fachadas que permite cambiar la biblioteca empleada sin modificar el código de la función.

Para agregar el ID de la solicitud a los registros de la función, use el appender de la biblioteca aws-lambda-java-log4j2. En el ejemplo siguiente, se muestra un archivo de configuración de Log4j 2 que agrega una marca temporal y un ID de solicitud a todos los registros.

ejemplo src/main/resources/log4j2.xml: configuración de appender.
<Configuration status="WARN"> <Appenders> <Lambda name="Lambda"> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n</pattern> </PatternLayout> </Lambda> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="Lambda"/> </Root> <Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>

Con esta configuración, en cada línea se antepone la fecha, la hora, el ID de solicitud, el nivel de registro y el nombre de clase.

ejemplo formato de registro con appender
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST 2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler - ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } 2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler - CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... }

SLF4J es una biblioteca de fachadas para los registros de código Java. En el código de la función, se utiliza la fábrica del registrador de SLF4J para recuperar un registrador con métodos para niveles de registro como info() y warn(). En la configuración de compilación, puede incluir la biblioteca de registros y el adaptador de SLF4J en el classpath. Si cambia las bibliotecas en la configuración de compilación, puede cambiar el tipo de registrador sin necesidad de modificar el código de la función. Es necesario utilizar SLF4J para capturar registros de SDK para Java.

En el siguiente ejemplo, la clase de controlador utiliza SLF4J para recuperar un registrador.

ejemplo src/main/java/example/HandlerS3.java: registro con SLF4J
import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Handler value: example.Handler public class HandlerS3 implements RequestHandler<S3Event, String>{ private static final Logger logger = LoggerFactory.getLogger(HandlerS3.class); Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(S3Event event, Context context) { ... logger.info("RECORD: " + record); logger.info("SOURCE BUCKET: " + srcBucket); logger.info("SOURCE KEY: " + srcKey); ... } }

La configuración de compilación toma dependencias del entorno de ejecución del appender de Lambda y del adaptador de SLF4J, y dependencias de implementación de Log4J 2.

ejemplo build.gradle: dependencias de registro
dependencies { ... implementation 'org.apache.logging.log4j:log4j-api:[2.17.1,)' implementation 'org.apache.logging.log4j:log4j-core:[2.17.1,)' implementation 'org.apache.logging.log4j:log4j-slf4j18-impl:[2.17.1,)' ... }

Cuando ejecuta el código localmente para realizar pruebas, el objeto contextual con el registrador de Lambda no está disponible y no hay ningún ID de solicitud que el appender de Lambda pueda utilizar. Para ver ejemplos de configuraciones de prueba, consulte las aplicaciones de la siguiente sección.

Código de registro de ejemplo

El repositorio de GitHub para esta guía contiene aplicaciones de ejemplo en las que se muestra el uso de diferentes configuraciones de registro. Cada una de las aplicaciones de ejemplo contiene scripts para facilitar la implementación y la limpieza, una plantilla de AWS SAM y recursos de soporte.

Aplicaciones de Lambda de ejemplo en Java
  • java-basic: una colección de funciones Java mínimas con pruebas unitarias y configuración de registro variable.

  • java-events: una colección de funciones Java que contiene un código básico sobre cómo gestionar los eventos de varios servicios, como Amazon API Gateway, Amazon SQS y Amazon Kinesis. Estas funciones utilizan la última versión de la biblioteca aws-lambda-java-events (3.0.0 y más recientes). Estos ejemplos no requieren utilizar AWS SDK como una dependencia.

  • s3-java: una función de Java que procesa los eventos de notificación de Amazon S3 y utiliza Java Class Library (JCL) para crear miniaturas de los archivos de imagen cargados.

  • Uso de API Gateway para invocar una función de Lambda: una función Java que escanea una tabla de Amazon DynamoDB que contiene información sobre los empleados. Luego, utiliza Amazon Simple Notification Service para enviar un mensaje de texto a los empleados que celebran sus aniversarios laborales. En este ejemplo, se utiliza API Gateway para invocar la función.

En la aplicación de ejemplo java-basic, se muestra una configuración de registro mínima que admite pruebas de registro. El código del controlador utiliza el registrador de LambdaLogger proporcionado por el objeto contextual. En el caso de las pruebas, la aplicación utiliza una clase TestLogger personalizada que implementa la interfaz LambdaLogger con un registrador de Log4j 2. SLF4J se utiliza como fachada para garantizar la compatibilidad con el SDK de AWS. Las bibliotecas de registro se excluyen de la salida de compilación para mantener un tamaño de paquete de implementación pequeño.