Escriba telemetría a su recurso Application Insights usando ILogger

Importante

Para utilizar esta capacidad, primero debe habilitar la función Application Insights de integración. Más información: Analice aplicaciones basadas en modelos y telemetría Microsoft Dataverse con Application Insights

Actualmente no hay soporte de ILogger dentro de una sesión de depuración/perfilado de complementos de la herramienta de registro de complementos o la extensión Power Platform Tools para Visual Studio.

Cuando habilita Application Insights para su organización, cualquier complemento escrito utilizando la interfaz ILogger proporcionada en el SDK para .NET escribirá telemetría en su recurso Application Insights.

La plataforma Dataverse captura los datos de Dataverse de telemetría de aplicaciones basadas en modelos y los exporta a su recurso de Application Insights. Habrá cierta latencia entre el momento en que se capturó y cuando esté disponible para usted en Application Insights. Debido a que Microsoft recopila esta telemetría, no es necesario que escriba ningún código para habilitarla.

Los datos de telemetría que provienen de complementos que utilizan la interfaz ILogger son diferentes de dos maneras:

  • Esta telemetría se escribe directamente en su recurso Application Insights y nunca se envía a Microsoft.
    • Habrá menos latencia al ver estos datos.
  • Debe actualizar su código de complemento para usar la interfaz ILogger.

El uso de ILogger proporciona datos de telemetría verdaderos y está diseñado para funcionar junto con los registros de seguimiento de complementos existentes escritos con la Interfaz de ITracingService. La siguiente tabla compara las capacidades:

Criterios ILogger para Application Insights ITracingService Trace para registros de seguimiento de complementos
Uso previsto Capture la telemetría a lo largo del tiempo para su análisis y depuración. Al desarrollar y depurar complementos
Cuánto tiempo se almacenan los datos De acuerdo a su período de retención de datos Application Insights, que es de 90 días por defecto 24 horas
Disponibles Solo para organizaciones que se hayan suscrito a la integración Application Insights. Disponible para cualquier organización cuando el seguimiento de complementos está habilitado.
Cantidad de datos Cada mensaje de registro puede pasar un valor de cadena. Solo se pueden escribir 10 kb de texto para cada ejecución de complemento. Cualquier otro se truncará.
Disponible en errores de runtime No Disponible en errores de cliente de aplicaciones controladas por modelos y como anotaciones en API web. Más información: Incluir más detalles con errores

Debería seguir utilizando el ITracingService.Trace para escribir en la tabla Registro de seguimiento de complementos cuando sea necesario. No todas las organizaciones habilitan Application Insights. Si su código de complemento utiliza la interfaz ILogger y la organización no tiene la integración Application Insights habilitada, no se escribirá nada. Por lo tanto, es importante seguir utilizando el método ITracingService Trace en sus complementos. Los registros de seguimiento de complementos siguen siendo una forma importante de capturar datos mientras se desarrollan y depuran complementos, pero nunca tuvieron la intención de proporcionar datos de telemetría. Más información: Complementos: seguimiento y registro

Debe usar ILogger porque proporciona telemetría sobre lo que sucede dentro de un complemento. Esta telemetría está integrada con el alcance más amplio de los datos capturados con la integración de Application Insights. La integración Application Insights le dirá cuándo se ejecuta un complemento, cuánto tiempo tarda en ejecutarse y si realiza solicitudes http externas, pero Microsoft no puede agregar ningún código de telemetría dentro de los complementos que escribe para extender el comportamiento de la plataforma.

Si es un ISV con un producto que incluye complementos, sus clientes que habilitan Application Insights agradecerán poder ver lo que está sucediendo dentro de sus complementos y estos datos pueden ayudarlo a respaldarlos si hay problemas. Pero los datos capturados con ILogger solo se enviarán al recurso del cliente suscrito. Solo podrá ver los datos capturados para sus propios entornos cuando tenga Application Insights habilitado.

Utilice ILogger

