Linguagem de consulta do Logging

Nesta página, descrevemos a linguagem de consulta do Logging usada para consultar dados de registros e criar coletores de registros.

As consultas podem ser usadas no painel do criador de consultas do Cloud Logging no Console do Google Cloud, na API Logging ou na interface de linha de comando.

A sintaxe da consulta

Nesta seção, discutimos sobre como as consultas são estruturadas e como a correspondência é realizada.

Consultas são expressões que podem especificar um conjunto de entradas de registro de qualquer número de registros. Uma consulta é uma expressão booleana que especifica um subconjunto de todas as entradas de registro no projeto.

É possível criar consultas com base nas quatro dimensões a seguir usando os operadores lógicos AND e OR:

Para ver exemplos de consultas comuns que podem ser usadas, acesse Consultas de amostra usando o visualizador de registros (visualização).

Notação de sintaxe

A sintaxe da consulta é descrita usando a seguinte notação:

  • a = e significa que a é um nome para a expressão e.
  • a b significa "a seguido de b".
  • a | b significa "a ou b."
  • ( e ) é usado no agrupamento.
  • [ e ] significa que e é opcional.
  • { e } significa que e pode ser repetido zero ou mais vezes.
  • "abc" significa que abc precisa ser escrito exatamente como aparece.

Resumo da sintaxe

Esta seção fornece uma visão geral da sintaxe da consulta.

Uma consulta é uma string que contém uma expressão:

   expression = ["NOT"] comparison { ("AND" | "OR") ["NOT"] comparison }

Uma comparação é um valor único ou uma expressão booleana:

  "The cat in the hat"
  resource.type = "gae_app"

A primeira linha é um exemplo de comparação que é um valor único. Esses tipos de comparações são restrições globais. Cada campo de uma entrada de registro é comparado ao valor usando implicitamente o operador has. Para este exemplo, se qualquer campo em uma LogEntry, ou sua payload, contiver a frase "The cat in the hat" (O gato no chapéu), a comparação será bem-sucedida.

A segunda linha é um exemplo de uma comparação que é uma expressão booleana da forma [FIELD_NAME] [OP] [VALUE]. Os elementos da comparação são descritos abaixo:

  • [FIELD_NAME]: é um campo em uma entrada de registro. Por exemplo, resource.type.

  • [OP]: é um operador de comparação. Por exemplo, =.

  • [VALUE]: é uma expressão numérica de string, de função ou entre parênteses. Por exemplo, "gae_app".

As seções a seguir fornecem mais detalhes sobre consultas e correspondências.

Operadores booleanos

Os operadores booleanos AND e OR são operadores de curto-circuito. O operador NOT tem a precedência mais alta, seguido por OR e AND, nessa ordem. Por exemplo, as duas expressões a seguir são equivalentes:

a OR NOT b AND NOT c OR d
(a OR (NOT b)) AND ((NOT c) OR d)

É possível omitir o operador AND entre comparações. Também é possível substituir o operador NOT pelo operador - (sinal de subtração). Por exemplo, as duas consultas a seguir são as mesmas:

a=b AND c=d AND NOT e=f
a=b c=d -e=f

AND e NOT sempre são usados nesta documentação.

Comparações

As comparações têm a seguinte forma:

[FIELD_NAME] [OP] [VALUE]

Os elementos da comparação são descritos abaixo:

  • [FIELD_NAME]: é o nome do caminho de um campo em uma entrada de registro. Os exemplos do nome do campo são:

    resource.type
    resource.labels.zone
    resource.labels.project_id
    insertId
    jsonPayload.httpRequest.protocol
    labels."compute.googleapis.com/resource_id"
    

    Para detalhes, consulte identificadores de caminho de acesso a um campo nesta página.

  • [OP]: é um operador de comparação, um dos seguintes:

    =           # equal
    !=          # not equal
    > < >= <=   # numeric ordering
    :           # "has" matches any substring in the log entry field
    =~          # regular expression search for a pattern
    !~          # regular expression search not for a pattern
    
  • [VALUE]: é uma expressão numérica de string, de função ou entre parênteses. As strings são usadas para representar texto arbitrário, além de valores booleanos, de enumeração e de string de bytes. O [VALUE] é convertido no tipo do campo antes da comparação.

