Geração de registros estruturados

Neste documento, você verá o conceito de geração de registros estruturados e os métodos para adicionar uma estrutura aos campos de payload da entrada de registro.

Visão geral

No Cloud Logging, registros estruturados se referem a entradas de registro que usam o campo jsonPayload para adicionar estrutura a seus payloads. A geração de registros estruturados se aplica a registros gravados pelo usuário.

É possível gravar registros estruturados no Logging de várias maneiras:

  • Como usar a API Cloud Logging para gravar entradas de registro
  • Como usar a ferramenta de linha de comando gcloud para gravar entradas de registro
  • Como usar o serviço BindPlane para ingerir registros
  • Como fornecer objetos JSON serializados ao agente do Logging

Cada um desses métodos é discutido nas seções a seguir.

Usar a API Logging

Se você usar a API Cloud Logging para gravar entradas de registro, será possível controlar a estrutura dos payloads enviando a estrutura LogEntry completa com uma jsonPayload para a API Cloud Logging.

Para mais informações, consulte a referência entries.write. Para exemplos de código, consulte Como gravar registros estruturados.

Usar a ferramenta gcloud

Se você usa a ferramenta gcloud para gravar entradas de registro, é possível controlar a estrutura dos payloads enviando a estrutura completa de LogEntry. por um jsonPayload para a API Cloud Logging.

Para exemplos de código, consulte a referência gcloud logging write.

Use o BindPlane

Se você usar o serviço BindPlane para ingerir os registros, seus payloads estarão no formato JSON e estruturados de acordo com o sistema de origem. Para informações sobre como localizar e visualizar registros ingeridos por meio do BindPlane, consulte a documentação dessa solução em Como encontrar dados do registro (em inglês).

Usar o agente do Logging

Se você usar o agente do Cloud Logging para obter suas entradas de registro, será possível especificar que o agente do Logging converta seus payloads em formato JSON.

Se você estiver usando o Google Kubernetes Engine ou o ambiente flexível do App Engine, será possível gravar registros estruturados como objetos JSON serializados em uma única linha para stdout ou stderr. Em seguida, o agente do Logging envia os registros estruturados para o Cloud Logging como o jsonPayload da estrutura LogEntry.

Alguns campos no objeto JSON são reconhecidos como especiais pelo agente do Logging e extraídos para a estrutura LogEntry. Esses campos especiais do JSON podem ser usados para definir os seguintes campos em LogEntry:

  • severity
  • spanId
  • labels definido pelo usuário.
  • httpRequest

Como o JSON é mais preciso e versátil do que as linhas de texto, é possível usar objetos JSON para escrever mensagens de várias linhas e adicionar metadados.

Para criar entradas de registro estruturadas para seus aplicativos usando o formato simplificado, consulte a tabela a seguir, que lista os campos e seus valores em JSON:

Campo do registro JSON campo LogEntry Função do agente do Cloud Logging Valor de exemplo
severity severity O agente do Logging tenta corresponder diversas strings de gravidade comum, que incluem a lista de strings LogSeverity reconhecida pela API Logging. "severity":"ERROR"
message textPayload (ou parte de jsonPayload) A mensagem que aparece na linha de entrada do registro no Explorador de registros. "message":"There was an error in the application."

Observação: message é salvo como textPayload se for o único campo restante depois que o agente do Logging remover os outros campos de finalidade especial e detect_json não tiver sido ativado. Caso contrário, message permanecerá em jsonPayload. Se a entrada de registro tiver um rastreamento de pilha de exceção, o rastreamento precisa ser definido neste campo de registro JSON message para que o rastreamento de pilha de exceção possa ser analisado e salvo no Error Reporting.
log (somente Google Kubernetes Engine legado) textPayload Aplica-se somente ao Google Kubernetes Engine legado: se, após a remoção de campos de finalidade especial, somente um campo de registro permanecer, esse registro será salvo como textPayload.
httpRequest httpRequest Um registro estruturado no formato do campo LogEntry HttpRequest. "httpRequest":{"requestMethod":"GET"}
campos relacionados ao tempo time, timestamp, etc. Para mais informações, consulte Campos relacionados ao tempo. "time":"2020-10-12T07:20:50.52Z"
logging.googleapis.com/insertId insertId Para mais informações, consulte insertId na página LogEntry. "logging.googleapis.com/insertId":"42"
logging.googleapis.com/labels labels O valor desse campo precisa ser um registro estruturado. Para mais informações, consulte labels na página LogEntry. "logging.googleapis.com/labels": {"user_label_1":"value_1","user_label_2":"value_2"}
logging.googleapis.com/operation operation O valor desse campo também é usado pelo Explorador de registros para agrupar entradas de registro relacionadas. Para mais informações, consulte operation na página LogEntry. "logging.googleapis.com/operation": {"id":"get_data","producer":"github.com/MyProject/MyApplication", "first":"true"}
logging.googleapis.com/sourceLocation sourceLocation Informações do local do código-fonte associadas à entrada do registro, se houver. Para mais informações, consulte LogEntrySourceLocation na página LogEntry. "logging.googleapis.com/sourceLocation": {"file":"get_data.py","line":"142","function":"getData"}
logging.googleapis.com/spanId spanId O ID do período dentro do trace associado à entrada de registro. Para mais informações, consulte spanId na página LogEntry. "logging.googleapis.com/spanId":"000000000000004a
logging.googleapis.com/trace trace Nome do recurso do trace associado à entrada de registro, se houver. Para mais informações, consulte trace na página LogEntry. "logging.googleapis.com/trace":"projects/my-projectid/traces/0679686673a"

