Fornece referências gerais para o uso da Structured Process Language (SPL) em diferentes cenários.
Otimização de instruções SPL
Várias instruções SPL podem produzir o mesmo resultado de processamento de dados. Escrever instruções SPL concisas e eficientes simplifica a manutenção e melhora o desempenho. A tabela a seguir apresenta algumas sugestões.
|
Sugestão |
Antes da otimização |
Após a otimização |
|
Combine cláusulas where consecutivas em uma única cláusula. |
|
|
|
Agrupe cláusulas extend consecutivas em uma só. |
|
|
|
Substitua a combinação de extend e project-away por project-rename. |
|
|
|
Modifique os valores dos campos diretamente em vez de usar extend para criar novos campos, exceto quando necessário. |
|
|
Tratamento de campos especiais
Campos de tempo
Durante a execução da SPL, o tipo de dados dos campos de tempo nos logs do Simple Log Service é sempre INTEGER ou BIGINT. Esses campos incluem o campo de timestamp de dados __time__ e a parte em nanossegundos do timestamp de dados __time_ns_part__.
Para atualizar o timestamp dos dados, use a instrução extend e garanta que o novo valor seja do tipo INTEGER ou BIGINT. Outras instruções não operam em campos de tempo. O comportamento delas é descrito a seguir:
project, project-away e project-rename: Essas instruções mantêm os campos de tempo por padrão. Não é possível renomeá-los ou sobrescrevê-los.
parse-regexp e parse-json: Se o resultado da extração incluir campos de tempo, eles serão ignorados.
Exemplo
Extraia valores de campos de tempo a partir de uma string de tempo existente.
-
Instrução SPL
* | parse-regexp time, '([\d\-\s:]+)\.(\d+)' as ts, ms | extend ts=date_parse(ts, '%Y-%m-%d %H:%i:%S') | extend __time__=cast(to_unixtime(ts) as INTEGER) | extend __time_ns_part__=cast(ms as INTEGER) * 1000000 | project-away ts, ms -
Dados de entrada
time: '2023-11-11 01:23:45.678' -
Resultado de saída
__time__: 1699637025 __time_ns_part__: 678000000 time: '2023-11-11 01:23:45.678'
Nomes de campos com caracteres especiais
Se um nome de campo contiver espaços ou outros caracteres especiais, coloque-o entre aspas duplas (") ao referenciá-lo. Por exemplo, se um campo for nomeado como A B, contendo um espaço, referencie-o como "A B" na instrução SPL:
* | where "A B" like '%error%'
Nomes de campos sem distinção entre maiúsculas e minúsculas
Nas consultas de varredura do SLS, os nomes de campos referenciados nas instruções SPL não diferenciam maiúsculas de minúsculas. Por exemplo, se um log contiver um campo chamado Method, você poderá referenciá-lo como method ou METHOD na instrução SPL.
Isso se aplica ao recurso de consulta de varredura do Simple Log Service. Para mais informações, consulte Consultas de varredura.
Exemplo
Use um nome de campo sem distinção entre maiúsculas e minúsculas em uma cláusula where.
-
Instrução SPL
* | where METHOD like 'Post%' -
Dados de entrada
Method: 'PostLogstoreLogs' -
Resultado de saída
Method: 'PostLogstoreLogs'
Resolução de conflitos de nomes de campos
Durante o upload de logs ou a execução da SPL, o processamento sensível a maiúsculas e minúsculas pode causar conflitos de nomes de campos. Por exemplo, um log bruto pode conter tanto o campo Method quanto o campo method. A SPL resolve esses conflitos de maneiras diferentes, dependendo do cenário.
Para evitar essas situações, padronize os nomes dos campos em seus logs brutos.
Conflitos nos dados de entrada
Se um log bruto contiver campos cujos nomes sejam idênticos ao ignorar a diferenciação entre maiúsculas e minúsculas, como Status e status, a SPL selecionará aleatoriamente um dos campos para entrada e descartará o outro. Por exemplo:
-
Instrução SPL
* | extend status_cast = cast(status as bigint) -
Dados de entrada
Status: '200' status: '404' -
Resultado do processamento
-
Possibilidade 1: O valor do campo Status é mantido.
Status: '200' -- The first column is retained, and the second column is discarded. status_cast: '200' -
Possibilidade 2: O valor do campo status é mantido.
status: '404' -- The second column is retained, and the first column is discarded. Status_cast: '404'
-
Conflitos nos resultados de saída
Cenário 1: Conflitos de campos de dados brutos
Durante a execução da SPL, podem ser gerados campos com nomes idênticos ao ignorar a diferenciação entre maiúsculas e minúsculas. A SPL seleciona aleatoriamente um deles para a saída. Por exemplo, se um campo de log contiver uma string JSON, o uso da instrução parse-json pode criar campos com nomes conflitantes:
-
Instrução SPL
* | parse-json content -
Dados de entrada
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}' -
Resultado de saída
-
Possibilidade 1: O campo Method é mantido.
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}' Method: 'PostLogs' -- The Method field is retained. status: '200' -
Possibilidade 2: O campo method é mantido.
content: '{"Method": "PostLogs", "method": "GetLogs", "status": "200"}' method: 'GetLogs' -- The method field is retained. status: '200'
-
Cenário 2: Conflitos com novos campos de dados gerados
Para evitar ambiguidades, a SPL preserva a capitalização dos nomes de novos campos gerados explicitamente pelas instruções. Isso se aplica aos nomes de campos gerados pela instrução extend e aos nomes de campos especificados explicitamente usando as nas instruções parse-regexp e parse-csv.
Por exemplo, se você usar extend para criar um novo campo Method, o nome do campo resultante permanecerá Method.
-
Instrução SPL
* | extend Method = 'Post' -
Dados de entrada
Status: '200' -
Resultado de saída
Status: '200' Method: 'Post'
Tratamento de conflitos de campos reservados do SLS
Isso se aplica aos recursos de consumo em tempo real e consulta de varredura do Simple Log Service.
Para obter a lista completa de campos reservados, consulte Campos reservados. A SPL lê dados da estrutura LogGroup como entrada. Para mais informações sobre a definição de LogGroup, consulte Codificação de dados. Se os dados brutos gravados no Simple Log Service não estiverem codificados no formato padrão LogGroup, alguns campos reservados poderão aparecer em LogContent em vez de sua localização padrão. A SPL trata esses campos reservados da seguinte forma:
Para os campos
__source__,__topic__,__time__e__time_ns_part__, a SPL lê seus valores da estrutura padrão LogGroup e ignora quaisquer campos com os mesmos nomes em LogContent.Para campos de tag com o prefixo
__tag__:, a SPL tenta primeiro ler seus valores da estrutura padrão LogGroup. Se nenhum valor for encontrado, a SPL o lê de LogContent. Por exemplo, para o campo__tag__:ip, a SPL tenta primeiro ler o campo com a chaveipda lista LogTag. Se o campo não existir, a SPL então lê o campo de log com a chave__tag__:ipdos campos de log personalizados em LogContent.
O campo __line__ para pesquisa de texto completo
Isso se aplica ao recurso de consulta de varredura do SLS.
Para filtrar logs brutos no console ou usando a operação de API GetLogstoreLogs, use o campo __line__.
Exemplo
-
Pesquise a palavra-chave error nos logs.
* | where __line__ like '%error%' -
Se um log contiver um campo chamado
__line__, coloque o nome do campo entre crases para referenciá-lo.* | where `__line__` ='20'
Políticas de retenção e sobrescrita de valores
Quando uma instrução SPL é executada e um campo de saída tem o mesmo nome que um campo de entrada existente, o valor do campo é determinado pela seguinte política:
Essas políticas não se aplicam à instrução extend. Para extend, se houver conflito de nome de campo, o novo valor será sempre utilizado.
Tipos de dados inconsistentes entre valores antigos e novos
O valor original do campo de entrada é mantido.
Exemplo
-
Exemplo 1: Um campo renomeado por uma instrução project tem um nome conflitante.
-
Instrução SPL
* | extend status=cast(status as BIGINT) -- Convert the type of the status field to BIGINT. | project code=status -- The new value's type (BIGINT) differs from the old value's type (VARCHAR), so the old value is kept. -
Dados de entrada
status: '200' code: 'Success' -
Resultado de saída
code: 'Success'
-
-
Exemplo 2: Um campo extraído por uma instrução parse-json tem um nome conflitante.
-
Instrução SPL
* | extend status=cast(status as BIGINT) -- Convert the type of the status field to BIGINT. | parse-json content -- The old type of status is BIGINT and the new type is VARCHAR. The old value is retained. -
Dados de entrada
status: '200' content: '{"status": "Success", "body": "this is test"}' -
Resultado de saída
content: '{"status": "Success", "body": "this is test"}' status: 200 body: 'this is test'
-
Tipos de dados consistentes entre valores antigos e novos
Se o valor de entrada for nulo, o novo valor será usado. Caso contrário, o comportamento é determinado pelo parâmetro mode na instrução, conforme definido na tabela a seguir.
Se o parâmetro mode não for especificado na instrução, seu valor padrão será overwrite.
|
Modo |
Descrição |
|
overwrite |
Sobrescreve o valor antigo com o novo valor. |
|
preserve |
Mantém o valor antigo e descarta o novo valor. |
Exemplo
-
Exemplo 1: Um campo renomeado por uma instrução project tem um nome conflitante e o mesmo tipo. O modo padrão é overwrite.
Instrução SPL
* | project code=status -- The old and new types of code are both VARCHAR. The new value is used based on the overwrite mode.-
Dados de entrada
status: '200' code: 'Success' -
Resultado de saída
code: '200'
-
Exemplo 2: Um campo extraído por uma instrução parse-json tem um nome conflitante e o mesmo tipo. O modo padrão é overwrite.
-
Instrução SPL
* | parse-json content -- The old and new types of status are both VARCHAR. The new value is used based on the overwrite mode. -
Dados de entrada
status: '200' content: '{"status": "Success", "body": "this is test"}' -
Resultado de saída
content: '{"status": "Success", "body": "this is test"}' status: 'Success' body: 'this is test'
-
-
Exemplo 3: Um campo extraído por uma instrução parse-json tem um nome conflitante e o mesmo tipo. O modo está definido como preserve.
-
Instrução SPL
* | parse-json -mode='preserve' content -- The old and new types of status are both VARCHAR. The old value is retained based on the preserve mode. -
Dados de entrada
status: '200' content: '{"status": "Success", "body": "this is test"}' -
Resultado de saída
content: '{"status": "Success", "body": "this is test"}' status: '200' body: 'this is test'
-
Conversão de tipos de dados
Tipo inicial
Quando a SPL processa dados, todos os campos de entrada são inicialmente do tipo VARCHAR, exceto os campos de tempo de log. Se o processamento subsequente exigir um tipo de dados diferente, converta o tipo explicitamente.
Exemplo
Para filtrar logs de acesso com código de status 5xx, converta o campo status para o tipo BIGINT antes da comparação.
* -- The initial type of the status field is VARCHAR.
| where cast(status as BIGINT) >= 500 -- Convert the type of the status field to BIGINT, and then perform the comparison.
Retenção de tipo
Após usar a instrução extend para converter o tipo de dados de um campo, o processamento subsequente mantém o tipo convertido.
Exemplo
* -- A Logstore is used as input data. Except for time fields, all fields are initially of the VARCHAR type.
| where __source__='127.0.0.1' -- Filter on the __source__ field.
| extend status=cast(status as BIGINT) -- Convert the type of the status field to BIGINT.
| project status, content
| where status>=500 -- The type of the status field remains BIGINT, so it can be directly compared with the number 500.
Tratamento de valores nulos em expressões SPL
Geração de valores nulos
Durante o processamento de dados da SPL, valores nulos são gerados nos seguintes cenários:
Se um campo usado em uma expressão SPL não existir nos dados de entrada, seu valor será tratado como nulo durante os cálculos.
Se ocorrer uma exceção durante o cálculo de uma expressão SPL, o resultado será nulo. Por exemplo, quando uma conversão de tipo cast falha ou um índice de array está fora dos limites.
Exemplo
-
Se um campo não existir, seu valor será tratado como nulo nos cálculos.
-
Instrução SPL
* | extend withoutStatus=(status is null) -
Dados de entrada
# Entry 1 status: '200' code: 'Success' # Entry 2 code: 'Success' -
Resultado de saída
# Entry 1 status: '200' code: 'Success' withoutStatus: false # Entry 2 code: 'Success' withoutStatus: true
-
-
Se ocorrer uma exceção durante o cálculo, o resultado será nulo.
-
Instrução SPL
* | extend code=cast(code as BIGINT) -- Failed to convert the code field to BIGINT. | extend values=json_parse(values) | extend values=cast(values as ARRAY(BIGINT)) | extend last=arr[10] -- Array index out of bounds. -
Dados de entrada
status: '200' code: 'Success' values: '[1,2,3]' -
Resultado de saída
status: '200' code: null values: [1, 2, 3] last: null
-
Eliminação de valores nulos
Para eliminar valores nulos durante os cálculos, use a expressão COALESCE. Ela retorna o primeiro valor não nulo de uma lista de expressões. Também é possível especificar um valor padrão para uso caso todas as expressões resultem em nulo.
Exemplo
Leia o último elemento de um array. Se o array estiver vazio, o valor padrão será 0.
-
Instrução SPL
* | extend values=json_parse(values) | extend values=cast(values as ARRAY(BIGINT)) | extend last=COALESCE(values[3], values[2], values[1], 0) -
Dados de entrada
# Entry 1 values: '[1, 2, 3]' # Entry 2 values: '[]' -
Resultado de saída
# Entry 1 values: [1, 2, 3] last: 3 # Entry 2 values: [] last: 0
Escape de caracteres
Aspas simples
Aspas simples delimitam literais de string. Se o literal de string contiver uma aspa simples, use uma aspa simples adicional para escapá-la.
Exemplo
-
Instrução SPL
* | extend user = 'Alice' | extend phone = 'Alice''s Phone' -
Resultado de saída
user: Alice phone: Alice's Phone
Aspas duplas
Aspas duplas delimitam nomes de campos. Se o nome do campo contiver uma aspa dupla, use uma aspa dupla adicional para escapá-la.
Exemplo
-
Instrução SPL
* | extend user_name = 'Alice' | extend "user name" = 'Alice' | extend "user""name" = 'Alice' -
Resultado de saída
user_name: Alice user name: Alice user"name: Alice
Outros caracteres especiais
Exemplo 1
Na SPL, a barra invertida (\) não é um caractere de escape e, portanto, é preservada como está.
-
Instrução SPL
* | extend a = 'foo\tbar' | extend b = 'foo\nbar' -
Resultado de saída
a: foo\tbar b: foo\nbar
Exemplo 2
Se uma string precisar incluir caracteres especiais, como tabulação ou nova linha, use a função chr para concatenar strings.
-
Instrução SPL
* | extend a = concat('foo', chr(9), 'bar') | extend b = concat('foo', chr(10), 'bar') -
Resultado de saída
a: foo bar b: foo bar
Tratamento de erros
Erro de sintaxe
Erros de sintaxe ocorrem quando uma instrução SPL está malformada, como nome de instrução incorreto, erro de referência de palavra-chave ou erro de especificação de tipo. Quando ocorre um erro de sintaxe, a SPL não processa nenhum dado. Corrija a instrução com base na mensagem de erro.
Erro de dados
Um erro de dados ocorre quando uma função ou conversão falha durante a execução da SPL. A SPL define o campo resultante como null. Como erros de dados podem ocorrer em qualquer linha, a SPL faz uma amostragem aleatória e retorna apenas algumas mensagens de erro. Você pode ignorar esses erros ou modificar a instrução SPL com base no conteúdo dos dados.
Erros de dados não interrompem todo o processo de execução. A instrução SPL ainda retorna resultados, mas o campo onde ocorreu o erro é definido como null.
Tempo limite de execução
Uma instrução SPL contém várias instruções, e seus tempos de execução variam dependendo do cenário de dados. Se o tempo total de execução exceder o período de tempo limite padrão, a execução será interrompida e um erro de tempo limite será retornado com um resultado vazio. O período de tempo limite padrão varia para consultas de varredura, consumo em tempo real e coleta Logtail.
Para resolver esse erro, simplifique sua instrução SPL para reduzir sua complexidade, por exemplo, otimizando expressões regulares complexas ou reduzindo o número de pipelines.
Limite de memória excedido
Uma instrução SPL contém várias instruções, e seu consumo de memória varia dependendo do cenário de dados. A execução da SPL é limitada a uma cota de memória específica. Se essa cota for excedida, a execução falhará e um erro de limite de memória excedido será retornado com um resultado vazio. A cota de memória padrão varia para consultas de varredura, consumo em tempo real e coleta Logtail.
Para resolver esse erro, simplifique sua instrução SPL para reduzir sua complexidade, diminua o número de pipelines ou verifique se o tamanho dos dados brutos é excessivo.