Se [VALUE] for uma combinação booleana de comparações entre parênteses, o nome do campo e o operador de comparação serão aplicados a cada elemento. Por exemplo:

    jsonPayload.cat = ("longhair" OR "shorthair")
    jsonPayload.animal : ("nice" AND "pet")

A primeira comparação verifica se o campo cat tem o valor “longhair” ou “shorthair”. A segunda verifica se o valor do campo animal contém as palavras "nice" e "pet", em qualquer ordem.

Identificadores de caminho de acesso a um campo

Todas as entradas de registro são instâncias do tipo LogEntry. O identificador que é (ou começa) do lado esquerdo de uma comparação precisa ter um campo definido no tipo LogEntry. Para detalhes sobre os possíveis identificadores e seus valores, revise o tipo LogEntry.

Esta é a lista atual de campos de entrada de registro. Cada campo é seguido do próximo nível de nomes desse campo, se aplicável:

  • httpRequest: {cacheFillBytes, cacheHit, cacheLookup, cacheValidatedWithOriginServer, latency, protocol, referer, remoteIp, requestMethod, requestSize, requestUrl, responseSize, serverIp, status, userAgent}
  • insertId
  • jsonPayload {variável}
  • labels {variável}
  • logName
  • metadata {systemLabels, userLabels}
  • operation{id, producer, first, last}
  • protoPayload {@type, variável}
  • receiveTimestamp
  • resource {type, labels}
  • severity
  • sourceLocation: {file, line, function}
  • spanId
  • textPayload
  • timestamp
  • trace

Você verá abaixo exemplos de identificadores de caminho de acesso a um campo que podem ser usados nas comparações:

  • resource.type: se seu primeiro identificador de caminho for resource, o próximo identificador precisará ter um campo do tipo MonitoredResource.

  • httpRequest.latency: se seu primeiro identificador de caminho for httpRequest, o próximo identificador precisará ter um campo do tipo HttpRequest.

  • labels.[KEY]: Se seu primeiro identificador de caminho for labels, o próximo identificador, [KEY], precisará ter uma das chaves dos pares de valor-chave que aparecem no campo labels.

  • logName: como o campo logName é uma string, não é possível segui-lo pelos nomes dos subcampos.

Para mais informações sobre como usar identificadores de caminho de acesso a um campo que fazem referência a objetos ou matrizes, vá para Tipos de objetos e matrizes nesta página.

Tipos de recursos monitorados

Para consultas mais rápidas, especifique um tipo de recurso monitorado. Para ver uma lista de tipos de recursos, acesse Tipos de recursos monitorados.

Por exemplo, as VMs do Compute Engine usam o tipo de recurso gce_instance, já as instâncias do Amazon EC2 usam aws_ec2_instance. Veja no exemplo a seguir como limitar as consultas para os dois tipos de VMs:

    resource.type = ("gce_instance" OR "aws_ec2_instance")

Os valores do tipo de recurso monitorados nos registros são indexados. O uso de correspondências de substring para eles resulta em consultas mais lentas.

Campos ausentes

Se você usar um nome de campo em uma consulta e esse campo não aparecer em uma entrada, o campo será ausente, indefinido ou padrão:

  • Se o campo fizer parte do payload da entrada de registro (jsonPayload ou protoPayload) ou se ele estiver em um rótulo na seção labels da entrada de registro, o campo, então, será ausente. Usar um campo ausente não exibirá um erro, mas todas as comparações que usem campos ausentes apresentarão uma falha silenciosa.

    Por exemplo: jsonPayload.nearest_store, protoPayload.name.nickname

  • Se estiver definido no tipo LogEntry, o campo será padronizado. As comparações seriam realizadas como se o campo estivesse presente e tivesse o valor padrão.

    Por exemplo: httpRequest.remoteIp, trace, operation.producer

  • Caso contrário, o campo é indefinido, que é um erro detectado antes de a consulta ser usada.

    Por exemplo: thud, operation.thud, textPayload.thud

