Entrainement
Parcours d’apprentissage
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Ce navigateur n’est plus pris en charge.
Effectuez une mise à niveau vers Microsoft Edge pour tirer parti des dernières fonctionnalités, des mises à jour de sécurité et du support technique.
Cet article s’applique à : ✔️ .NET Core 3.1 et versions ultérieures ✔️ .NET Framework 4.5 et versions ultérieures
Le guide de prise en main vous a montré comment créer un EventSource minimal et collecter des événements dans un fichier de trace. Ce tutoriel explique plus en détail la création d’événements à l’aide de System.Diagnostics.Tracing.EventSource.
[EventSource(Name = "Demo")]
class DemoEventSource : EventSource
{
public static DemoEventSource Log { get; } = new DemoEventSource();
[Event(1)]
public void AppStarted(string message, int favoriteNumber) => WriteEvent(1, message, favoriteNumber);
}
La structure de base d’un EventSource dérivé est toujours la même. En particulier:
Log
, qui représente ce singleton.data
.<
ou >
. Bien que les méthodes définies par l’utilisateur ne puissent pas non plus contenir ces caractères, async
méthodes seront réécrites par le compilateur pour les contenir. Pour être sûr que ces méthodes générées ne deviennent pas des événements, marquez toutes les méthodes non-événement sur un EventSource avec le NonEventAttribute..
ou -
comme séparateur, tel que « MyCompany-Samples-Demo », ou le nom de l’assembly ou de l’espace de noms pour lequel EventSource fournit des événements. Il n’est pas recommandé d’inclure « EventSource » dans le cadre du nom public.Chaque événement a un niveau de détail et les abonnés aux événements activent souvent tous les événements d’un EventSource jusqu’à un certain niveau de détail. Les événements déclarent leur niveau de verbosité à l'aide de la propriété Level. Par exemple, dans cet EventSource ci-dessous, un abonné qui demande des événements de niveau Informational et inférieur ne journalisera pas l’événement Verbose DebugMessage.
[EventSource(Name = "MyCompany-Samples-Demo")]
class DemoEventSource : EventSource
{
public static DemoEventSource Log { get; } = new DemoEventSource();
[Event(1, Level = EventLevel.Informational)]
public void AppStarted(string message, int favoriteNumber) => WriteEvent(1, message, favoriteNumber);
[Event(2, Level = EventLevel.Verbose)]
public void DebugMessage(string message) => WriteEvent(2, message);
}
Si le niveau de détail d’un événement n’est pas spécifié dans EventAttribute, il est défini par défaut sur Informational.
Utilisez des niveaux inférieurs à Informational pour des avertissements ou des erreurs relativement rares. En cas de doute, respectez la valeur par défaut d’Informational et utilisez Verbose pour les événements qui se produisent plus fréquemment que 1 000 événements/s.
Certains systèmes de suivi d’événements prennent en charge les mots clés comme mécanisme de filtrage supplémentaire. Contrairement aux verbes qui catégorisent les événements par niveau de détail, les mots clés sont destinés à catégoriser les événements en fonction d’autres critères tels que des zones de fonctionnalité de code ou qui seraient utiles pour diagnostiquer certains problèmes. Les mots clés sont des indicateurs de bits nommés et chaque événement peut avoir n’importe quelle combinaison de mots clés qui lui sont appliqués. Par exemple, EventSource ci-dessous définit certains événements liés au traitement des demandes et à d’autres événements liés au démarrage. Si un développeur souhaitait analyser les performances du démarrage, il peut uniquement activer la journalisation des événements marqués avec le mot clé de démarrage.
[EventSource(Name = "Demo")]
class DemoEventSource : EventSource
{
public static DemoEventSource Log { get; } = new DemoEventSource();
[Event(1, Keywords = Keywords.Startup)]
public void AppStarted(string message, int favoriteNumber) => WriteEvent(1, message, favoriteNumber);
[Event(2, Keywords = Keywords.Requests)]
public void RequestStart(int requestId) => WriteEvent(2, requestId);
[Event(3, Keywords = Keywords.Requests)]
public void RequestStop(int requestId) => WriteEvent(3, requestId);
public class Keywords // This is a bitvector
{
public const EventKeywords Startup = (EventKeywords)0x0001;
public const EventKeywords Requests = (EventKeywords)0x0002;
}
}
Les mots clés doivent être définis à l’aide d’une classe imbriquée appelée Keywords
et chaque mot clé individuel est défini par un membre typé public const EventKeywords
.
Les mots clés sont plus importants lors de la distinction entre les événements à volume élevé. Cela permet à un consommateur d’événements d’augmenter le niveau de détail mais de gérer les performances et la taille du journal en n’activant que des sous-ensembles restreints d’événements. Les événements déclenchés plus de 1 000/s sont de bons candidats pour un mot-clé unique.
EventSource exige que tous les paramètres d’événement puissent être sérialisés afin qu’il accepte uniquement un ensemble limité de types. Voici les éléments suivants :
La classe EventSource a été conçue afin qu’elle ne lève jamais d’exception par défaut. Il s’agit d’une propriété utile, car la journalisation est souvent traitée comme facultative, et vous ne souhaitez généralement pas qu’une erreur écrive un message de journal pour provoquer l’échec de votre application. Toutefois, cela rend difficile la recherche d’une erreur dans votre EventSource. Voici plusieurs techniques qui peuvent vous aider à résoudre les problèmes suivants :
L’ETW a des concepts de Tâches et OpCodes, qui sont des mécanismes supplémentaires pour le balisage et le filtrage des événements. Vous pouvez associer des événements à des tâches et des opcodes spécifiques à l’aide des propriétés Task et Opcode. Voici un exemple :
[EventSource(Name = "Samples-EventSourceDemos-Customized")]
public sealed class CustomizedEventSource : EventSource
{
static public CustomizedEventSource Log { get; } = new CustomizedEventSource();
[Event(1, Task = Tasks.Request, Opcode=EventOpcode.Start)]
public void RequestStart(int RequestID, string Url)
{
WriteEvent(1, RequestID, Url);
}
[Event(2, Task = Tasks.Request, Opcode=EventOpcode.Info)]
public void RequestPhase(int RequestID, string PhaseName)
{
WriteEvent(2, RequestID, PhaseName);
}
[Event(3, Keywords = Keywords.Requests,
Task = Tasks.Request, Opcode=EventOpcode.Stop)]
public void RequestStop(int RequestID)
{
WriteEvent(3, RequestID);
}
public class Tasks
{
public const EventTask Request = (EventTask)0x1;
}
}
Vous pouvez créer implicitement des objets EventTask en déclarant deux méthodes d’événement avec des ID d’événement successifs qui suivent le modèle de nommage <EventName>Début et <EventName>Fin. Ces événements doivent être déclarés à la suite l'un de l'autre dans la définition de la classe et la méthode <EventName>Start doit venir en premier.
Ce concept est uniquement important lors de l’abonnement à EventSource à partir d’ETW. ETW a deux façons différentes de consigner les événements, le format manifeste et le format auto-décrivant (parfois appelé tracelogging). Les objets EventSource basés sur un manifeste génèrent et consignent un document XML représentant les événements définis sur la classe lors de l’initialisation. Cela nécessite que EventSource se reflète sur lui-même pour générer le fournisseur et les métadonnées d’événement. Les métadonnées au format auto-décrivant pour chaque événement sont transmises en ligne avec les données de l'événement plutôt que de manière anticipée. L’approche auto-décrivante prend en charge les méthodes Write plus flexibles qui peuvent envoyer des événements arbitraires sans avoir créé de méthode de journalisation d’événements prédéfinie. Il est également légèrement plus rapide au démarrage, car il évite de réfléchir avec impatience. Toutefois, les métadonnées supplémentaires émises avec chaque événement ajoutent une petite surcharge de performances, ce qui peut ne pas être souhaitable lors de l’envoi d’un volume élevé d’événements.
Pour utiliser le format d’événement auto-décrivant, construisez votre EventSource à l’aide du constructeur EventSource(String), du constructeur EventSource(String, EventSourceSettings) ou en définissant l’indicateur EtwSelfDescribingEventFormat sur EventSourceSettings.
Un type EventSource peut implémenter une interface afin d’intégrer en toute transparence dans différents systèmes de journalisation avancés qui utilisent des interfaces pour définir une cible de journalisation commune. Voici un exemple d’utilisation possible :
public interface IMyLogging
{
void Error(int errorCode, string msg);
void Warning(string msg);
}
[EventSource(Name = "Samples-EventSourceDemos-MyComponentLogging")]
public sealed class MyLoggingEventSource : EventSource, IMyLogging
{
public static MyLoggingEventSource Log { get; } = new MyLoggingEventSource();
[Event(1)]
public void Error(int errorCode, string msg)
{ WriteEvent(1, errorCode, msg); }
[Event(2)]
public void Warning(string msg)
{ WriteEvent(2, msg); }
}
Vous devez spécifier l’EventAttribute sur les méthodes d’interface, sinon (pour des raisons de compatibilité), la méthode ne sera pas traitée comme une méthode de journalisation. L’implémentation de méthode d’interface explicite n’est pas autorisée afin d’empêcher les collisions d’affectation de noms.
Dans la plupart des cas, vous pourrez écrire des types qui dérivent directement de la classe EventSource. Toutefois, il est parfois utile de définir des fonctionnalités qui seront partagées par plusieurs types EventSource dérivés, tels que les surcharges WriteEvent personnalisées (voir optimiser les performances pour les événements en volume élevé ci-dessous).
Les classes de base abstraites peuvent être utilisées tant qu’elles ne définissent pas de mots clés, de tâches, d’opcodes, de canaux ou d’événements. Voici un exemple où la classe UtilBaseEventSource définit une surcharge WriteEvent optimisée nécessaire par plusieurs EventSources dérivés dans le même composant. L’un de ces types dérivés est illustré ci-dessous sous la forme OptimizedEventSource.
public abstract class UtilBaseEventSource : EventSource
{
protected UtilBaseEventSource()
: base()
{ }
protected UtilBaseEventSource(bool throwOnEventWriteErrors)
: base(throwOnEventWriteErrors)
{ }
protected unsafe void WriteEvent(int eventId, int arg1, short arg2, long arg3)
{
if (IsEnabled())
{
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 2;
descrs[2].DataPointer = (IntPtr)(&arg3);
descrs[2].Size = 8;
WriteEventCore(eventId, 3, descrs);
}
}
}
[EventSource(Name = "OptimizedEventSource")]
public sealed class OptimizedEventSource : UtilBaseEventSource
{
public static OptimizedEventSource Log { get; } = new OptimizedEventSource();
[Event(1, Keywords = Keywords.Kwd1, Level = EventLevel.Informational,
Message = "LogElements called {0}/{1}/{2}.")]
public void LogElements(int n, short sh, long l)
{
WriteEvent(1, n, sh, l); // Calls UtilBaseEventSource.WriteEvent
}
#region Keywords / Tasks /Opcodes / Channels
public static class Keywords
{
public const EventKeywords Kwd1 = (EventKeywords)1;
}
#endregion
}
La classe EventSource a plusieurs surcharges pour WriteEvent, y compris un pour le nombre variable d’arguments. Quand aucune des autres surcharges ne correspond, la méthode params est appelée. Malheureusement, la surcharge des paramètres est relativement coûteuse. En particulier, il :
C’est probablement 10 à 20 fois plus cher que les types spécialisés. Cela n’a pas beaucoup d’importance pour les cas de volume faible, mais pour les événements de volume élevé, il peut être important. Il y a deux cas importants pour assurer que la surcharge de paramètres n’est pas utilisée :
Voici un exemple d’ajout d’une surcharge WriteEvent qui prend quatre arguments entiers
[NonEvent]
public unsafe void WriteEvent(int eventId, int arg1, int arg2,
int arg3, int arg4)
{
EventData* descrs = stackalloc EventProvider.EventData[4];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
descrs[2].DataPointer = (IntPtr)(&arg3);
descrs[2].Size = 4;
descrs[3].DataPointer = (IntPtr)(&arg4);
descrs[3].Size = 4;
WriteEventCore(eventId, 4, (IntPtr)descrs);
}
Commentaires sur .NET
.NET est un projet open source. Sélectionnez un lien pour fournir des commentaires :
Entrainement
Parcours d’apprentissage
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Documentation
Guide de journalisation avec EventSource
Bien démarrer avec EventSource - .NET
Tutoriel pour créer un EventSource de base et comprendre les concepts clés
Collecter et afficher les traces EventSource - .NET
Tutoriel pour la collecte et l’affichage des traces d’événements EventSource