Partilhar via


log_reduce_fl()

Aplica-se a: ✅Microsoft FabricAzure Data Explorer

A função log_reduce_fl() encontra padrões comuns em colunas textuais semiestruturadas, como linhas de log, e agrupa as linhas de acordo com os padrões extraídos. Ele gera uma tabela de resumo contendo os padrões encontrados classificados de cima para baixo por sua respectiva frequência.

Pré-requisitos

  • O plug-in Python deve ser habilitado no cluster. Isso é necessário para o Python embutido usado na função.

Sintaxe

T| invoke log_reduce_fl(reduce_col [ , use_logram [, use_drain [, custom_regexes [, custom_regexes_policy [, delimitadores [ , similarity_th [ , tree_depth [ , trigram_th [, bigram_th ]]]]]]]]])

Saiba mais sobre as convenções de sintaxe.

Parâmetros

A descrição dos parâmetros a seguir é um resumo. Para obter mais informações, consulte Mais sobre a seção de algoritmo .

Nome Digitar Obrigatória Descrição
reduce_col string ✔️ O nome da coluna de cadeia de caracteres à qual a função é aplicada.
use_logram bool Ative ou desative o algoritmo Logram. O valor padrão é true.
use_drain bool Ative ou desative o algoritmo Drenar. O valor padrão é true.
custom_regexes dynamic Uma matriz dinâmica contendo pares de símbolos de expressão regular e substituição a serem pesquisados em cada linha de entrada e substituídos por seus respectivos símbolos correspondentes. O valor padrão é dynamic([]). A tabela regex padrão substitui números, endereços IP e GUIDs.
custom_regexes_policy string Ou 'preceder', 'anexar' ou 'substituir'. Controla se custom_regexes são anexadas/anexadas/substituem as padrão. O valor padrão é 'prepend'.
delimiters dynamic Uma matriz dinâmica que contém cadeias de caracteres delimitadoras. O valor padrão é dynamic([" "]), definindo o espaço como o único delimitador de caractere único.
similarity_th real Limite de similaridade, usado pelo algoritmo Drenar. Aumentar similarity_th resulta em bancos de dados mais refinados. O valor padrão é 0,5. Se Drenar estiver desabilitado, esse parâmetro não terá efeito.
tree_depth int Aumentar o tree_depth melhora o tempo de execução do algoritmo Drain, mas pode reduzir sua precisão. O valor padrão é 4. Se Drenar estiver desabilitado, esse parâmetro não terá efeito.
trigram_th int Diminuir o trigram_th aumenta as chances de o Logram substituir tokens por curingas. O valor padrão é 10. Se o Logram estiver desabilitado, esse parâmetro não terá efeito.
bigram_th int Diminuir o bigram_th aumenta as chances de Logram substituir tokens por curingas. O valor padrão é 15. Se o Logram estiver desabilitado, esse parâmetro não terá efeito.

Mais sobre o algoritmo