Para testar se há um campo ausente ou padronizado sem testar um determinado valor no campo, use a comparação :*. Por exemplo, a seguinte comparação será bem-sucedida se o campo operation.id estiver explicitamente presente em uma entrada de registro:

operation.id:*

Observe o comportamento das seguintes consultas:

  • Ao usar o operador booleano NOT em um campo ausente, o resultado será TRUE:

    # Returns TRUE
    NOT missingField=foo
    
  • Ao usar o operador de comparação diferente != em um campo ausente, o resultado será FALSE:

    # Returns FALSE
    missingField!=foo
    

Tipos de objetos e matrizes

Cada campo de entrada de registro pode conter um escalar, um objeto ou uma matriz.

  • Um campo escalar armazena um único valor, como 174.4 ou -1. Um string também é considerado um escalar. Os campos que podem ser convertidos em (ou de) uma string, como Duration e Timestamp, também são tipos escalares.

  • Um tipo de objeto armazena uma coleção de valores nomeados, como o seguinte valor JSON:

    {"age": 24, "height": 67}
    

    Consulte o valor dentro de um objeto. Por exemplo, se jsonPayload.x contivesse o valor anterior, jsonPayload.x.age teria o valor 24.

  • Um campo de matriz armazena uma lista de valores, todos do mesmo tipo. Por exemplo, um campo com medições pode ter uma matriz de números:

    {8.5, 9, 6}
    

    Quando as comparações são realizadas e [FIELD_NAME] é um campo de matriz, cada membro da matriz é comparado a [VALUE] e os resultados são unidos usando o operador OR. Por exemplo, se jsonPayload.shoeSize é um campo de matriz que armazena {8.5, 9, 6}, a comparação:

    jsonPayload.shoeSize < 7
    

    é equivalente a:

    8.5 < 7 OR 9 < 7 OR 6 < 7
    

    Neste exemplo, a comparação geral é avaliada como bem-sucedida.

Valores e conversões

O primeiro passo na avaliação de uma comparação é converter o valor do lado direito para o tipo do campo de entrada de registro. Tipos de campo escalares são permitidos em comparações, junto com dois tipos adicionais que têm os valores representados como strings: Duration e Timestamp. Para uma lista de tipos escalares, vá para a lista de tipos de buffer do protocolo escalar. A tabela a seguir explica quais valores podem ser convertidos para os tipos de campo de registro:

Tipo de campo Valor de consulta permitido
bool "True" ou "false" em letras minúsculas ou maiúsculas. Exemplos: "True", "true".
bytes Uma string que contém qualquer sequência de bytes. Exemplo: "\377\377".
Duration Uma string que contém um número decimal assinado seguido de uma das unidades "ns", "us", "ms", "s", "m" ou "h". As durações são medidas com precisão até a casa dos nanossegundos. Exemplo: "3.2s".
enum O nome de um tipo de enumeração literal, indiferente a maiúsculas. Exemplos: "WARNING", que é um valor do tipo LogSeverity.
double Qualquer número, com ou sem sinal e uma parte expoente, ou as strings de valor especial "NaN", "-Infinity" e "Infinity" (em letras maiúsculas ou não). Exemplos: "-3.2e-8", "nan".
intNN Qualquer inteiro assinado que não exceda o tamanho do tipo. Exemplo: "-3".
string Qualquer string que contenha texto codificado em UTF-8 ou ASCII de 7 bits. Aspas incorporadas precisam ser precedidas de uma barra invertida.
Timestamp Uma string no formato RFC 3339 ou ISO 8601. Por exemplo: "2014-10-02T15:01:23.045Z" (RFC 3339), "2014-10-02" (ISO 8601). Em expressões de consulta, os carimbos de data/hora no formato RFC 3339 podem especificar um fuso horário com "Z" ou ±hh:mm. Os carimbos de data/hora são representados com precisão de nanosegundos.
uintNN Qualquer inteiro não assinado que não exceda o tamanho do tipo. Exemplo: "1234".

