O blog da AWS

Apresentando a versão 2 do Powertools for AWS Lambda (Java)

Por Philipp Page, SA Engineer.

Os aplicativos modernos dependem cada vez mais de tecnologias Serverless, como o Amazon Web Services (AWS) Lambda, para fornecer escalabilidade, eficiência de custos e agilidade. O Serverless Applications Lens para o AWS Well-Architected Framework se concentra em como projetar, implantar e arquitetar seus aplicativos Serverless para superar alguns desses desafios.

O Powertools for AWS Lambda é um kit de ferramentas para desenvolvedores que ajuda você a implementar as melhores práticas Serverless e traduz diretamente as recomendações do AWS Well-Architected em utilitários acionáveis e fáceis de usar. Após a adoção contínua e bem-sucedida do Powertools for AWS em Python, Java, TypeScript e .NET pela comunidade, esta publicação anuncia a disponibilidade geral do Powertools for AWS Lambda (Java) v2, com grandes melhorias de desempenho, utilitários principais aprimorados e um novo utilitário Kafka.

O Powertools for AWS (Java) v2 fornece três utilitários principais atualizados:

  • Logging: um módulo de logging idiomático Java redesenhado que fornece logging estruturado que simplifica a agregação e a análise de loggings.
  • Métricas: uma experiência de métricas aprimorada que permite a coleta de métricas personalizadas usando o CloudWatch Embedded Metric Format (EMF).
  • Rastreamento: uma forma baseada em anotações de coletar dados de rastreamento distribuídos com o AWS X-Ray para visualizar e analisar fluxos de solicitações.

Junto com os principais utilitários atualizados, a v2 do kit de ferramentas para desenvolvedores adiciona dois novos recursos:

  • Suporte de imagem nativa do GraalVM: suporte de imagem nativa para o GraalVM em todos os utilitários principais, reduzindo os tempos de inicialização a frio do Lambda em até 75,61% (p95).
  • Utilitário Kafka: esse novo utilitário se integra ao Amazon Managed Streaming for Apache Kafka (Amazon MSK) e às fontes de eventos autogerenciadas do Kafka no Lambda e permite que os desenvolvedores desserializem diretamente em tipos nativos do Kafka, como ConsumerRecords.

Saiba mais sobre como migrar para a v2 em nosso guia de atualização.

Introdução ao uso do Powertools for AWS Lambda (Java) v2

O Powertools for AWS Lambda (Java) v2 está prontamente acessível como um pacote Java no Maven Central e se integra a ferramentas de criação populares, como Maven e Gradle. Esta postagem se concentra em exemplos de implementação baseados em Maven para ajudar você a começar rapidamente. Os exemplos do Gradle estão disponíveis para todos os utilitários na documentação e no repositório de exemplos.

O kit de ferramentas é compatível com o Java 11 e versões mais recentes, garantindo que você possa usar os recursos modernos do Java ao criar aplicativos Serverless. Exemplos de como instalar cada utilitário estão descritos em cada seção da postagem e exemplos completos de configuração também estão disponíveis na documentação do Powertools.

Logging

O utilitário Logging ajuda a implementar o logging estruturado ao ser executado no Lambda enquanto ainda usa bibliotecas de logging Java conhecidas, como slf4j, log4j e logback. A v2 do Logging permite que você faça o seguinte:

  • Logs JSON estruturados de saída enriquecidos com contexto Lambda
  • Escolha o back-end de logging de sua escolha entre log4j2 e logback
  • Adicione argumentos estruturados aos loggings que são serializados em objetos JSON aninhados arbitrariamente
  • Adicione chaves de log globais usando o Contexto de Diagnóstico Mapeado (MDC) padrão do slf4j

Para adicionar o utilitário de logging ao seu projeto, inclua-o como uma dependência no seu projeto Java Maven. O exemplo a seguir mostra como adicionar o back-end de logging log4j2 ao seu aplicativo:

<!-- In the dependencies section -->
<dependency>
    <groupId>software.amazon.lambda</groupId>
    <artifactId>powertools-logging-log4j</artifactId>
    <!-- Alternatively, if you wish to use the logback backend
    <artifactId>powertools-logging-logback</artifactId> 
    -->
    <version>2.1.1</version>
</dependency>
<!-- In the build plugins section -->
<plugin>
    <groupId>dev.aspectj</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>software.amazon.lambda</groupId>
                <artifactId>powertools-logging</artifactId>
                <version>2.1.1</version>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
