Perguntas comuns e soluções para consulta e análise de logs no formato JSON no Simple Log Service, incluindo configuração de índice, funções JSON e tratamento de arrays JSON.
Log de exemplo
Os exemplos neste tópico utilizam logs JSON de um sistema de processamento de pedidos.
{
"request":{
"clientIp":"20xxx30",
"http.path":"/order/buy",
"param":{
"userId": "186453",
"orders":[
{
"commodity":["bread","milk","meat"],
"payment":132
},
{
"commodity":["milk","beer"],
"payment":49
}
]
}
},
"response":"{\"errcode\":400,\"msg\":\"insufficient\"}"
}
O campo request/@parmname contém informações da solicitação de pedido em formato JSON. Uma solicitação pode incluir vários pedidos para um usuário, cada um com os product adquiridos e o pagamento total.
-
O campo response/@parmname contém o resultado do processamento do pedido.
Em caso de sucesso, o valor do campo response/@parmname é
SUCCESS.Em caso de falha, o valor do campo response/@parmname é um objeto JSON contendo
errcodeemsg.
Use o Logtail para Collect logs in JSON mode no Simple Log Service para consulta e análise.
Como configure um índice
Configure um índice antes de consultar ou analisar dados de log. Considere os pontos a seguir ao configurar índices para logs JSON.
How to selecione an index type
O Simple Log Service suporta índices de texto completo e índices de campo. Escolha conforme o seu caso de uso. Crie an index.
Para consultar todos os campos, crie um índice de texto completo. Para consultar apenas campos específicos, crie índices de campo para eles e reduza custos.
Para execute análise SQL em um campo, crie um índice de campo para ele e ative estatísticas.
Quando um índice de texto completo e índices de campo estiverem configurados simultaneamente, o índice de campo terá precedência para os campos que o possuírem.
Por exemplo, para analisar os campos request/@parmname e response/@parmname, crie índices de campo para eles e ative estatísticas.
How to selecione a data type for a field in the index configuration
Ao configurar um índice, defina o tipo de dados de um campo como text, long, double ou JSON. Data types.
Considere os seguintes pontos ao definir um tipo de dados para um campo JSON.
-
Se o valor de um campo não estiver no formato JSON padrão, mas contiver conteúdo JSON, defina o tipo de dados como text. Se o valor estiver no formato JSON padrão, defina-o como JSON.
NotaPara logs JSON que não são totalmente válidos, o Simple Log Service consegue analisar as partes válidas.
Após definir o tipo de dados como JSON, crie um índice para um nó folha dentro do objeto JSON para obter consultas mais rápidas. Isso gera taxas adicionais de indexação.
O Simple Log Service suporta índices para nós folha em objetos JSON, mas não para nós filhos que contenham nós folha.
O Simple Log Service não suporta índices para campos cujos valores sejam arrays JSON, nem para campos dentro de um array JSON. Para esses campos, utilize funções JSON para análise em tempo real.
Com base no log de exemplo, crie os seguintes índices.
-
Campo request/@parmname
request/@parmname: O valor está em formato JSON. Defina o tipo de dados como JSON e ative estatísticas.
request.clientIp/@parmname: Frequentemente analisado. Crie um índice separado, defina o tipo de dados como text e ative estatísticas.
request.http.path/@parmname: Raramente analisado. Não crie um índice separado — analise-o sob demanda usando funções JSON.
request.param/@parmname: Um nó filho que contém nós folha. A indexação não é suportada.
request.param.userId/@parmname: Frequentemente analisado. Crie um índice separado, defina o tipo de dados como text e ative estatísticas.
request.param.orders/@parmname: O valor é um array JSON. A indexação não é suportada.
-
Campo response/@parmname
O valor do campo response/@parmname nem sempre está em formato JSON. Defina seu tipo de dados como text e ative estatísticas.
Após criar o índice, os logs recém-coletados serão exibidos com base na configuração de índice.
How to defina an alias
Para caminhos longos de nós folha JSON, defina um alias. Column aliases.
Na configuração de índice, você pode definir aliases para nós folha de campos do tipo JSON. Por exemplo, defina o alias de request.clientIp como ip e defina o alias de request.param.userId como id.
Nomes de campos e aliases devem ser únicos em todos os campos de uma configuração de índice.
Para campos do tipo JSON, a unicidade é determinada pelo caminho completo do nó folha. Por exemplo, definir o alias do campo response/@parmname como clientIp/@parmname não entra em conflito com o nome do campo request.clientIp/@parmname.
Como consultar e analisar um campo JSON indexado
Uma instrução de consulta e análise segue o formato query statement|analytic statement. Em uma instrução analítica, coloque nomes de campos entre aspas duplas ("") e strings entre aspas simples (''). Especifique o caminho completo para campos aninhados — por exemplo, Key1.Key2.Key3, request.clientIp ou request.param.userId. Query and analyze JSON logs.
Por exemplo, para encontrar endereços IP de cliente para o usuário 186499:
*
and request.param.userId: 186499 |
SELECT
distinct("request.clientIp")
Quando usar funções JSON
Para grandes conjuntos de dados com estruturas JSON complexas, porém fixas, onde o desempenho da consulta é importante, crie índices de campo para nós folha JSON. Para conjuntos de dados menores ou análises ad-hoc, use funções JSON sem índices de campo para economizar custos. As funções JSON permitem o processamento e a análise dinâmica de conteúdo JSON. Em alguns casos, elas são a única opção.
-
O valor do campo nem sempre está em formato JSON ou requer pré-processamento.
Por exemplo, o campo response/@parmname contém JSON com um campo errcode/@parmname apenas quando uma solicitação falha. Para analisar a distribuição de errcode/@parmname, filtre as solicitações com falha e extraia errcode/@parmname com uma função JSON.
* not response :SUCCESS | SELECT json_extract_scalar(response, '$.errcode') AS errcode
O campo não pode ser indexado. Para nós JSON que não suportam indexação — como request.param/@parmname e request.param.orders/@parmname — as funções JSON são a única maneira de execute análise em tempo real.
Como escolha entre json_extract e json_extract_scalar
Tanto json_extract quanto json_extract_scalar extraem conteúdo de objetos ou arrays JSON. A principal diferença é o tipo de retorno.
-
json_extractretorna um tipo JSON;json_extract_scalarretorna um tipo varchar.NotaIsso refere-se a tipos de dados SQL (varchar, bigint, boolean, JSON, array, date), que diferem dos tipos de dados de índice do SLS. Use a função
typeofpara verificar o tipo de dados de um objeto SQL. typeof function. json_extractpode analisar qualquer subestrutura de um objeto JSON.json_extract_scalaranalisa apenas nós folha escalares (string, booleano ou número) e retorna a string correspondente.
Ambas as funções podem extrair o campo clientIp/@parmname do campo request/@parmname.
-
Usando
json_extract:* | SELECT json_extract(request, '$.clientIp')Nos resultados da consulta e análise, como nenhum alias foi definido, o nome da coluna exibe o padrão
_col0, contendo o valorclientIpextraído porjson_extract. -
Usando
json_extract_scalar:* | SELECT json_extract_scalar(request, '$.clientIp')Após execute a instrução de consulta acima, o resultado da consulta exibe o valor do campo extraído em uma única coluna
_col0.
Para extrair o primeiro octeto do valor clientIp/@parmname, use json_extract_scalar para extrair clientIp/@parmname e, em seguida, use split_part para extrair o primeiro número. json_extract não funciona aqui porque split_part requer uma entrada varchar.
* |
SELECT
split_part(
json_extract_scalar(request, '$.clientIp'),
'.',
1
) AS segment