Se ocorrer erro na tentativa de conversão, a comparação falhará.

Quando uma conversão exigir uma string, também será possível usar um número ou um texto sem aspas se eles não contiverem caracteres especiais, como espaços e operadores. Da mesma maneira, quando uma conversão exigir um número, será possível usar uma string com um conteúdo que seja número.

Os tipos intNN e uintNN representam tipos inteiros de vários tamanhos, como int32 e uint64. Os valores que serão convertidos em tipos de números inteiros de 64 bits precisam ser gravados como strings. Por exemplo: "9223372036854775807".

Tipos de campos de registro

Veja como o tipo de um campo de entrada de registro é determinado:

  • Os campos de registro definidos no tipo LogEntry e no tipo de componente são campos do buffer de protocolo. Os campos de buffer de protocolo têm tipos explícitos.

  • Os campos de registro que fazem parte de objetos protoPayload também são campos de buffer de protocolo e têm tipos explícitos. O nome do tipo de buffer de protocolo é armazenado no campo "@type" de protoPayload. Para mais informações, analise o mapeamento JSON.

  • Os campos de registro dentro de jsonPayload têm tipos que são inferidos do valor do campo quando a entrada de registro é recebida:

    • Os campos com valores são números sem aspas e têm tipo double.
    • Os campos com valores são true ou false e têm tipo bool.
    • Os campos com valores que são strings com tipo string.

    Os inteiros longos (64 bits) são armazenados em campos de string, porque não podem ser representados exatamente como valores double.

  • Os tipos Duration e Timestamp só são reconhecidos em campos de buffer de protocolo. Em outros lugares, esses valores são armazenados em campos de string.

Operadores de comparação

O significado dos operadores de igualdade (=, !=) e desigualdade (<, <=, >, >=) depende do tipo subjacente do lado esquerdo nome do campo.

  • Todos os tipos numéricos: os símbolos de igualdade e desigualdade têm significado normal para os números.
  • bool: igualdade significa o mesmo valor booliano. A desigualdade é definida por true > false.
  • enum: igualdade significa o mesmo valor de enumeração. A desigualdade usa os valores numéricos subjacentes dos literais de enumeração.
  • Duration: igualdade significa a mesma duração de duração. A desigualdade se baseia no comprimento da duração. Por exemplo: como durações, "1s" > "999ms".
  • Timestamp: igualdade significa o mesmo instante no tempo. Se a e b forem valores Timestamp, a < b significa a é anterior a b.
  • bytes: os operandos são comparados de byte a byte, da esquerda para a direita.
  • string: as comparações ignoram letras maiúsculas e minúsculas. Mais especificamente, primeiro os dois operandos passam pelo processo de normalização unicode NFKC_CF. Depois, usam comparações lexicográficas. No entanto, as pesquisas de expressões regulares não são normalizadas. Para mais informações sobre como pesquisar entradas de registro usando expressões regulares, consulte Como consultar e filtrar entradas de registro usando expressões regulares.

O operador substring (:) é aplicável a string e bytes e é tratado como igualdade, com a diferença de que o operando à direita só precisa se igualar a parte do campo à esquerda. As correspondências de substring em campos indexados não aproveitam os índices de registro.

Restrições globais

Se a comparação consistir em um único valor, é chamada de restrição global. O Logging usa o operador has (:) para determinar se algum campo em uma entrada de registro ou o respectivo payload contém a restrição global. Se isso acontecer, a comparação será bem-sucedida.

A consulta mais simples gravada em termos de uma restrição global é um valor único:

"The Cat in The Hat"

É possível combinar restrições globais usando os operadores AND e OR para uma consulta mais interessante. Por exemplo, se você desejar exibir todas as entradas de registro que tenham um campo que contenha cat e um campo que contenha hat ou bat, escreva a consulta como:

(cat AND (hat OR bat))

Nesse caso, há três restrições globais: cat, hat e bat. Essas restrições globais são aplicadas separadamente e os resultados são combinados, como se a expressão tivesse sido escrita sem parênteses.

