Partager via


Écrire la télémétrie sur votre ressource Application Insights en utilisant ILogger

Important

Pour utiliser cette fonctionnalité, vous devez d′abord activer la fonctionnalité de l′intégration Application Insights. Plus d′informations : Analyser les applications pilotées par modèle et la télémétrie Microsoft Dataverse avec Application Insights

Il n’y a actuellement aucun support de ILogger dans une session de profilage/débogage de plug-in de l’outil d’enregistrement de plug-in ou de l’extension Power Platform Tools pour Visual Studio.

Si vous activez Application Insights pour votre organisation, tout plug-in écrit à l′aide de l′interface ILogger fournie dans les assemblys SDK pour .NET écrivent la télémétrie sur votre ressource Application Insights.

La plateforme Dataverse capture les données de télémétrie de l’application pilotée par modèle et Dataverse et les exporte vers votre ressource Application Insights. Vous constatez une certaine latence entre le moment de la capture et la disponibilité des données dans Application Insights. Cette télémétrie étant collectée par Microsoft, vous n′avez pas besoin d′écrire de code pour l′activer.

Les données de télémétrie provenant des plug-ins utilisant l′interface ILogger sont différentes de deux manières :

  • Cette télémétrie est écrite directement dans votre ressource Application Insights et n′est jamais envoyée à Microsoft.
    • Cela signifie que la visualisation de ces données prend moins de temps.
  • Vous devez mettre à jour le code du plug-in pour utiliser l′interface ILogger.

L′interface ILogger fournit de vraies données de télémétrie et est conçue pour fonctionner avec les journaux de suivi des plug-ins existants écrits en utilisant l′interface ITracingService. Le tableau suivant offre un comparatif des fonctionnalités :

Critères ILogger pour Application Insights Suivi ITracingService pour les journaux de suivi des plug-ins
Utilisation prévue Capturer la télémétrie au fil du temps pour l′analyse et le débogage. Lors du développement et du débogage des plug-ins
Durée de stockage des données En fonction de la période de conservation des données Application Insights choisie, elle est de 90 jours par défaut 24 heures
Disponible Uniquement pour les organisations abonnées à l′intégration Application Insights. Disponible pour toute organisation si le traçage des plug-ins est activé.
Quantité de données Chaque message de journal peut transmettre une valeur de chaîne. Écriture de seulement 10 Ko de texte par exécution de plug-in. Tout texte supplémentaire est tronqué.
Disponible dans les erreurs de runtime Non Disponible dans les erreurs client des application pilotées par modèle et comme annotations dans l′API web. Plus d′informations : Inclure des détails supplémentaires avec des erreurs

Vous devez continuer à utiliser l′interface ITracingService.Trace pour écrire dans la table du journal de suivi des plug-ins si nécessaire. Toutes les organisations n′activent pas Application Insights. Si le code de plug-in utilise l′interface ILogger et que l′organisation n′a pas activé l′intégration Application Insights, rien n′est écrit. Il est donc important de continuer à utiliser la méthode de suivi ITracingService dans les plug-ins. Les journaux de suivi des plug-ins restent un moyen intéressant pour capturer les données lors du développement et du débogage des plug-ins même s′ils n′ont jamais été conçus pour fournir des données de télémétrie. Plus d′informations : Plug-ins : traçage et journalisation

Vous devez utiliser ILogger, car elle fournit une télémétrie sur ce qui se passe dans un plug-in. Cette télémétrie est intégrée à la plus grande étendue de données capturées avec l’intégration Application Insights. L′intégration Application Insights indique à quel moment un plug-in s′exécute, la durée de son exécution et s′il effectue des requêtes http externes, mais Microsoft ne peut ajouter aucun code de télémétrie dans les plug-ins écrits pour étendre le comportement de la plateforme.