</plugin>

Crie um anexador JsonTemplateLayout personalizado em seu arquivo log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="JsonAppender" target="SYSTEM_OUT">
            <JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="JsonLogger" level="INFO" additivity="false">
            <AppenderRef ref="JsonAppender"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="JsonAppender"/>
        </Root>
    </Loggers>
</Configuration>

Para adicionar loggings estruturados às suas funções, aplique a anotação @Logging ao seu handler do Lambda e use a conhecida API Java slf4j ao escrever instruções de log. Isso permite que você adote o utilitário de logging sem a maior refatoração de código. O Powertools gerencia o roteamento para o backend de logging correto para você. O exemplo a seguir mostra como adicionar chaves de log globais usando o MDC e adicionar um argumento de entrada estruturado à sua mensagem de log:

public class App implements RequestHandler<SQSEvent, String> {
    private static final Logger log = LoggerFactory.getLogger(App.class);

    @Logging
    public String handleRequest(final SQSEvent input, final Context context) {
        // Add a global log key using Mapped Diagnostic Context MDC
        MDC.put("myCustomKey", "willBeLoggedForAllLogStatements");

        // Log a message with a structured argument (any JSON serializable Object)
        log.info("My message", entry("anotherCustomKey", Map.of("nested", "object")));

        // ... return response
    }
}

O Lambda envia a seguinte saída formatada em JSON para o Amazon CloudWatch Logs (observe como o mapa Java é serializado automaticamente em um objeto JSON):

