Debug dei client API Google Data: esplorare il traffico dall'interno del tuo programma

Jeffrey Scudder, team delle API di dati di Google
giugno 2007

Introduzione

A volte è utile sostituire il cavo. Ciò è particolarmente vero quando si scrive software che utilizza servizi web come le API di dati di Google, in cui molte operazioni comportano l'invio di richieste HTTP. Quando tutto il resto non va a buon fine, puoi verificare che il programma stia facendo ciò che ti aspettavi vedendo i byte effettivi trasmessi e ricevuti. Molte delle librerie client per le API di dati di Google hanno una modalità di debug che mostra il traffico HTTP. Ciò è particolarmente utile quando non hai accesso a uno snapshot di pacchetti come WireShark o Navigator.

Non posso contare il numero di volte in cui avrei potuto giurare il mio programma era corretto, solo per verificare nell'ambito di un'analisi dei pacchetti la presenza di un carattere di nuova riga aggiuntivo o di un'intestazione HTTP con un nome errato. Programmare con un servizio web senza guardare il traffico HTTP può essere come provare a infilare un ago a occhi chiusi.

Tuttavia, potresti trovarti in una situazione in cui uno snapshot di pacchetti non è disponibile o non è adeguato per gestire i pacchetti criptati. Niente paura, puoi aggirare questa limitazione sfruttando alcuni meccanismi di logging nel programma. Utilizzando queste funzionalità di logging, puoi vedere alcuni, se non tutti, i dati scambiati, anche per i dati HTTPS criptati o per il codice in esecuzione da remoto.

Per questo articolo ho scritto codice di esempio di diagnostica in tre linguaggi utilizzando le librerie client dell'API Google Data per Java, .NET e Python. In ciascun esempio attivo il logging o il debug, quindi mi eseguo l'autenticazione utilizzando l'accesso client, quindi ottengo un elenco dei miei fogli di lavoro Google e ne stampo i titoli.

Java

Puoi utilizzare le classi java.util.logging per impostare i livelli di logging (e di conseguenza esporre i dati sul traffico) per un paio di oggetti chiave nella libreria client. Nell'esempio seguente, ho scelto di esaminare le intestazioni HTTP e le attività dell'analizzatore sintattico XML per ottenere una visione completa di ciò che viaggia in rete.

La libreria client Java di Google Data ha classi separate per gestire le richieste HTTP e l'analisi XML; pertanto, devo creare due oggetti Logger, uno per ogni classe: com.google.gdata.client.http.HttpGDataRequest gestisce il traffico HTTP mentre com.google.gdata.util.XmlParser è responsabile dell'analisi XML.

Le istanze logger registrano le attività per HttpGDataRequest e XmlParser e puoi controllare il livello di dettaglio dell'output di ogni logger. Per questa dimostrazione, ho scelto di visualizzare tutti gli eventi prodotti dagli oggetti HttpGDataRequest e XmlParser.

Dopo aver creato e configurato i logger, devo spiegargli cosa fare quando ricevono un evento dai loro corsi. Per ora voglio scrivere tutte le informazioni di logging sulla console, quindi creo un ConsoleHandler e lo aggiungo a entrambi i logger.

Ecco il mio codice campione:

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());
       
}
   
}
}

Quando esegui questo programma, nella console vedrai qualcosa di simile a questo (ho tagliato alcune delle parti meno interessanti):

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

Poiché questi log possono diventare molto grandi, potresti voler essere più selettivo nell'impostazione dei livelli dei logger. Puoi anche creare un elemento FileHandler invece di ConsoleHandler per archiviare i dati di log e utilizzarli in un secondo momento.

Ovviamente, se Java non è la tua soluzione, puoi provare .NET.

.NET

Per acquisire il traffico HTTP nella libreria client .NET, puoi sostituire la fabbrica di richieste predefinita nel client con una GDataLoggingRequestFactory.

Le richieste HTTP nella libreria .NET vengono create da GDataRequestFactory, all'interno di ciascun oggetto di servizio. Le normali fabbriche di richiesta non eseguono alcun logging, ma GDataLoggingRequestFactory, che è una sottoclasse del GDataRequestFactory, ha il logging integrato. Puoi specificare il percorso completo del file di log impostando CombinedFileName.

Dopo aver configurato la fabbrica delle richieste, devi sostituirla nell'oggetto Service impostando RequestFactory dell'oggetto servizio. Il codice potrebbe avere il seguente aspetto:

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();
       
}
   
}
}

Il file di log risultante contiene le richieste e le risposte XML. Ecco un esempio abbreviato che ho formattato utilizzando 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>

Ma forse ti interessano i linguaggi di scripting e preferisci utilizzare Python.

Python

Per acquisire il traffico HTTP nella libreria client Python, puoi fare eco al traffico dell'intestazione HTTP nella console attivando la modalità di debug nel client HTTP. L'oggetto di servizio ha un membro di debug che puoi impostare su True.

Se imposti il debug su true, viene impostato il flag di debug nell'oggetto HTTPRequest sottostante contenuto nell'oggetto di servizio.

Ecco un esempio che richiama le intestazioni HTTP inviate dal server dei fogli di lavoro quando chiedi un elenco dei tuoi fogli di lavoro.

#!/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

e vedrai il seguente aspetto su 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

Man mano che esegui operazioni aggiuntive, come un inserimento o un aggiornamento, vedrai i dati della richiesta corrispondenti richiamati sulla tua console.

Conclusione

Questo breve tutorial ha illustrato come aggiungere la funzionalità di logging di base a un programma Java, .NET o Python che utilizza le librerie client dell'API Google Data. Queste tecniche possono essere utili se devi eseguire il debug delle piattaforme di scambio HTTP, ma non hai accesso a uno snapshot di pacchetti. Ho solo grattato la superficie con questi esempi. Molti dei meccanismi di logging presenti in queste lingue sono molto più potenti di quanto mostrato qui. Per saperne di più sul logging o sulle API di dati di Google, consulta l'elenco delle risorse di seguito.

Puoi trovare le librerie client illustrate in questo articolo in queste pagine:

Voci della knowledge base correlate:

Gruppi di discussione: ne abbiamo già alcuni, altri ne verranno aggiunti man mano che vengono implementate altre API di dati di Google. I gruppi vengono monitorati attivamente.

Sarei felice di ricevere domande o suggerimenti. Entra nel gruppo di discussione e inizia a pubblicare post.