Juin 2007
Introduction
Parfois, rien ne remplace le fait de voir ce qui est transmis. Cela est particulièrement vrai lors de l'écriture de logiciels qui utilisent des services Web tels que les API Google Data, où de nombreuses opérations impliquent l'envoi de requêtes HTTP. En dernier recours, vous pouvez vérifier que votre programme fait ce que vous attendez en examinant les octets réellement transmis et reçus. De nombreuses bibliothèques clientes pour les API Google Data disposent d'un mode débogage qui affiche le trafic HTTP. Cela est particulièrement utile lorsque vous n'avez pas accès à un renifleur de paquets comme WireShark ou Fiddler.
Je ne peux pas compter le nombre de fois où j'ai juré que mon programme était correct, pour ensuite découvrir, en inspectant 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 un service Web sans examiner le trafic HTTP, c'est un peu comme essayer d'enfiler une aiguille les yeux fermés.
Toutefois, il peut arriver qu'un renifleur de paquets ne soit pas disponible ou ne soit pas adapté aux paquets chiffrés. Ne vous inquiétez pas, vous pouvez contourner cette limitation en utilisant certains mécanismes de journalisation dans le programme. En utilisant ces fonctionnalités de journalisation, vous pouvez voir une partie ou la totalité des données échangées, même pour les données HTTPS chiffrées ou le code exécuté à distance.
Pour cet article, j'ai écrit un exemple de code de diagnostic en trois langues à 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 la 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 Google Data 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 de journalisation 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 créé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 souhaite écrire toutes les informations de journalisation dans la console. Je crée donc un ConsoleHandler
et l'ajoute à mes 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 résultat semblable à celui-ci s'affiche dans la console (j'ai supprimé certaines parties 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 devenir assez volumineux. Vous pouvez donc être plus sélectif lorsque vous définissez les niveaux des enregistreurs. Vous pouvez également créer un FileHandler
au lieu d'un ConsoleHandler
pour stocker les données de journaux et les utiliser ultérieurement.
Bien sûr, si Java ne vous convient pas, 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 dans le client par un GDataLoggingRequestFactory
.
Les requêtes HTTP de la bibliothèque .NET sont créées par GDataRequestFactory
, qui se trouve dans chaque objet Service. Les fabriques de requêtes normales n'effectuent aucune journalisation, mais GDataLoggingRequestFactory
, qui est une sous-classe de GDataRequestFactory
, intègre la journalisation. 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 remplacer la fabrique de requêtes dans votre objet Service en définissant le RequestFactory
de l'objet 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 obtenu contient les requêtes et les réponses XML. Voici un exemple abrégé que j'ai mis en forme à 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 peut-être êtes-vous un passionné de langages de script et préférez-vous utiliser Python.
Python
Pour capturer le trafic HTTP dans la bibliothèque cliente Python, vous pouvez afficher le trafic d'en-tête HTTP dans la console en activant le mode débogage dans le client HTTP. L'objet de service comporte un membre de débogage que vous pouvez définir sur True.
Définir le débogage sur "true" définira l'indicateur de débogage dans l'objet HTTPRequest
sous-jacent contenu dans l'objet de service.
Voici un exemple qui renverra les en-têtes HTTP envoyés par le serveur de feuilles de calcul lorsque vous demandez la 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
La console affichera un résultat semblable à celui-ci :
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 s'affichent dans la console.
Conclusion
Ce bref tutoriel a montré comment ajouter des fonctionnalités de journalisation de base à un programme Java, .NET ou Python qui utilise les bibliothèques clientes des API Google Data. Ces techniques peuvent être utiles si vous devez déboguer des échanges HTTP, mais que vous n'avez pas accès à un renifleur de paquets. Je n'ai fait qu'effleurer le sujet avec ces exemples. De nombreux mécanismes de journalisation présents dans ces langages sont beaucoup plus puissants que ceux présentés ici. Pour 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 :
Articles de la base de connaissances associés :
- 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 déboguer HTTP ?
- Qu'est-ce que l'API Google Spreadsheets ?
Groupes de discussion : nous en avons plusieurs, et d'autres seront ajoutés à mesure que d'autres API Google Data seront déployées. Nous surveillons activement les groupes.
N'hésitez pas à me contacter si vous avez des questions ou des suggestions. Rejoignez le groupe de discussion et commencez à publier des messages.