Juni 2007
Einführung
Manchmal gibt es keinen Ersatz dafür, was über das Kabel hinausgeht. Dies gilt besonders für das Schreiben von Software, die Webdienste wie die Google Data APIs nutzt, bei denen viele Vorgänge mit HTTP-Anfragen verbunden sind. Wenn alles andere fehlschlägt, können Sie prüfen, ob Ihr Programm die von Ihnen erwarteten Aktionen ausführt. Sehen Sie sich dazu die tatsächlich übertragenen und empfangenen Byte an. Viele Clientbibliotheken für die Google Data APIs haben einen Debugging-Modus, in dem der HTTP-Traffic angezeigt wird. Dies ist besonders nützlich, wenn Sie keinen Zugriff auf einen Paket-Sniffer wie WireShark oder Fiddler haben.
Ich kann nicht messen, wie oft ich mein Programm für richtig hielt, und habe bei der Prüfung eines Paket-Trace festgestellt, dass es einen zusätzlichen Zeilenumbruch oder einen falsch benannten HTTP-Header gibt. Die Programmierung mit einem Webdienst, ohne den HTTP-Traffic zu betrachten, kann wie ein Versuch sein, eine Nadel mit geschlossenen Augen zu verbinden.
Es kann jedoch vorkommen, dass ein Paket-Sniffer nicht verfügbar ist oder nicht für verschlüsselte Pakete geeignet ist. Sie können diese Einschränkung umgehen, indem Sie Logging-Mechanismen ins Programm aufnehmen. Mit diesen Logging-Funktionen können Sie einige, wenn nicht sogar alle, ausgetauschten Daten sehen, auch für verschlüsselte HTTPS-Daten oder Code für die Remote-Ausführung.
Für diesen Artikel habe ich Beispiel-Diagnosecode in drei Sprachen mithilfe der Google Data API-Clientbibliotheken für Java, .NET und Python geschrieben. In jedem Beispiel aktiviere ich Logging oder Debugging, authentifizieren mich mit Client-Login, erhalte eine Liste meiner Google-Tabellen und drucke deren Titel aus.
Java
Sie können die java.util.logging
-Klassen verwenden, um die Logging-Ebenen (und folglich die Trafficdaten) für einige wichtige Objekte in der Clientbibliothek festzulegen. Im folgenden Beispiel habe ich mir die HTTP-Header und die Aktivitäten des XML-Parsers angesehen, um einen vollständigen Überblick über die Übertragung zu erhalten.
Die Google Data-Java-Clientbibliothek hat separate Klassen für die Verarbeitung von HTTP-Anfragen und XML-Parsing. Daher muss ich zwei Logger-Objekte erstellen, eines für jede Klasse: com.google.gdata.client.http.HttpGDataRequest
übernimmt den HTTP-Traffic, während com.google.gdata.util.XmlParser
für das XML-Parsing verantwortlich ist.
Die Logger-Instanzen zeichnen Aktivitäten für HttpGDataRequest
und XmlParser
auf. Sie können die Detailebene der Ausgabe jedes Loggers steuern. Für diese Demo habe ich ausgewählt, dass alle Ereignisse angezeigt werden, die von den Objekten HttpGDataRequest
und XmlParser
erzeugt werden.
Nachdem ich meine Logger erstellt und konfiguriert habe, muss ich ihnen mitteilen, was zu tun ist, wenn sie ein Ereignis von ihren Klassen erhalten. Ich möchte zuerst alle Logging-Informationen in die Konsole schreiben. Daher erstelle ich ein ConsoleHandler
und füge es beiden Loggern hinzu.
Hier ist mein Beispielcode:
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());
}
}
}
Wenn du dieses Programm ausführst, siehst du in der Konsole in etwa Folgendes (Ich habe einige der weniger interessanten Teile ausgeschnitten):
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
Diese Logs können ziemlich groß werden. Daher sollten Sie die Protokollierungsebenen selektiv festlegen. Sie könnten auch FileHandler
anstelle von ConsoleHandler
erstellen, um die Logdaten für die spätere Verwendung zu speichern.
Wenn Java nicht Ihre Tasche ist, könnten Sie .NET ausprobieren.
.NET
Zum Erfassen des HTTP-Traffics in der .NET-Clientbibliothek können Sie die Standardanfrage-Factory im Client durch GDataLoggingRequestFactory
ersetzen.
Die HTTP-Anfragen in der .NET-Bibliothek werden vom GDataRequestFactory
erstellt, der sich in jedem Dienstobjekt befindet. Die normalen Anfrage-Factorys führen kein Logging aus, aber GDataLoggingRequestFactory
ist eine Unterklasse von GDataRequestFactory
und verfügt über integriertes Logging. Sie können den vollständigen Pfad der Logdatei angeben. Legen Sie dazu CombinedFileName
fest.
Nachdem Sie Ihre Anfrage-Factory eingerichtet haben, ersetzen Sie die Request-Factory in Ihrem Serviceobjekt durch Festlegen von RequestFactory
des Dienstobjekts.
Ihr Code könnte dann so aussehen:
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();
}
}
}
Die resultierende Protokolldatei enthält die XML-Anfragen und -Antworten. Hier ist ein abgekürztes Beispiel, das ich mit tidy formatiert habe.
<?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>
Vielleicht ist Ihnen aber auch die Skriptsprache wichtig und Sie bevorzugen Python.
Python
Um den HTTP-Traffic in der Python-Clientbibliothek zu erfassen, können Sie den HTTP-Header-Traffic auf die Konsole übertragen. Aktivieren Sie dazu den Debug-Modus im HTTP-Client. Das Dienstobjekt hat ein Debug-Mitglied, das Sie auf True setzen können.
Wenn Sie „debug“ auf „true“ setzen, wird das Debug-Flag im zugrunde liegenden HTTPRequest
-Objekt festgelegt, das im Dienstobjekt enthalten ist.
Das folgende Beispiel gibt die HTTP-Header zurück, die vom Tabellenserver gesendet werden, wenn Sie eine Liste Ihrer Tabellen anfordern.
#!/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
Die Konsole sollte in etwa so aussehen:
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
Wenn Sie weitere Vorgänge wie das Einfügen oder Aktualisieren ausführen, werden die entsprechenden Anfragedaten an Ihre Konsole übertragen.
Fazit
In dieser kurzen Anleitung wird veranschaulicht, wie Sie einem Java-, .NET- oder Python-Programm, das die Google Data API-Clientbibliotheken verwendet, grundlegende Logging-Funktionen hinzufügen können. Diese Techniken können nützlich sein, wenn Sie Fehler in HTTP-Exchanges beheben müssen, aber keinen Zugriff auf einen Paket-Sniffer haben. Ich habe die Oberfläche nur mit diesen Beispielen zerkratzt. Viele der in diesen Sprachen vorhandenen Logging-Mechanismen sind viel leistungsfähiger als die hier gezeigten. Weitere Informationen zum Logging und zu den Google Data APIs finden Sie in der Ressourcenliste unten.
Die in diesem Artikel behandelten Clientbibliotheken finden Sie auf den folgenden Seiten:
Zugehörige Knowledge Base-Elemente:
- Wie erhalte ich HTTP-Logging-Informationen in der Java-Clientbibliothek?
- Wie erhalte ich HTTP-Logging-Informationen in der .NET-Clientbibliothek?
- Welche guten Tools gibt es für das HTTP-Debugging?
- Was ist die Google Tabellen API?
Diskussionsgruppen: Es gibt etliche solcher Gruppen, zu denen immer mehr hinzukommen. Wir beobachten die Gruppen aktiv.
Wenn Sie Fragen oder Anregungen haben, können Sie sich gern an uns wenden. Werfen Sie einen Blick in die Diskussionsgruppe und beginnen Sie mit dem Posten.