Important
À partir de la version 14.0.0 de l'agent Node.js, les clients d'Apollo Server n'ont plus besoin d'installer et d'utiliser @newrelic/apollo-server-plugin. L'instrumentation est automatiquement appliquée à chaque instance Apollo Server.
Consultez notre Guide de migration Apollo Server pour plus de détails.
Le plugin New Relic Apollo Server instrumente votre application Apollo Server pour donner une visibilité sur votre charge GraphQL . Cela vous aide à découvrir et à diagnostiquer la cause de votre requêteGraphQL lente. La version d'Apollo Server prise en charge est 2.14 ou ultérieure.
Le plug-in enregistre les temps globaux des requêtes et utilise le tracing distribué pour découvrir les problèmes d’itinéraire. Utilisez cette instrumentation pour voir si le problème provient de la résolution d'une donnée demandée ou d'un travail effectué sur d'autres services ou bases de données.
Compatibilité
Le plugin New Relic fonctionne avec les modules Apollo Server suivants :
@apollo/server@apollo/gateway@apollo/subgraphapollo-server(>= 2.14)apollo-server-expressapollo-server-hapiapollo-server-koaapollo-server-fastifyapollo-server-lambda
D'autres plugins peuvent fonctionner, en fonction de leur implémentation sous-jacente, mais ils n'ont pas été vérifiés.
Métriques
Deux nouvelles métriques ont été introduites pour comprendre le comportement de vos opérations GraphQL au sein et à travers les transactions. Lisez ce qui suit pour en savoir plus à ce sujet ou accédez directement à la section Visualisations pour voir quelques façons recommandées d’utiliser ces données.
Pour plus d’informations sur l’interrogation des métriques et la création de graphiques, consultez la section Ressources.
Métriques d'opération
/GraphQL/operation/ApolloServer/[operation-type]/[operation-name]/[deepest-unique-path]
Les métriques d’opération incluent le type d’opération, le nom de l’opération et le chemin le plus profond. Ces métriques représentent les durées des requêtes ou mutations individuelles. Utilisez-les pour comparer les performances en dehors du contexte des transactions individuelles, qui peuvent contenir plusieurs requêtes.
Type d'opération : indique si l'opération était une requête ou une mutation.
Nom de l'opération : le nom de l'opération lorsqu'il est fourni ou <anonymous>.
Chemin unique le plus profond : le chemin le plus profond inclus dans l'ensemble de sélection d'une requête où un seul champ a été sélectionné à chaque niveau. Étant donné que les noms d'opération peuvent être réutilisés, cela aide à mieux déterminer l'unicité d'une opération donnée. Consultez la description dans la section transactions pour plus de détails.
Métriques de résolution de champ
/GraphQL/resolve/ApolloServer/[parent-type].[field-name]
Les métriques de résolution capturent la durée passée à résoudre un élément particulier de données GraphQL demandées. Utilisez-les pour trouver des résolveurs spécifiques qui peuvent contribuer à ralentir les requêtes entrantes, pour distinguer les résolveurs de champs portant le même nom sur différents types, ou pour identifier le même résolveur appliqué à différents types.
Ceux-ci diffèrent légèrement dans leur nommage par rapport à leurs équivalents de segment et de span. Pour mieux visualiser les relations, le chemin complet vers un champ est représenté par des segments et des spans (par exemple, libraries.books.title). Pour comprendre la durée agrégée sur toutes les utilisations et transactions, ces métriques utilisent le nom du champ sans le chemin complet.
Métriques des champs et des arguments
/GraphQL/field/ApolloServer/[parent-type].[field-name] /GraphQL/arg/ApolloServer/[parent-type].[field-name]/[arg-name]
Les métriques de champ ne sont capturées que lorsque config.apollo_server.field_metrics est true. Contrairement aux métriques de résolution de champ, cela capture chaque fois qu'un champ ou un argument de résolveur est rencontré. Utilisez ces métriques pour déterminer si un champ dans un schéma GraphQL est toujours utilisé et peut être supprimé en toute sécurité.
Tous les champs et arguments qui ont été demandés au cours du dernier jour
FROM Metric SELECT count(newrelic.timeslice.value) where appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/{kind}/ApolloServer/{field}' where kind = 'arg' or kind = 'field' FACET kind, field limit max since 1 day agoVisualisations
Les requêtes suivantes utilisent ces métriques pour vous aider à comprendre le comportement de vos applications Apollo GraphQL.
Top 10 des opérations
Pour obtenir une liste des 10 opérations les plus lentes, utilisez la requête suivante à la demande ou dans un dashboard.
FROM Metric SELECT average(newrelic.timeslice.value) * 1000 WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{operation}' FACET operation LIMIT 10Le type de graphique à barres (Bar) offre une visualisation similaire à la vue d’ensemble de la transaction.
Un type de graphique tableau (Table) est également utile pour afficher une répartition des opérations. Utilisez le METRIC_FORMAT pour plus de flexibilité de tri et de visualisation. La requête suivante génère des colonnes pour le type d'opération, le nom de l'opération, le chemin le plus profond et AVG Duration (MS).
FROM Metric SELECT average(newrelic.timeslice.value) * 1000 as 'AVG Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{type}/{name}/{deepest-path}' FACET type, name, `deepest-path` LIMIT 20Temps d'opération moyen
Pour suivre la durée moyenne des opérations au fil du temps, utilisez une requête similaire avec TIMESERIES.
FROM Metric SELECT average(newrelic.timeslice.value) WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{operation}' TIMESERIES FACET operationAffichez ceci avec le type de graphique ligne (Line), qui vous permet de voir toutes les opérations ou d’en activer/désactiver individuellement.
Top 10 des résolveurs
Pour obtenir une liste des 10 résolveurs les plus lents, utilisez la requête suivante à la demande ou dans le cadre d'un dashboard.
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{type}.{field}' FACET field LIMIT 20Si vous souhaitez inclure le type parent :
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{field}' FACET field LIMIT 20Le type de graphique à barres (Bar) donne une visualisation similaire à la vue d’ensemble de la transaction. Le type de graphique Tableau (Table) est également utile pour afficher une répartition du champ et de la Average Duration (MS).
Temps moyen du résolveur
Pour suivre la durée moyenne au fil du temps pour les résolveurs, utilisez une requête similaire avec TIMESERIES.
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' TIMESERIES WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{field}' FACET fieldAffichez ceci avec le type de graphique ligne (Line), qui vous permet de voir tous les résolveurs ou de les activer/désactiver individuellement.
Ressources
Segments et spans
Les segments et les spans (lorsque le tracing distribué est activé) sont capturés pour les opérations GraphQL, la résolution de champ et le travail instrumenté supplémentaire qui se produit dans le cadre de la résolution de champ, comme l'exécution d'une requête dans une base de données.
Segments/spans d'opération
/GraphQL/operation/ApolloServer/[operation-type]/[operation-name]/[deepest-unique-path]
Les segments et spans d’opération incluent le type d’opération, le nom de l’opération et le chemin unique le plus profond. Ils représentent la durée individuelle et les attributs d'une invocation spécifique au sein d'une transaction ou trace.
Pour plus de détails sur les parties, voir la section transactions.
Attributs
Nom | Description | Défaut |
|---|---|---|
|
| Compris |
| Nom donné à l'opération ou | Compris |
| La requête GraphQL d'origine avec les arguments offusqués | Compris |
Pour exclure l'attribut de requête (ou tout attribut), ajoutez le nom de l'attribut à la liste d'exclusion attributes ou aux listes d'exclusion des attributs de segment et de span individuellement.
Pour plus d’informations sur l’inclusion et l’exclusion d’attributs, consultez la documentation sur les attributs.
Champ de résolution des segments/spans
/GraphQL/resolve/ApolloServer/[path]
Les segments et les spans résolus utilisent le chemin de résolution du champ individuel pour mieux se différencier au sein d'une trace ou d'une transaction donnée. Par exemple, le chemin libraries.books est utilisé au lieu de simplement books. Ils représentent la durée individuelle et les attributs d'un champ spécifique résolu dans le cadre de l'opération GraphQL.
Attributs
Nom | Description | Défaut |
|---|---|---|
| Nom du champ résolu | Compris |
| Type de retour ( | Compris |
| Type du parent de ce champ ( | Compris |
| Chemin de résolution complet du champ ( | Compris |
| Arg passé à la requête ou mutation GraphQL pour ce résolveur capturé sous forme de paires valeur clé | Exclu |
Pour capturer les attributs args, ajoutez graphql.field.args.* à la liste d'inclusion attributes ou aux listes d'inclusion des attributs de segment et de span individuellement.
Pour plus d’informations sur l’inclusion et l’exclusion d’attributs, consultez la documentation sur les attributs.
Transactions
query { libraries { books { title author { name } } }}post /query/<anonymous>/libraries.books
Les transactions sont capturées en tant que transactions web, associées au framework sous-jacent (Express, Koa, etc.), et nommées en fonction des opérations GraphQL exécutées.
L'agent utilise plusieurs détails pour regrouper les représentations uniques de requête dans un nom de transaction : la méthode HTTP, le type d'opération, le nom de l'opération et le chemin résolu le plus profond (le premier, s'il y en a plusieurs).
La représentation brute d’une transaction ressemble à ce qui suit : /WebTransaction/{framework-name}/POST//{operation-type}/{operation-name}/{deepest-unique-path}
Pour une utilisation d'Apollo Server avec Express, cela peut ressembler à : /WebTransaction/Expressjs/POST//query/<anonymous>/libraries.books
La transaction sur New Relic One s'affichera finalement de la manière suivante : post /query/<anonymous>/libraries.books.
Détails
Méthode HTTP
La méthode HTTP pour la requête web. Les requêtes peuvent arriver via GET ou POST, les faisant remonter de la même manière que les autres transactions web.
Type d'opération
Indique si l'opération était une requête ou une mutation.
Nom de l'opération
Le nom de l'opération lorsqu'il est fourni ou <anonymous>.
query { libraries } utiliserait le nom d'opération <anonymous> car aucun nom n'a été fourni.
Une requête nommée telle que query GetLibraries { libraries } utiliserait le nom d'opération GetLibraries.
Chemin unique le plus profond
Le chemin le plus profond inclus dans l'ensemble de sélection d'une requête où un seul champ a été sélectionné à chaque niveau. Étant donné que les noms d’opération peuvent être réutilisés, cela permet de déterminer plus précisément le caractère unique d’une opération donnée.
L'agent utilise le chemin unique le plus profond (au lieu du chemin le plus profond) pour éviter de prendre une décision de nommage arbitraire qui pourrait suggérer ou masquer des détails sur ce qui cause des lenteurs dans une application.
Pour la requête :
query { libraries { branch booksInStock { isbn title author } magazinesInStock { issue title } }}Le chemin unique le plus profond se résout en libraries car plusieurs champs sont sélectionnés au-delà de ce point. Tout résolveur exécuté au-delà de ce point peut contribuer aux caractéristiques de performance de la transaction.
Si la requête sélectionne un seul champ par résolveur, le chemin complet est utilisé car chaque ensemble de sélection est unique.
La requête :
query { libraries { booksInStock { title } }}Résultats dans le chemin unique le plus profond : libraries.booksInStock.title.
id et les champs __typename sont automatiquement exclus de la décision de dénomination.
Par exemple, une requête de sous-graphe fédéré :
query { libraries { branch __typename id }}Résultats dans le chemin unique le plus profond : libraries.branch.
Types d'union et fragments en ligne
Pour les types d'union qui utilisent des fragments en ligne, le nom de la transaction utilise les crochets < ... > pour indiquer le champ sélectionné sous-jacent lorsqu'un seul type de résultat est spécifié dans la requête.
Pour le schéma suivant :
union SearchResult = Book | Author
type Book { title: String!}
type Author { name: String!}
type Query { search(contains: String): [SearchResult!]}Et la requête suivante :
query example { search(contains: "author") { __typename ... on Author { name } }}Donne le nom de transaction suivant :
post /query/example/search<Author>.name
Cependant, si la requête renvoie à la fois Book et Author :
query example { search(contains: "author") { __typename ... on Author { name } ... on Book { title } }}Le nom de la transaction qui en résulte est :
post /query/example/search
Nommage en cas d'erreur
Les erreurs d'analyse ou de validation d'une requête GraphQL peuvent affecter le nommage de la transaction.
Erreurs de validation
Si une requête a été analysée mais a échoué lors de la validation, l'agent nomme la transaction en fonction de ce qui a été tenté. Par exemple, cela se produit lorsqu'un champ dans la requête GraphQL entrante n'existe pas.
Dans cette situation, l'agent utilise le document analysé pour indiquer chaque élément prévu, y compris le calcul du chemin prévu le plus profond.
Voici un exemple de requête pour un champ qui n'existe pas (doesnotexist) et ce à quoi cela ressemble dans NR One.
query GetBooksByLibrary { libraries { books { doesnotexist { name } } }}post /query/GetBooksByLibrary/libraries.books.doesnotexist.name
Erreurs d'analyse
Si une opération demandée ne peut pas être analysée, l'agent nomme la transaction à l'aide d'un caractère générique (*) à la place des éléments habituels de l'opération. Dans cette situation, la requête est invalide, et il n'y a aucun élément identifiable sur lequel s'appuyer.
Voici un exemple auquel il manque un } de fermeture qui ne peut pas être analysé et ce à quoi cela ressemble dans NR One.
query GetBooksByLibrary { libraries { books { title author { name } } }// missing closing }post /*
Dans ces situations, l'attribut query sur la span d'opération associée à l'erreur est le meilleur moyen d'identifier le responsable.
Requêtes par lots
Apollo Server prend en charge les requêtes par lots. Dans ces situations, plusieurs opérations en jeu affectent le nommage.
Pour mieux identifier les regroupements de transactions, l'agent agrège les noms d'opérations après un indicateur /batch supplémentaire. Ces noms peuvent être assez longs.
Voici un exemple de requête par lots et de ce à quoi cela ressemble dans NR One.
[ { query: query GetBookForLibrary { library(branch: "downtown") { books { title author { name } } } } }, { query: mutation { addThing(name: "added thing!") } }]post /batch/query/GetBookForLibrary/library.books/mutation/<anonymous>/addThing
Ici, vous voyez batch/ suivi de query/GetBookForLibrary/library.books et mutation/<anonymous>/addThing.