ILogger es una interfaz común para capturar información de registro. La implementación proporcionada con los ensamblados del SDK para .NET proporciona métodos comunes para respaldar el establecimiento de un alcance y diferentes niveles de registro. Actualmente no existe una configuración para controlar qué nivel de registros se escriben. Los niveles se pueden utilizar dentro de Application Insights para filtrar qué registros ver.

El siguiente es un ejemplo de un complemento que utiliza tanto ILogger como ITracingService.Trace.

Nota

Asegúrese de incluir using Microsoft.Xrm.Sdk.PluginTelemetry;. No use using Microsoft.Extensions.Logging;, de lo contrario la instancia de ILogger será nula.

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);
            }
        }
    }
}

Cuando este complemento se registra en un paso PostOperation para el Create de una entidad account, puede usar registros de Application Insights para ver la salida en unos minutos. Puede usar Lenguaje de consulta Kusto (KQL) para consultar los resultados.

Puede filtrar elementos para una sola operación utilizando el operation_ParentId que representa el identificador de solicitud del encabezado de respuesta.

Filtrar elementos para una sola operación mediante operation_ParentId.

La entrada de registro de seguimiento del complemento correspondiente se ve así:

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

La información establecida con el Método BeginScope no es visible en las filas devueltas en Application Insights. Estos datos se establecen dentro de los registros customDimensions agregados dentro de ese ámbito. Puede utilizar esta consulta para mostrar los registros dentro del alcance.

Esta consulta limita los resultados a los registros agregados durante el ámbito Callback

Esta consulta limita los resultados a los registros agregados durante el ámbito Callback.

Y esta consulta limita los resultados a los registros agregados durante el ámbito OutboundCall:

esta consulta limita los resultados a los registros agregados durante el ámbito OutboundCall.

Excepciones de registro

En la parte inferior del ejemplo de código del complemento anterior, el siguiente código usa LogError para registrar una excepción detectada y lanza un InvalidPluginExecutionException:

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

Con el código de complemento anterior, puede generar una excepción al pasar un valor no válido a los datos de configuración del registro de pasos. En este ejemplo, el valor es NOT_A_URL.

Causa un error al ingresar un valor de configuración no válido en el registro del paso del complemento.

Este valor anula el valor predeterminado (https://www.bing.com) y hará que la llamada saliente falle.

No hay nada de malo en la solicitud que un cliente puede enviar:

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"
}

Pero debido al registro incorrecto del paso del complemento, la respuesta devuelve el siguiente error con todos los detalles cuando se usa el encabezado Prefer: odata.include-annotations="*":

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."
    }
}

El registro de seguimiento del complemento contiene estos datos de excepción, que incluyen datos 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>

Dentro de Application Insights, si ve los seguimientos dentro del ámbito de esta solicitud y con el ámbito establecido en OutboundCall como se mostró anteriormente, puede ver que la única entrada es que comenzó la llamada saliente.

Ver seguimientos dentro del ámbito de esta solicitud y con el ámbito establecido en OutboundCall.

Dentro de Application Insights, cuando cambia su consulta para usar exceptions en vez de traces, verá tres excepciones registradas:

Cambie su consulta para usar excepciones en lugar de seguimientos.

En la que cloud_RoleInstance es igual a SandboxRoleInstance es la que fue escrita debido al método ILogger LogError. Los otros dos representan ubicaciones diferentes donde se registró el error en el servidor.

Nota

El SandboxRoleInstance client_Type es PC. Esto se debe a que el complemento se ejecuta en un entorno limitado aislado como cliente y no en el servidor.

Puede concentrarse en el registro de errores escrito por su código filtrando en el cloud_RoleInstance:

Puede concentrarse en el registro de errores escrito por su código filtrando en el cloud_RoleInstance.

El texto del mensaje formateado se captura como parte de customDimensions.

Consultar también

Analice aplicaciones basadas en modelos y telemetría Microsoft Dataverse con Application Insights
Complementos
Depurar un complemento
Ver registros de seguimiento
Servicio de seguimiento
Tabla PluginTraceLog

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).