Si vous êtes éditeur de logiciels indépendant et disposez d′un produit qui inclut des plug-ins, vos clients qui activent Application Insights apprécient de visualiser ce qui se passe dans les plug-ins et ces données peuvent contribuer à les aider en cas de problème. Mais les données capturées à l′aide d′ILogger ne sont envoyées qu′à la ressource du client abonné. Vous ne pouvez voir que les données capturées pour vos environnements personnels si vous avez activé Application Insights.

Utiliser ILogger

ILogger est une interface commune pour la capture d′informations de journal. L′implémentation proposée avec les assemblys du SDK pour .NET fournit des méthodes communes pour prendre en charge une étendue et de différents niveaux de journalisation. Actuellement, aucun paramètre ne permet de contrôler le niveau des journaux en cours d′écriture. Les niveaux peuvent être utilisés dans Application Insights pour filtrer les journaux à afficher.

Voici un exemple de plug-in utilisant à la fois ILogger et ITracingService.Trace.

Notes

Veillez à inclure using Microsoft.Xrm.Sdk.PluginTelemetry;. N’utilisez pas using Microsoft.Extensions.Logging;, sinon l’instance ILogger sera nulle.

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.PluginTelemetry;
using System;
using System.Net.Http;

namespace ILoggerExample
{
    public class AccountPostOperation : IPlugin
    {
        private string webAddress;
        public AccountPostOperation(string config)
        {

            if (string.IsNullOrEmpty(config))
            {
                webAddress = "https://www.bing.com";
            }
            else
            {
                webAddress = config;
            }
        }


        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService =
               (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            ILogger logger = (ILogger)serviceProvider.GetService(typeof(ILogger));

            IPluginExecutionContext context = (IPluginExecutionContext)
               serviceProvider.GetService(typeof(IPluginExecutionContext));

            try
            {
                string startExecMsg = "Start execution of AccountPostOperation";
                logger.LogInformation(startExecMsg);
                tracingService.Trace(startExecMsg);

                Entity entity = (Entity)context.InputParameters["Target"];
                if (entity.LogicalName != "account")
                {

                    string wrongEntityMsg = "Plug-in registered for wrong entity {0}";
                    logger.LogWarning(wrongEntityMsg, entity.LogicalName);
                    tracingService.Trace(wrongEntityMsg, entity.LogicalName);
                    return;
                }

                string activityMsg = "Callback";

                using (logger.BeginScope(activityMsg))
                {
                    tracingService.Trace(activityMsg);

                    string startTaskMsg = "Start Task Creation";
                    logger.LogInformation(startTaskMsg);
                    tracingService.Trace(startTaskMsg);

                    Entity followup = new Entity("task");
                    followup["subject"] = "Send e-mail to the new customer.";
                    followup["description"] =
                        "Follow up with the customer. Check if there are any new issues that need resolution.";
                    followup["scheduledstart"] = DateTime.Now.AddDays(7);
                    followup["scheduledend"] = DateTime.Now.AddDays(7);
                    followup["category"] = context.PrimaryEntityName;

                    // Refer to the account in the task activity.
                    if (context.OutputParameters.Contains("id"))
                    {
                        Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
                        string regardingobjectidType = "account";

                        followup["regardingobjectid"] =
                        new EntityReference(regardingobjectidType, regardingobjectid);

                    }

                    // Obtain the IOrganizationService reference.
                    IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider
                    .GetService(typeof(IOrganizationServiceFactory));

                    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
                    //Create the task
                    service.Create(followup);

                    string endTaskMsg = "Task creation completed";
                    logger.LogInformation(endTaskMsg);
                    tracingService.Trace(endTaskMsg);
                }

                string outBoundScope = "OutboundCall";

                using (logger.BeginScope(outBoundScope))
                {

                    string outboundStartMsg = "Outbound call started";
                    logger.LogInformation(outboundStartMsg);
                    tracingService.Trace(outboundStartMsg);

                    using (HttpClient client = new HttpClient())
                    {
                        client.Timeout = TimeSpan.FromMilliseconds(15000); //15 seconds
                        client.DefaultRequestHeaders.ConnectionClose = true; //Set KeepAlive to false

                        HttpResponseMessage response = client
                            .GetAsync(webAddress)
                            .GetAwaiter()
                            .GetResult(); //Make sure it is synchronous

                        response.EnsureSuccessStatusCode();

                        string responseText = response.Content
                            .ReadAsStringAsync()
                            .GetAwaiter()
                            .GetResult(); //Make sure it is synchronous

                        string shortResponseText = responseText.Substring(0, 20);

                        logger.LogInformation(shortResponseText);
                        tracingService.Trace(shortResponseText);

                        string outboundEndMsg = "Outbound call ended successfully";

                        logger.LogInformation(outboundEndMsg);
                        tracingService.Trace(outboundEndMsg);

                    }

                }

            }
            catch (Exception e)
            {
                string errMsg = "Plugin failed";
                logger.LogError(e, errMsg);
                tracingService.Trace($"{errMsg}:{e.Message}");
                throw new InvalidPluginExecutionException(e.Message, e);
            }
        }
    }
}