A função executa várias passagens sobre as linhas a serem reduzidas a padrões comuns. A lista a seguir explica os passes:

  • Substituições de expressões regulares: nesta passagem, cada linha é correspondida independentemente a um conjunto de expressões regulares e cada expressão correspondente é substituída por um símbolo de substituição. As expressões regulares padrão substituem endereços IP, números e GUIDs por /<IP>, <GUID> e /<NUM.> O usuário pode anexar/anexar expressões mais regulares a elas, ou substituí-las por novas ou lista vazia modificando custom_regexes e custom_regexes_policy. Por exemplo, para substituir números inteiros por <WNUM> , defina custom_regexes=pack_array('/^\d+$/', '<WNUM'>); para cancelar expressões regulares, substitua o conjunto custom_regexes_policy='replace'. Para cada linha, a função mantém uma lista das expressões originais (antes das substituições) a serem geradas como parâmetros dos tokens de substituição genéricos.

  • Tokenização: semelhante à etapa anterior, cada linha é processada de forma independente e dividida em tokens com base no conjunto de delimitadores. Por exemplo, para definir a quebra de tokens por vírgula, ponto ou ponto-e-vírgula, defina delimiters=pack_array(',', '.', ';').

  • Aplicar algoritmo Logram: esta passagem é opcional, dependendo use_logram é verdadeira. Recomendamos usar o Logram quando uma grande escala for necessária e quando os parâmetros puderem aparecer nos primeiros tokens da entrada de log. OTOH, desative-o quando as entradas de log forem curtas, pois o algoritmo tende a substituir tokens por curingas com muita frequência nesses casos. O algoritmo Logram considera 3 tuplas e 2 tuplas de tokens. Se uma tupla de 3 tokens for comum nas linhas de log (ela aparece mais de trigram_th vezes), é provável que todos os três tokens façam parte do padrão. Se a 3-tupla for rara, é provável que ela contenha uma variável que deve ser substituída por um curinga. Para 3-tuplas raras, consideramos a frequência com que as 2-tuplas contidas na 3-tupla aparecem. Se uma tupla 2 for comum (aparece mais de bigram_th vezes), é provável que o token restante seja um parâmetro e não faça parte do padrão.
    O algoritmo Logram é fácil de paralelizar. Requer duas passagens no corpus logarítmico: a primeira para contar a frequência de cada 3-tupla e 2-tupla, e a segunda para aplicar a lógica descrita anteriormente a cada entrada. Para paralelizar o algoritmo, precisamos apenas particionar as entradas de log e unificar as contagens de frequência de diferentes trabalhadores.

  • Aplicar algoritmo de drenagem: esta passagem é opcional, dependendo use_drain é verdadeira. Drain é um algoritmo de análise de log baseado em uma árvore de prefixo de profundidade truncada. As mensagens de log são divididas de acordo com seu comprimento e, para cada comprimento, os primeiros tree_depth tokens da mensagem de log são usados para construir uma árvore de prefixo. Se nenhuma correspondência para os tokens de prefixo for encontrada, uma nova ramificação será criada. Se uma correspondência para o prefixo foi encontrada, procuramos o padrão mais semelhante entre os padrões contidos na folha da árvore. A similaridade de padrão é medida pela proporção de tokens não curinga correspondentes de todos os tokens. Se a semelhança do padrão mais semelhante estiver acima do limite de similaridade (o parâmetro similarity_th), a entrada de log corresponderá ao padrão. Para esse padrão, a função substitui todos os tokens não correspondentes por curingas. Se a semelhança do padrão mais semelhante estiver abaixo do limite de similaridade, um novo padrão contendo a entrada de log será criado.
    Definimos o tree_depth padrão como 4 com base no teste de vários logs. Aumentar essa profundidade pode melhorar o tempo de execução, mas pode degradar a precisão dos padrões; diminuir é mais preciso, mas mais lento, pois cada nó executa muito mais testes de similaridade.
    Normalmente, o Drain generaliza e reduz os padrões de forma eficiente (embora seja difícil de ser paralelizado). No entanto, como ele depende de uma árvore de prefixo, pode não ser ideal em entradas de log contendo parâmetros nos primeiros tokens. Isso pode ser resolvido na maioria dos casos aplicando o Logram primeiro.

Definição de função

Você pode definir a função inserindo seu código como uma função definida por consulta ou criando-a como uma função armazenada em seu banco de dados, da seguinte maneira:

Defina a função usando a instrução let a seguir. Nenhuma permissão é necessária.

Importante

Uma instrução let não pode ser executada sozinha. Ele deve ser seguido por uma instrução de expressão tabular. Para executar um exemplo funcional de log_reduce_fl(), consulte Exemplo.

