Registro em log da função do AWS Lambda em Java - AWS Lambda

Registro em log da função do AWS Lambda em Java

Sua função do Lambda vem com um grupo de logs do CloudWatch Logs, com um fluxo de logs para cada instância de sua função. O tempo de execução envia detalhes sobre cada invocação para o fluxo de logs e retransmite os logs e outras saídas do código da função.

Para gerar os logs do código da função, use métodos no java.lang.System ou qualquer módulo de registro em log que grave no stdout ou no stderr. A biblioteca aws-lambda-java-core fornece uma classe do logger chamada LambdaLogger que você pode acessar a partir do objeto de contexto. A classe do logger oferece suporte a logs de várias linhas.

O exemplo a seguir usa o logger LambdaLogger fornecido pelo objeto de contexto.

exemplo 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; } }

exemplo formato do log

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

O tempo de execução do Java registra em log as linhas START, END e REPORT para cada invocação. A linha do relatório fornece os seguintes detalhes:

Registro em log de relatório

  • RequestId – o ID de solicitação exclusivo para a invocação.

  • Duração – a quantidade de tempo que o método de manipulador da função gastou processando o evento.

  • Duração faturada – a quantia de tempo faturada para a invocação.

  • Tamanho da memória – a quantidade de memória alocada para a função.

  • Memória máxima utilizada – a quantidade de memória utilizada pela função.

  • Duração inicial – para a primeira solicitação atendida, a quantidade de tempo que o tempo de execução levou para carregar a função e executar o código fora do método do manipulador.

  • XRAY TraceId – para solicitações rastreadas, o ID de rastreamento do AWS X-Ray.

  • SegmentId – para solicitações rastreadas, o ID do segmento do X-Ray.

  • Amostragem – para solicitações rastreadas, o resultado da amostragem.

Você pode visualizar logs no console do Lambda, no console do CloudWatch Logs ou na linha de comando.

Visualizar logs no Console de gerenciamento da AWS

O console do Lambda mostra a saída de log quando você testa uma função na página de configuração da função. Para visualizar log para todas as invocações, use o console do CloudWatch Logs.

Para visualizar os logs da função doLambda

  1. Abra a página Logs do console do CloudWatch.

  2. Escolha o nome do grupo de logs para a sua função (/aws/lambda/function-name).

  3. Escolha o primeiro fluxo da lista.

Cada fluxo de log corresponde a uma instância da sua função. Novos fluxos aparecem quando você atualiza a função e quando instâncias adicionais são criadas para processar várias invocações simultâneas. Para encontrar logs para invocações específicas, você pode instrumentar a função com o X-Ray e registrar detalhes sobre a solicitação e o fluxo de log no rastreamento. Para obter um exemplo de aplicativo que correlaciona logs e rastreamentos com o X-Ray, consulte Aplicativo de exemplo de processador de erros para o AWS Lambda.

Usar a AWS CLI

Para obter logs para uma invocação a partir da linha de comando, use a opção --log-type. A resposta inclui um campo LogResult que contém até 4 KB de logs codificados em base64 da invocação.

