Juin 2007
Introduction
Parfois, il n'y a pas de substitut pour voir ce qui passe par-dessus le fil. Cela est particulièrement vrai lorsque vous écrivez des logiciels qui utilisent des services Web tels que les API Google Data, où de nombreuses opérations impliquent l'envoi de requêtes HTTP. Lorsque toutes les autres solutions ont échoué, vous pouvez vérifier que votre programme fait bien ce que vous attendiez en affichant les octets réellement transmis et reçus. De nombreuses bibliothèques clientes pour les API Google Data disposent d'un mode de débogage qui affiche le trafic HTTP. Cela est particulièrement utile lorsque vous n'avez pas accès à un outil de détection de paquets tel que WireShark ou Fiddler.
Je ne peux pas compter le nombre de fois où j'aurais pu jurer que mon programme était correct, mais seulement après avoir inspecté une trace de paquet, qu'il y avait un caractère de nouvelle ligne supplémentaire ou un en-tête HTTP mal nommé. Programmer à l'aide d'un service Web sans regarder le trafic HTTP, c'est comme essayer de faire passer une aiguille, les yeux fermés.
Cependant, vous pouvez vous retrouver dans une situation où un outil de détection de paquets n'est pas disponible ou est inadéquat pour traiter des paquets chiffrés. Ne vous inquiétez pas : vous pouvez contourner cette limitation en exploitant certains mécanismes de journalisation en programme. En utilisant ces fonctionnalités de journalisation, vous pouvez voir une partie, voire la totalité, des données échangées, même pour des données HTTPS chiffrées ou du code d'exécution à distance.
Pour cet article, j'ai rédigé des exemples de code de diagnostic en trois langages à l'aide des bibliothèques clientes de l'API Google Data pour Java, .NET et Python. Dans chaque exemple, j'active la journalisation ou le débogage, je m'authentifie à l'aide de la connexion client, puis j'obtiens une liste de mes feuilles de calcul Google et j'imprime leurs titres.
Java
Vous pouvez utiliser les classes java.util.logging
pour définir les niveaux de journalisation (et donc exposer les données de trafic) pour quelques objets clés de la bibliothèque cliente. Dans l'exemple ci-dessous, j'ai choisi d'examiner les en-têtes HTTP et les activités de l'analyseur XML pour obtenir une vue complète de ce qui transite sur le réseau.
La bibliothèque cliente Java de Google comporte des classes distinctes pour gérer les requêtes HTTP et l'analyse XML. Je dois donc créer deux objets Logger, un pour chaque classe : com.google.gdata.client.http.HttpGDataRequest
gère le trafic HTTP, tandis que com.google.gdata.util.XmlParser
est responsable de l'analyse XML.
Les instances d'enregistreur enregistrent les activités pour HttpGDataRequest
et XmlParser
, et vous pouvez contrôler le niveau de détail de la sortie de chaque enregistreur. Pour cette démonstration, j'ai choisi d'afficher tous les événements produits par les objets HttpGDataRequest
et XmlParser
.
Une fois mes enregistreurs enregistrés et configurés, je dois leur indiquer ce qu'ils doivent faire lorsqu'ils reçoivent un événement de leurs classes. Pour l'instant, je veux écrire toutes les informations de journalisation dans la console. Je vais donc créer un ConsoleHandler
et l'ajouter aux deux enregistreurs.
Voici mon exemple de code:
import com.google.gdata.client.spreadsheet.*;
import com.google.gdata.data.spreadsheet.*;
import com.google.gdata.util.*;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.*;
public class PrintSpreadsheetsWithLogging {
public static void main(String [] args) throws AuthenticationException,
ServiceException, IOException {
// Configure the logging mechanisms.
Logger httpLogger = Logger.getLogger("com.google.gdata.client.http.HttpGDataRequest");
httpLogger.setLevel(Level.ALL);
Logger xmlLogger = Logger.getLogger("com.google.gdata.util.XmlParser");
xmlLogger.setLevel(Level.ALL);
// Create a log handler which prints all log events to the console.
ConsoleHandler logHandler = new ConsoleHandler();
logHandler.setLevel(Level.ALL);
httpLogger.addHandler(logHandler);
xmlLogger.addHandler (logHandler);
SpreadsheetService service = new SpreadsheetService("testing-loggingExampleApp-1");
service.setUserCredentials(email, password);
// Get a list of your spreadsheets.
URL metafeedUrl = new URL("http://spreadsheets.google.com/feeds/spreadsheets/private/full ");
SpreadsheetFeed feed = service.getFeed(metafeedUrl, SpreadsheetFeed.class);
// Print the title of each spreadsheet.
List spreadsheets = feed.getEntries();
for (int i = 0; i < spreadsheets.size(); i++) {
SpreadsheetEntry entry = (SpreadsheetEntry)spreadsheets.get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
}
}
Lorsque vous exécutez ce programme, un message semblable au suivant s'affiche dans la console (j'ai retiré certaines des sections les moins intéressantes):
Jun 7, 2007 10:24:50 AM ...HttpGDataRequest setPrivateHeader FINER: Authorization: <Not Logged> Jun 7, 2007 10:24:50 AM ...HttpGDataRequest setHeader FINER: User-Agent: ... ... Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute FINE: 200 OK Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute FINER: Date: Thu, 07 Jun 2007 17:25:24 GMT Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute FINER: null: HTTP/1.1 200 OK Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute FINER: Content-Type: application/atom+xml; charset=UTF-8 Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute FINER: Last-Modified: Thu, 07 Jun 2007 17:25:22 GMT ... Jun 7, 2007 10:25:20 AM ...XmlParser startElement FINE: Start element id Jun 7, 2007 10:25:20 AM ...XmlParser endElement FINE: End element id ... Jun 7, 2007 10:25:20 AM ...XmlParser startElement FINE: Start element title Jun 7, 2007 10:25:20 AM ...XmlParser startElement FINER: Attribute type='text' Jun 7, 2007 10:25:20 AM ...XmlParser endElement FINE: End element title ... Jun 7, 2007 10:25:20 AM ...XmlParser endElement FINE: End element entry ... Jun 7, 2007 10:25:20 AM ...XmlParser endElement FINE: End element feed
Ces journaux peuvent être assez volumineux. Par conséquent, nous vous conseillons de faire preuve de sélectivité pour définir les niveaux des enregistreurs. Vous pouvez également créer un objet FileHandler
au lieu d'un objet ConsoleHandler
afin de pouvoir stocker les données de journal pour une utilisation ultérieure.
Bien sûr, si Java n'est pas votre sac, vous pouvez essayer .NET.
.NET
Pour capturer le trafic HTTP dans la bibliothèque cliente .NET, vous pouvez remplacer la fabrique de requêtes par défaut du client par un GDataLoggingRequestFactory
.
Les requêtes HTTP de la bibliothèque .NET sont créées par le GDataRequestFactory
qui se trouve dans chaque objet Service. Les usines de requêtes normales n'effectuent aucune journalisation, mais la journalisation est intégrée à GDataLoggingRequestFactory
, qui est une sous-classe de GDataRequestFactory
. Vous pouvez spécifier le chemin d'accès complet du fichier journal en définissant CombinedFileName
.
Après avoir configuré votre fabrique de requêtes, vous devez la remplacer dans votre objet Service en définissant le RequestFactory
de l'objet de service.
Votre code peut se présenter comme suit:
using System;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Spreadsheets;
namespace LogginTest
{
class Program
{
static void Main(string[] args)
{
SpreadsheetsService service = new SpreadsheetsService("-exampleApp-1");
service.setUserCredentials(email, password);
Google.GData.Client.GDataLoggingRequestFactory factory = new GDataLoggingRequestFactory("wise", "SpreadsheetsLoggingTest");
factory.MethodOverride = true;
factory.CombinedLogFileName = "c:\\temp\\xmllog.log";
Console.WriteLine("Log file name:" + factory.CombinedLogFileName);
service.RequestFactory = factory;
SpreadsheetQuery query = new SpreadsheetQuery();
SpreadsheetFeed feed = service.Query(query);
Console.WriteLine("Your spreadsheets:");
foreach (SpreadsheetEntry entry in feed.Entries)
{
Console.WriteLine(entry.Title.Text);
}
Console.ReadKey();
}
}
}
Le fichier journal résultant contient les requêtes et réponses XML. Voici un exemple abrégé que j'ai formaté à l'aide de tidy.
<?xml version='1.0' encoding='utf-8'?> <feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'> <id> http://spreadsheets.google.com/feeds/spreadsheets/private/full</id> <updated>2007-06-07T22:05: 02.674Z</updated> <link rel='self' type='application/atom+xml' href='http://spreadsheets.google.com/feeds/spreadsheets/private/full'> </link> ... <entry> <updated>2007-03-28T17:28:57.250Z</updated> <category scheme=' http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#spreadsheet'> <title type='text'>events</title> <content type='text'>events</content> ... </entry> <entry> <updated>2007-05-25T22:11:08.200Z</updated> <category scheme=' http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#spreadsheet'> </category> <title type='text'>UnitTest</title> <content type='text'>UnitTest</content> ... </entry> ... </feed>
Mais vous préférez les langages de script, et vous préférez utiliser Python.
Python
Pour capturer le trafic HTTP dans la bibliothèque cliente Python, vous pouvez répercuter le trafic de l'en-tête HTTP vers la console en activant le mode de débogage dans le client HTTP. L'objet de service possède un membre de débogage que vous pouvez définir sur True.
Si vous définissez le débogage sur "true", l'option de débogage est définie dans l'objet HTTPRequest
sous-jacent contenu dans l'objet de service.
Voici un exemple qui renvoie les en-têtes HTTP envoyés par le serveur de feuilles de calcul lorsque vous demandez une liste de vos feuilles de calcul.
#!/usr/bin/python
import gdata.spreadsheet.service
client = gdata.spreadsheet.service.SpreadsheetsService()
client.debug = True
client.ClientLogin(email, password)
feed = client.GetSpreadsheetsFeed()
for entry in feed.entry:
print entry.title.text
Un message semblable au suivant s'affiche sur votre console:
reply: 'HTTP/1.1 200 OK\r\n' header: Content-Type: application/atom+xml; charset=UTF-8 header: Last-Modified: Thu, 07 Jun 2007 18:22:35 GMT header: Cache-Control: max-age=0, must-revalidate, private header: Transfer-Encoding: chunked ... header: Date: Thu, 07 Jun 2007 18:22:35 GMT header: Server: GFE/1.3
Lorsque vous effectuez des opérations supplémentaires, telles qu'une insertion ou une mise à jour, les données de requête correspondantes sont renvoyées à votre console.
Conclusion
Ce tutoriel rapide montre comment ajouter une fonctionnalité de journalisation de base dans un programme Java, .NET ou Python utilisant les bibliothèques clientes de l'API Google Data. Ces techniques peuvent être utiles si vous devez déboguer des places de marché HTTP, mais que vous n'avez pas accès à un outil de détection de paquets. Je n'ai effleuré la surface qu'avec ces exemples. La plupart des mécanismes de journalisation présents dans ces langages sont bien plus puissants que ceux présentés ici. Si vous souhaitez en savoir plus sur la journalisation ou les API Google Data, consultez la liste des ressources ci-dessous.
Les bibliothèques clientes abordées dans cet article sont disponibles sur les pages suivantes:
Éléments de la base de connaissances associée:
- Comment obtenir des informations de journalisation HTTP dans la bibliothèque cliente Java ?
- Comment obtenir des informations de journalisation HTTP dans la bibliothèque cliente .NET ?
- Quels sont les bons outils pour le débogage HTTP ?
- Qu'est-ce que l'API Google Sheets ?
Groupes de discussion: nous avons beaucoup d'API et d'autres seront bientôt déployées, car d'autres API Google Data seront déployées. Nous surveillons activement les groupes.
Si vous avez des questions ou des suggestions, n'hésitez pas à nous contacter. Rejoignez le groupe de discussion et commencez à publier des posts.