Uma restrição global é uma maneira fácil de consultar os registros em busca de um valor específico. Por exemplo, se você estiver procurando em seu registro de atividades por entradas contendo qualquer menção de GCE_OPERATION_DONE, é possível usar a seguinte consulta:

    logName = "projects/my-project-id/logs/compute.googleapis.com%2Factivity_log" AND
    "GCE_OPERATION_DONE"

Embora as restrições globais sejam fáceis, elas podem ser lentas; para mais informações, analise Como encontrar entradas de registro rapidamente nesta página.

Funções

É possível usar funções integradas como restrições globais nas consultas:
function = identifier ( [ argument { , argument } ] )

onde argument é um valor, um nome de campo ou um parênteses expressão. As funções são descritas nas seções a seguir.

log_id

A função log_id retorna entradas de registro que correspondem ao argumento [LOG_ID] indicado no campo logName:

  log_id([LOG_ID])

Por exemplo, a consulta a seguir retorna todas as entradas de registro com cloudaudit.googleapis.com%2Factivity [LOG_ID]:

  log_id("cloudaudit.googleapis.com/activity")

sample

A função sample seleciona uma fração do número total de entradas de registro:

sample([FIELD], [FRACTION])

[FIELD] é o nome de um campo na entrada de registro, como logName ou jsonPayload.a_field. O valor do campo determina se a entrada do registro estará na amostra. O tipo de campo precisa ser uma string ou um valor numérico. Definir [FIELD] como insertId é uma boa escolha, porque cada entrada de registro tem um valor diferente para esse campo.

[FRACTION] é a fração de entradas de registro que têm valores para [FIELD] a serem incluídos. É um número maior do que 0,0 e não superior a 1,0. Por exemplo, se você especificar 0.01, a amostra conterá aproximadamente 1% de todas as entradas de registro com valores para [FIELD]. Se [FRACTION] for 1, todas as entradas de registro que tenham valores para [FIELD] serão escolhidas.

Por exemplo: a consulta a seguir retorna 25% das entradas de registro do log syslog:

    logName = "projects/my-project/logs/syslog" AND sample(insertId, 0.25)

Detalhes: um algoritmo determinístico, baseado em hash, é usado para determinar se uma entrada de registro está incluída na amostra ou excluída dela. A precisão da amostra resultante depende da distribuição dos valores em hash. Se os valores em hash não forem distribuídos uniformemente, a amostra resultante poderá estar distorcida. No pior dos casos, quando [FIELD] sempre contém o mesmo valor, a amostra resultante contém a [FRACTION] de todas as entradas de registro ou nenhuma entrada de registro.

Se [FIELD] aparecer em uma entrada de registro:

  • será calculado um hash do valor;
  • o valor em hash, que é um número, será dividido pelo valor máximo possível de hash;
  • se a fração resultante for menor que ou igual a [FRACTION], a entrada de registro será incluída na amostra. Caso contrário, ela será excluída da amostra.

Se [FIELD] não aparecer em uma entrada de registro:

  • Se [FIELD] fizer parte da seção de payload da entrada de registro ou labels, a entrada de registro não será selecionada para a amostra, mesmo que [FRACTION] seja 1.
  • caso contrário, a entrada de registro seria tratada como se [FIELD] estivesse na entrada de registro e o valor de [FIELD] fosse o valor padrão. O valor padrão é determinado pelo tipo LogEntry. Para mais informações sobre campos ausentes e padrão, veja os campos Ausentes nesta página.

Para excluir entradas de registro com campos padronizados da amostra, use o operador de verificação de campo, :*. A consulta a seguir produz uma amostra de 1% de entradas de registro que forneceram explicitamente um valor para field:

field:* AND sample(field, 0.01)

ip_in_net

A função ip_in_net determina se um endereço IP em uma entrada de registro está contido em uma sub-rede. É possível usá-la para saber se uma solicitação vem de uma fonte interna ou externa. Por exemplo:

ip_in_net([FIELD], [SUBNET])