$ aws lambda invoke --function-name my-function out --log-type Tail { "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }

Você pode usar o utilitário base64 para decodificar os logs.

$ aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text | base64 -d 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: 100 ms Memory Size: 128 MB Max Memory Used: 73 MB

O utilitário base64 está disponível no Linux, macOS e Ubuntu no Windows. Para macOS, o comando é base64 -D.

Para obter eventos de log completos a partir da linha de comando, você pode incluir o nome do fluxo de logs na saída de sua função, conforme mostrado no exemplo anterior. O script de exemplo a seguir invoca uma função chamada my-function e faz o download dos últimos 5 eventos de log.

exemplo Script get-logs.sh

Este exemplo requer que my-function retorne um ID de fluxo de log.

#!/bin/bash aws lambda invoke --function-name my-function --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 $(cat out) --limit 5

O script usa sed para remover aspas do arquivo de saída e dorme por 15 segundos para permitir que os logs estejam disponíveis. A saída inclui a resposta do Lambda, e a saída do comando get-log-events.

$ ./get-logs.sh { "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: 100 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

Excluir logs

Os grupos de logs não são excluídos automaticamente quando você exclui uma função. Para evitar armazenar logs de maneira indefinida, exclua o grupo de logs ou configure um período de retenção após o qual os logs serão excluídos automaticamente.

Registro em log avançado com Log4j 2 e SLF4J

Para personalizar a saída de log, oferecer suporte ao registro em log durante testes de unidade e registrar chamadas do AWS SDK, use o Apache Log4j 2 com o SLF4J. O Log4j é uma biblioteca de registro em log para programas Java que permite configurar níveis de log e usar bibliotecas de appender. O SLF4J é uma biblioteca de fachada que permite alterar qual biblioteca você usa sem alterar o código da função.

Para adicionar o ID de solicitação aos logs da sua função, use o appender na biblioteca aws-lambda-java-log4j2. O exemplo a seguir mostra um arquivo de configuração Log4j 2 que adiciona um timestamp e o ID de solicitação a todos os logs.

exemplo src/main/resources/log4j2.xml – configuração do 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>

Com essa configuração, cada linha é precedida com a data, a hora, o ID da solicitação, o nível do log e o nome da classe.

exemplo formato de log com o 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", ... }

O SLF4J é uma biblioteca de fachada para registro em log em código Java. No código da função, use o logger factory SLF4J para recuperar um logger com métodos para níveis de log como info() e warn(). Na configuração da compilação, inclua a biblioteca de registro em log e o adaptador SLF4J no classpath. Alterando as bibliotecas na configuração de compilação, é possível alterar o tipo de logger sem alterar o código da função. O SLF4J é necessário para capturar logs do SDK para Java.

No exemplo a seguir, a classe de manipulador usa o SLF4J para recuperar um logger.

exemplo src/main/java/example/Handler.java – registro em log com o SLF4J

import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Handler value: example.Handler public class Handler implements RequestHandler<SQSEvent, String>{ private static final Logger logger = LoggerFactory.getLogger(Handler.class); Gson gson = new GsonBuilder().setPrettyPrinting().create(); LambdaAsyncClient lambdaClient = LambdaAsyncClient.create(); @Override public String handleRequest(SQSEvent event, Context context) { String response = new String(); // call Lambda API logger.info("Getting account settings"); CompletableFuture<GetAccountSettingsResponse> accountSettings = lambdaClient.getAccountSettings(GetAccountSettingsRequest.builder().build()); // log execution details logger.info("ENVIRONMENT VARIABLES: {}", gson.toJson(System.getenv())); ...

A configuração de compilação usa dependências de tempo de execução no appender e no adaptador SLF4J do Lambda, além de dependências de implementação no Log4J 2.

exemplo build.gradle – dependências de registro em log

dependencies { implementation platform('software.amazon.awssdk:bom:2.10.73') implementation platform('com.amazonaws:aws-xray-recorder-sdk-bom:2.4.0') implementation 'software.amazon.awssdk:lambda' implementation 'com.amazonaws:aws-xray-recorder-sdk-core' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-core' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2-instrumentor' implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.1.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'org.apache.logging.log4j:log4j-api:2.13.0' implementation 'org.apache.logging.log4j:log4j-core:2.13.0' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.13.0' runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.2.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0' }

Quando você executa seu código localmente para testes, o objeto de contexto com o logger do Lambda não está disponível e não há nenhum ID de solicitação para o appender do Lambda usar. Para obter exemplos de configurações de teste, consulte os aplicativos de exemplo na próxima seção.

Código de exemplo de registro em log

O repositório do GitHub para este guia inclui aplicativos de exemplo que demonstram o uso de várias configurações de registro em log. Cada aplicativo de exemplo inclui scripts para fácil implantação e limpeza, um modelo do AWS SAM e recursos de suporte.

Aplicativos de exemplo do Lambda em Java

  • blank-java – uma função Java que mostra o uso das bibliotecas Java do Lambda, registro em log, variáveis de ambiente, camadas, rastreamento do AWS X-Ray, testes de unidade e do AWS SDK.

  • java-basic – uma função Java mínima com testes de unidade e configuração de registro em log variável.

  • java-events – uma função Java mínima que usa a biblioteca aws-lambda-java-events com tipos de evento que não exigem o AWS SDK como dependência, como o Amazon API Gateway.

  • java-events-v1sdk – uma função Java que usa a biblioteca aws-lambda-java-events com tipos de evento que exigem o AWS SDK como dependência (Amazon Simple Storage Service, Amazon DynamoDB e Amazon Kinesis).

  • s3-java – uma função Java que processa eventos de notificação do Amazon S3 e usa a Java Class Library (JCL) para criar miniaturas de arquivos de imagem enviados por upload.

O aplicativo de exemplo java-basic mostra uma configuração mínima de registro em log que oferece suporte a testes de registro em log. O código do manipulador usa o logger LambdaLogger fornecido pelo objeto de contexto. Para testes, o aplicativo usa uma classe TestLogger personalizada que implementa a interface LambdaLogger com um logger Log4j 2. Ele usa o SLF4J como fachada para compatibilidade com o AWS SDK. As bibliotecas de registro em log são excluídas da saída de compilação para manter o pacote de implantação pequeno.

O aplicativo de exemplo blank-java se baseia na configuração básica com o registro em log do AWS SDK e o appender Log4j 2 do Lambda. Ele usa o Log4j 2 no Lambda com o appender personalizado que adiciona o ID de solicitação de invocação à cada linha.