Si ce plug-in est enregistré sur une étape PostOperation synchrone pour Create d′une entité account, utilisez les journaux Application Insights pour afficher la sortie en quelques minutes. Utilisez Langage de requête Kusto (KQL) pour interroger les résultats.

Vous pouvez filtrer les éléments pour une seule opération en utilisant operation_ParentId, qui représente l′ID de requête de l′en-tête de réponse.

Filtrer les éléments pour une seule opération à l′aide de operation_ParentId.

L′entrée du journal de suivi des plug-ins correspondante ressemble à ce qui suit :

Start execution of AccountPostOperation
Callback
Start Task Creation
Task creation completed
Outbound call started
<!doctype html><html
Outbound call ended successfully 

Notez que les informations définies avec la méthode BeginScope n′apparaissent pas dans les lignes renvoyées dans Application Insights. Ces données sont définies sous customDimensions des journaux ajoutés dans cette étendue. Utilisez cette requête pour afficher les journaux dans l′étendue.

Cette requête limite les résultats aux journaux ajoutés lors de l′étendue Callback

Cette requête limite les résultats aux journaux ajoutés lors de l′étendue Callback.

Et cette requête limite les résultats aux journaux ajoutés lors de l′étendue OutboundCall :

La requête limite les résultats aux journaux ajoutés lors de l′étendue OutboundCall.

Exceptions de journalisation

Sous l′exemple de code de plug-in ci-dessus, le code suivant utilise LogError pour enregistrer une exception détectée et renvoie une exception InvalidPluginExecutionException :

catch (Exception e)
{
    string errMsg = "Plugin failed";
    logger.LogError(e, errMsg);
    tracingService.Trace($"{errMsg}:{e.Message}");
    throw new InvalidPluginExecutionException(e.Message, e);
}

À l′aide du code de plug-in ci-dessus, provoquez une exception en transmettant une valeur non valide aux données de configuration d′enregistrement d′étape. Dans cet exemple, la valeur est NOT_A_URL.

Provoque une erreur en entrant une valeur de configuration non valide dans l′enregistrement de l′étape du plug-in.

