.NET ou le SDK de traçage d'.NET Core

Le traçage avec Instana est automatique, mais si vous souhaitez bénéficier d'une visibilité encore plus grande sur du code personnalisé, une zone spécifique de l'application ou un composant interne, vous pouvez utiliser le SDK de traçage .NET ou .NET Core d' Instana.

Installation du kit SDK

Instana met à disposition le SDK pour .NET ou .NET Core sous forme de package NuGet sur le flux officiel de nuget.org. Recherchez Instana.Tracing.Core.Sdk pour le trouver et l'ajouter à votre projet.

Traçage de votre propre code

Les exemples suivants montrent comment ajouter des fonctions de traçage distribué à votre code.

Remarque : le SDK est en cours de développement; veillez donc à consulter cette page à chaque mise à jour afin de vous assurer que vous utilisez bien les API les plus récentes.

Création d'une étendue simple

Le moyen le plus simple de tracer un appel de méthode consiste à utiliser l'API CustomSpan.Create.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // your original code here
    }
}
 

Le code précédent crée un intervalle intermédiaire, représentant votre méthode et le temps passé à l'intérieur de celle-ci.

Si vous souhaitez créer une plage d'entrée ou de sortie au lieu d'utiliser une plage intermédiaire, vous pouvez utiliser des API de commodité (appelées CustomSpan.CreateEntry pour la plage d'entrée et CustomSpan.CreateExit pour la plage de sortie).

Création d'une étendue simple et capture d'exceptions

Si vous souhaitez annoter les segments créés avec les erreurs survenues lors du traitement du corps de la méthode, vous pouvez le faire manuellement en utilisant la méthode ` APICustomSpan.SetError ` comme suit :

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        try
        {
        // your original code here
        }
        catch(Exception e)
        {
            span.SetError(e.ToString());
        }
    }
}
 

Une approche plus simple et préférée consiste à utiliser les API CustomSpan.WrapAction ou CustomSpan.Wrap<T> à la place.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

Si le bloc de code que vous souhaitez encapsuler renvoie une valeur dont vous avez besoin pour la suite du traitement, utilisez plutôt la méthode ` APICustomSpan.Wrap<T> `.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return myBooleanValue;
            }, true);
    }
}
 

Vous savez maintenant comment créer des entrées, des sorties et des intermédiaires. Vous avez également appris à capturer des exceptions à l'aide des API SetError ou WrapAction (ou Wrap<T>).

Ajout de données dans vos étendues

Une étendue à elle seule se compose simplement d'une temporisation, d'une pile d'appels et d'un nom. Ce n'est pas si utile dans la plupart des scénarios. Vous devez donc ajouter des données à votre plage. Une étendue peut contenir des données (Data) et des balises (Tags), pour lesquelles la classe CustomSpan propose des API simples.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetData("username", userName);
        span.SetData("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

Les données sont transférées vers le backend d' Instana et peuvent être téléchargées depuis l'interface utilisateur de Instana en téléchargeant une trace. Cependant, les données présentées ici n'apparaissent pas dans l'interface utilisateur d' Instana.

Ajout de balises dans vos étendues

Au lieu d'utiliser SetData, vous pouvez également utiliser SetTag, qui prend un tableau de chaînes comme clé, qui peut être utilisé pour structurer les données que vous transmettez à l'étendue en tant que hiérarchie.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetTag("username", userName);
        span.SetTag("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

Les balises sont affichées directement dans la vue Détails de l'appel et peuvent également être recherchées dans l'analyse sans limite.

Mappage de vos étendues personnalisées à un service

En général, vous souhaitez associer vos intervalles personnalisés à un service logique dans les perspectives d'application d' Instana, ce qui est aussi simple que d'appeler la SetServicename méthode ` API ` (qui ne prend qu'une chaîne de caractères). Pour distinguer les points de terminaison implémentés à l'aide du SDK, vous pouvez également fournir un point de terminaison permettant un mappage plus détaillé via l'interface SetEndpointNameAPI.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetServiceName("AwesomeSDKService");
        span.SetEndpointName("TracingEndpoint");
        .
        .
        .
    }
}
 

Vous pouvez définir un service et un noeud final sur chaque plage, mais ces paramètres sont supprimés dans les plages INTERMEDIATE (ils sont hérités du dernier ENTRYprécédent).

Enregistrer les résultats de votre intervalle

La méthode que vous instrumentez renvoie une valeur. Vous pouvez supposer que le fait d'avoir cette valeur dans votre trace aide à l'identification et à la résolution des problèmes. Entrez la méthode d'API SetResult.

public bool MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return resultingBoolean;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

Imbrication d'étendues

Imbriquer les étendues est aussi simple que d'appeler une méthode à partir d'une autre. Par exemple, vous pouvez supposer qu'une méthode sert d'entrée, alors que son étendue enfant est un intermédiaire.

public bool MyTracedEntryMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.CreateEntry())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                List<string> data = this.GetSomeDataFromSomewhere();
                // do some heavy processing
                return theResultICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}