{

  "level": "INFO",
  "message": "My message",
  "cold_start": true,
  "function_arn": "arn:aws:lambda:us-east-1:012345678912:function:AppFunction",
  "function_memory_size": 512,
  "function_name": "AppFunction",
  "function_request_id": "0150a2a4-c5aa-4277-9345-17bad039f6c0",
  "function_version": "$LATEST",
  "sampling_rate": 0.1,
  "service": "powertools-java-sample",
  "timestamp": "2025-05-20T08:35:28.565Z",
  "myCustomKey": "willBeLoggedForAllLogStatements",
  "anotherCustomKey": {
    "nested": "object"
  }

Métricas

O CloudWatch oferece métricas de serviço integradas essenciais para monitorar a taxa de transferência de aplicativos, as taxas de erro e o uso de recursos. Os usuários também precisam capturar métricas personalizadas específicas da carga de trabalho relevantes para seu caso de uso comercial, seguindo as melhores práticas do AWS Well-Architected.

O Powertools for AWS (Java) permite que você crie métricas personalizadas de forma assíncrona, enviando métricas no CloudWatch EMF diretamente para a saída padrão — uma abordagem que não precisa de outra configuração. O serviço Lambda envia as métricas formatadas em EMF para o CloudWatch em seu nome.

O utilitário Metrics permite que você:

  • Crie métricas personalizadas de forma assíncrona usando o CloudWatch EMF
  • Reduza a latência evitando a publicação síncrona de métricas
  • Rastreie automaticamente inícios a frio em uma métrica personalizada do CloudWatch
  • Evite validar manualmente sua saída em relação à especificação EMF
  • Mantenha seu código limpo evitando a descarga manual para a saída padrão

Para adicionar o utilitário Metrics ao seu projeto, adicione a seguinte dependência do Maven:

<!-- In the dependencies section -->
<dependency>
    <groupId>software.amazon.lambda</groupId>
    <artifactId>powertools-metrics</artifactId>
    <version>2.1.1</version>
</dependency>
<!-- In the build plugins section -->
<plugin>
    <groupId>dev.aspectj</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>software.amazon.lambda</groupId>
                <artifactId>powertools-metrics</artifactId>
                <version>2.1.1</version>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
</plugin>

Para adicionar métricas personalizadas à sua função do Lambda, coloque a anotação @FlushMetrics no seu manipulador do Lambda. A biblioteca se encarrega de validar e transferir suas métricas para a saída padrão antes que a função Lambda termine. O exemplo a seguir mostra como você pode capturar automaticamente uma métrica de inicialização a frio e emitir suas próprias métricas personalizadas:

public class App implements RequestHandler<SQSEvent, String> {
    private static final Logger log = LoggerFactory.getLogger(App.class);
    private static final Metrics metrics = MetricsFactory.getMetricsInstance();

    // This configures a default namespace and service dimension for all metrics
    @FlushMetrics(namespace = "ServerlessAirline", service = "payment", captureColdStart = true)
    public String handleRequest(final SQSEvent input, final Context context) {
        // The Metrics instance is a singleton
        metrics.addMetric("CustomMetric1", 1, MetricUnit.COUNT);

        // Publish metrics with non-default configuration options
        DimensionSet dimensionSet = new DimensionSet();
        dimensionSet.addDimension("Service", "AnotherService");
        metrics.flushSingleMetric("CustomMetric2", 1, MetricUnit.COUNT, "AnotherNamespace", dimensionSet);

        // ... return response
    }
}

AWS CloudWatch Metrics Graph View of metrics generated by Metrics utility example.

Figura 1. Visualização do gráfico de métricas do AWS CloudWatch

Rastreamento

O utilitário Tracing fornece uma integração baseada em anotações com o X-Ray para rastreamento distribuído com configuração mínima. O rastreamento permite que você:

  • Obtenha visibilidade de seus próprios métodos, chamadas e interações de serviços da AWS visualizadas no console X-Ray
  • Capture automaticamente respostas e erros do método
  • Capture automaticamente as informações de inicialização a frio do Lambda como parte de seus rastreamentos
  • Adicione metadados personalizados aos rastreamentos para obter mais informações de contexto e depuração
  • Ative ou desative os recursos de rastreamento por meio de variáveis de ambiente sem alterações no código

Para adicionar o utilitário Tracing ao seu projeto, adicione a seguinte dependência do Maven:

<!-- In the dependencies section -->
<dependency>
    <groupId>software.amazon.lambda</groupId>
    <artifactId>powertools-tracing</artifactId>
    <version>2.1.1</version>
</dependency>
<!-- In the build plugins section -->
<plugin>
    <groupId>dev.aspectj</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <configuration>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>software.amazon.lambda</groupId>
                <artifactId>powertools-tracing</artifactId>
                <version>2.1.1</version>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
</plugin>

Para habilitar o rastreamento em sua função do Lambda, anote seu manipulador (handler) do Lambda e seus métodos personalizados que você deseja rastrear com a anotação @Tracing. Cada anotação é mapeada para um subsegmento do seu manipulador principal do Lambda no X-Ray e fica visível no console.

public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
    private static final Logger log = LoggerFactory.getLogger(App.class);

    @Tracing
    public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
        // ... business logic
        
        // Get calling IP with tracing
        String location = getCallingIp("https://checkip.amazonaws.com");

        // ... return response
    }

    @Tracing(segmentName = "Location service")
    private String getCallingIp(String address) {
        // Implementation to get IP address
        log.info("Retrieving caller IP address");
        
        // Add custom metadata to current sub-segment
        URL url = new URL(address);
        putMetadata("getCallingIp", address);
        
        // ...
        return "127.0.0.1";
    }
}

O console X-Ray exibe um mapa de serviço gerado quando o tráfego começa a fluir pelo seu aplicativo. A aplicação da anotação Tracing ao seu método manipulador de funções do Lambda ou a qualquer outro método na cadeia de execução fornece uma visibilidade abrangente dos padrões de tráfego em todo o aplicativo. A figura a seguir mostra como os metadados personalizados adicionados no exemplo estão associados ao subsegmento personalizado.

Picture showing the generated traces in the AWS X-Ray console. Shows the custom named Location service trace along with its metadata as a JSON object.

Figura 2. Visualização de rastreamento em cascata do AWS X-Ray

Reduzindo a duração da partida a frio do Lambda

Um recurso importante do Powertools for AWS Lambda (Java) v2 é o suporte de imagem nativa do GraalVM para todos os utilitários principais. Compilar suas funções do Lambda em executáveis nativos permite reduzir significativamente os tempos de inicialização a frio (cold start) e o uso de memória. O uso do Powertools v2 com o GraalVM permite reduzir as inicializações a frio em até 75,61% (p95) em comparação com o uso do tempo de execução Java gerenciado. O benchmark a seguir compara os tempos de inicialização a frio de um aplicativo usando todos os utilitários principais (logging, métricas, rastreamento) no runtime java21 gerenciado em comparação com o runtime provided.al2023 fornecido pelo Lambda executando uma imagem nativa compilada do GraalVM (acesse os runtimes Lambda compatíveis):