Ceci remplace la valeur par défaut (https://www.bing.com) et provoque l′échec de l′appel sortant.

Il n′y a rien de mal avec la requête qu′un client peut envoyer :

POST [Organization URI]/api/data/v9.1/accounts HTTP/1.1
Prefer: odata.include-annotations="*"
Authorization: Bearer [REDACTED]
Content-Type: application/json

{
  "name":"Test account"
}

Mais à cause de l′enregistrement incorrect de l′étape du plug-in, la réponse renvoie l′erreur suivante avec tous les détails lorsque l′en-tête Prefer: odata.include-annotations="*" est utilisé :

HTTP/1.1 400 Bad Request
Content-Type: application/json; odata.metadata=minimal
x-ms-service-request-id: 8fd35fd6-5329-4bd5-a1b7-757f91822322
REQ_ID: 8fd35fd6-5329-4bd5-a1b7-757f91822322
OData-Version: 4.0
Date: Sat, 24 Apr 2021 18:24:46 GMT

{
    "error": {
        "code": "0x80040265",
        "message": "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.",
        "@Microsoft.PowerApps.CDS.ErrorDetails.OperationStatus": "0",
        "@Microsoft.PowerApps.CDS.ErrorDetails.SubErrorCode": "-2146233088",
        "@Microsoft.PowerApps.CDS.HelpLink": "http://go.microsoft.com/fwlink/?LinkID=398563&error=Microsoft.Crm.CrmException%3a80040265&client=platform",
        "@Microsoft.PowerApps.CDS.TraceText": "\r\n[ILoggerExample: ILoggerExample.AccountPostOperation]\r\n[2ee952aa-90a4-eb11-b1ac-000d3a8f6891: ILoggerExample.AccountPostOperation: Create of account]\r\n\r\n\t\r\n\tStart execution of AccountPostOperation\r\n\tCallback\r\n\tStart Task Creation\r\n\tTask creation completed\r\n\tOutbound call started\r\n\tPlugin failed:An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.\r\n\t\r\n",
        "@Microsoft.PowerApps.CDS.InnerError.Message": "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."
    }
}

Le journal de suivi des plug-ins contient ces données d′exception, qui incluent les données ExceptionDetails.

Exception type: System.ServiceModel.FaultException`1[Microsoft.Xrm.Sdk.OrganizationServiceFault]
Message: An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.Detail: 
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
  <ActivityId>09bf305c-8272-4fc4-801b-479280cb3069</ActivityId>
  <ErrorCode>-2147220891</ErrorCode>
  <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
    <KeyValuePairOfstringanyType>
      <d2p1:key>OperationStatus</d2p1:key>
      <d2p1:value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:int">0</d2p1:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <d2p1:key>SubErrorCode</d2p1:key>
      <d2p1:value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:int">-2146233088</d2p1:value>
    </KeyValuePairOfstringanyType>
  </ErrorDetails>
  <HelpLink i:nil="true" />
  <Message>An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.</Message>
  <Timestamp>2021-04-24T18:24:46.4900727Z</Timestamp>
  <ExceptionRetriable>false</ExceptionRetriable>
  <ExceptionSource>PluginExecution</ExceptionSource>
  <InnerFault i:nil="true" />
  <OriginalException>PluginExecution</OriginalException>
  <TraceText>
Start execution of AccountPostOperation
Callback
Start Task Creation
Task creation completed
Outbound call started
Plugin failed:An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
</TraceText>
</OrganizationServiceFault>

Dans Application Insights, si vous affichez les suivis limités à cette requête et avec l′étendue définie sur OutboundCall comme indiqué précédemment, vous observez que la seule entrée indique que l′appel sortant a commencé.

Afficher les suivis limités à cette requête et avec l′étendue définie sur OutboundCall.

Dans Application Insights, si vous modifiez la requête pour utiliser exceptions plutôt que traces, 3 exceptions sont journalisées :

Basculer la requête pour utiliser des exceptions plutôt que des suivis.

L′exception indiquant que cloud_RoleInstance est égal à SandboxRoleInstance a été écrite à cause de la méthode LogError de l′interface ILogger. Les deux autres exceptions correspondent aux différents emplacements où l′erreur a été journalisée sur le serveur.

Notes

SandboxRoleInstance client_Type est PC. Cela s′explique par le fait que le plug-in s′exécute dans un bac à sable isolé en tant que client plutôt que sur le serveur.

Vous pouvez vous concentrer sur le journal des erreurs écrit par votre code en filtrant sur cloud_RoleInstance :

Se concentrer sur le journal des erreurs écrit par votre code en filtrant sur RoleInstance.

Le texte du message formaté est capturé dans customDimensions.

Voir aussi

Analyser les applications pilotées par modèle et la télémétrie Microsoft Dataverse avec Application Insights
Plug-ins
Déboguer un plug-in
Afficher les journaux de suivi
Service de traçage
Table PluginTraceLog

Notes

Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)

Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).