Na maioria dos casos, use json_extract_scalar — seu tipo de retorno varchar se compõe naturalmente com outras funções SQL. Use json_extract quando precisar trabalhar com a própria estrutura JSON. Por exemplo, para contar os pedidos em uma solicitação (o comprimento do array request.param.orders/@parmname):
* |
SELECT
json_array_length((json_extract(request, '$.param.orders')))
Nos resultados da consulta e análise, a coluna _col0 retorna o comprimento do array JSON (ou seja, número de pedidos) em cada solicitação, com valores de exemplo sendo 2.
json_extract_scalar retorna um tipo varchar. Por exemplo, o número 2 no resultado anterior é varchar. Para realizar cálculos como soma, primeiro converta-o para bigint usando cast. Type conversion functions.
Como defina um caminho JSON
Ao usar funções como json_extract, especifique um caminho JSON para direcionar a parte do objeto JSON a ser extraída. O formato é $.a.b, onde $ é o nó raiz e pontos (.) referenciam nós filhos.
Para nomes de campos JSON que contêm caracteres especiais — como http.path/@parmname, http path/@parmname ou http-path/@parmname — use colchetes [] em vez de ponto e coloque o nome do campo entre aspas duplas. Exemplo: * |SELECT json_extract_scalar(request, '$["http.path"]').
Ao consultar via SDK, escape as aspas duplas. Exemplo: * | select json_extract_scalar(request, '$[\"http.path\"]').
Para extrair um elemento de um array JSON, use colchetes [] com um índice baseado em zero.
-
Visualize o pagamento do primeiro pedido do usuário:
* | SELECT json_extract_scalar(request, '$.param.orders[0].payment')A tabela de resultados da consulta mostra duas linhas na coluna
_col0, ambas com valor132. -
Visualize o segundo produto adquirido no primeiro pedido do usuário:
* | SELECT json_extract_scalar(request, '$.param.orders[0].commodity[1]')A coluna
_col0retorna dois registros, ambos com valormilk.
Como analisar um array JSON
Para analisar um array JSON, combine cast com a cláusula UNNEST para expandir o array e, em seguida, agregue os resultados.
Example 1
Para calcular o pagamento total de todos os pedidos bem-sucedidos:
-
Filtre as solicitações bem-sucedidas e extraia o campo orders/@parmname usando
json_extract.* and response: SUCCESS | SELECT json_extract(request, '$.param.orders')_col0 [{"commodity":["bread","milk","meat"],"payment":132},{"commodity":["milk","beer","rice"],"payment":49}] [{"commodity":["bread","milk","meat"],"payment":132},{"commodity":["milk","beer","rice"],"payment":49}] -
Converta o array JSON para um tipo array.
* and response: SUCCESS | SELECT cast( json_extract(request, '$.param.orders') AS array(json) )_col0 ["{"commodity":["bread","milk","meat"],"payment":132}","{"commodity":["milk","beer","rice"],"payment":49}"] ["{"commodity":["bread","milk","meat"],"payment":132}","{"commodity":["milk","beer","rice"],"payment":49}"] -
Use
UNNESTpara expandir o array em linhas individuais.* and response: SUCCESS | SELECT orderinfo FROM log, unnest( cast( json_extract(request, '$.param.orders') AS array(json) ) ) AS t(orderinfo)Resultados da consulta e análise:
orderinfo {"commodity":["milk","beer","rice"],"payment":49} {"commodity":["milk","beer","rice"],"payment":49} -
Extraia o valor payment/@parmname usando
json_extract_scalar, converta para bigint e some.* and response: SUCCESS | SELECT sum( cast( json_extract_scalar(orderinfo, '$.payment') AS bigint ) ) FROM log, unnest( cast( json_extract(request, '$.param.orders') AS array(json) ) ) AS t(orderinfo)O resultado retornado é
10860.
Example 2
Para contar a quantidade de cada product em todas as solicitações bem-sucedidas: extraia o campo orders/@parmname, converta para array(json) e expanda com UNNEST — cada linha é um pedido. Extraia o campo commodity/@parmname, converta e expanda novamente — cada linha é um product. Agrupe e conte.
*
and response: SUCCESS |
SELECT
item,
count(1) AS cnt
FROM (
SELECT
orderinfo
FROM log,
unnest(
cast(
json_extract(request, '$.param.orders') AS array(json)
)
) AS t(orderinfo)
),
unnest(
cast(
json_extract(orderinfo, '$.commodity') AS array(json)
)
) AS t(item)
GROUP BY
item
ORDER BY
cnt DESC
Os resultados da consulta contêm duas colunas: item e cnt. As estatísticas de contagem de compras para cada commodity são:
"milk": 120
"bread": 60
"rice": 60
"beer": 60
"meat": 60