Observação: se não for gravando em stdout ou stderr, o valor deste campo deverá ser formatado como projects/[PROJECT-ID]/traces/[TRACE-ID] para que possa ser usado pelo Explorador de registros e pelo Visualizador de Trace para agrupar entradas de registro e exibi-las alinhadas aos traces. Se autoformat_stackdriver_trace for verdadeiro e [V] corresponder ao formato traceId do ResourceTrace, o campo trace do LogEntry tem o valor. projects/[PROJECT-ID]/traces/[V].
logging.googleapis.com/trace_sampled traceSampled O valor desse campo precisa ser true ou false. Para mais informações, consulte traceSampled na página LogEntry. logging.googleapis.com/trace_sampled": false

Para criar entradas de registro no formato simplificado, crie uma representação JSON da entrada usando os campos. Todos os campos são opcionais.

Veja a seguir um exemplo de entrada de registro JSON simplificada:

{
  "severity":"ERROR",
  "message":"There was an error in the application.",
  "httpRequest":{
    "requestMethod":"GET"
  },
  "times":"2020-10-12T07:20:50.52Z",
  "logging.googleapis.com/insertId":"42",
  "logging.googleapis.com/labels":{
    "user_label_1":"value_1",
    "user_label_2":"value_2"
  },
  "logging.googleapis.com/operation":{
    "id":"get_data",
    "producer":"github.com/MyProject/MyApplication",
     "first":"true"
  },
  "logging.googleapis.com/sourceLocation":{
    "file":"get_data.py",
    "line":"142",
    "function":"getData"
  },
  "logging.googleapis.com/spanId":"000000000000004a",
  "logging.googleapis.com/trace":"projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824",
  "logging.googleapis.com/trace_sampled":false
}

Veja a seguir um exemplo de entrada de registro resultante:

{
  "insertId": "42",
  "jsonPayload": {
    "message": "There was an error in the application",
    "times": "2019-10-12T07:20:50.52Z"
  },
  "httpRequest": {
    "requestMethod": "GET"
  },
  "resource": {
    "type": "k8s_container",
    "labels": {
      "container_name": "hello-app",
      "pod_name": "helloworld-gke-6cfd6f4599-9wff8",
      "project_id": "stackdriver-sandbox-92334288",
      "namespace_name": "default",
      "location": "us-west4",
      "cluster_name": "helloworld-gke"
    }
  },
  "timestamp": "2020-11-07T15:57:35.945508391Z",
  "severity": "ERROR",
  "labels": {
    "user_label_2": "value_2",
    "user_label_1": "value_1"
  },
  "logName": "projects/stackdriver-sandbox-92334288/logs/stdout",
  "operation": {
    "id": "get_data",
    "producer": "github.com/MyProject/MyApplication",
    "first": true
  },
  "trace": "projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824",
  "sourceLocation": {
    "file": "get_data.py",
    "line": "142",
    "function": "getData"
  },
  "receiveTimestamp": "2020-11-07T15:57:42.411414059Z",
  "spanId": "000000000000004a"
}

Configuração do agente do Logging

O agente do Logging google-fluentd é um empacotamento específico do Cloud Logging para o coletor de dados de registro do Fluentd. Esse agente acompanha a configuração padrão do Fluentd e usa plug-ins de entrada dele para receber registros de evento de origens externas, como arquivos em disco, ou para analisar registros de entrada.