let log_reduce_fl=(tbl:(*), reduce_col:string,
              use_logram:bool=True, use_drain:bool=True, custom_regexes: dynamic = dynamic([]), custom_regexes_policy: string = 'prepend',
              delimiters:dynamic = dynamic(' '), similarity_th:double=0.5, tree_depth:int = 4, trigram_th:int=10, bigram_th:int=15)
{
    let default_regex_table = pack_array('(/|)([0-9]+\\.){3}[0-9]+(:[0-9]+|)(:|)', '<IP>', 
                                         '([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})', '<GUID>', 
                                         '(?<=[^A-Za-z0-9])(\\-?\\+?\\d+)(?=[^A-Za-z0-9])|[0-9]+$', '<NUM>');
    let kwargs = bag_pack('reduced_column', reduce_col, 'delimiters', delimiters,'output_column', 'LogReduce', 'parameters_column', '', 
                          'trigram_th', trigram_th, 'bigram_th', bigram_th, 'default_regexes', default_regex_table, 
                          'custom_regexes', custom_regexes, 'custom_regexes_policy', custom_regexes_policy, 'tree_depth', tree_depth, 'similarity_th', similarity_th, 
                          'use_drain', use_drain, 'use_logram', use_logram, 'save_regex_tuples_in_output', True, 'regex_tuples_column', 'RegexesColumn', 
                          'output_type', 'summary');
    let code = ```if 1:
        from log_cluster import log_reduce
        result = log_reduce.log_reduce(df, kargs)
    ```;
    tbl
    | extend LogReduce=''
    | evaluate python(typeof(Count:int, LogReduce:string, example:string), code, kwargs)
};
// Write your query to use the function here.

Exemplo

O exemplo a seguir usa o operador invoke para executar a função. Este exemplo usa logs do sistema de arquivos distribuídos do Apache Hadoop.

Para usar uma função definida por consulta, invoque-a após a definição da função inserida.

let log_reduce_fl=(tbl:(*), reduce_col:string,
              use_logram:bool=True, use_drain:bool=True, custom_regexes: dynamic = dynamic([]), custom_regexes_policy: string = 'prepend',
              delimiters:dynamic = dynamic(' '), similarity_th:double=0.5, tree_depth:int = 4, trigram_th:int=10, bigram_th:int=15)
{
    let default_regex_table = pack_array('(/|)([0-9]+\\.){3}[0-9]+(:[0-9]+|)(:|)', '<IP>', 
                                         '([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})', '<GUID>', 
                                         '(?<=[^A-Za-z0-9])(\\-?\\+?\\d+)(?=[^A-Za-z0-9])|[0-9]+$', '<NUM>');
    let kwargs = bag_pack('reduced_column', reduce_col, 'delimiters', delimiters,'output_column', 'LogReduce', 'parameters_column', '', 
                          'trigram_th', trigram_th, 'bigram_th', bigram_th, 'default_regexes', default_regex_table, 
                          'custom_regexes', custom_regexes, 'custom_regexes_policy', custom_regexes_policy, 'tree_depth', tree_depth, 'similarity_th', similarity_th, 
                          'use_drain', use_drain, 'use_logram', use_logram, 'save_regex_tuples_in_output', True, 'regex_tuples_column', 'RegexesColumn', 
                          'output_type', 'summary');
    let code = ```if 1:
        from log_cluster import log_reduce
        result = log_reduce.log_reduce(df, kargs)
    ```;
    tbl
    | extend LogReduce=''
    | evaluate python(typeof(Count:int, LogReduce:string, example:string), code, kwargs)
};
//
// Finding common patterns in HDFS logs, a commonly used benchmark for log parsing
//
HDFS_log
| take 100000
| invoke log_reduce_fl(reduce_col="data")

Saída

