Instrumentação Lambda com Serverless Framework e Elven Plugin


Sumário

  • Visão geral
  • Pré-requisitos
  • Instalação
  • Quick Start
  • Configuração do plugin
  • Referência de opções
  • Controle por função
  • Variáveis de ambiente injetadas
  • Layers aplicadas
  • Exemplos completos
  • Boas práticas
  • Troubleshooting
  • FAQ

Visão geral

O elven-instrumentation-serverless-plugin automatiza toda a instrumentação das suas funções Lambda. Com uma única configuração no serverless.yml, o plugin:

  1. Adiciona as layers de OpenTelemetry e Elven Log Extension em cada função
  2. Injeta todas as variáveis de ambiente necessárias para traces e logs
  3. Detecta a arquitetura (x86_64/arm64) e aplica as layers corretas
  4. Gera nomes de serviço padronizados automaticamente ({service}_{stage}_{function})
┌──────────────────────────────────────────────────────────────┐
│                   serverless.yml                             │
│                                                              │
│  plugins:                                                    │
│    - elven-instrumentation-serverless-plugin                 │
│                                                              │
│  custom:                                                     │
│    elvenLayerPlugin:                                         │
│      tenant: "meu-tenant"        ──────┐                     │
│      token: "meu-token"                │                     │
│                                        ▼                     │
│                              ┌─────────────────┐             │
│                              │  Plugin injeta:  │             │
│                              │  - 2 layers      │             │
│                              │  - 14+ env vars  │             │
│                              └────────┬────────┘             │
│                                       │                      │
│  functions:                           ▼                      │
│    api:      ← layers + envs injetados automaticamente       │
│    worker:   ← layers + envs injetados automaticamente       │
│    cron:     ← layers + envs injetados automaticamente       │
└──────────────────────────────────────────────────────────────┘
Componente O que faz
Plugin Serverless Injeta layers e variáveis de ambiente automaticamente no deploy
Layer OpenTelemetry Instrumenta o runtime Node.js — gera traces e spans automaticamente
Layer Elven Log Extension Captura logs da função via Lambda Logs API e envia para Loki

Pré-requisitos

  • Serverless Framework v3 ou v4 instalado
  • Node.js 18+
  • Coletor OpenTelemetry (OTLP) implantado na sua infraestrutura (a Elven realiza o deploy do collector no seu ambiente — não é um endpoint compartilhado)
  • Credenciais da Elven Observability:
  • Tenant ID
  • API Token
  • Endpoint do seu Collector OTLP

Instalação

npm install --save-dev elven-instrumentation-serverless-plugin

Adicione o plugin no serverless.yml:

plugins:
  - elven-instrumentation-serverless-plugin

Verificar instalação:

npx serverless print 2>&1 | grep -i elven

Quick Start

1. Configure o plugin no serverless.yml

service: minha-api

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1

plugins:
  - elven-instrumentation-serverless-plugin

custom:
  elvenLayerPlugin:
    tenant: "seu-tenant-id"
    token: "seu-api-token"

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: /hello
          method: get

2. Deploy normalmente

npx serverless deploy

O plugin automaticamente:

  • Adiciona as layers de OTel e Log Extension na função
  • Injeta as variáveis de ambiente com nome de serviço minha-api_dev_hello
  • Configura o endpoint OTLP e Loki da Elven

Pronto! Ao invocar a função, traces e logs já aparecem na Elven Observability.

Output do plugin no deploy

✅ [Elven] Instrumented function: minha-api_dev_hello (x86_64)
🏗️  [Elven] Architecture: x86_64
📍 [Elven] Region: us-east-1
📦 [Elven] Default layers applied:
      - arn:aws:lambda:us-east-1:184161586896:layer:opentelemetry-nodejs-0_20_0:1
      - arn:aws:lambda:us-east-1:911167927290:layer:elven-lambda-log-extension:8

Configuração do plugin

Todas as opções ficam dentro de custom.elvenLayerPlugin no serverless.yml:

custom:
  elvenLayerPlugin:
    # === Obrigatórios ===
    tenant: "seu-tenant-id"
    token: "seu-api-token"

    # === Opcionais ===
    region: "us-east-1"                                    # default: us-east-1
    collector_endpoint: "https://otel-collector.minha-infra.com:4318"  # URL do seu collector
    logs_endpoint: "https://loki.elvenobservability.com"   # default: endpoint Elven
    architecture: "x86_64"                                 # default: x86_64
    log_version: "8"                                       # versão da layer de logs (x86_64)
    log_version_arm64: "7"                                 # versão da layer de logs (arm64)
    enabled_instrumentations: "http,express,pg"            # default: todas
    disabled_instrumentations: ""                          # default: nenhuma
    layers:                                                # override completo das layers
      - "arn:aws:lambda:us-east-1:..."
      - "arn:aws:lambda:us-east-1:..."

Referência de opções

Opções obrigatórias

Opção Descrição Exemplo
tenant Tenant ID na Elven Observability "meu-tenant"
token API Token de autenticação "eyJhbGci..."

Opções opcionais

Opção Default Descrição
region us-east-1 Região AWS das layers
collector_endpoint — (obrigatório) URL do seu coletor OTLP (ex: https://otel-collector.minha-infra.com:4318)
logs_endpoint https://loki.elvenobservability.com URL base do Loki (sem /loki/api/v1/push)
architecture x86_64 Arquitetura padrão: x86_64 ou arm64
log_version 8 Versão da layer de logs para x86_64
log_version_arm64 7 Versão da layer de logs para arm64
enabled_instrumentations todas Instrumentações OTel habilitadas (separadas por vírgula)
disabled_instrumentations nenhuma Instrumentações OTel a desabilitar
layers auto Override completo da lista de layers (substitui as layers padrão)

Ordem de resolução da arquitetura

A arquitetura é resolvida nesta ordem de precedência:

  1. custom.elvenLayerPlugin.architecture
  2. Variável de ambiente LAMBDA_ARCHITECTURE
  3. provider.architecture do Serverless
  4. Default: x86_64

Para funções individuais, function.architecture tem prioridade sobre o valor global.


Controle por função

Desabilitar instrumentação em uma função específica

Adicione disableElven: true na função:

functions:
  api:
    handler: handler.api
    # instrumentada normalmente

  internal:
    handler: handler.internal
    disableElven: true
    # NÃO será instrumentada

  worker:
    handler: handler.worker
    # instrumentada normalmente

Output no deploy:

✅ [Elven] Instrumented function: minha-api_dev_api (x86_64)
⚠️  [Elven] Skipping instrumentation for function: internal
✅ [Elven] Instrumented function: minha-api_dev_worker (x86_64)

Sobrescrever variáveis por função

O plugin não sobrescreve variáveis de ambiente já definidas na função. Isso permite customizar por função:

functions:
  api:
    handler: handler.api
    # Usa configuração padrão do plugin

  heavy-worker:
    handler: handler.worker
    environment:
      OTEL_TRACES_SAMPLER: "traceidratio"
      OTEL_TRACES_SAMPLER_ARG: "0.1"
      # Sampling de 10% — demais variáveis são injetadas pelo plugin

Funções com arquiteturas diferentes

O plugin detecta a arquitetura por função e aplica as layers corretas:

provider:
  architecture: x86_64  # padrão para todas

functions:
  api:
    handler: handler.api
    # usa x86_64 (do provider)

  ml-inference:
    handler: handler.inference
    architecture: arm64
    # usa arm64 — layers arm64 aplicadas automaticamente

Variáveis de ambiente injetadas

O plugin injeta as seguintes variáveis em cada função:

OpenTelemetry (Traces)

Variável Valor Descrição
AWS_LAMBDA_EXEC_WRAPPER /opt/otel-handler Ativa o wrapper OTel no runtime
OTEL_SERVICE_NAME {service}_{stage}_{function} Nome do serviço nos traces
OTEL_TRACES_SAMPLER always_on Estratégia de sampling
OTEL_LAMBDA_TRACE_MODE capture Modo de captura de traces
OTEL_PROPAGATORS tracecontext,baggage,xray Propagadores de contexto
OTEL_RESOURCE_ATTRIBUTES service.name=...,environment=... Atributos de recurso
OTEL_EXPORTER_OTLP_ENDPOINT collector_endpoint Endpoint OTLP
OTEL_NODE_ENABLED_INSTRUMENTATIONS lista de instrumentações Instrumentações habilitadas
OTEL_NODE_DISABLED_INSTRUMENTATIONS (condicional) Instrumentações desabilitadas

Elven Log Extension (Logs)

Variável Valor Descrição
LOKI_URL logs_endpoint URL base do Loki
LOKI_TENANT_ID tenant Tenant ID para o Loki
LOKI_AUTH_TOKEN token Token de autenticação
DEBUG false Debug da log extension

Nota sobre LOKI_URL: O plugin envia apenas a URL base (ex: https://loki.elvenobservability.com). A log extension appenda /loki/api/v1/push automaticamente.

Naming convention automática

O OTEL_SERVICE_NAME segue o padrão:

{serviceName}_{stage}_{functionName}

Exemplo: serviço ecommerce, stage prod, função checkoutecommerce_prod_checkout


Layers aplicadas

O plugin adiciona automaticamente duas layers:

x86_64

Layer ARN
OpenTelemetry Node.js arn:aws:lambda:{region}:184161586896:layer:opentelemetry-nodejs-0_20_0:1
Elven Log Extension arn:aws:lambda:{region}:911167927290:layer:elven-lambda-log-extension:{version}

arm64

Layer ARN
OpenTelemetry Node.js arn:aws:lambda:{region}:184161586896:layer:opentelemetry-nodejs-0_20_0:1
Elven Log Extension arn:aws:lambda:{region}:911167927290:layer:elven-lambda-log-extension-arm64:{version}

Override de layers

Para usar layers customizadas (ex: versão diferente ou layer própria):

custom:
  elvenLayerPlugin:
    tenant: "meu-tenant"
    token: "meu-token"
    layers:
      - "arn:aws:lambda:us-east-1:184161586896:layer:opentelemetry-nodejs-0_20_0:1"
      - "arn:aws:lambda:us-east-1:911167927290:layer:elven-lambda-log-extension:8"

Ao definir layers, a seleção automática por arquitetura é desabilitada. Certifique-se de usar as layers corretas para a arquitetura das suas funções.


Exemplos completos

Exemplo 1 — API REST simples

service: users-api

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  stage: ${opt:stage, 'dev'}

plugins:
  - elven-instrumentation-serverless-plugin

custom:
  elvenLayerPlugin:
    tenant: "meu-tenant"
    token: "meu-api-token"

functions:
  getUsers:
    handler: src/handlers/users.list
    events:
      - http:
          path: /users
          method: get

  getUser:
    handler: src/handlers/users.get
    events:
      - http:
          path: /users/{id}
          method: get

  createUser:
    handler: src/handlers/users.create
    events:
      - http:
          path: /users
          method: post

Exemplo 2 — Microserviço com múltiplas arquiteturas

service: ml-pipeline

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  architecture: x86_64

plugins:
  - elven-instrumentation-serverless-plugin

custom:
  elvenLayerPlugin:
    tenant: "meu-tenant"
    token: "meu-api-token"
    region: "us-east-1"

functions:
  api:
    handler: src/api.handler
    events:
      - http:
          path: /predict
          method: post

  inference:
    handler: src/inference.handler
    architecture: arm64
    memorySize: 1024
    timeout: 30
    events:
      - sqs:
          arn: !GetAtt InferenceQueue.Arn

  data-ingestion:
    handler: src/ingestion.handler
    timeout: 300
    events:
      - schedule: rate(5 minutes)

Exemplo 3 — Instrumentações seletivas com funções excluídas

service: ecommerce

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1

plugins:
  - elven-instrumentation-serverless-plugin

custom:
  elvenLayerPlugin:
    tenant: "meu-tenant"
    token: "meu-api-token"
    enabled_instrumentations: "http,express,pg,redis,undici"

functions:
  checkout:
    handler: src/checkout.handler
    events:
      - http:
          path: /checkout
          method: post

  payments:
    handler: src/payments.handler
    events:
      - sqs:
          arn: !GetAtt PaymentsQueue.Arn

  # Função interna — sem necessidade de observabilidade
  migrations:
    handler: src/migrations.handler
    disableElven: true
    events:
      - schedule: rate(1 day)

Exemplo 4 — Usando variáveis do Serverless para credenciais

Para não hardcodar credenciais no serverless.yml:

custom:
  elvenLayerPlugin:
    tenant: ${env:ELVEN_TENANT}
    token: ${env:ELVEN_TOKEN}
    region: ${self:provider.region}

Deploy passando as variáveis:

ELVEN_TENANT=meu-tenant ELVEN_TOKEN=meu-token npx serverless deploy

Ou usando SSM Parameter Store:

custom:
  elvenLayerPlugin:
    tenant: ${ssm:/elven/tenant}
    token: ${ssm:/elven/token}

Exemplo 5 — Customizar sampling por função

custom:
  elvenLayerPlugin:
    tenant: "meu-tenant"
    token: "meu-token"

functions:
  # Função com alto volume → sampling de 10%
  high-traffic-api:
    handler: src/api.handler
    environment:
      OTEL_TRACES_SAMPLER: "traceidratio"
      OTEL_TRACES_SAMPLER_ARG: "0.1"
    events:
      - http:
          path: /search
          method: get

  # Função crítica → capturar tudo (default do plugin)
  checkout:
    handler: src/checkout.handler
    events:
      - http:
          path: /checkout
          method: post

Boas práticas

Credenciais seguras

Nunca hardcode credenciais no serverless.yml. Use uma das opções:

# Opção 1: Variáveis de ambiente
tenant: ${env:ELVEN_TENANT}
token: ${env:ELVEN_TOKEN}

# Opção 2: SSM Parameter Store
tenant: ${ssm:/elven/tenant}
token: ${ssm:/elven/token~true}  # ~true para decrypt SecureString

# Opção 3: Secrets Manager
tenant: ${ssm:/aws/reference/secretsmanager/elven-tenant}

Instrumentações seletivas

Habilite apenas as instrumentações que o projeto realmente usa. Menos instrumentações = cold start mais rápido:

custom:
  elvenLayerPlugin:
    enabled_instrumentations: "http,pg,redis,undici"

Instrumentações disponíveis: http, express, graphql, grpc, hapi, ioredis, koa, mongodb, mysql, net, pg, redis, memcached, mongoose, amqplib, bunyan, cassandra-driver, connect, kafkajs, knex, mysql2, nestjs-core, pino, restify, socket.io, undici, winston

Timeout da função

As layers adicionam \~200-400ms de overhead no cold start. Certifique-se de que o timeout acomoda isso:

provider:
  timeout: 10  # mínimo recomendado

Para funções com múltiplas instrumentações, considere 30 segundos.

Memória

Mais memória = mais CPU = cold start mais rápido. Para funções instrumentadas, recomendamos pelo menos 256 MB:

provider:
  memorySize: 256

Stages

O plugin usa o stage do Serverless para compor o nome do serviço e o atributo environment:

# Deploy em staging → nomes: ecommerce_staging_checkout
npx serverless deploy --stage staging

# Deploy em production → nomes: ecommerce_production_checkout
npx serverless deploy --stage production

Troubleshooting

O deploy falha com erro de layer

Sintoma: Erro Layer version arn:aws:lambda:... does not exist.

Causas possíveis:

  1. Região incorreta — A layer não está disponível na região configurada. Verifique region no plugin
  2. Versão inexistente — Verifique se log_version / log_version_arm64 estão corretos
# Verificar se a layer existe na região
aws lambda get-layer-version <br>
  --layer-name opentelemetry-nodejs-0_20_0 <br>
  --version-number 1 <br>
  --region us-east-1 <br>
  --query "LayerVersionArn"

A função falha ao iniciar (timeout ou crash)

Sintoma: Runtime.ExitError ou timeout no cold start.

Verificações:

  1. Timeout muito baixo — Aumente para pelo menos 10 segundos
  2. Layer incompatível com a arquitetura — Verifique se a função arm64 está recebendo a layer arm64
  3. Wrapper incorreto — O plugin seta AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-handler. Se a layer OTel não estiver presente, isso causa crash
# Verificar configuração da função após deploy
npx serverless info --verbose

Traces não aparecem na Elven

Sintoma: Função executa normalmente, mas nenhum trace aparece.

Verificações:

  1. Confirme que collector_endpoint está correto
  2. Confirme que o token é válido
  3. Se sobrescreveu OTEL_TRACES_SAMPLER na função, verifique o valor
# Ver as variáveis de ambiente da função
aws lambda get-function-configuration <br>
  --function-name minha-api-dev-hello <br>
  --query "Environment.Variables" <br>
  --output table

Logs não aparecem no Loki

Sintoma: Traces funcionam, mas logs não aparecem.

Verificações:

  1. logs_endpoint deve ser a URL base (sem /loki/api/v1/push). A extension adiciona o path automaticamente * Correto: https://loki.elvenobservability.com * Errado: https://loki.elvenobservability.com/loki/api/v1/push
  2. Confirme que tenant e token estão corretos
  3. Habilite debug temporariamente na função:
functions:
  minha-funcao:
    handler: handler.handler
    environment:
      DEBUG: "true"

Depois invoque e verifique os logs no CloudWatch.

Plugin não aparece no output do deploy

Sintoma: Nenhuma mensagem [Elven] no deploy.

Verificações:

  1. O plugin está na seção plugins do serverless.yml
  2. O pacote está instalado: npm ls elven-instrumentation-serverless-plugin
  3. A seção custom.elvenLayerPlugin existe (mesmo que vazia, o plugin precisa ser listado em plugins)

Variáveis de ambiente não são injetadas

Sintoma: A função não tem as variáveis esperadas.

Causa: O plugin não sobrescreve variáveis já definidas na função. Se você definiu OTEL_SERVICE_NAME manualmente na função, o plugin não vai substituir.

Verificação:

npx serverless print --path functions.minhaFuncao.environment

FAQ

Preciso configurar algo em cada função? Não. O plugin instrumenta todas as funções automaticamente. A única configuração necessária é o bloco custom.elvenLayerPlugin com tenant e token.

Posso desabilitar em funções específicas? Sim. Adicione disableElven: true na definição da função.

Funciona com Serverless Framework v4? Sim. O plugin é compatível com v3 e v4 do Serverless Framework.

O plugin funciona com outros runtimes além de Node.js? As layers padrão do plugin são para Node.js. Para outros runtimes (Python, Java, Ruby), use a opção layers para especificar as layers corretas. Consulte a documentação de instrumentação Lambda manual para os ARNs de cada runtime.

O plugin sobrescreve minhas variáveis de ambiente? Não. O plugin só injeta variáveis que não existem na função. Se você definir uma variável manualmente, ela tem prioridade.

O plugin sobrescreve minhas layers? Não. O plugin adiciona as layers sem remover as existentes. Não há duplicação — se a layer já existe, não é adicionada novamente.

Como atualizar a versão das layers? Altere log_version e log_version_arm64 no custom.elvenLayerPlugin. Para a layer OTel, use a opção layers com os ARNs atualizados.

Posso usar com monorepo / múltiplos serverless.yml? Sim. Cada serverless.yml é independente. Use a mesma configuração elvenLayerPlugin em cada um, preferencialmente via variáveis de ambiente ou SSM para evitar duplicação.

Qual o impacto no tamanho do deployment? As layers não contam no limite de 50 MB do pacote de deploy (ZIP). Elas contam no limite total de 250 MB (código + layers descomprimidos).

Posso usar junto com outros plugins do Serverless? Sim. O plugin roda no hook before:package:initialize e não interfere com outros plugins. A ordem no plugins array geralmente não importa.

Como vejo quais variáveis o plugin injetou? Use npx serverless print para ver a configuração completa resolvida, ou verifique direto na AWS:

aws lambda get-function-configuration <br>
  --function-name {service}-{stage}-{function} <br>
  --query "Environment.Variables"