Berichten tagged Logging
CouchDB
26 sep
Enige tijd geleden ben in begonnen met CouchDB te spelen. Kennis maken met nieuwe technologieën gaat wat mij betreft altijd het beste door het bedenken van een soort project. Nu CouchDB 1.0.0 (1.0.1 is nu je beste optie!) is uitgebracht dacht ik dat het goed zou zijn om (eindelijk) een blog over mijn bevindingen tot nu toe te schrijven.
Ik bedacht het volgende project: Een eenvoudige (OSGi) log listener die zijn log berichten in een CouchDB database opslaat.
In Luminis maken we veel gebruik van OSGi. Het is een modulaire framework (geschreven in Java) die je toestaat om verschillende modules (de zogenaamde ‘bundels’) te combineren. Elke module kan zelfstandig werken of maakt gebruik van de functionaliteiten die door andere bundels worden aangeboden. Een slimme combinatie van verschillende bundels zal (bijna als ‘emerging behavior’) resulteren in een volledige applicatie die perfect bij uw behoeften past. De functionaliteit van een bepaalde bundel wordt beschikbaar gemaakt via interfaces, zodat implementaties kunnen veranderen zonder de interactie met andere bundels te veranderen.
Een van de compendium diensten die beschikbaar zijn is de LogService. Deze service biedt andere services de mogelijkheid berichten in een centrale log aan te maken. Het is vervolgens aan de logservice implementatie waar deze log berichten belanden. Logging wordt meestal verstuurd naar je console of een bestand, wat goed is in de meeste gevallen. Soms echter, is inloggen op het apparaat zelf en het ophalen van het logboekbestand voor inspectie geen gemakkelijke taak. Neem bijvoorbeeld een Android toestel. Met dank aan Aaron Miller’s werk, we zijn nu in staat om CouchDB draaien op Android. Android apps (EZDroid apps) zijn nu in staat om hun logging gegevens op te slaan in deze lokale instantie van CouchDB. Deze gegevens kunnen vervolgens eenvoudig worden gerepliceerd naar een andere instantie voor inspectie.
Ook voor beperkte apparaten (waar er bijvoorbeeld beperkte opslagruimte beschikbaar is) loggen naar een
bestand is gewoon geen optie.
Daarom dacht ik aan de volgende scenario’s waar
- CouchDB is lokaal geïnstalleerd op het apparaat/server. Toegang tot CouchDB is dan gegarandeerd en geen logging wordt gemist. Een nadeel zou kunnen zijn dat de OSGi applicatie een lokale installatie van CouchDB vereist (voor degenen die dat als een nadeel zien!).
- CouchDB is geïnstalleerd op een externe instantie. Toegang tot de CouchDB instantie zou wegens het netwerk instabiliteit kunnen worden onderbroken. Dan kunnen sommige log berichten verloren gaan. Omdat de meeste applicaties een werkende internet verbinding vereisen, ik denk dat we hiermee kunnen leven.
Het doel van het project is een JSON representatie van de werkelijk gelogde berichten op te slaan in CouchDB. Dit kan gemakkelijk worden bereikt door middel van een LogListener .
In beide gevallen ontvangt de OSGi LogListener, die binnen de OSGi applicatie ‘leeft’, alle LogEntries die naar de logservice worden verzonden (met wat extra meta-data). Het enige wat de LogListener dan nog hoeft te doen is de conversie naar JSON en het aanmaken van een nieuw document in een database op het CouchDB server. Als men dan de log-berichten zou willen inspecteren, kan een enkele call naar de CouchDB server een replicatie van de database naar uw lokale CouchDB instantie initiëren. Zodra dit gebeurd is, kun je off-line de logs inspecteren.
Installatie en het basis gebruik van CouchDB wordt hier niet beschreven, er zijn al uitstekende beschrijvingen beschikbaar op de Wiki, Halorgium’s GitHub en O’Reilly Free Book .
Om bovengenoemde te testen heb ik een LogListener implementatie gemaakt. Ik gebruik json-simple om een LogEntry te converteren naar JSON en dat resulteert in een JSON Object, zoals bijvoorbeeld:
{
'message': 'This is a test message',
'time': 1269783246909,
'level': 'LOG_DEBUG',
'serviceReference': {},
'bundle': {
'id': 5,
'lastModified': 1269783246510,
'location': 'file:bundle/net.luminis.log.couchdb-1.0.0.jar',
'symbolicName': 'net.luminis.log.couchdb'
}
}
Een unieke serverID/instanceID zou ook kunnen worden toegevoegd om onderscheid te kunnen maken tussen server instanties, mocht je logging van verschillende apparaten naar een centrale server te sturen.
De bovenstaande JSON data POST ik naar de server. Omdat ik zelf geen ‘_id’ in de JSON string heb gedefinieerd, zal CouchDB er een voor mij aanmaken. De HTTP (1.0) POST wordt uitgevoerd door middel van een kale socket naar de CouchDB server.:
POST /db HTTP/1.0
Content-Length: xxx
Content-Type: application/json
{ ... the data here ... }
Het antwoord is ook een geldig JSON object die kan worden gecontroleerd om te kijken of alles is goed gegaan (samen met de HTTP response code, natuurlijk).
In mijn huidige implementatie, kan ik kiezen tussen twee modes; ofwel elk bericht wordt verstuurd naar de CouchDB instantie op een bepaalde tijdstip, of ik stuur alle berichten in bulk-modus elke x seconden. De laatste is waarschijnlijk het beste voor remote couchdb gevallen.