[FIELD] é um campo com valor de string na entrada de registro em que há um intervalo ou endereço IP. O campo pode ser repetido e, nesse caso, apenas um deles terá um endereço ou intervalo contido na sub-rede.

[SUBNET] é uma constante de string para um intervalo ou endereço IP. Será um erro se [SUBNET] não for um intervalo ou endereço IP válido, conforme descrito mais adiante nesta seção.

Por exemplo: a consulta a seguir testa um endereço IP no payload das entradas de registro do registro my_log:

    logName = "projects/my_project/logs/my_log" AND
    ip_in_net(jsonPayload.realClientIP, "10.1.2.0/24")

Detalhes: se [FIELD] estiver ausente, padronizado ou não contiver um intervalo ou endereço IP válido em uma entrada de registro, a função retornará "false". Para mais informações sobre campos ausentes e padrão, veja os campos ausentes nesta página.

Veja a seguir alguns exemplos de endereços IP e intervalos compatíveis:

  • IPv4: 10.1.2.3
  • Sub-rede IPv4: 10.1.2.0/24
  • CIDR IPv6: 1234:5678:90ab:cdef:1234:5678:90ab:cdef
  • Sub-rede CIDR IPv6: 1:2::/48

Como pesquisar por tempo

Na interface, é possível definir limites específicos relacionados à data e hora das entradas de registro a serem exibidas. Por exemplo, se você adicionar as seguintes condições à sua consulta, o Visualizador de registros exibirá exatamente as entradas de registro no período de 30 minutos indicado e não poderá rolar para fora desse período:

timestamp >= "2016-11-29T23:00:00Z"
timestamp <= "2016-11-29T23:30:00Z"

Ao escrever uma consulta com carimbo de data/hora, você precisa usar datas e horas no formato mostrado acima.

Também é possível pesquisar entradas de registro usando atalhos timestamp. Por exemplo, você consegue inserir uma data com um operador de comparação para gerar todas as entradas de registro após um determinado dia:

  timestamp > "2016-11-29"

Como usar expressões regulares

É possível usar expressões regulares para criar consultas e filtros para coletores, métricas e onde mais os filtros de registro forem usados. Há a opção de usar expressões regulares no Criador de consultas e com a gcloud command-line tool.

Uma expressão regular é uma sequência de caracteres que define uma pesquisa. A linguagem de consulta usa a sintaxe RE2. Para uma explicação completa sobre a sintaxe RE2, acesse a wiki RE2 no GitHub (em inglês).

As consultas de expressão regular têm as seguintes características:

  • Somente campos do tipo string podem ter correspondência com uma expressão regular.

  • A normalização de strings não é realizada. Por exemplo, kubernetes não é considerado igual a KUBERNETES. Para mais informações, consulte a seção Operadores de comparação.

  • As consultas diferenciam maiúsculas de minúsculas e não são ancoradas por padrão.

  • É possível usar os operadores booleanos entre várias expressões regulares no lado direito do operador de comparação de expressões regulares, =~ e !~.

Uma consulta de expressão regular tem a seguinte estrutura:

Corresponde a um padrão:

jsonPayload.message =~ "regular expression pattern"

Não corresponde a um padrão:

jsonPayload.message !~ "regular expression pattern"

=~ e !~ alteram a consulta para uma consulta de expressão regular, e o padrão que você está tentando corresponder precisa estar entre aspas duplas. Para consultar padrões que contêm aspas duplas, faça o escape deles usando uma barra invertida.

Exemplos de como consultar registros usando expressões regulares

Tipo de consulta Exemplo
Consulta padrão sourceLocation.file =~ "foo"
Consulta com pesquisa que não diferencia maiúsculas de minúsculas labels.subnetwork_name =~ "(?i)foo"
Consulta que contém aspas jsonPayload.message =~ "field1=\"bar.*\""
Consulta que usa um or booleano labels.pod_name =~ "(foo|bar)"
Consulta com o uso de âncoras logName =~ "/my%2Flog$"
Consulta que não corresponde a um padrão labels.pod_name !~ "foo"
Consulta com o uso de operador booleano labels.env =~ ("^prod.*server" OR "^staging.*server")