Compartilhar via


TripPin parte 8 - Adicionando diagnósticos

Observação

Este conteúdo atualmente faz referência ao conteúdo de uma implementação antiga para diagnóstico no Visual Studio. O conteúdo será atualizado em um futuro próximo para abranger o novo SDK do Power Query no Visual Studio Code.

Este tutorial de várias partes aborda a criação de uma nova extensão de fonte de dados para o Power Query. O tutorial deve ser seguido sequencialmente; cada lição se baseia no conector criado nas lições anteriores, adicionando incrementalmente novos recursos a ele.

Nesta lição, você vai:

  • Saber mais sobre a função Diagnostics.Trace
  • Usar as funções auxiliares de Diagnóstico para adicionar informações de rastreamento para ajudar a depurar seu conector

Como habilitar o diagnóstico

Os usuários do Power Query podem habilitar o registro em log de rastreamento marcando a caixa de seleção em Opções | Diagnóstico.

Habilitar o rastreamento no Power Query.

Depois de habilitado, todas as consultas subsequentes farão com que o mecanismo da M emita informações de rastreamento para arquivos de log localizados em um diretório de usuário fixo.

Ao executar consultas da M no SDK do Power Query, o rastreamento é habilitado no nível do projeto. Na página de propriedades do projeto, há três configurações relacionadas ao rastreamento:

  • Limpar log – quando essa configuração estiver definida como true, o log será redefinido/limpo quando você executar suas consultas. Recomendamos que você mantenha essa configuração definida como true.
  • Mostrar Rastreamentos do Mecanismo – essa configuração controla a saída de rastreamentos internos do mecanismo da M. Esses rastreamentos são úteis apenas para membros da equipe do Power Query, portanto, você normalmente deixa definida como false.
  • Mostrar Rastreamentos do Usuário – essa configuração controla as informações de rastreamento produzidas pelo conector. Você vai querer definir essa configuração como true.

Propriedades de projeto.

Depois de habilitado, você começará a ver entradas de log na janela Saída de Consulta da M, na guia Log.

Diagnostics.Trace

A função Diagnostics.Trace é usada para registrar mensagens no log de rastreamento do mecanismo da M.

Diagnostics.Trace = (traceLevel as number, message as text, value as any, optional delayed as nullable logical as any) => ...

Importante

A M é uma linguagem funcional com avaliação lenta. Ao usar Diagnostics.Trace, tenha em mente que a função só será chamada se a expressão da qual ela faz parte for realmente avaliada. Exemplos disso podem ser encontrados mais adiante neste tutorial.

O parâmetro traceLevel pode ser um dos seguintes valores (em ordem decrescente):

  • TraceLevel.Critical
  • TraceLevel.Error
  • TraceLevel.Warning
  • TraceLevel.Information
  • TraceLevel.Verbose

Quando o rastreamento está habilitado, o usuário pode selecionar o nível máximo de mensagens que deseja ver. Todas as mensagens de rastreamento desse nível para abaixo serão enviadas para o log. Por exemplo, se o usuário selecionar o nível "Aviso", as mensagens de rastreamento TraceLevel.Warning, TraceLevel.Error e TraceLevel.Critical aparecerão nos logs.

O parâmetro message é o texto real que será gerado para o arquivo de rastreamento. O texto não conterá o parâmetro value, a menos que você o inclua explicitamente no texto.

O parâmetro value é o que a função retornará. Se o parâmetro delayed for definido como true, value será uma função de parâmetro zero que retornará o valor real que você está avaliando. Quando delayed for definido como false, value será o valor real. Um exemplo de como isso funciona pode ser encontrado abaixo.

Usando Diagnóstico. Rastreamento no conector TripPin

Para obter um exemplo prático de como usar Diagnostics.Trace e o impacto do parâmetro delayed, atualize a função GetSchemaForEntity do conector do TripPin para encapsular a exceção error:

GetSchemaForEntity = (entity as text) as type =>
    try
        SchemaTable{[Entity=entity]}[Type]
    otherwise
        let
            message = Text.Format("Couldn't find entity: '#{0}'", {entity})
        in
            Diagnostics.Trace(TraceLevel.Error, message, () => error message, true);

Você pode forçar um erro durante a avaliação (para fins de teste!) passando um nome de entidade inválido para a função GetEntity. Aqui você altera a linha withData na função TripPinNavTable, substituindo [Name] por "DoesNotExist".

TripPinNavTable = (url as text) as table =>
    let
        // Use our schema table as the source of top level items in the navigation tree
        entities = Table.SelectColumns(SchemaTable, {"Entity"}),
        rename = Table.RenameColumns(entities, {{"Entity", "Name"}}),
        // Add Data as a calculated column
        withData = Table.AddColumn(rename, "Data", each GetEntity(url, "DoesNotExist"), type table),
        // Add ItemKind and ItemName as fixed text values
        withItemKind = Table.AddColumn(withData, "ItemKind", each "Table", type text),
        withItemName = Table.AddColumn(withItemKind, "ItemName", each "Table", type text),
        // Indicate that the node should not be expandable
        withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each true, type logical),
        // Generate the nav table
        navTable = Table.ToNavigationTable(withIsLeaf, {"Name"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
    in
        navTable;

Habilite o rastreamento para seu projeto e execute as consultas de teste. Na guia Errors, você deverá ver o texto do erro gerado:

Mensagem de erro.

Além disso, na guia Log, você verá a mesma mensagem. Se você usar valores diferentes para os parâmetros message e value, elas serão diferentes.

Log de erros.

Observe também que o campo Action da mensagem de log contém o nome (Tipo de Fonte de Dados) da sua extensão (nesse caso, Engine/Extension/TripPin). Isso facilita a localização das mensagens relacionadas à sua extensão quando há várias consultas envolvidas e/ou o rastreamento do sistema (mecanismo de mashup) está habilitado.

Avaliação atrasada

Como exemplo do funcionamento do parâmetro delayed, você fará algumas modificações e executará as consultas novamente.

Primeiro, defina o valor delayed como false, mas deixe o parâmetro value como está:

Diagnostics.Trace(TraceLevel.Error, message, () => error message, false);

Ao executar a consulta, você receberá um erro que "Não é possível converter um valor do tipo Função em Tipo" e não o erro real gerado. Isso ocorre porque a chamada agora está retornando um valor function, em vez do valor em si.

Em seguida, remova a função do parâmetro value:

Diagnostics.Trace(TraceLevel.Error, message, error message, false);

Ao executar a consulta, você receberá o erro correto, mas se verificar a guia Log, não haverá mensagens. Isso ocorre porque o error acaba sendo gerado/avaliado durante a chamada para Diagnostics.Trace, portanto, a mensagem nunca é realmente produzida.

Agora que você entende o impacto do parâmetro delayed, não se esqueça de redefinir o conector de volta para um estado funcional antes de continuar.

Funções auxiliares de diagnóstico no Diagnostics.pqm

O arquivo Diagnostics.pqm incluído neste projeto contém muitas funções auxiliares que facilitam o rastreamento. Conforme mostrado no tutorial anterior, você pode incluir esse arquivo em seu projeto (lembrando de definir a Ação de Build como Compilar) e, em seguida, carregá-lo no arquivo do conector. A parte inferior do arquivo do conector agora deve estar semelhante ao snippet de código abaixo. Explore à vontade as várias funções fornecidas por este módulo, mas neste exemplo, você só usará as funções Diagnostics.LogValue e Diagnostics.LogFailure.

// Diagnostics module contains multiple functions. We can take the ones we need.
Diagnostics = Extension.LoadFunction("Diagnostics.pqm");
Diagnostics.LogValue = Diagnostics[LogValue];
Diagnostics.LogFailure = Diagnostics[LogFailure];

Diagnostics.LogValue

A função Diagnostics.LogValue é muito semelhante à Diagnostics.Trace e pode ser usada para gerar o valor do que você está avaliando.

Diagnostics.LogValue = (prefix as text, value as any) as any => ...

O parâmetro prefix é colocado antes da mensagem de log. Você usaria isso para descobrir qual chamada gerou a mensagem. O parâmetro value é o que a função retornará e também será gravado no rastreamento como uma representação de texto do valor M. Por exemplo, se value for igual a um table com colunas A e B, o log conterá a representação #table equivalente: #table({"A", "B"}, {{"row1 A", "row1 B"}, {"row2 A", row2 B"}})

Observação

Serializar valores de M em texto pode ser uma operação cara. Tome cuidado com o tamanho potencial dos valores que você está gerando para o rastreamento.

Observação

A maioria dos ambientes do Power Query truncará mensagens de rastreamento com um comprimento máximo.

Como exemplo, você atualizará a função TripPin.Feed para rastrear os argumentos url e schema passados para a função.

TripPin.Feed = (url as text, optional schema as type) as table =>
    let
        _url = Diagnostics.LogValue("Accessing url", url),
        _schema = Diagnostics.LogValue("Schema type", schema),
        //result = GetAllPagesByNextLink(url, schema)
        result = GetAllPagesByNextLink(_url, _schema)
    in
        result;

Você precisa usar os novos valores _url e _schema na chamada para GetAllPagesByNextLink. Se você usar os parâmetros originais da função, as chamadas Diagnostics.LogValue nunca serão realmente avaliadas, e nenhuma mensagem será gravada no rastreamento. A programação funcional é divertida!

Agora, ao executar suas consultas, você verá novas mensagens no log.

Acessando a URL:

Acessando a URL da mensagem.

Tipo de esquema:

Mensagem de tipo de esquema.

Você vê a versão serializada do parâmetro schema type, em vez do que obteria ao fazer um simples Text.FromValue em um valor de tipo (o que resulta em "tipo").

Diagnostics.LogFailure

A função Diagnostics.LogFailure pode ser usada para encapsular chamadas de função e só gravará no rastreamento se a chamada de função falhar (ou seja, retornar um error).

Diagnostics.LogFailure = (text as text, function as function) as any => ...

Internamente, Diagnostics.LogFailure adiciona um operador try à chamada function. Se a chamada falhar, o valor text será gravado no rastreamento antes de retornar o error original. Se a chamada function for bem-sucedida, o resultado será retornado sem gravar nada no rastreamento. Como os erros da M não contêm um rastreamento de pilha completo (ou seja, você normalmente só vê a mensagem do erro), isso pode ser útil quando você deseja identificar o local em que o erro foi gerado.

Como um exemplo (ruim), modifique a linha withData da função TripPinNavTable para forçar um erro mais uma vez:

withData = Table.AddColumn(rename, "Data", each Diagnostics.LogFailure("Error in GetEntity", () => GetEntity(url, "DoesNotExist")), type table),

No rastreamento, você pode encontrar a mensagem de erro resultante que contém seu text e as informações de erro originais.

Mensagem LogFailure.

Não se esqueça de redefinir a função para um estado operacional antes de prosseguir com o próximo tutorial.

Conclusão

Esta breve (mas importante) lição mostrou como usar as funções auxiliares de diagnóstico para fazer registrar nos arquivos de rastreamento do Power Query. Quando usadas corretamente, essas funções são úteis na depuração de problemas no conector.

Observação

Como desenvolvedor de conector, é sua responsabilidade garantir que não haja registro de informações confidenciais nem PII (de identificação pessoal) como parte do log de diagnóstico. Você também deve ter cuidado para não gerar muitas informações de rastreamento, pois elas podem ter um impacto negativo no desempenho.

Próximas etapas

TripPin Parte 9 – TestConnection