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.
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 comotrue
. - 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
.
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:
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.
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:
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.
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.