O Fluentd tem uma lista de analisadores compatíveis (em inglês) que extraem e convertem os registros em payloads (JSON) estruturados.

Ao configurar uma origem de registro com format [PARSER_NAME], é possível aproveitar os analisadores integrados fornecidos pelo Fluentd.

As amostras de código a seguir mostram a configuração do Fluentd, o registro de entrada e o payload estruturado de saída, que faz parte de uma entrada de registro do Cloud Logging:

  • Configuração do Fluentd:

      <source>
        @type tail
    
        format syslog # <--- This uses a predefined log format regex named
                      # `syslog`. See details at https://docs.fluentd.org/parser/syslog.
    
        path /var/log/syslog
        pos_file /var/lib/google-fluentd/pos/syslog.pos
        read_from_head true
        tag syslog
      </source>
    
  • Registro (entrada):

      <6>Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test
    
  • Payload estruturado (saída):

        jsonPayload: {
            "pri": "6",
            "host": "192.168.0.1",
            "ident": "fluentd",
            "pid": "11111",
            "message": "[error] Syslog test"
        }
    

Para mais informações sobre como o analisador syslog funciona, consulte a documentação detalhada do Fluentd (em inglês).

Analisadores padrão já ativados

A tabela a seguir mostra os analisadores padrão que serão incluídos no agente se você ativar a geração de registros estruturados:

Nome do analisador Arquivo de configuração
syslog /etc/google-fluentd/config.d/syslog.conf
nginx /etc/google-fluentd/config.d/nginx.conf
apache2 /etc/google-fluentd/config.d/apache.conf
apache_error /etc/google-fluentd/config.d/apache.conf

Para instruções sobre como ativar a geração de registros estruturados ao instalar o agente do Logging, consulte a seção "Instalação".

Instalação

Para ativar a geração de registros estruturados, você precisa alterar a configuração padrão do agente do Stackdriver Logging ao instalá-lo (ou reinstalá-lo). A ativação da geração de registros estruturados substitui os arquivos de configuração listados anteriormente, mas não altera a operação do próprio agente.

Quando você ativa a geração de registros estruturados, os registros listados são convertidos em entradas de registro com formatos diferentes dos anteriores à ativação de registros estruturados. Se os registros estiverem sendo roteados para destinos fora do Logging, a alteração poderá afetar qualquer aplicativo pós-processamento. Por exemplo, se o roteamento de registros para o BigQuery, o BigQuery rejeita as novas entradas de registro para o restante do dia como tendo um esquema incorreto.

Para instruções sobre como instalar o agente do Logging e ativar a geração de registros estruturada, consulte Como instalar o agente do Logging.

É possível encontrar os arquivos de configuração do agente do Logging em /etc/google-fluentd/config.d/, que agora precisam incluir os analisadores padrão já ativados.

Configurar o formato do registro de acesso do Apache

Por padrão, o agente do Logging armazena dados do registro de acesso do Apache no campo jsonPayload. Por exemplo:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": ...,
  "jsonPayload": {
    "user"   : "some-user",
    "method" : "GET",
    "code"   : 200,
    "size"   : 777,
    "host"   : "192.168.0.1",
    "path"   : "/some-path",
    "referer": "some-referer",
    "agent"  : "Opera/12.0"
  },
  ...
}

Como alternativa, é possível configurar o agente Logging para extrair determinados campos para o campo httpRequest. Por exemplo:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": {
    "requestMethod": "GET",
    "requestUrl": "/some-path",
    "requestSize": "777",
    "status": "200",
    "userAgent": "Opera/12.0",
    "serverIp": "192.168.0.1",
    "referrer":"some-referrer",
  },
  "jsonPayload": {
    "user":"some-user"
  },
  ...
}

A configuração do campo httpRequest, como exibido na amostra anterior, auxilia no rastreamento: o Console do Cloud apresenta todos os registros de uma determinada solicitação HTTP em uma hierarquia pai-filho.

Para configurar essa extração, adicione o seguinte ao final do /etc/google-fluentd/config.d/apache.conf:

  <filter apache-access>
    @type record_transformer
    enable_ruby true
    <record>
      httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "serverIp" => record['host'],
      "referer" => record['referer']} }
    </record>
    remove_keys method, path, size, code, agent, host, referer
  </filter>