Meio ambiente p95 (ms) Mínimo (ms) Média (ms) Máximo (ms) Memória máxima (MB) N
Powertools para AWS (Java) v2: JVM 1682,92 124,55 124,55 2229,81 205,04 234
Ferramentas avançadas para AWS (Java) v2: GraalVM 542,86 404,92 504,77 752,85 93,46 369

Essa melhoria é particularmente valiosa para aplicativos e funções sensíveis à latência que escalam com frequência. Confira um exemplo completo de trabalho no GitHub.

Integração de mapeamento de origem de eventos do Lambda MSK

O novo utilitário Kafka introduzido com o Powertools for AWS Lambda (Java) v2 simplifica o trabalho com o Lambda MSK Event Source Mapping (ESM) e fontes de eventos Kafka autogerenciadas. Ele fornece uma experiência familiar para desenvolvedores que trabalham com o Apache Kafka, permitindo a conversão direta de eventos do Lambda para os tipos nativos do Kafka. Os principais recursos incluem:

  • Desserialização direta em objetos Kafka ConsumerRecords<K, V> usando a interface RequestHandler nativa do Lambda
  • Suporte para desserializar loggings codificados em JSON, Avro e Protobuf para campos de chave e valor com e sem o uso de um Logging de Esquema ao produzir as mensagens

Para adicionar o utilitário Kafka ao seu projeto, inclua a biblioteca powertools-kafka como uma dependência do Maven em seu pom.xml:

<!-- In the dependencies section -->
<dependency>
    <groupId>software.amazon.lambda</groupId>
    <artifactId>powertools-kafka</artifactId>
    <version>2.1.1</version>
</dependency>
<!-- Kafka clients dependency - compatibility works for >= 3.0.0 -->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>4.0.0</version>
</dependency>

Use a anotação @Deserialization em seu manipulador Lambda para desserializar mensagens como Kafka ConsumerRecords nativos. Certifique-se de especificar o tipo de desserializador. O exemplo a seguir mostra como desserializar valores de logging codificados em Avro com chaves String. Como em um handler Lambda normal, declare o tipo de entrada para sua função nos parâmetros genéricos do RequestHandler e o utilitário descobrirá os tipos de desserialização automaticamente. A classe AvroProduct no exemplo a seguir é uma classe Java gerada automaticamente usando a biblioteca Java org.apache.avro.avro.

public class App implements RequestHandler<ConsumerRecords<String, AvroProduct>, Void> {
    private static final Logger log = LoggerFactory.getLogger(App.class);

    @Deserialization(type = DeserializationType.KAFKA_AVRO)
    public Void handleRequest(ConsumerRecords<String, AvroProduct> consumerRecords, Context context) {
        log.info("Deserialized {} records.", consumerRecords.records().size()); 

        // ... Business logic 
        
        return null;
    }
}

Conclusão

O Powertools for AWS Lambda (Java) v2 representa a próxima evolução no kit de ferramentas para criar aplicativos Serverless robustos, observáveis e de alto desempenho. Ao longo desta postagem, exploramos os principais utilitários de observabilidade aprimorados com seus novos recursos, os ganhos de desempenho por meio do suporte a imagens nativas do GraalVM e o novo utilitário Kafka que suporta o uso de padrões familiares do Kafka ao trabalhar no Lambda.

O Powertools também oferece mais utilitários para lidar com padrões comuns de design Serverless. Cada utilitário é projetado com os mesmos princípios de clareza e sobrecarga mínima. Para saber mais:

  1. Visite a documentação para obter guias e exemplos detalhados
  2. Experimente os aplicativos de amostra
  3. Participe da comunidade no GitHub para compartilhar sua experiência e obter ajuda

Seu próximo aplicativo Serverless o aguarda com o Powertools for AWS Lambda (Java) v2. Adoraríamos ouvir seus comentários!

Este conteúdo foi traduzido da postagem original do blog, que pode ser encontrada aqui.

Biografia dos Autores

Philipp Page, SA Engineer

Biografia do Tradutor

Rodrigo Peres é Arquiteto de Soluções na AWS, com mais de 20 anos de experiência trabalhando com arquitetura de soluções, desenvolvimento de sistemas e modernização de sistemas legados.

Biografia do Revisor

Daniel Abib é arquiteto de soluções sênior na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e segurança. Ele trabalha apoiando clientes corporativos, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/