Count LogReduce Exemplo
55356 081110 <NUM><NUM> INFO dfs. FSNamesystem: BLOCK* NameSystem.delete: blk_<NUM> é adicionado ao invalidSet de <IP> 081110 220623 26 INFO dfs. FSNamesystem: BLOCK* NameSystem.delete: blk_1239016582509138045 é adicionado a invalidSet de 10.251.123.195:50010
10278 081110 <NUM><NUM> INFO dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: blockMap atualizado: <IP> é adicionado ao tamanho <blk_<NUM> NUM> 081110 215858 27 INFO dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: blockMap atualizado: 10.250.11.85:50010 é adicionado ao blk_5080254298708411681 tamanho 67108864
10256 081110 <NUM><NUM> INFO dfs. DataNode$PacketResponder: NUM do PacketResponder <para o bloco blk_<NUM> terminando 081110 215858 15496 INFO dfs.> DataNode$PacketResponder: PacketResponder 2 para terminação de bloco blk_-7746692545918257727
10256 081110 <NUM><NUM> INFO dfs. DataNode$PacketResponder: Bloco recebido blk_<NUM> de tamanho <NUM> do <IP> 081110 215858 15485 INFO dfs. DataNode$PacketResponder: Bloco recebido blk_5080254298708411681 de tamanho 67108864 de /10.251.43.21
9140 081110 <NUM><NUM> INFO dfs. DataNode$DataXceiver: Bloco de recebimento blk_<NUM> src: <IP> dest: <IP> 081110 215858 15494 INFO dfs. DataNode$DataXceiver: Bloco de recebimento blk_-7037346755429293022 src: /10.251.43.21:45933 dest: /10.251.43.21:50010
3047 081110 <NUM><NUM> INFO dfs. FSNamesystem: BLOCK* NameSystem.allocateBlock: /user/root/rand3/temporary/task<NUM><NUM>m<NUM_<>NUM/>part-NUM.>< <>081110 215858 26 INFO dfs. FSNamesystem: BLOCK NameSystem.allocateBlock: /user/root/rand3/_temporary/task_200811101024_0005_m_001805_0/part-01805. blk-7037346755429293022
1402 081110 <NUM><NUM> INFO>< :> <bloco blk_<NUM><> <> 081110 215957 15556 INFO dfs. DataNode $ DataTransfer: 10.250.15.198: 50010: bloco transmitido blk_-3782569120714539446 para / 10.251.203.129: 50010
177 081110 <NUM><NUM> INFO<> :><> <><< *> 081110 215859 13 INFO dfs. DataBlockScanner: Verificação bem-sucedida para blk_-7244926816084627474
36 081110 <NUM><NUM> INFO <>:><> <>< para o bloco <*> 081110 215924 15636 INFO dfs. DataNode$BlockReceiver: Recebendo pacote vazio para o bloco blk_3991288654265301939
12 081110 <NUM><NUM> INFO dfs. FSNamesystem: BLOCK* <>><> <> <> <><><> <081110 215953 19 INFO dfs. FSNamesystem: BLOCK* pede a 10.250.15.198:50010 para replicar blk_-3782569120714539446 para datanode(s) 10.251.203.129:50010
12 081110 <NUM><NUM> INFO>< : <>> <> <<>><bloco blk_<NUM><> <> 081110 215955 18 INFO dfs. DataNode: 10.250.15.198:50010 Thread inicial para transferir o bloco blk_-3782569120714539446 para 10.251.203.129:50010
12 081110 <NUM><NUM> INFO dfs. DataNode$DataXceiver: Bloco recebido blk_<NUM> src: <IP> dest: <IP> de tamanho <NUM> 081110 215957 15226 INFO dfs. DataNode$DataXceiver: Bloco recebido blk_-3782569120714539446 src: /10.250.15.198:51013 dest: /10.250.15.198:50010 de tamanho 14474705
6 081110 <NUM><NUM><> dfs. FSNamesystem: BLOCK NameSystem.addStoredBlock:> <<> <>><> <<<> <>> tamanho <NUM> 081110 215924 27 WARN dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: solicitação addStoredBlock redundante recebida para blk_2522553781740514003 no tamanho 10.251.202.134:50010 67108864
6 081110 <NUM><NUM> INFO dfs. DataNode$DataXceiver: <> <>>> <<<>:<> <<>><> <> 081110 215936 15714 INFO dfs. DataNode$DataXceiver: writeBlock blk_720939897861061328 exceção recebida java.io.IOException: Não foi possível ler do fluxo
3 081110 <NUM><NUM> INFO dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: <> <>> <<<>> <><>tamanho <NUM>> <<> <<>><>><><> <. 081110 220635 28 INFO dfs. FSNamesystem: BLOCK NameSystem.addStoredBlock: solicitação addStoredBlock recebida para blk_-81196479666306310 no tamanho 10.250.17.177:50010 53457811 Mas não pertence a nenhum arquivo.
1 081110 <NUM><NUM:> <<<<>>>> <<<>>>> <> < . . <><> <><> <> 081110 220631 19 WARN dfs. FSDataset: Erro inesperado ao tentar excluir o bloco blk_-2012154052725261337. BlockInfo não encontrado em volumeMap.