private List<string> GetSomeDataFromSomewhere()
{
    using(var span = CustomSpan.Create())
    {
        List<string> result = span.WrapAction(
            ()=>{
                // read data from somewhere...
                return theListICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

Le résultat de cette plage est une plage d'entrée avec une plage intermédiaire comme enfant. Techniquement, l'imbrication n'a pas de limites sur la profondeur, mais vous ne devez pas créer d'étendues dans une récursivité profonde.

Analyse de la traçabilité distributed distribuée

Tous les services dont il a été question jusqu'à présent étaient limités à un seul service. Ils n'ont jamais contacté un autre composant, qui a également tracé son activité. Pour obtenir une véritable trace distribuée dans les limites du service, vous devez établir des corrélations.

La fonction de corrélation dans le traçage décrit comment définir les données de corrélation dans un appel d'exit et comment récupérer ces données et poursuivre ce contexte sur l'entrée de l'autre composant.

Pour obtenir cette corrélation, CustomSpan comporte des surcharges des méthodes CustomSpan.CreateExit et CustomSpan.CreateEntry .

Alors que la méthode CustomSpan.CreateExit peut utiliser Action<string, string> comme argument, CustomSpan.CreateEntry prend Func<DistributedTraceInformation>.

Par exemple, supposons que vous ayez une Message classe que vous transmettez au service distant que vous appelez.

    public class Message
    {
        public Message()
        {
            this.Tags = new Dictionary<string, string>();
        }
        public Dictionary<string, string> Tags { get; private set; }
        public int Payload { get; set; }

        public void AddTag(string tagName, string tagValue)
        {
            this.Tags.Add(tagName, tagValue);
        }
    }
 

La partie appropriée du message est la méthode AddTag , qui prend deux chaînes. Cette méthode est la signature que vous devez fournir à CustomSpan.CreateExit.

En utilisant cette méthode lorsque vous appelez CreateExit, vous écrivez les données de corrélation dans l'instance de Message.

public void MyLocalEntryMethod()
{
    // this methd will create an entry span and then call our method
    // that communicates with the remote-service (and thus create our exit span)
    using(var span = CustomSpan.CreateEntry())
    {
        span.WrapAction(()=>{
            CallRemoteService();
        })
    }
}

public void CallRemoteService()
{
    Message message = new Message();
    using(var exitSpan = CustomSpan.CreateExit(this, message.AddTag))
    {
        exitSpan.WrapAction( ()=>{
            var service = new RemoteService();
            service.ValidateRequest(message);
        }
    }
}
 

Ainsi, lorsque votre message quitte la portée de votre composant local avec un appel à service.ValidateRequest(message), le message transporte les données de corrélation dans sa liste de balises. Vous pouvez voir comment ces balises sont extraites sur le site de l'appelé.

public void ValidateRequest(Message message)
{
    using(var span = CustomSpan.CreateEntry(this, ()=>ExtractCorrelationData(message))
    {
        // do whatever this method is supposed to do, we only care for extraction
        // if the correlation-data anyway :-)
    }
}

private DistributedTraceInformation ExtractCorrelationData(Message message)
{
    var dti = new DistributedTraceInformation();
    dti.ParentSpanId = Convert.ToInt64(message.Tags[TracingConstants.ExternalParentSpanIdHeader], 16);
    dti.TraceId = Convert.ToInt64(message.Tags[TracingConstants.ExternalTraceIdHeader], 16);
    return dti;
}
 

La partie appropriée du message est ExtractCorrelationData. Comme vous avez utilisé la méthode Message.AddTag lors de la création de l'exit, le SDK écrit l'ID approprié (parent-span-id et trace-id) dans la liste des balises du message avant que le SDK ne l'envoie au service.

Le service peut maintenant extraire à nouveau ces valeurs en lisant les balises (vous pouvez les identifier à l'aide des constantes utilisées comme clés dans le code précédent). L'instance de DistributedTraceInformationque vous créez est ensuite utilisée par le SDK pour ajouter l'exit nouvellement créé à la trace existante. La plage d'entrée que vous créez est donc l'équivalent de l'exit sur le service local.

Division des traces

Vous pouvez trouver des exemples où le traçage automatisé fait trop de choses et où la trace créée est trop longue pour être compréhensible. Par exemple, de telles instances peuvent se produire dans une communication WCF en duplex long lorsque le serveur envoie des mises à jour aux clients via un rappel sur la progression d'une tâche d'arrière-plan à exécution longue. Cette communication génère une longue trace qui risque d'être trop longue pour être affichée dans l'interface utilisateur d' Instana.

Dans de tels cas, vous pouvez fractionner la trace en plusieurs traces. Plus spécifiquement, vous pouvez fractionner chaque rappel au client en une trace distincte. Pour utiliser cette option, vous pouvez utiliser CreateEntryForNewTrace à partir de CustomSpan pour arrêter la trace en cours et en créer une nouvelle à partir de ce point. Vous pouvez effectuer cette opération côté serveur, juste avant l'appel au client:

var callbackChanell = OperationContext.Current.GetCallbackChannel<IMathResult>();
if (callbackChanell != null)
{
    using (var span = CustomSpan.CreateEntryForNewTrace(this))
    {
        callbackChanell.SendStatusUpdate(new MathArguments() { InParam = args.InParam, Progress = (float)i / args.InParam, Result = generator.Next(1000, 9999) });
    }
}
 

SDK déclaratif utilisant les attributs d'.NET

Le SDK déclaratif d' Instana permet la traçabilité distribuée automatique dans les applications d'.NET Core, grâce à une approche basée sur les attributs. En décorant les méthodes avec [InstanaTrace] l'attribut, vous pouvez générer des traces sans avoir à écrire de code de traçage explicite.

Le SDK prend en charge les fonctionnalités suivantes :

  • Types de segments configurables (ENTRY, INTERMEDIATE, EXIT)
  • Noms de balises de portée personnalisés
  • Capture automatique des arguments de méthode et des valeurs de retour
  • Étiquettes personnalisées
  • Masquage intégré des données sensibles

L'instrumentation est appliquée de manière transparente lors de l'exécution par le biais d'une réécriture, ce qui nécessite uniquement l'activation de la variable d'environnement INSTANA_NET_ATTR_SDK_TRACING. Cette approche déclarative élimine le besoin d'un codage intensif tout en offrant un contrôle précis sur le comportement de traçage, rendant ainsi l'observabilité distribuée accessible sans nécessiter d'expertise approfondie en matière de traçage.

Fonctionnement

Les étapes suivantes décrivent le fonctionnement du SDK déclaratif :

  1. Ajoutez l'attribut - Ajoutez l'attribut à votre méthode [InstanaTrace] et configurez les options de traçage.
  2. Détection automatique - Le profileur « Instana » détecte l'attribut lors de l'exécution.
  3. Injection de bytecode - Du code de traçage est automatiquement inséré autour de votre méthode.
  4. Création de span - Instana gère automatiquement la création de span, la collecte de données et la propagation du contexte.

Aucun fichier de configuration ni aucune configuration manuelle n'est nécessaire. Ajoutez l'attribut et le traçage fonctionne.

Remarque : pour activer le traçage basé sur les attributs, définissez la variable d'environnement INSTANA_NET_ATTR_SDK_TRACING=true.

Les exemples suivants montrent comment utiliser des attributs pour générer des segments d'entrée et de sortie dans votre code.

Portée de base

[InstanaTrace(SpanKind = SpanKind.ENTRY, SpanName = "ProcessOrder")]
public string ProcessOrder(int orderId)
{
    return "Order processed";
}
 

Le code suivant est généré pour la méthode :

{
    "sdk.type": "ENTRY",
    "sdk.name": "ProcessOrder",
    "custom.args.orderId": "12345",
    "custom.result": "Order processed"
}
 

Portée de sortie avec informations sur le service

Exit permet de suivre les appels sortants vers des services externes, des bases de données ou des API. Ils collectent des informations sur les services et permettent un traçage distribué au-delà des limites du système.

[InstanaTrace(
    SpanKind = SpanKind.EXIT,
    ServiceName = "UserService",
    EndpointName = "/api/users/fetch")]
public User GetUser(string userId)
{
    return new User { Id = userId };
}
 

Protection des données sensibles

Le SDK protège automatiquement les données sensibles en masquant les paramètres de méthode et les valeurs de retour qui contiennent des mots-clés courants liés à la sécurité. Les paramètres dont le nom correspond à password, secret, token, apikey api_key,, ou credentials (sans distinction de majuscules/minuscules) sont automatiquement remplacés par ***REDACTED*** dans les données de portée capturées. Cela permet d'éviter toute divulgation accidentelle d'informations sensibles dans les traces.

[InstanaTrace]
public bool Authenticate(string username, string password)
{
    return true;
}
 
{
    "custom.args.username": "john_doe",
    "custom.args.password": "[REDACTED]"
}
 

Traitement des incidents

Si vous rencontrez des problèmes avec le SDK déclaratif, vérifiez les points suivants :

  1. Vérifiez que la variable d'environnement INSTANA_NET_ATTR_SDK_TRACING est définie sur true.
  2. Assurez-vous que le profileur Instana est correctement associé à votre application.
  3. Vérifiez que votre projet fait référence à la fois au SDK et aux paquets profiler/rewriter.

Si aucune portée n'est détectée, procédez aux vérifications suivantes :

  1. Vérifiez que la méthode instrumentée est bien appelée pendant l'exécution de l'application.
  2. Consultez les journaux du profileur pour vérifier que la réécriture s'effectue correctement.
  3. Assurez-vous que les données de trace sont correctement transmises au backend Instana.

Si vous avez des questions concernant le SDK « .NET » ou « .NET Core », veuillez contacter le service d'assistance de IBM.