Collecter des informations détaillées sur le chargement d’assembly
À compter de .NET 5, le runtime peut émettre des événements via EventPipe
avec des informations détaillées sur le chargement d’assembly managé pour faciliter le diagnostic des problèmes de chargement d’assembly. Ces événements sont émis par le fournisseur Microsoft-Windows-DotNETRuntime
sous le mot clé AssemblyLoader
(0x4
).
Prérequis
- SDK .NET 5 ou versions ultérieures
- Outil
dotnet-trace
Notes
L’étendue des fonctionnalités dotnet-trace
est supérieure à la collecte d’informations détaillées sur le chargement d’assembly. Pour plus d’informations sur l’utilisation de dotnet-trace
, consultez dotnet-trace
.
Collecter une trace avec des événements de chargement d’assembly
Vous pouvez utiliser dotnet-trace
pour tracer un processus existant ou lancer un processus enfant et le tracer à partir du démarrage.
Suivre un processus existant
Pour activer le chargement des événements d’assembly dans le runtime et collecter une trace de ceux-ci, utilisez dotnet-trace
avec la commande suivante :
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id <pid>
Cette commande collecte une trace du fichier spécifié <pid>
, en activant les événements AssemblyLoader
dans le fournisseur Microsoft-Windows-DotNETRuntime
. Le résultat est un fichier .nettrace
.
Utiliser dotnet-trace pour lancer un processus enfant et le tracer à partir du démarrage
Parfois, il peut être utile de collecter la trace d’un processus à partir de son démarrage. Pour les applications exécutant .NET 5 ou versions ultérieures, vous pouvez utiliser dotnet-trace
.
La commande suivante lance hello.exe avec arg1
et arg2
en tant qu’arguments de ligne de commande et collecte une trace à partir du démarrage du runtime :
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 -- hello.exe arg1 arg2
Vous pouvez arrêter de collecter la trace en appuyant sur Entrée ou Ctrl + C. Cela ferme également hello.exe.
Notes
- Le lancement de hello.exe via
dotnet-trace
redirige ses entrées et sorties, et vous ne pourrez pas interagir avec sur la console par défaut. Utilisez le commutateur--show-child-io
pour interagir avecstdin
etstdout
. - Quitter l’outil via Ctrl+C ou
SIGTERM
mettre fin en toute sécurité à l’outil et au processus enfant. - Si le processus enfant se termine avant l’outil, l’outil se ferme également et la trace doit être visible en toute sécurité.
Afficher une trace
Le fichier de trace collecté peut être affiché sur Windows à l’aide de l’affichage Événements dans PerfView. Tous les événements de chargement d’assembly sont préfixés par Microsoft-Windows-DotNETRuntime/AssemblyLoader
.
Exemple (sur Windows)
Cet exemple utilise l’exemple de points d’extension de chargement d’assembly. L’application tente de charger un assembly MyLibrary
qui n’est pas référencé par l’application et nécessite donc d’être géré dans un point d’extension de chargement d’assembly pour être correctement chargé.
Collecter la trace
Accédez au répertoire avec l’exemple téléchargé. Générez l’application avec :
dotnet build
Lancez l’application avec des arguments indiquant qu’elle doit s’interrompre jusqu’à ce que vous appuyiez sur une touche. Lors de la reprise, il tente de charger l’assembly dans
AssemblyLoadContext
(par défaut). La gestion n’est pas nécessaire pour une charge réussie. Accédez au répertoire de sortie et exécutez :AssemblyLoading.exe /d default
Recherchez l’identifiant de processus de l’application.
dotnet-trace ps
La sortie répertorie les processus disponibles. Par exemple :
35832 AssemblyLoading C:\src\AssemblyLoading\bin\Debug\net5.0\AssemblyLoading.exe
Attachez
dotnet-trace
à l’application en cours d’exécution.dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4 --process-id 35832
Dans la fenêtre exécutant l’application, appuyez sur n’importe quelle touche pour permettre au programme de continuer. Le suivi s’arrête automatiquement une fois l’application terminée.
Afficher la trace
Ouvrez la trace collectée dans PerfView et ouvrez l’affichage Événements. Filtrez la liste des événements sur les événements Microsoft-Windows-DotNETRuntime/AssemblyLoader
.
Tous les chargements d’assembly qui se sont produits dans l’application après le suivi sont affichés. Pour inspecter l’opération de chargement de l’assembly d’intérêt pour cet exemple (MyLibrary
), nous pouvons effectuer un filtrage supplémentaire.
Chargements d’assemblys
Filtrez l’affichage sur les événements Start
et Stop
sous Microsoft-Windows-DotNETRuntime/AssemblyLoader
à l’aide de la liste des événements à gauche. Ajoutez les colonnes AssemblyName
, ActivityID
et Success
à l’affichage. Filtrez pour afficher les événements contenant MyLibrary
.
Nom de l'événement | AssemblyName | ActivityID | Succès |
---|---|---|---|
AssemblyLoader/Start |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | |
AssemblyLoader/Stop |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | False |
Vous devriez voir une paire Start
/Stop
avec Success=False
sur l’événement Stop
, indiquant que l’opération de chargement a échoué. Notez que les deux événements ont le même identifiant d’activité. L’identifiant d’activité peut être utilisé pour filtrer tous les autres événements de chargement d’assembly sur ceux correspondant à cette opération de chargement.
Décomposition de la tentative de chargement
Pour obtenir une décomposition plus détaillée de l’opération de chargement, filtrez l’affichage sur les événements ResolutionAttempted
sousMicrosoft-Windows-DotNETRuntime/AssemblyLoader
en utilisant la liste des événements à gauche. Ajoutez les colonnes AssemblyName
, Stage
et Result
à l’affichage. Filtrez les événements avec l’identifiant d’activité de la Start
/Stop
paire.
Nom de l'événement | AssemblyName | Étape | Résultats |
---|---|---|---|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
FindInLoadContext |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
ApplicationAssemblies |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AssemblyLoadContextResolvingEvent |
AssemblyNotFound |
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AppDomainAssemblyResolveEvent |
AssemblyNotFound |
Les événements ci-dessus indiquent que le chargement d’assembly a tenté de résoudre l’assembly en recherchant dans le contexte de chargement actuel, en exécutant la logique de détection par défaut pour les assemblys d’application managée, en appelant des gestionnaires pour l’événement AssemblyLoadContext.Resolving et en appelant des gestionnaires pour AppDomain.AssemblyResolve. Pour toutes ces étapes, l’assembly n’a pas été trouvé.
Points d’extension
Pour voir quels points d’extension ont été appelés, filtrez l’affichage sur AssemblyLoadContextResolvingHandlerInvoked
et AppDomainAssemblyResolveHandlerInvoked
sous Microsoft-Windows-DotNETRuntime/AssemblyLoader
à l’aide de la liste des événements à gauche. Ajoutez les colonnes AssemblyName
et HandlerName
à l’affichage. Filtrez les événements avec l’identifiant d’activité de la Start
/Stop
paire.
Nom de l'événement | AssemblyName | HandlerName |
---|---|---|
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAssemblyLoadContextResolving |
AssemblyLoader/AppDomainAssemblyResolveHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAppDomainAssemblyResolve |
Les événements ci-dessus indiquent qu’un gestionnaire nommé OnAssemblyLoadContextResolving
a été appelé pour l’événement AssemblyLoadContext.Resolving et qu’un gestionnaire nommé OnAppDomainAssemblyResolve
a été appelé pour l’événement AppDomain.AssemblyResolve.
Collecter une autre trace
Exécutez l’application avec des arguments de sorte que son gestionnaire pour l’événement AssemblyLoadContext.Resolving charge l’assembly MyLibrary
.
AssemblyLoading /d default alc-resolving
Collectez et ouvrez un autre fichier .nettrace
à l’aide des étapes de ci-dessus.
Filtrez à nouveau les événements Start
et Stop
pour MyLibrary
. Vous devriez voir une paire Start
/Stop
avec un autre Start
/Stop
au milieu. L’opération de charge interne représente la charge déclenchée par le gestionnaire pour le moment AssemblyLoadContext.Resolving lorsqu’il a appelé AssemblyLoadContext.LoadFromAssemblyPath. Cette fois, vous devez voir Success=True
sur l’événement Stop
, indiquant que l’opération de chargement a réussi. Le champ ResultAssemblyPath
affiche le chemin d’accès de l’assembly résultant.
Nom de l'événement | AssemblyName | ActivityID | Succès | ResultAssemblyPath |
---|---|---|---|---|
AssemblyLoader/Start |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | ||
AssemblyLoader/Start |
MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |
//1/2/1/ | ||
AssemblyLoader/Stop |
MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |
//1/2/1/ | True | C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
AssemblyLoader/Stop |
MyLibrary, Culture=neutral, PublicKeyToken=null |
//1/2/ | True | C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
Nous pouvons ensuite examiner les événements ResolutionAttempted
avec l’identifiant d’activité de la charge externe pour déterminer l’étape à laquelle l’assembly a été résolu avec succès. Cette fois, les événements montrent que l’étape AssemblyLoadContextResolvingEvent
a réussi. Le champ ResultAssemblyPath
affiche le chemin d’accès de l’assembly résultant.
Nom de l'événement | AssemblyName | Étape | Résultats | ResultAssemblyPath |
---|---|---|---|---|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
FindInLoadContext |
AssemblyNotFound |
|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
ApplicationAssemblies |
AssemblyNotFound |
|
AssemblyLoader/ResolutionAttempted |
MyLibrary, Culture=neutral, PublicKeyToken=null |
AssemblyLoadContextResolvingEvent |
Success |
C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
L’affichage des événements AssemblyLoadContextResolvingHandlerInvoked
montre que le gestionnaire nommé OnAssemblyLoadContextResolving
a été appelé. Le champ ResultAssemblyPath
affiche le chemin d’accès de l’assembly retourné par le gestionnaire.
Nom de l'événement | AssemblyName | HandlerName | ResultAssemblyPath |
---|---|---|---|
AssemblyLoader/AssemblyLoadContextResolvingHandlerInvoked |
MyLibrary, Culture=neutral, PublicKeyToken=null |
OnAssemblyLoadContextResolving |
C:\src\AssemblyLoading\bin\Debug\net5.0\MyLibrary.dll |
Notez qu’il n’existe plus d’événement ResolutionAttempted
avec l’étape AppDomainAssemblyResolveEvent
ou tout événement AppDomainAssemblyResolveHandlerInvoked
, car l’assembly a été correctement chargé avant d’atteindre l’étape de l’algorithme de chargement qui déclenche l’événement AppDomain.AssemblyResolve.