Pourquoi un tableau de bord ?
Vous n’avez pas besoin de tableau de bord pour utiliser CloudPeek : les préréglages et les widgets IA fonctionnent sans. Un tableau de bord en vaut la peine quand vous voulez choisir exactement quelles métriques surveiller : vos propres métriques personnalisées, des ressources particulières, des calculs de métriques, des seuils ou les alarmes de votre choix. Trouver le bon espace de noms et les bonnes dimensions, écrire des calculs de métriques et définir des seuils est bien plus simple avec un clavier et un grand écran, et CloudWatch dispose déjà de l’outil pour cela.
Un tableau de bord CloudWatch devient alors tout simplement votre liste de ce qu’il faut surveiller :
- Chaque widget est un élément que vous pouvez épingler. Un widget regroupe une ou plusieurs métriques : le CPU de trois instances sur un graphique linéaire, vos cinq plus gros coûts sur un graphique à barres, un taux d’erreur calculé à partir de deux métriques dans un nombre.
- Chaque tableau de bord est un ensemble de widgets qui vont ensemble. Un par service, un pour les dépenses, un pour l’astreinte. Vous pouvez épingler depuis autant de tableaux de bord et de comptes que vous le souhaitez.
- Un tableau de bord n’est que du JSON : il peut donc être défini dans CloudFormation, Terraform, l’AWS CDK ou tout autre outil capable d’écrire une chaîne de caractères, et déployé avec les services qu’il surveille.
Vous avez déjà des tableaux de bord ? Épinglez directement à partir de ceux-ci. Ou créez-en un petit uniquement pour votre téléphone, avec seulement les widgets que vous voulez voir en un coup d’œil.
Le concevoir dans la console AWS
- Ouvrez la console CloudWatch, choisissez Tableaux de bord › Créer un tableau de bord et nommez-le.
- Choisissez un type de widget : Ligne, Aires empilées, Nombre, Jauge, Barres, Secteurs, Tableau, Texte ou État des alarmes. Ils fonctionnent tous dans CloudPeek (consultez la référence des widgets).
- Dans l’onglet Parcourir, choisissez un espace de noms, comme ApplicationELB ou l’un des vôtres, puis cochez les métriques que vous voulez sur ce widget.
- Dans l’onglet Métriques représentées graphiquement, définissez la statistique, la période et le libellé de chaque métrique. Choisissez Ajouter une expression mathématique pour une expression comme un taux d’erreur, et décochez les entrées que vous ne voulez pas tracer.
- Dans l’onglet Options, ajoutez des annotations horizontales pour les seuils et définissez les limites de l’axe Y. Une jauge a besoin à la fois d’un minimum et d’un maximum.
- Choisissez Créer un widget, donnez-lui un titre court, puis enregistrez le tableau de bord avec Enregistrer.
Ouvrez le tableau de bord dans CloudPeek : chaque widget y est dessiné tel qu’il apparaîtra sur votre écran d’accueil. Épinglez ceux que vous voulez, ou ajoutez-les avec Créer un widget › Depuis un tableau de bord (voir Créer un widget).
Le rendre lisible sur un téléphone
Sur votre écran d’accueil, un widget ne mesure que quelques centimètres. Quelques habitudes le rendent bien plus lisible :
- Une question par widget. « L’API est-elle en bonne santé ? » se lit mieux avec un nombre pour le taux d’erreur et une jauge pour la latence qu’avec un seul graphique à huit lignes.
- Peu de séries par graphique. Sur les widgets moyens et grands, la légende liste jusqu’à quatre séries, puis « +N de plus ». Un petit widget n’a pas de légende du tout.
- Des titres courts. Sur iPhone et iPad, le widget en ligne de l’écran verrouillé garde environ 18 caractères du titre, et le widget circulaire environ 8.
- Choisissez la vue adaptée au coup d’œil. Un nombre avec
"sparkline": trueaffiche la dernière valeur et sa tendance ; une jauge la situe dans une plage que vous définissez ; un graphique à barres établit un classement. Voyez à quoi ressemble chaque type. - Définissez la plage qui vous intéresse. Le
startpropre à un widget remplace celui du tableau de bord, et sans l’un ni l’autre, CloudPeek affiche les 3 dernières heures. Chaque widget indique la période qu’il couvre. - Des libellés plutôt que des ID. Donnez un
labelaux métriques, pour que la légende affiche « Checkout API » plutôt que « app/checkout-api/50dc6c495c0c9188 ». Un libellé dynamique comme${PROP('Dim.ServiceName')}nomme chaque série d’après la valeur d’une dimension.
Exemple : un tableau de bord de santé d’une API
Trois widgets pour un Application Load Balancer : le taux d’erreur sous forme de nombre, la latence p99 sous forme de jauge, et les requêtes face aux erreurs sur un graphique linéaire. Dans CloudPeek, ils se présentent ainsi :
{
"start": "-PT3H",
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 6,
"height": 6,
"properties": {
"title": "5xx error rate",
"view": "singleValue",
"region": "us-east-1",
"period": 300,
"sparkline": true,
"metrics": [
[ { "expression": "100 * FILL(m2, 0) / m1", "label": "Errors (%)", "id": "e1" } ],
[ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "stat": "Sum", "id": "m1", "visible": false } ],
[ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "stat": "Sum", "id": "m2", "visible": false } ]
]
}
},
{
"type": "metric",
"x": 6,
"y": 0,
"width": 6,
"height": 6,
"properties": {
"title": "Latency p99",
"view": "gauge",
"region": "us-east-1",
"stat": "p99",
"period": 300,
"yAxis": { "left": { "min": 0, "max": 2 } },
"metrics": [
[ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "label": "p99 (s)" } ]
]
}
},
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"title": "Requests and errors",
"view": "timeSeries",
"region": "us-east-1",
"stat": "Sum",
"period": 300,
"metrics": [
[ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "label": "Requests" } ],
[ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "label": "5xx", "yAxis": "right", "color": "#d62728" } ]
]
}
}
]
}
- Taux d’erreur : l’expression
100 * FILL(m2, 0) / m1divise les réponses 5xx par les requêtes.FILLcompte une période sans erreur comme zéro au lieu de laisser un trou. Les deux entrées ont"visible": false, si bien que seul le taux est affiché. - Latence : une jauge prend le
minet lemaxde l’axe Y comme plage (de 0 à 2 secondes ici). Sans eux, CloudPeek suppose une plage de 0 à 100. - Requêtes et erreurs :
"yAxis": "right"donne au nombre de 5xx sa propre échelle, pour qu’une poignée d’erreurs ne soit pas écrasée par des milliers de requêtes."."reprend la valeur placée au même endroit sur la ligne précédente. - Remplacez
app/checkout-api/50dc6c495c0c9188par le nom de votre équilibreur de charge, tel qu’il figure dans son ARN aprèsloadbalancer/, ou laissez CloudFormation ou Terraform le renseigner, comme ci-dessous.
Le gérer en tant que code
Concevez un tableau de bord dans la console jusqu’à ce qu’il vous convienne, puis copiez son JSON depuis Actions › Afficher/modifier la source dans votre code d’infrastructure. Dès lors, il est relu, versionné et déployé avec les services qu’il surveille, et il est identique dans chaque compte et chaque région où vous le déployez.
Rien ne vous oblige à mettre vos tableaux de bord dans du code. Un tableau de bord que vous modifiez dans la console est tout aussi bien pris en compte par CloudPeek à sa prochaine actualisation.
Si un tableau de bord est géré par CloudFormation ou Terraform, considérez la console comme un brouillon : les modifications que vous y enregistrez sont écrasées au déploiement suivant. Essayez une idée dans la console, puis recopiez la source dans votre code (Actions › Afficher/modifier la source).
Conservez le JSON dans votre gestionnaire de versions et déployez-le avec put-dashboard. Pour partir d’un tableau de bord conçu dans la console :
aws cloudwatch get-dashboard \
--dashboard-name Checkout-API \
--query DashboardBody --output text > api-health.json
aws cloudwatch put-dashboard \
--dashboard-name Checkout-API \
--dashboard-body file://api-health.json
put-dashboard remplace tout le tableau de bord, si bien que le fichier en est toujours la description complète.
Une ressource AWS::CloudWatch::Dashboard prend le JSON sous forme de chaîne. Enveloppez-le dans !Sub et vous pourrez y insérer des valeurs de la même pile, comme la dimension de l’équilibreur de charge, au lieu de coller des ID :
CheckoutApiDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: Checkout-API
DashboardBody: !Sub
- |
{
"start": "-PT3H",
"widgets": [
{
"type": "metric", "x": 0, "y": 0, "width": 6, "height": 6,
"properties": {
"title": "5xx error rate",
"view": "singleValue",
"region": "${AWS::Region}",
"period": 300,
"sparkline": true,
"metrics": [
[ { "expression": "100 * FILL(m2, 0) / m1", "label": "Errors (%)", "id": "e1" } ],
[ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "${Alb}", { "stat": "Sum", "id": "m1", "visible": false } ],
[ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "stat": "Sum", "id": "m2", "visible": false } ]
]
}
},
{
"type": "metric", "x": 6, "y": 0, "width": 6, "height": 6,
"properties": {
"title": "Latency p99",
"view": "gauge",
"region": "${AWS::Region}",
"stat": "p99",
"period": 300,
"yAxis": { "left": { "min": 0, "max": 2 } },
"metrics": [
[ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "${Alb}", { "label": "p99 (s)" } ]
]
}
},
{
"type": "metric", "x": 12, "y": 0, "width": 12, "height": 6,
"properties": {
"title": "Requests and errors",
"view": "timeSeries",
"region": "${AWS::Region}",
"stat": "Sum",
"period": 300,
"metrics": [
[ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "${Alb}", { "label": "Requests" } ],
[ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "label": "5xx", "yAxis": "right", "color": "#d62728" } ]
]
}
}
]
}
- Alb: !GetAtt LoadBalancer.LoadBalancerFullName
LoadBalancerest la ressourceAWS::ElasticLoadBalancingV2::LoadBalancerdu même modèle ; sonLoadBalancerFullNameest exactement la valeur qu’attend la dimensionLoadBalancerde CloudWatch.- Dans
!Sub, CloudFormation lit chaque${…}comme l’une de ses propres variables. Écrivez un libellé dynamique CloudWatch comme${LAST}sous la forme${!LAST}. - Les tableaux de bord sont globaux, mais chaque widget indique sa région.
${AWS::Region}reprend celle de la pile.
Une ressource aws_cloudwatch_dashboard prend le JSON sous forme de chaîne. Écrivez-le en HCL dans un jsonencode, et vous pourrez utiliser des références, des variables et des expressions for au lieu de coller des ID :
resource "aws_lb" "checkout" {
name = "checkout-api"
subnets = ["subnet-11111111", "subnet-22222222"]
}
locals {
alb = aws_lb.checkout.arn_suffix # the LoadBalancer dimension: app/checkout-api/…
region = "us-east-1" # where the load balancer is
}
resource "aws_cloudwatch_dashboard" "checkout_api" {
dashboard_name = "Checkout-API"
dashboard_body = jsonencode({
start = "-PT3H"
widgets = [
{
type = "metric", x = 0, y = 0, width = 6, height = 6
properties = {
title = "5xx error rate"
view = "singleValue"
region = local.region
period = 300
sparkline = true
metrics = [
[{ expression = "100 * FILL(m2, 0) / m1", label = "Errors (%)", id = "e1" }],
["AWS/ApplicationELB", "RequestCount", "LoadBalancer", local.alb, { stat = "Sum", id = "m1", visible = false }],
[".", "HTTPCode_Target_5XX_Count", ".", ".", { stat = "Sum", id = "m2", visible = false }],
]
}
},
{
type = "metric", x = 6, y = 0, width = 6, height = 6
properties = {
title = "Latency p99"
view = "gauge"
region = local.region
stat = "p99"
period = 300
yAxis = { left = { min = 0, max = 2 } }
metrics = [
["AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", local.alb, { label = "p99 (s)" }],
]
}
},
{
type = "metric", x = 12, y = 0, width = 12, height = 6
properties = {
title = "Requests and errors"
view = "timeSeries"
region = local.region
stat = "Sum"
period = 300
metrics = [
["AWS/ApplicationELB", "RequestCount", "LoadBalancer", local.alb, { label = "Requests" }],
[".", "HTTPCode_Target_5XX_Count", ".", ".", { label = "5xx", yAxis = "right", color = "#d62728" }],
]
}
},
]
})
}
- L’attribut
arn_suffixd’unaws_lbest exactement la valeur qu’attend la dimensionLoadBalancerde CloudWatch. - Terraform lit
${…}dans une chaîne comme une interpolation. Écrivez un libellé dynamique CloudWatch comme${LAST}sous la forme$${LAST}. - Vous préférez garder le JSON dans un fichier ?
dashboard_body = file("api-health.json")fonctionne aussi, outemplatefile()pour y insérer des valeurs. - Pour faire gérer par Terraform un tableau de bord créé dans la console, ajoutez un bloc
importavec son nom commeid, ou exécutezterraform import aws_cloudwatch_dashboard.checkout_api Checkout-API.
L’AWS CDK, Pulumi et d’autres outils fonctionnent de la même façon : tout ce qui peut définir le corps d’un tableau de bord peut définir ce qu’affiche CloudPeek.
Comment les modifications arrivent sur votre téléphone
- Chaque fois qu’un widget épinglé s’actualise depuis AWS, CloudPeek relit le tableau de bord : une modification enregistrée dans la console ou déployée depuis votre code apparaît donc à l’actualisation suivante. Pour la voir tout de suite, touchez le bouton d’actualisation du widget.
- Les widgets de CloudPeek suivent leur widget de tableau de bord quand vous le déplacez, le redimensionnez, le renommez ou modifiez ses métriques. Si CloudPeek ne parvient pas à savoir de quel widget il s’agissait, il continue d’afficher la dernière version trouvée.
- Un titre ou une région que vous lui avez donnés dans l’aperçu de Créer un widget, ainsi qu’un titre, une région ou une plage de temps choisis avec Modifier dans CloudPeek, sont conservés et appliqués à ce que contient le tableau de bord (voir Modifier un widget).
- Si vous supprimez ou renommez le tableau de bord, le widget conserve ses dernières données et affiche Tableau de bord supprimé.
- Ajouter à nouveau le même widget reconnecte les widgets de l’écran d’accueil qui l’affichaient (voir Ajouter à nouveau le même widget).