Ta boîte à outils : helpers shell, scripts et raccourcis
Le gain du jour : taper
gerr api-commandesau lieu d’une commande de quatre lignes, et partager ces raccourcis avec toute l’équipe dans le dépôt.
Un helper, c’est quoi ?
Un helper est un petit outil qui emballe une commande longue derrière un nom court. Tu le tapes cent fois par semaine, donc chaque seconde gagnée compte.
Les filtres de la leçon 3 sont puissants, mais longs à retaper. Le but ici n’est pas d’apprendre de nouvelles requêtes. C’est de ranger celles que tu connais déjà là où tu les retrouves en deux secondes.
On construit la boîte dans cet ordre : le shell, gcloud lui-même, un script Python, la console, l’éditeur, puis le partage en équipe.
1. Des fonctions shell
Une fonction shell est une commande que tu définis toi-même, avec des arguments. Elle marche à l’identique dans bash et dans zsh.
# tools/gcloud-helpers.sh : helpers de lecture des logs (lecture seule)
# Usage : export GCP_PROJECT=mon-projet-dev ; source tools/gcloud-helpers.sh
# Erreurs récentes d'un service Cloud Run : gerr api-commandes 30m
gerr() {
local service="$1" freshness="${2:-1h}"
[ -n "$service" ] || { echo "usage: gerr SERVICE [FRESHNESS]" >&2; return 1; }
gcloud logging read \
"resource.type=\"cloud_run_revision\" AND resource.labels.service_name=\"$service\" AND severity>=ERROR" \
--project="${GCP_PROJECT:?définis GCP_PROJECT}" \
--freshness="$freshness" --limit=50 \
--format='value(timestamp,severity,jsonPayload.message)'
}
# Toute une requête, dans l'ordre chronologique : gtrace 7c1e9a0f...
gtrace() {
local trace_id="$1"
[ -n "$trace_id" ] || { echo "usage: gtrace TRACE_ID" >&2; return 1; }
gcloud logging read \
"trace=\"projects/${GCP_PROJECT:?définis GCP_PROJECT}/traces/$trace_id\"" \
--project="$GCP_PROJECT" --freshness=7d --limit=200 --format=json \
| jq -r 'reverse | .[]
| "\(.timestamp) \(.severity // "DEFAULT") \(.jsonPayload.message // .textPayload // "")"'
}
# Ce qu'un utilisateur a déclenché : guser u-42 1d
guser() {
local user_id="$1" freshness="${2:-1d}"
[ -n "$user_id" ] || { echo "usage: guser USER_ID [FRESHNESS]" >&2; return 1; }
gcloud logging read "jsonPayload.userId=\"$user_id\"" \
--project="${GCP_PROJECT:?définis GCP_PROJECT}" \
--freshness="$freshness" --limit=100 --format=json \
| jq '.[] | {timestamp, severity, service: .resource.labels.service_name, message: .jsonPayload.message}'
}
Trois détails comptent :
${GCP_PROJECT:?...}arrête la fonction si la variable est vide. Pas de lecture silencieuse dans le mauvais projet.gtracelit en ordre décroissant puis inverse avecjq reverse. Pourquoi pas--order=asc? Parce que--freshnessne fonctionne qu’en ordredesc.--limitest toujours là. Un helper sans limite peut déverser des milliers de lignes.
Où ranger ce fichier ? Dans ton ~/.zshrc, il ne sert qu’à toi. Dans le dépôt
(tools/gcloud-helpers.sh), il est versionné, relu en code review, et toute
l’équipe a la même version. La seconde option gagne presque toujours.
2. Ce que gcloud fait déjà pour toi
Avant d’écrire un helper, vérifie que gcloud ne le fait pas déjà.
Les configurations nommées. Une par environnement, vues en
leçon 1. Deux variantes utiles
en plus : --configuration=prod vise une configuration pour une seule commande, et
la variable CLOUDSDK_ACTIVE_CONFIG_NAME fait de même pour tout un terminal.
Les valeurs par défaut. Chaque configuration garde ses propriétés. Une région fixée une fois t’évite de la retaper :
gcloud config set run/region europe-west1 # utilisée par gcloud run
gcloud config list # vérifie ce qui est actif
Le shell interactif. gcloud beta interactive (aussi en alpha) ouvre un
shell avec autocomplétion des commandes, des flags et des ressources. Il reste en
préversion : pratique pour découvrir une commande, pas pour un script.
Les pages d’aide thématiques. Deux pages valent le détour :
gcloud topic filters # la syntaxe de --filter (celle de gcloud, pas de Logging)
gcloud topic formats # tout ce que --format sait faire : value, table, json, csv
Le débogage de gcloud lui-même. Quand une commande échoue sans raison claire :
gcloud logging read 'severity>=ERROR' --limit=1 --verbosity=debug
gcloud logging read 'severity>=ERROR' --limit=1 --log-http
--verbosity accepte debug, info, warning (le défaut), error, critical
et none. --log-http écrit chaque requête et réponse HTTP sur stderr. Tu vois
alors l’API appelée, le projet visé, et le vrai message d’erreur.
gcloud masque les jetons OAuth dans cette sortie par défaut. Mais les réponses contiennent tes logs, donc parfois des données sensibles. Lis-la dans ton terminal, et ne la colle jamais telle quelle dans un ticket ou un chat. Si tu dois la partager, garde seulement l’URL appelée et le code d’erreur.
3. Un script Python pour résumer
Pour une vue d’ensemble (« quelles erreurs, combien de fois »), un petit script
avec google-cloud-logging fait mieux que le shell. Il utilise les ADC de ta
machine, comme en leçon 4.
"""Résumé des erreurs récentes, groupées par message (lecture seule)."""
import argparse
from collections import Counter
from datetime import datetime, timedelta, timezone
from google.cloud import logging
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--project", required=True)
parser.add_argument("--service", required=True)
parser.add_argument("--hours", type=int, default=1)
args = parser.parse_args()
since = datetime.now(timezone.utc) - timedelta(hours=args.hours)
filtre = "\n".join([
'resource.type="cloud_run_revision"',
f'resource.labels.service_name="{args.service}"',
"severity>=ERROR",
f'timestamp>="{since:%Y-%m-%dT%H:%M:%SZ}"',
])
client = logging.Client(project=args.project)
compteur: Counter[str] = Counter()
for entry in client.list_entries(
filter_=filtre, order_by=logging.DESCENDING, max_results=1000
):
payload = entry.payload
if isinstance(payload, dict):
message = payload.get("message", "(sans message)")
else:
message = str(payload)
compteur[message[:80]] += 1
print(f"{sum(compteur.values())} erreurs sur {args.hours} h pour {args.service}")
for message, nb in compteur.most_common(10):
print(f"{nb:>5} {message}")
if __name__ == "__main__":
main()
$ python3 tools/resume_erreurs.py --project=mon-projet-dev --service=api-commandes
57 erreurs sur 1 h pour api-commandes
50 stock service timeout after 5000ms
6 PaymentDeclined: card expired
1 KeyError: 'userId'
Ce qu’il faut savoir sur list_entries :
filter_prend le même langage de requête que le Logs Explorer. Le tiret bas évite le conflit avec la fonctionfilterde Python.- Sans
timestampdans le filtre, la bibliothèque ajoute d’elle-même une fenêtre de 24 heures. Ici, on fixe la nôtre. max_resultsjoue le rôle de--limit.entry.payloadest undictpour un log JSON et une chaîne pour un log texte.
4. Les raccourcis de la console
Le Logs Explorer a sa propre mémoire, dans la Query library :
- Recent : tes 10 000 dernières requêtes uniques sur 30 jours. Tu as lancé un bon filtre hier ? Il est là.
- Saved : tes requêtes nommées (64 caractères maximum), avec une description.
- Share with project : une requête sauvegardée devient visible par tout le projet. Les lecteurs peuvent la lancer, mais pas la modifier.
- Suggested et la bibliothèque prédéfinie : des requêtes toutes faites selon les produits que ton projet utilise.
Le lien de partage d’une requête est déjà décrit en leçon 3.
Cloud Shell est un terminal dans le navigateur, avec gcloud déjà installé et
connecté à ton compte. Ton dossier personnel garde 5 Go entre les sessions, ce qui
suffit pour y déposer gcloud-helpers.sh. Le quota par défaut est de 50 heures par
semaine, et le dossier est supprimé après 120 jours sans connexion.
5. Les raccourcis de l’éditeur
Cloud Code est l’extension Google pour VS Code et les IDE JetBrains. Dans VS Code, la commande Cloud Code: View Logs ouvre un Log Viewer. Tu choisis le type Cloud Run Logs, le service, une révision, et tu actives Streaming pour voir les lignes arriver. Il couvre aussi les logs Kubernetes. Pratique quand tu codes, mais le Logs Explorer reste plus riche pour une vraie enquête.
jq lit le JSON en terminal. Avec --format=json, gcloud rend une liste. Quatre
motifs suffisent pour démarrer :
jq '.[0]' # la première entrée, en entier
jq -r '.[] | .jsonPayload.message // .textPayload' # le message, JSON ou texte
jq '[.[] | select(.httpRequest.status >= 500)]' # garder les 5xx
jq 'length' # combien d'entrées
6. Partager avec l’équipe
Un Makefile à la racine du dépôt donne des noms connus de tous. Il réutilise le
fichier de helpers au lieu de copier les commandes.
GCP_PROJECT ?= mon-projet-dev
FRESHNESS ?= 1h
HELPERS := . tools/gcloud-helpers.sh
.PHONY: logs-errors logs-trace logs-summary
logs-errors: ## make logs-errors SERVICE=api-commandes
@GCP_PROJECT=$(GCP_PROJECT) bash -c '$(HELPERS) && gerr "$(SERVICE)" "$(FRESHNESS)"'
logs-trace: ## make logs-trace TRACE=7c1e9a0f...
@GCP_PROJECT=$(GCP_PROJECT) bash -c '$(HELPERS) && gtrace "$(TRACE)"'
logs-summary: ## make logs-summary SERVICE=api-commandes
python3 tools/resume_erreurs.py --project=$(GCP_PROJECT) --service=$(SERVICE)
Un nouveau venu tape make logs-errors SERVICE=api-commandes le premier jour, sans
rien installer d’autre que gcloud et jq. Si l’équipe préfère just, le principe est
le même : une recette par helper, dans un justfile versionné.
Les bonnes pratiques
- Un helper lit, il n’écrit pas. Aucun
delete,updateoudeploycaché derrière un nom court. Une commande qui modifie quelque chose se tape en entier. --projectexplicite dans tout script. La configuration active change d’un terminal à l’autre. Un script qui s’y fie finit par lire la prod en croyant lire la dev, ou l’inverse.- Aucun identifiant dans le dépôt. Pas de clé de compte de service, pas de jeton. En local, les helpers utilisent ton compte gcloud et les ADC. En CI, l’identité vient de la plateforme.
- Une limite partout.
--limitpour gcloud,max_resultsen Python.
Vérifie ta compréhension
Tu veux que gtrace affiche une requête dans l'ordre chronologique sur les 7 derniers jours. Pourquoi ne pas simplement ajouter --order=asc à côté de --freshness=7d ?
Le script resume_erreurs.py tourne en CI et lit parfois le mauvais projet. Quelle est la meilleure correction ?
À toi de jouer
Crée
tools/gcloud-helpers.shavecgerr,gtraceetguser, charge-le avecsource, puis lancegerr TON_SERVICE 30m.Fixe ta région par défaut avec
gcloud config set run/region, puis parcoursgcloud topic formats.Lance une commande qui échoue avec
—log-httpet repère l’URL appelée et le code d’erreur.Exécute
resume_erreurs.pysur un service et compare son top 3 avecgerr.Sauvegarde ta meilleure requête dans la Query library et active
Share with project.Ajoute les cibles
logs-errorsetlogs-summaryauMakefiledu dépôt, et fais-les relire en code review.
🗂 Fiche de référence associée : Google Cloud et Cloud Logging — antisèche.