Para mais detalhes sobre como configurar suas entradas de registro, consulte Como modificar registros.

Configurar o formato de registro de acesso nginx

Por padrão, o agente do Logging armazena dados de registro de acesso nginx no campo jsonPayload. Por exemplo:

  {
    "logName": ...,
    "resource": ...,
    "httpRequest": ...,
    "jsonPayload": {
      "remote":"127.0.0.1",
      "host":"192.168.0.1",
      "user":"some-user",
      "method":"GET",
      "path":"/some-path",
      "code":"200",
      "size":"777",
      "referrer":"some-referrer",
      "agent":"Opera/12.0",
      "http_x_forwarded_for":"192.168.3.3"
    },
    ...
  }

Como alternativa, é possível configurar o agente Logging para extrair determinados campos para o campo httpRequest. Por exemplo:

  {
    "logName": ...,
    "resource": ...,
    "httpRequest": {
      "requestMethod": "GET",
      "requestUrl": "/some-path",
      "requestSize": "777",
      "status": "200",
      "userAgent": "Opera/12.0",
      "remoteIp": "127.0.0.1",
      "serverIp": "192.168.0.1",
      "referrer":"some-referrer",
    },
    "jsonPayload": {
      "user":"some-user",
      "http_x_forwarded_for":"192.168.3.3"
    },
    ...
  }

A configuração do campo httpRequest, como exibido na amostra anterior, auxilia no rastreamento: o Console do Cloud apresenta todos os registros de uma determinada solicitação HTTP em uma hierarquia pai-filho.

Para configurar essa extração, adicione o seguinte ao final do /etc/google-fluentd/config.d/nginx.conf:

<filter nginx-access>
  @type record_transformer
  enable_ruby true
  <record>
    httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "remoteIp" => record['remote'], "serverIp" => record['host'], "referer" => record['referer']} }
  </record>
  remove_keys method, path, size, code, agent, remote, host, referer
</filter>

Para mais detalhes sobre como configurar suas entradas de registro, consulte Como modificar registros.

Criar seu próprio analisador

Se os registros não forem compatíveis com os analisadores padrão, será possível criar seus próprios. Os analisadores consistem em uma expressão regular usada para combinar registros e aplicar rótulos às partes.

Estes exemplos mostram uma linha no registro, uma configuração com uma expressão regular que indica o formato da linha de registro e a entrada de registro ingerida:

  • Uma linha no registro:

    REPAIR CAR $500
    
  • Uma configuração com uma expressão regular que indica o formato da linha de registro:

    $ sudo vim /etc/google-fluentd/config.d/test-structured-log.conf
    $ cat /etc/google-fluentd/config.d/test-structured-log.conf
    <source>
      @type tail
    
      # Format indicates the log should be translated from text to
      # structured (JSON) with three fields, "action", "thing" and "cost",
      # using the following regex:
      format /(?<action>\w+) (?<thing>\w+) \$(?<cost>\d+)/
      # The path of the log file.
      path /tmp/test-structured-log.log
      # The path of the position file that records where in the log file
      # we have processed already. This is useful when the agent
      # restarts.
      pos_file /var/lib/google-fluentd/pos/test-structured-log.pos
      read_from_head true
      # The log tag for this log input.
      tag structured-log
    </source>
    
  • A entrada de registro resultante:

     {
      insertId:  "eps2n7g1hq99qp"
      jsonPayload: {
        "action": "REPAIR"
        "thing": "CAR"
        "cost": "500"
      }
      labels: {
        compute.googleapis.com/resource_name:  "add-structured-log-resource"
      }
      logName:  "projects/my-sample-project-12345/logs/structured-log"
      receiveTimestamp:  "2018-03-21T01:47:11.475065313Z"
      resource: {
        labels: {
          instance_id:  "3914079432219560274"
          project_id:  "my-sample-project-12345"
          zone:  "us-central1-c"
        }
        type:  "gce_instance"
      }
      timestamp:  "2018-03-21T01:47:05.051902169Z"
     }
    

Ver registros estruturados

Para pesquisar registros e visualizar entradas de registro com o Console do Cloud, consulte Como usar o Explorador de registros.

Para ler entradas de registro usando a ferramenta de linha de comando gcloud ou, consulte Como ler entradas de registro.

Para ler entradas de registro por meio da API Logging, consulte o método entries.list.

Resolver problemas

Para resolver problemas comuns encontrados na instalação ou interação com o agente do Logging, consulte Como resolver problemas do agente.