logging: replaced Funambol logging with our own infrastructure

Currently EvolutionSyncClient writes the following information:
- SyncEvolution messages via Logging.h to stdout if level higher
  than configured log level
- SyncEvolution messages into client.log: all messages if file
  is enabled (logdir setting)
- Synthesis global log (if logdir enabled)
- Synthesis session log (if logdir enabled)
- Synthesis message dump (if logdir enabled)
This commit is contained in:
Patrick Ohly 2009-02-16 16:11:17 +01:00 committed by Patrick Ohly
parent bcc349a569
commit d801974f74
18 changed files with 698 additions and 304 deletions

View file

@ -96,7 +96,7 @@ enum {
#include "EvolutionSyncClient.h"
#include "AddressBookSource.h"
#include <common/base/Log.h>
#include "Logging.h"
#include <common/base/util/StringBuffer.h>
#include "vocl/VConverter.h"
@ -1211,7 +1211,7 @@ void AddressBookSource::listAllItems(RevisionMap_t &revisions)
void AddressBookSource::close()
{
if (m_addressbook && !hasFailed()) {
LOG.debug("flushing address book");
SE_LOG_DEBUG(this, NULL, "flushing address book");
// store changes persistently
if (!ABSave(m_addressbook)) {
throwError("saving address book");
@ -1222,7 +1222,7 @@ void AddressBookSource::close()
// sleep a bit before returning control
sleep(2);
LOG.debug("done with address book");
SE_LOG_DEBUG(this, NULL, "done with address book");
}
m_addressbook = NULL;
@ -1253,7 +1253,7 @@ SyncItem *AddressBookSource::createItem(const string &uid, bool asVCard30)
#ifdef USE_ADDRESS_BOOK_VCARD
ref<CFDataRef> vcard(ABPersonCopyVCardRepresentation(person), "vcard");
LOG.debug("%*s", (int)CFDataGetLength(vcard), (const char *)CFDataGetBytePtr(vcard));
SE_LOG_DEBUG(this, NULL, "%*s", (int)CFDataGetLength(vcard), (const char *)CFDataGetBytePtr(vcard));
item->setData(CFDataGetBytePtr(vcard), CFDataGetLength(vcard));
#else
string vcard;
@ -1300,7 +1300,7 @@ AddressBookSource::InsertItemResult AddressBookSource::insertItem(const string &
person.set(PersonCreateWrapper(m_addressbook), "contact");
}
try {
LOG.debug("storing vCard for %s:\n%s",
SE_LOG_DEBUG(this, NULL, "storing vCard for %s:\n%s",
update ? luid.c_str() : "new contact",
data.c_str());
vCard2ABPerson converter(data, person);
@ -1348,14 +1348,14 @@ void AddressBookSource::deleteItem(const string &uid)
throwError(string("deleting contact ") + uid);
}
} else {
LOG.debug("%s: %s: request to delete non-existant contact ignored",
SE_LOG_DEBUG(this, NULL, "%s: %s: request to delete non-existant contact ignored",
getName(), uid.c_str());
}
}
void AddressBookSource::logItem(const string &uid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string line;
#if 0
@ -1386,13 +1386,13 @@ void AddressBookSource::logItem(const string &uid, const string &info, bool debu
line += "): ";
line += info;
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s", line.c_str() );
}
}
void AddressBookSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string line;
const char *data = (const char *)item.getData();
int datasize = item.getDataSize();
@ -1446,7 +1446,7 @@ void AddressBookSource::logItem(const SyncItem &item, const string &info, bool d
line += ": ";
line += info;
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s", line.c_str() );
}
}

View file

@ -18,7 +18,7 @@ using namespace std;
#include "EvolutionSmartPtr.h"
#include "e-cal-check-timezones.h"
#include <common/base/Log.h>
#include "Logging.h"
#include <boost/foreach.hpp>
@ -105,7 +105,7 @@ char *EvolutionCalendarSource::authenticate(const char *prompt,
{
const char *passwd = getPassword();
LOG.debug("%s: authentication requested, prompt \"%s\", key \"%s\" => %s",
SE_LOG_DEBUG(this, NULL, "%s: authentication requested, prompt \"%s\", key \"%s\" => %s",
getName(), prompt, key,
passwd && passwd[0] ? "returning configured password" : "no password configured");
return passwd && passwd[0] ? strdup(passwd) : NULL;
@ -241,8 +241,7 @@ void EvolutionCalendarSource::setItemStatusThrow(const char *key, int status)
{
switch (status) {
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA:
LOG.error("%s: item %.80s: conflict, will be replaced by server\n",
getName(), key);
SE_LOG_ERROR(this, NULL, "item %.80s: conflict, will be replaced by server\n", key);
break;
}
TrackingSyncSource::setItemStatusThrow(key, status);
@ -284,7 +283,7 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co
propstart = data.find("\nCATEGORIES", propstart + 1);
}
if (modified) {
LOG.debug("after replacing , with \\, in CATEGORIES:\n%s", data.c_str());
SE_LOG_DEBUG(this, NULL, "after replacing , with \\, in CATEGORIES:\n%s", data.c_str());
}
eptr<icalcomponent> icomp(icalcomponent_new_from_string((char *)data.c_str()));
@ -504,7 +503,7 @@ EvolutionCalendarSource::ICalComps_t EvolutionCalendarSource::removeEvents(const
&gerror)) {
if (gerror->domain == E_CALENDAR_ERROR &&
gerror->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
LOG.debug("%s: %s: request to delete non-existant item ignored",
SE_LOG_DEBUG(this, NULL, "%s: %s: request to delete non-existant item ignored",
getName(), uid.c_str());
g_clear_error(&gerror);
} else {
@ -545,7 +544,7 @@ void EvolutionCalendarSource::deleteItem(const string &luid)
&gerror)) {
if (gerror->domain == E_CALENDAR_ERROR &&
gerror->code == E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
LOG.debug("%s: %s: request to delete non-existant item ignored",
SE_LOG_DEBUG(this, NULL, "%s: %s: request to delete non-existant item ignored",
getName(), luid.c_str());
g_clear_error(&gerror);
} else {
@ -557,8 +556,8 @@ void EvolutionCalendarSource::deleteItem(const string &luid)
void EvolutionCalendarSource::logItem(const string &luid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
(LOG.*(debug ? &Log::debug : &Log::info))("%s: %s: %s", getName(), luid.c_str(), info.c_str());
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s: %s", luid.c_str(), info.c_str());
}
}
@ -584,7 +583,7 @@ static string extractProp(const char *data, const char *keyword)
void EvolutionCalendarSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
const char *keyptr = item.getKey();
string key;
if (!keyptr || !keyptr[0]) {
@ -600,7 +599,7 @@ void EvolutionCalendarSource::logItem(const SyncItem &item, const string &info,
} else {
key = keyptr;
}
(LOG.*(debug ? &Log::debug : &Log::info))("%s: %s: %s", getName(), key.c_str(), info.c_str());
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s: %s", key.c_str(), info.c_str());
}
}
@ -661,7 +660,7 @@ string EvolutionCalendarSource::retrieveItemAsString(const ItemID &id)
propstart = data.find("\nCATEGORIES", propstart + 1);
}
if (modified) {
LOG.debug("after replacing \\, with , in CATEGORIES:\n%s", data.c_str());
SE_LOG_DEBUG(this, NULL, "after replacing \\, with , in CATEGORIES:\n%s", data.c_str());
}
return data;

View file

@ -17,7 +17,7 @@ using namespace std;
#include "EvolutionContactSource.h"
#include "SyncEvolutionUtil.h"
#include <common/base/Log.h>
#include "Logging.h"
#include "vocl/VConverter.h"
using namespace vocl;
@ -153,7 +153,7 @@ void EvolutionContactSource::open()
}
while (authmethod) {
const char *method = (const char *)authmethod->data;
LOG.debug("%s: trying authentication method \"%s\", user %s, password %s",
SE_LOG_DEBUG(this, NULL, "%s: trying authentication method \"%s\", user %s, password %s",
getName(), method,
user && user[0] ? "configured" : "not configured",
passwd && passwd[0] ? "configured" : "not configured");
@ -162,11 +162,10 @@ void EvolutionContactSource::open()
passwd ? passwd : "",
method,
&gerror)) {
LOG.debug("%s: authentication succeeded", getName());
SE_LOG_DEBUG(this, NULL, "authentication succeeded");
break;
} else {
LOG.error("%s: authentication failed: %s",
getName(), gerror->message);
SE_LOG_ERROR(this, NULL, "authentication failed: %s", gerror->message);
g_clear_error(&gerror);
}
authmethod = authmethod->next;
@ -211,14 +210,14 @@ void EvolutionContactSource::beginSyncThrow(bool needAll,
E_CONTACT_OSSO_CONTACT_STATE);
bool deleted = false;
while (nextState) {
LOG.debug("checking X-OSSO-CONTACT-STATE %p of uid %s",
SE_LOG_DEBUG(this, NULL, "checking X-OSSO-CONTACT-STATE %p of uid %s",
nextState->data, uid);
if ((char *)nextState->data < (char *)1024) {
LOG.info("broken X-OSSO-CONTACT-STATE %p, please report this to the SyncEvolution developer",
nextState->data);
SE_LOG_INFO(this, NULL, "broken X-OSSO-CONTACT-STATE %p, please report this to the SyncEvolution developer",
nextState->data);
} else {
LOG.debug("X-OSSO-CONTACT-STATE %p = %s",
nextState->data, (char *)nextState->data);
SE_LOG_DEBUG(this, NULL, "X-OSSO-CONTACT-STATE %p = %s",
nextState->data, (char *)nextState->data);
if (nextState->data && !strcmp((char *)nextState->data, "DELETED")) {
deleted = true;
}
@ -351,7 +350,7 @@ SyncItem *EvolutionContactSource::createItem(const string &uid)
if (!vcardstr) {
throwError(string("failure extracting contact from Evolution " ) + uid);
}
LOG.debug("%s", vcardstr.get());
SE_LOG_DEBUG(this, NULL, "%s", vcardstr.get());
std::auto_ptr<VObject> vobj(VConverter::parse(vcardstr));
if (vobj.get() == 0) {
@ -391,7 +390,7 @@ SyncItem *EvolutionContactSource::createItem(const string &uid)
// convert from 3.0 to 2.1?
if (m_vcardFormat == EVC_FORMAT_VCARD_21) {
LOG.debug("convert to 2.1");
SE_LOG_DEBUG(this, NULL, "convert to 2.1");
// escape extended properties so that they are preserved
// as custom values by the server
@ -476,8 +475,8 @@ SyncItem *EvolutionContactSource::createItem(const string &uid)
vobj->fromNativeEncoding();
arrayptr<char> finalstr(vobj->toString(), "VOCL string");
LOG.debug("after conversion:");
LOG.debug("%s", (char *)finalstr);
SE_LOG_DEBUG(this, NULL, "after conversion:");
SE_LOG_DEBUG(this, NULL, "%s", (char *)finalstr);
auto_ptr<SyncItem> item( new SyncItem( uid.c_str() ) );
item->setData( (char *)finalstr, strlen(finalstr) );
@ -493,7 +492,7 @@ string EvolutionContactSource::preparseVCard(SyncItem& item)
// convert to 3.0 to get rid of quoted-printable encoded
// non-ASCII chars, because Evolution does not support
// decoding them
LOG.debug("%s", data.c_str());
SE_LOG_DEBUG(this, NULL, "%s", data.c_str());
std::auto_ptr<VObject> vobj(VConverter::parse((char *)data.c_str()));
if (vobj.get() == 0) {
throwError(string("failure parsing contact " ) + item.getKey());
@ -670,19 +669,18 @@ string EvolutionContactSource::preparseVCard(SyncItem& item)
vobj->fromNativeEncoding();
arrayptr<char> voclstr(vobj->toString(), "VOCL string");
data = (char *)voclstr;
LOG.debug("after conversion to 3.0:");
LOG.debug("%s", data.c_str());
SE_LOG_DEBUG(this, NULL, "after conversion to 3.0:");
SE_LOG_DEBUG(this, NULL, "%s", data.c_str());
return data;
}
void EvolutionContactSource::setItemStatusThrow(const char *key, int status)
{
switch (status) {
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA: {
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA: {
// make a copy before allowing the server to overwrite it
LOG.error("%s: contact %s: conflict, will be replaced by server contact - create copy",
getName(), key);
SE_LOG_ERROR(this, NULL, "contact %s: conflict, will be replaced by server contact - create copy", key);
EContact *contact;
GError *gerror = NULL;
@ -690,8 +688,7 @@ void EvolutionContactSource::setItemStatusThrow(const char *key, int status)
key,
&contact,
&gerror ) ) {
LOG.error("%s: item %.80s: reading original for copy failed",
getName(), key);
SE_LOG_ERROR(this, NULL, "item %.80s: reading original for copy failed", key);
break;
}
eptr<EContact, GObject> contactptr( contact, "contact" );
@ -701,8 +698,7 @@ void EvolutionContactSource::setItemStatusThrow(const char *key, int status)
! e_book_add_contact(m_addressbook,
copy,
&gerror)) {
LOG.error("%s: item %.80s: making copy failed",
getName(), key);
SE_LOG_ERROR(this, NULL, "item %.80s: making copy failed", key);
break;
}
break;
@ -794,7 +790,7 @@ int EvolutionContactSource::deleteItemThrow(SyncItem& item)
if (!e_book_remove_contact( m_addressbook, item.getKey(), &gerror ) ) {
if (gerror->domain == E_BOOK_ERROR &&
gerror->code == E_BOOK_ERROR_CONTACT_NOT_FOUND) {
LOG.debug("%s: %s: request to delete non-existant contact ignored",
SE_LOG_DEBUG(this, NULL, "%s: %s: request to delete non-existant contact ignored",
getName(), item.getKey());
g_clear_error(&gerror);
} else {
@ -833,7 +829,7 @@ const char *EvolutionContactSource::getMimeVersion() const
void EvolutionContactSource::logItem(const string &uid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string line;
EContact *contact;
GError *gerror = NULL;
@ -864,13 +860,13 @@ void EvolutionContactSource::logItem(const string &uid, const string &info, bool
line += "): ";
line += info;
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s", line.c_str() );
}
}
void EvolutionContactSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string line;
const char *data = (const char *)item.getData();
int datasize = item.getDataSize();
@ -925,7 +921,7 @@ void EvolutionContactSource::logItem(const SyncItem &item, const string &info, b
line += ": ";
line += info;
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s", line.c_str() );
}
}

View file

@ -12,7 +12,7 @@ using namespace std;
#include "EvolutionMemoSource.h"
#include "EvolutionSmartPtr.h"
#include <common/base/Log.h>
#include "Logging.h"
SyncItem *EvolutionMemoSource::createItem(const string &luid)
{

View file

@ -227,13 +227,11 @@ void FileSyncSource::deleteItem(const string &uid)
void FileSyncSource::logItem(const string &uid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
// If there was a good way to extract a short string identifying
// the item with uid, we would use it here and log it like this:
// (LOG.*(debug ? &Log::debug : &Log::info))("%s: %s %s",
// getName() /* out sync source name */,
// itemName,
// info.c_str());
// SE_LOG(this, NULL, debug ? Logger::DEBUG : Logger::INFO, "%s %s",
// itemName, info.c_str());
//
// Alternatively we could just log the uid. EvolutionSyncSource::logItem()
// is an utility function which extracts a short string from certain
@ -263,7 +261,7 @@ void FileSyncSource::logItem(const string &uid, const string &info, bool debug)
void FileSyncSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
if (!item.getData()) {
// operation on item without data, fall back to logging via uid
logItem(string(item.getKey()), info, debug);

View file

@ -9,7 +9,7 @@
#include "SQLiteContactSource.h"
#include <common/base/Log.h>
#include "Logging.h"
#include "vocl/VConverter.h"
#include <algorithm>
@ -219,7 +219,7 @@ SyncItem *SQLiteContactSource::createItem(const string &uid)
vobj.fromNativeEncoding();
arrayptr<char> finalstr(vobj.toString(), "VOCL string");
LOG.debug("%s", (char *)finalstr);
SE_LOG_DEBUG(this, NULL, "%s", (char *)finalstr);
cxxptr<SyncItem> item( new SyncItem( uid.c_str() ) );
item->setData( (char *)finalstr, strlen(finalstr) );
@ -378,15 +378,15 @@ void SQLiteContactSource::deleteItem(const string &uid)
void SQLiteContactSource::logItem(const string &uid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
(LOG.*(debug ? &Log::debug : &Log::info))("%s: %s %s",
getName(),
m_sqlite.findColumn("ABPerson",
"ROWID",
uid.c_str(),
"FirstSort",
uid.c_str()).c_str(),
info.c_str());
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
SE_LOG(this, NULL, debug ? Logger::DEBUG : Logger::INFO,
"%s %s",
m_sqlite.findColumn("ABPerson",
"ROWID",
uid.c_str(),
"FirstSort",
uid.c_str()).c_str(),
info.c_str());
}
}
@ -397,7 +397,7 @@ void SQLiteContactSource::logItem(const SyncItem &item, const string &info, bool
return;
}
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string data = (const char *)item.getData();
// avoid pulling in a full vcard parser by just searching for a specific property,
@ -412,11 +412,10 @@ void SQLiteContactSource::logItem(const SyncItem &item, const string &info, bool
name = data.substr(start, end - start);
}
}
(LOG.*(debug ? &Log::debug : &Log::info))("%s: %s %s",
getName(),
name.c_str(),
info.c_str());
SE_LOG(this, NULL, debug ? Logger::DEBUG : Logger::INFO,
"%s %s",
name.c_str(),
info.c_str());
}
}

View file

@ -6,10 +6,12 @@
#include "EvolutionSyncSource.h"
#include "SyncEvolutionUtil.h"
#include <posix/base/posixlog.h>
#include "Logging.h"
#include "LogStdout.h"
#include "TransportAgent.h"
#include "CurlTransportAgent.h"
#include "SoupTransportAgent.h"
using namespace SyncEvolution;
#include <list>
#include <memory>
@ -32,6 +34,7 @@ using namespace std;
#include <errno.h>
#include "synthesis/enginemodulebridge.h"
#include "synthesis/SDK_util.h"
SourceList *EvolutionSyncClient::m_sourceListPtr;
@ -48,7 +51,12 @@ EvolutionSyncClient::EvolutionSyncClient(const string &server,
{
// Use libsynthesis that we were linked against. The name
// of a .so could be given here, too, to use that instead.
sysync::TSyError err = m_engine->Connect("[]", 0, 0);
sysync::TSyError err = m_engine->Connect("[]", 0,
sysync::DBG_PLUGIN_NONE|
sysync::DBG_PLUGIN_INT|
sysync::DBG_PLUGIN_DB|
sysync::DBG_PLUGIN_EXOT|
sysync::DBG_PLUGIN_ALL);
if (err) {
throwError("Connect");
}
@ -63,19 +71,17 @@ EvolutionSyncClient::~EvolutionSyncClient()
// this class owns the logging directory and is responsible
// for redirecting output at the start and end of sync (even
// in case of exceptions thrown!)
class LogDir {
class LogDir : public LoggerStdout {
string m_logdir; /**< configured backup root dir, empty if none */
int m_maxlogdirs; /**< number of backup dirs to preserve, 0 if unlimited */
string m_prefix; /**< common prefix of backup dirs */
string m_path; /**< path to current logging and backup dir */
string m_logfile; /**< path to log file there, empty if not writing one */
const string &m_server; /**< name of the server for this synchronization */
LogLevel m_oldLogLevel; /**< logging level to restore */
bool m_restoreLog; /**< false if nothing needs to be restored because setLogdir() was never called */
string m_logfile; /**< path to log file there, empty if not writing one */
FILE *m_file; /**< file handle for log file, NULL if not writing one */
public:
LogDir(const string &server) : m_server(server),
m_restoreLog(false)
LogDir(const string &server) : m_server(server), m_file(NULL)
{
// SyncEvolution-<server>-<yyyy>-<mm>-<dd>-<hh>-<mm>
m_prefix = "SyncEvolution-";
@ -117,7 +123,7 @@ public:
try {
getLogdirs(path, entries);
} catch(const std::exception &ex) {
LOG.error("%s", ex.what());
SE_LOG_ERROR(NULL, NULL, "%s", ex.what());
return "";
}
@ -140,6 +146,7 @@ public:
void setLogdir(const char *path, int maxlogdirs, int logLevel = 0) {
m_maxlogdirs = maxlogdirs;
if (path && !strcasecmp(path, "none")) {
m_path = "";
m_logfile = "";
} else if (path && path[0]) {
m_logdir = path;
@ -169,7 +176,7 @@ public:
break;
}
if (errno != EEXIST) {
LOG.debug("%s: %s", m_path.c_str(), strerror(errno));
SE_LOG_DEBUG(NULL, NULL, "%s: %s", m_path.c_str(), strerror(errno));
EvolutionSyncClient::throwError(m_path, errno);
}
seq++;
@ -188,22 +195,32 @@ public:
if (m_logfile.size()) {
// redirect logging into that directory, including stderr,
// after truncating it
FILE *file = fopen(m_logfile.c_str(), "w");
if (file) {
fclose(file);
#ifdef POSIX_LOG
POSIX_LOG.
#endif
setLogFile(NULL, m_logfile.c_str(), true);
} else {
LOG.error("creating log file %s failed", m_logfile.c_str());
m_file = fopen(m_logfile.c_str(), "w");
if (!m_file) {
SE_LOG_ERROR(NULL, NULL, "creating log file %s failed", m_logfile.c_str());
}
}
m_oldLogLevel = LOG.getLevel();
LOG.setLevel(logLevel > 0 ? (LogLevel)(logLevel - 1) /* fixed level */ :
m_logfile.size() ? LOG_LEVEL_DEBUG /* default for log file */ :
LOG_LEVEL_INFO /* default for console output */ );
m_restoreLog = true;
// update log level of default logger and our own replacement
Level level;
switch (logLevel) {
case 0:
// default for console output
level = INFO;
break;
case 1:
level = ERROR;
break;
case 2:
level = INFO;
break;
default:
level = DEBUG;
break;
}
instance().setLevel(level);
setLevel(level);
setLogger(this);
}
/** sets a fixed directory for database files without redirecting logging */
@ -243,38 +260,48 @@ public:
++it, ++deleted) {
string path = m_logdir + "/" + *it;
string msg = "removing " + path;
LOG.info(msg.c_str());
SE_LOG_INFO(NULL, NULL, msg.c_str());
rm_r(path);
}
}
}
// remove redirection of stderr and (optionally) also of logging
void restore(bool all) {
if (!m_restoreLog) {
return;
// remove redirection of logging
void restore() {
if (&instance() == this) {
setLogger(NULL);
}
if (all) {
if (m_logfile.size()) {
#ifdef POSIX_LOG
POSIX_LOG.
#endif
setLogFile(NULL, "-", false);
}
LOG.setLevel(m_oldLogLevel);
} else {
if (m_logfile.size()) {
#ifdef POSIX_LOG
POSIX_LOG.
#endif
setLogFile(NULL, m_logfile.c_str(), false);
}
if (m_file) {
fclose(m_file);
m_file = NULL;
}
}
~LogDir() {
restore(true);
restore();
}
virtual void messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args)
{
if (m_file) {
va_list argscopy;
va_copy(argscopy, args);
// once to file, with full debugging
// TODO: configurable level of detail for file
LoggerStdout::messagev(m_file, level, DEBUG,
prefix, file, line, function,
format, argscopy);
va_end(argscopy);
}
// to stdout
LoggerStdout::messagev(level, prefix, file, line, function, format, args);
}
};
@ -316,11 +343,11 @@ public:
BOOST_FOREACH(EvolutionSyncSource *source, *this) {
string file = databaseName(*source, suffix);
LOG.debug("creating %s", file.c_str());
SE_LOG_DEBUG(NULL, NULL, "creating %s", file.c_str());
out.open(file.c_str());
source->exportData(out);
out.close();
LOG.debug("%s created", file.c_str());
SE_LOG_DEBUG(NULL, NULL, "%s created", file.c_str());
}
}
@ -351,7 +378,7 @@ public:
m_logdir.setLogdir(logDirPath, maxlogdirs, logLevel);
} else {
// at least increase log level
LOG.setLevel(LOG_LEVEL_DEBUG);
LoggerBase::instance().setLevel(Logger::DEBUG);
}
}
@ -422,7 +449,7 @@ public:
void syncDone(bool success) {
if (m_doLogging) {
// ensure that stderr is seen again
m_logdir.restore(false);
m_logdir.restore();
if (m_reportTodo) {
// haven't looked at result of sync yet;
@ -434,31 +461,12 @@ public:
try {
dumpDatabases("after");
} catch (const std::exception &ex) {
LOG.error( "%s", ex.what() );
SE_LOG_ERROR(NULL, NULL, "%s", ex.what() );
m_prepared = false;
}
}
string logfile = m_logdir.getLogfile();
#ifndef LOG_HAVE_SET_LOGGER
// scan for error messages
if (!m_quiet && logfile.size()) {
ifstream in;
in.open(m_logdir.getLogfile().c_str());
while (in.good()) {
string line;
getline(in, line);
if (line.find("[ERROR]") != line.npos) {
success = false;
cout << line << "\n";
} else if (line.find("[INFO]") != line.npos) {
cout << line << "\n";
}
}
in.close();
}
#endif
cout << flush;
cerr << flush;
cout << "\n";
@ -675,8 +683,7 @@ boost::shared_ptr<TransportAgent> EvolutionSyncClient::createTransportAgent()
void EvolutionSyncClient::displayServerMessage(const string &message)
{
LOG.info("message from server: %s",
message.c_str());
SE_LOG_INFO(NULL, NULL, "message from server: %s", message.c_str());
}
void EvolutionSyncClient::displaySyncProgress(sysync::TEngineProgressEventType type,
@ -694,21 +701,21 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* preparing (e.g. preflight in some clients), extra1=progress, extra2=total */
/* extra2 might be zero */
if (extra2) {
LOG.info("%s: preparing %d/%d",
source.getName(), extra1, extra2);
SE_LOG_INFO(NULL, NULL, "%s: preparing %d/%d",
source.getName(), extra1, extra2);
} else {
LOG.info("%s: preparing %d",
source.getName(), extra1);
SE_LOG_INFO(NULL, NULL, "%s: preparing %d",
source.getName(), extra1);
}
break;
case PEV_DELETING:
/* deleting (zapping datastore), extra1=progress, extra2=total */
if (extra2) {
LOG.info("%s: deleting %d/%d",
source.getName(), extra1, extra2);
SE_LOG_INFO(NULL, NULL, "%s: deleting %d/%d",
source.getName(), extra1, extra2);
} else {
LOG.info("%s: deleting %d",
source.getName(), extra1);
SE_LOG_INFO(NULL, NULL, "%s: deleting %d",
source.getName(), extra1);
}
break;
case PEV_ALERTED:
@ -716,27 +723,27 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* datastore alerted (extra1=0 for normal, 1 for slow, 2 for first time slow,
extra2=1 for resumed session) */
LOG.info("%s: %s %s sync",
source.getName(),
extra2 ? "resuming" : "starting",
extra1 == 0 ? "normal" :
extra1 == 1 ? "slow" :
extra1 == 2 ? "first time" :
"unknown");
SE_LOG_INFO(NULL, NULL, "%s: %s %s sync",
source.getName(),
extra2 ? "resuming" : "starting",
extra1 == 0 ? "normal" :
extra1 == 1 ? "slow" :
extra1 == 2 ? "first time" :
"unknown");
break;
case PEV_SYNCSTART:
/* sync started */
LOG.info("%s: started",
source.getName());
SE_LOG_INFO(NULL, NULL, "%s: started",
source.getName());
break;
case PEV_ITEMRECEIVED:
/* item received, extra1=current item count,
extra2=number of expected changes (if >= 0) */
if (extra2 > 0) {
LOG.info("%s: received %d/%d",
source.getName(), extra1, extra2);
SE_LOG_INFO(NULL, NULL, "%s: received %d/%d",
source.getName(), extra1, extra2);
} else {
LOG.info("%s: received %d",
SE_LOG_INFO(NULL, NULL, "%s: received %d",
source.getName(), extra1);
}
break;
@ -744,10 +751,10 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* item sent, extra1=current item count,
extra2=number of expected items to be sent (if >=0) */
if (extra2 > 0) {
LOG.info("%s: sent %d/%d",
SE_LOG_INFO(NULL, NULL, "%s: sent %d/%d",
source.getName(), extra1, extra2);
} else {
LOG.info("%s: sent %d",
SE_LOG_INFO(NULL, NULL, "%s: sent %d",
source.getName(), extra1);
}
break;
@ -755,14 +762,14 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* item locally processed, extra1=# added,
extra2=# updated,
extra3=# deleted */
LOG.info("%s: added %d, updated %d, removed %d",
SE_LOG_INFO(NULL, NULL, "%s: added %d, updated %d, removed %d",
source.getName(), extra1, extra2, extra3);
break;
case PEV_SYNCEND:
/* sync finished, probably with error in extra1 (0=ok),
syncmode in extra2 (0=normal, 1=slow, 2=first time),
extra3=1 for resumed session) */
LOG.info("%s: %s%s sync done %s",
SE_LOG_INFO(NULL, NULL, "%s: %s%s sync done %s",
source.getName(),
extra3 ? "resumed " : "",
extra2 == 0 ? "normal" :
@ -854,7 +861,7 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
extra2);
break;
default:
LOG.debug("%s: progress event %d, extra %d/%d/%d",
SE_LOG_DEBUG(NULL, NULL, "%s: progress event %d, extra %d/%d/%d",
source.getName(),
type, extra1, extra2, extra3);
}
@ -882,7 +889,7 @@ void EvolutionSyncClient::throwError(const string &action, int error)
void EvolutionSyncClient::fatalError(void *object, const char *error)
{
LOG.error("%s", error);
SE_LOG_ERROR(NULL, NULL, "%s", error);
if (m_sourceListPtr) {
m_sourceListPtr->syncDone(false);
}
@ -1054,8 +1061,58 @@ void EvolutionSyncClient::getConfigTemplateXML(string &xml, string &configname)
void EvolutionSyncClient::getConfigXML(string &xml, string &configname)
{
getConfigTemplateXML(xml, configname);
const string tag("<datastore/>");
size_t index = xml.find("<datastore/>");
string tag;
size_t index;
tag = "<debug/>";
index = xml.find(tag);
if (index != xml.npos) {
stringstream debug;
bool logging = !m_sourceListPtr->getLogdir().empty();
// @TODO be more selective about which Synthesis logging
// options we enable. Currently it logs everything when logging
// at all.
debug <<
" <debug>\n"
// logpath is a config variable set by EvolutionSyncClient::doSync()
" <logpath>$(logpath)</logpath>\n"
" <logflushmode>flush</logflushmode>\n"
" <logformat>html</logformat>\n"
" <folding>auto</folding>\n"
" <timestamp>yes</timestamp>\n"
" <timestampall>no</timestampall>\n"
" <timedsessionlognames>no</timedsessionlognames>\n"
" <subthreadmode>separate</subthreadmode>\n"
" <singlegloballog>yes</singlegloballog>\n";
if (logging) {
debug <<
" <sessionlogs>yes</sessionlogs>\n"
" <globallogs>yes</globallogs>\n"
" <msgdump>yes</msgdump>\n"
" <xmltranslate>yes</xmltranslate>\n"
" <enable option=\"all\"/>\n"
" <enable option=\"userdata\"/>\n"
" <enable option=\"scripts\"/>\n"
" <enable option=\"exotic\"/>\n";
} else {
debug <<
" <sessionlogs>no</sessionlogs>\n"
" <globallogs>no</globallogs>\n"
" <msgdump>no</msgdump>\n"
" <xmltranslate>no</xmltranslate>\n"
" <disable option=\"all\"/>";
}
debug <<
" </debug>\n";
xml.replace(index, tag.size(), debug.str());
}
tag = "<datastore/>";
index = xml.find(tag);
if (index != xml.npos) {
stringstream datastores;
@ -1084,7 +1141,7 @@ int EvolutionSyncClient::sync()
int res = 1;
if (!exists()) {
LOG.error("No configuration for server \"%s\" found.", m_server.c_str());
SE_LOG_ERROR(NULL, NULL, "No configuration for server \"%s\" found.", m_server.c_str());
throwError("cannot proceed without configuration");
}
@ -1098,16 +1155,10 @@ int EvolutionSyncClient::sync()
getLogLevel());
// dump some summary information at the beginning of the log
#ifdef LOG_HAVE_DEVELOPER
# define LOG_DEVELOPER developer
#else
# define LOG_DEVELOPER debug
#endif
LOG.LOG_DEVELOPER("SyncML server account: %s", getUsername());
LOG.LOG_DEVELOPER("client: SyncEvolution %s for %s",
getSwv(), getDevType());
LOG.LOG_DEVELOPER("device ID: %s", getDevID());
LOG.LOG_DEVELOPER("%s", EDSAbiWrapperDebug());
SE_LOG_DEV(NULL, NULL, "SyncML server account: %s", getUsername());
SE_LOG_DEV(NULL, NULL, "client: SyncEvolution %s for %s", getSwv(), getDevType());
SE_LOG_DEV(NULL, NULL, "device ID: %s", getDevID());
SE_LOG_DEV(NULL, NULL, "%s", EDSAbiWrapperDebug());
// instantiate backends, but do not open them yet
initSources(sourceList);
@ -1167,13 +1218,13 @@ int EvolutionSyncClient::sync()
res = 0;
} catch (const std::exception &ex) {
LOG.error( "%s", ex.what() );
SE_LOG_ERROR(NULL, NULL, "%s", ex.what() );
// something went wrong, but try to write .after state anyway
m_sourceListPtr = NULL;
sourceList.syncDone(false);
} catch (...) {
LOG.error( "unknown error" );
SE_LOG_ERROR(NULL, NULL, "unknown error" );
m_sourceListPtr = NULL;
sourceList.syncDone(false);
}
@ -1204,7 +1255,12 @@ void EvolutionSyncClient::doSync()
if (err) {
throwError("open config vars");
}
getEngine().SetStrValue(keyH, "defout_path", m_sourceListPtr->getLogdir());
string logdir = m_sourceListPtr->getLogdir();
if (logdir.size()) {
getEngine().SetStrValue(keyH, "defout_path", logdir);
} else {
getEngine().SetStrValue(keyH, "defout_path", "/dev/null");
}
getEngine().SetStrValue(keyH, "device_uri", getDevID());
getEngine().SetStrValue(keyH, "device_name", getDevType());
// TODO: redirect to log file?
@ -1214,7 +1270,7 @@ void EvolutionSyncClient::doSync()
string xml, configname;
getConfigXML(xml, configname);
LOG.debug("%s", xml.c_str());
SE_LOG_DEBUG(NULL, NULL, "%s", xml.c_str());
err = getEngine().InitEngineXML(xml.c_str());
if (err) {
throwError(string("error parsing ") + configname);
@ -1305,7 +1361,7 @@ void EvolutionSyncClient::doSync()
getEngine().CloseKey(targetH);
err = getEngine().OpenSubkey(targetH, targetsH, KEYVAL_ID_NEXT, 0);
}
// run an HTTP client sync session
boost::shared_ptr<TransportAgent> agent(createTransportAgent());
if (getUseProxy()) {
@ -1473,10 +1529,10 @@ void EvolutionSyncClient::doSync()
}
// loop until session done or aborted with error
} catch (const std::exception &ex) {
LOG.error("%s", ex.what());
SE_LOG_ERROR(NULL, NULL, "%s", ex.what());
stepCmd = STEPCMD_ABORT;
} catch (...) {
LOG.error("unknown error");
SE_LOG_ERROR(NULL, NULL, "unknown error");
stepCmd = STEPCMD_ABORT;
}
} while (stepCmd != STEPCMD_DONE && stepCmd != STEPCMD_ERROR);
@ -1491,7 +1547,7 @@ void EvolutionSyncClient::status()
{
EvolutionSyncConfig config(m_server);
if (!exists()) {
LOG.error("No configuration for server \"%s\" found.", m_server.c_str());
SE_LOG_ERROR(NULL, NULL, "No configuration for server \"%s\" found.", m_server.c_str());
throwError("cannot proceed without configuration");
}
@ -1505,7 +1561,7 @@ void EvolutionSyncClient::status()
}
sourceList.setLogdir(getLogDir(), 0, LOG_LEVEL_NONE);
LOG.setLevel(LOG_LEVEL_INFO);
LoggerBase::instance().setLevel(Logger::INFO);
string prevLogdir = sourceList.getPrevLogdir();
bool found = access(prevLogdir.c_str(), R_OK|X_OK) == 0;
@ -1515,7 +1571,7 @@ void EvolutionSyncClient::status()
sourceList.dumpDatabases("current");
sourceList.dumpLocalChanges("after", "current");
} catch(const std::exception &ex) {
LOG.error("%s", ex.what());
SE_LOG_ERROR(NULL, NULL, "%s", ex.what());
}
} else {
cerr << "Previous log directory not found.\n";

View file

@ -5,7 +5,7 @@
#include "EvolutionSyncSource.h"
#include "EvolutionSyncClient.h"
#include "SyncEvolutionUtil.h"
#include <common/base/Log.h>
#include "Logging.h"
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
@ -79,7 +79,7 @@ void EvolutionSyncSource::handleException()
} catch (std::exception &ex) {
setErrorF(getLastErrorCode() == ERR_NONE ? ERR_UNSPECIFIED : getLastErrorCode(),
"%s", ex.what());
LOG.error("%s", getLastErrorMsg());
SE_LOG_ERROR(this, NULL, "%s", getLastErrorMsg());
setFailed(true);
}
}
@ -344,19 +344,7 @@ void EvolutionSyncSource::getDatastoreXML(string &xml)
int EvolutionSyncSource::beginSync() throw()
{
string buffer;
buffer += getName();
buffer += ": sync mode is ";
SyncMode mode = getSyncMode();
buffer += mode == SYNC_SLOW ? "'slow'" :
mode == SYNC_TWO_WAY ? "'two-way'" :
mode == SYNC_REFRESH_FROM_SERVER ? "'refresh from server'" :
mode == SYNC_REFRESH_FROM_CLIENT ? "'refresh from client'" :
mode == SYNC_ONE_WAY_FROM_SERVER ? "'one-way from server'" :
mode == SYNC_ONE_WAY_FROM_CLIENT ? "'one-way from client'" :
mode == SYNC_NONE ? "'none' (for debugging)" :
"???";
LOG.info( buffer.c_str() );
// start background thread if not running yet:
// necessary to catch problems with Evolution backend
@ -546,8 +534,8 @@ void EvolutionSyncSource::setItemStatusThrow(const char *key, int status)
break;
default:
if (status < 200 || status > 300) {
LOG.error("%s: unexpected SyncML status response %d for item %.80s\n",
getName(), status, key);
SE_LOG_ERROR(this, NULL, "unexpected SyncML status response %d for item %.80s\n",
status, key);
setFailed(true);
}
}
@ -570,7 +558,7 @@ void EvolutionSyncSource::databaseModified()
void EvolutionSyncSource::logItemUtil(const string data, const string &mimeType, const string &mimeVersion,
const string &uid, const string &info, bool debug)
{
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
string name;
if (mimeType == "text/plain") {
@ -625,23 +613,51 @@ void EvolutionSyncSource::logItemUtil(const string data, const string &mimeType,
}
if (name.size()) {
(LOG.*(debug ? &Log::debug : &Log::info))("%s: %s %s",
getName(),
name.c_str(),
info.c_str());
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL,
"%s %s",
name.c_str(),
info.c_str());
} else {
(LOG.*(debug ? &Log::debug : &Log::info))("%s: LUID %s %s",
getName(),
uid.c_str(),
info.c_str());
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL,
"LUID %s %s",
uid.c_str(),
info.c_str());
}
}
}
void EvolutionSyncSource::setLevel(Level level)
{
LoggerBase::instance().setLevel(level);
}
Logger::Level EvolutionSyncSource::getLevel()
{
return LoggerBase::instance().getLevel();
}
void EvolutionSyncSource::messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args)
{
string newprefix = getName();
if (prefix) {
newprefix += ": ";
newprefix += prefix;
}
LoggerBase::instance().messagev(level, newprefix.c_str(),
file, line, function,
format, args);
}
SyncItem *EvolutionSyncSource::Items::start()
{
m_it = begin();
LOG.debug("start scanning %s items", m_type.c_str());
SE_LOG_DEBUG(&m_source, NULL, "start scanning %s items", m_type.c_str());
return iterate();
}
@ -649,7 +665,7 @@ SyncItem *EvolutionSyncSource::Items::iterate()
{
if (m_it != end()) {
const string &uid( *m_it );
LOG.debug("next %s item: %s", m_type.c_str(), uid.c_str());
SE_LOG_DEBUG(&m_source, NULL, "next %s item: %s", m_type.c_str(), uid.c_str());
++m_it;
if (&m_source.m_deletedItems == this) {
// just tell caller the uid of the deleted item

View file

@ -8,6 +8,8 @@
#include "config.h"
#include "SyncEvolutionConfig.h"
#include "EvolutionSmartPtr.h"
#include "Logging.h"
using namespace SyncEvolution;
#include <boost/shared_ptr.hpp>
#include <string>
@ -21,7 +23,7 @@ using namespace std;
#include <spds/SyncSource.h>
#include <spdm/ManagementNode.h>
#include <base/Log.h>
#include "Logging.h"
#include "eds_abi_wrapper.h"
@ -282,7 +284,7 @@ class TestRegistry : public vector<const RegisterSyncSourceTest *>
*
* It also adds Evolution specific interfaces and utility functions.
*/
class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig
class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig, public LoggerBase
{
public:
/**
@ -612,6 +614,27 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig
const string &uid, const string &info, bool debug = false);
/**@}*/
/**
* Logging utility code.
*
* Every sync source adds "<name>" as prefix to its output.
* All calls are redirected into EvolutionSyncClient logger.
*
* @TODO call EvolutionSyncClient instead of logger singleton
*/
/**@{*/
virtual void setLevel(Level level);
virtual Level getLevel();
virtual void messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args);
/**@}*/
protected:
#ifdef HAVE_EDS
/**

60
src/core/LogStdout.cpp Normal file
View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2009 Patrick Ohly
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "LogStdout.h"
namespace SyncEvolution {
void LoggerStdout::messagev(FILE *file,
Level msglevel,
Level filelevel,
const char *prefix,
const char *filename,
int line,
const char *function,
const char *format,
va_list args)
{
if (msglevel <= filelevel) {
// TODO: print time
fprintf(file, "[%s] ", levelToStr(msglevel));
if (prefix) {
fprintf(file, "%s: ", prefix);
}
// TODO: print debugging information, perhaps only in log file
vfprintf(file, format, args);
// TODO: add newline only when needed, add prefix to all lines
fprintf(file, "\n");
fflush(file);
}
}
void LoggerStdout::messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args)
{
messagev(stdout, level, getLevel(),
prefix, file, line, function,
format, args);
}
}

53
src/core/LogStdout.h Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2009 Patrick Ohly
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INCL_LOGSTDOUT
#define INCL_LOGSTDOUT
#include "Logging.h"
#include <stdio.h>
namespace SyncEvolution {
/**
* A logger which writes to stdout or a file.
*/
class LoggerStdout : public LoggerBase
{
public:
virtual void messagev(FILE *file,
Level msglevel,
Level filelevel,
const char *prefix,
const char *filename,
int line,
const char *function,
const char *format,
va_list args);
virtual void messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args);
};
} // namespace
#endif // INCL_LOGSTDOUT

63
src/core/Logging.cpp Normal file
View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2009 Patrick Ohly
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Logging.h"
#include "LogStdout.h"
namespace SyncEvolution {
static LoggerStdout DefaultLogger;
LoggerBase *LoggerBase::m_logger;
LoggerBase &LoggerBase::instance()
{
if (m_logger) {
return *m_logger;
} else {
return DefaultLogger;
}
}
void Logger::message(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
...)
{
va_list args;
va_start(args, format);
messagev(level, prefix, file, line, function, format, args);
va_end(args);
}
const char *Logger::levelToStr(Level level)
{
switch (level) {
case ERROR: return "ERROR";
case WARNING: return "WARNING";
case INFO: return "INFO";
case DEV: return "DEVELOPER";
case DEBUG: return "DEBUG";
default: return "???";
}
}
}

200
src/core/Logging.h Normal file
View file

@ -0,0 +1,200 @@
/*
* Copyright (C) 2009 Patrick Ohly
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INCL_LOGGING
#define INCL_LOGGING
#include <stdarg.h>
namespace SyncEvolution {
/**
* Abstract interface for logging in SyncEvolution. Can be
* implemented by other classes to add information (like a certain
* prefix) before passing the message on to a global instance for the
* actual processing.
*/
class Logger
{
public:
/**
* Which of these levels is the right one for a certain message
* is a somewhat subjective choice. Here is a definition how they
* are supposed to be used:
* - error: severe problem which the user and developer have to
* know about
* - warning: a problem that was handled, but users and developers
* probably will want to know about
* - info: information about a sync session which the user
* will want to read during/after each sync session
* - developer: information about a sync session that is not
* interesting for a user (for example, because it
* is constant and already known) but which should
* be in each log because developers need to know
* it. Messages logged with this calls will be included
* at LOG_LEVEL_INFO, therefore messages should be small and
* not recur so that the log file size remains small.
* - debug: most detailed logging, messages may be arbitrarily large
*
* Here is a decision tree which helps to pick the right level:
* - an error: => ERROR
* - a non-fatal error: => WARNING
* - it changes during each sync or marks important steps
* in the sync: INFO
* - small, non-recurring message which is important for developers
* who read a log produced at LOG_LEVEL_INFO: DEVELOPER
* - everything else: DEBUG
*/
typedef enum {
/**
* only error messages printed
*/
ERROR,
/**
* error and warning messages printed
*/
WARNING,
/**
* errors and info messages for users and developers will be
* printed: use this to keep the output consise and small
*/
INFO,
/**
* important messages to developers
*/
DEV,
/**
* all messages will be printed, including detailed debug
* messages
*/
DEBUG
} Level;
static const char *levelToStr(Level level);
virtual ~Logger() {}
/**
* output a single message
*
* @param level level for current message
* @param prefix inserted at beginning of each line, if non-NULL
* @param file source file where message comes from, if non-NULL
* @param line source line number, if file is non-NULL
* @param function surrounding function name, if non-NULL
* @param format sprintf format
* @param args parameters for sprintf: consumed by this function,
* make copy with va_copy() if necessary!
*/
virtual void messagev(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
va_list args) = 0;
/** default: redirect into messagev() */
virtual void message(Level level,
const char *prefix,
const char *file,
int line,
const char *function,
const char *format,
...)
#ifdef __GNUC__
__attribute__((format(printf, 7, 8)))
#endif
;
};
/**
* Global logging, implemented as a singleton with one instance per
* process.
*
* @TODO avoid global variable
*/
class LoggerBase : public Logger
{
public:
LoggerBase() : m_level(INFO) {}
/**
* Grants access to the singleton which implements logging.
* The implementation of this function and thus the Log
* class itself is platform specific: if no Log instance
* has been set yet, then this call has to create one.
*/
static LoggerBase &instance();
/**
* Overrides the default Logger implementation. The Logger class
* itself will never delete the active logger.
*
* @param logger will be used for all future logging activities;
* NULL is allowed and implies that the default
* Logger implementation will be created if needed
*/
static void setLogger(LoggerBase *logger) { m_logger = logger; }
virtual void setLevel(Level level) { m_level = level; }
virtual Level getLevel() { return m_level; }
private:
static LoggerBase *m_logger;
Level m_level;
};
/**
* Vararg macro which passes the message through a specific
* Logger class instance (if non-NULL) and otherwise calls
* the global logger directly. Adds source file and line.
*
* @TODO make source and line info optional for release
* @TODO add function name (GCC extension)
*/
#define SE_LOG(_level, _instance, _prefix, _format, _args...) \
do { \
if (_instance) { \
static_cast<Logger *>(_instance)->message(_level, \
_prefix, \
__FILE__, \
__LINE__, \
0, \
_format, \
##_args); \
} else { \
LoggerBase::instance().message(_level, \
_prefix, \
__FILE__, \
__LINE__, \
0, \
_format, \
##_args); \
} \
} while(false)
#define SE_LOG_ERROR(_instance, _prefix, _format, _args...) SE_LOG(Logger::ERROR, _instance, _prefix, _format, ##_args)
#define SE_LOG_WARNING(_instance, _prefix, _format, _args...) SE_LOG(Logger::WARNING, _instance, _prefix, _format, ##_args)
#define SE_LOG_INFO(_instance, _prefix, _format, _args...) SE_LOG(Logger::INFO, _instance, _prefix, _format, ##_args)
#define SE_LOG_DEV(_instance, _prefix, _format, _args...) SE_LOG(Logger::DEV, _instance, _prefix, _format, ##_args)
#define SE_LOG_DEBUG(_instance, _prefix, _format, _args...) SE_LOG(Logger::DEBUG, _instance, _prefix, _format, ##_args)
} // namespace
#endif // INCL_LOGGING

View file

@ -32,6 +32,11 @@ CORE_SOURCES = \
eds_abi_wrapper.h \
eds_abi_wrapper.cpp \
\
Logging.h \
Logging.cpp \
LogStdout.h \
LogStdout.cpp \
\
TransportAgent.h \
CurlTransportAgent.h \
CurlTransportAgent.cpp \

View file

@ -23,9 +23,9 @@
namespace SyncEvolution {
SoupTransportAgent::SoupTransportAgent() :
m_status(INACTIVE),
m_session(soup_session_async_new()),
m_loop(g_main_loop_new(g_main_context_default(), TRUE), "Soup main loop"),
m_status(INACTIVE),
m_response(NULL)
{
}

View file

@ -364,7 +364,7 @@ void VObject::toNativeEncoding()
// value
if (_wcsicmp(charset, TEXT("UTF-8")) &&
_wcsicmp(charset, TEXT("\"UTF-8\""))) {
LOG.error("ignoring unsupported charset");
// log error("ignoring unsupported charset");
}
vprop->removeParameter(TEXT("CHARSET"));
}

View file

@ -5,8 +5,6 @@
#include <config.h>
#include <stddef.h>
#include <base/Log.h>
#include <posix/base/posixlog.h>
#include <spds/spdsutils.h>
#include <iostream>
@ -49,37 +47,6 @@ extern "C" EContact *e_contact_new_from_vcard(const char *vcard)
}
#endif
#ifdef LOG_HAVE_SET_LOGGER
class CmdLineLogger : public POSIXLog {
protected:
virtual void printLine(bool firstLine,
time_t time,
const char *fullTime,
const char *shortTime,
const char *utcTime,
LogLevel level,
const char *levelPrefix,
const char *line) {
POSIXLog::printLine(firstLine,
time,
fullTime,
shortTime,
utcTime,
level,
levelPrefix,
line);
if (level <= LOG_LEVEL_INFO &&
getLogFile()) {
/* POSIXLog is printing to file, therefore print important lines to stdout */
fprintf(stdout, "%s [%s] %s\n",
shortTime,
levelPrefix,
line);
}
}
};
#endif
int main( int argc, char **argv )
{
#ifdef ENABLE_MAEMO
@ -100,17 +67,6 @@ int main( int argc, char **argv )
g_type_init();
#endif
#ifdef LOG_HAVE_SET_LOGGER
static CmdLineLogger logger;
Log::setLogger(&logger);
#endif
#ifdef POSIX_LOG
POSIX_LOG.
#endif
setLogFile(NULL, "-");
LOG.reset();
LOG.setLevel(LOG_LEVEL_INFO);
resetError();
setvbuf(stderr, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
@ -142,9 +98,9 @@ int main( int argc, char **argv )
return 1;
}
} catch ( const std::exception &ex ) {
LOG.error( "%s", ex.what() );
SE_LOG_ERROR(NULL, NULL, "%s", ex.what());
} catch (...) {
LOG.error( "unknown error" );
SE_LOG_ERROR(NULL, NULL, "unknown error");
}
return 1;

View file

@ -9,37 +9,7 @@
<!-- this string is output to every session debug logfile to identify the config in use -->
<configidstring>SyncEvolution client config</configidstring>
<debug>
<!-- path where logfiles are stored -->
<logpath>$(logpath)</logpath>
<logflushmode>flush</logflushmode> <!-- buffered is fastest mode, but may loose data on process abort. Other options: "flush" (after every line) or "openclose" (safest, slowest, like in 2.x server) -->
<!-- per session log -->
<sessionlogs>yes</sessionlogs> <!-- by default, create a session log file for every sync session (might be disabled for special users/devices in scripts) -->
<!-- debug format options -->
<logformat>html</logformat> <!-- html is nicely colored and easily viewable with a web browser. Other options: "xml", "text" -->
<timestamp>yes</timestamp> <!-- show timestamps for structure elements in log -->
<timestampall>no</timestampall> <!-- don't show timestamp for every log line -->
<timedsessionlognames>yes</timedsessionlognames> <!-- session logs also have the session start timestamp in the filename - makes them more easily sortable -->
<!-- thread logging mode -->
<subthreadmode>separate</subthreadmode> <!-- write log info from subthreads into separate log files. Other options: "suppress" -->
<!-- basic debug level selection -->
<!-- enable option="extended"/ --> <!-- "extended" is a good choice for start testing. For production, use "normal" or "minimal" -->
<!-- <enable option="normal"/> --> <!-- "normal" provides rich debug info, but still in reasonable size -->
<!-- <enable option="minimal"/> --> <!-- "minimal" just shows basic flow and error. Not suitable for debugging -->
<!-- <enable option="maximal"/> --> <!-- "maximal" can create VERY LARGE logs and cause HEAVY SLOWDOWN. Only for detail debugging -->
<enable option="all"/> <!-- "all" shows EVERYTHING possible, and way too much for any normal situation. For hardcore debugging ONLY! -->
<!-- additional debug info switches -->
<enable option="userdata"/> <!-- Make this <disable ...> if you don't want user data in the logs -->
<enable option="scripts"/> <!-- Make this <enable ...> to show script execution in logs -->
<enable option="exotic"/> <!-- Make this <enable ...> to include very in-detail info. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
<!-- see manual for more debug info switches -->
<!-- global log options -->
<globallogs>yes</globallogs> <!-- by default, do not log global session dispatching, creation etc. (not useful in multi-user operation) -->
<singlegloballog>no</singlegloballog> <!-- a new global log will be started for every start of the server/application -->
<!-- SyncML message dumping options -->
<msgdump>yes</msgdump> <!-- do not dump syncml traffic 1:1 to files -->
<xmltranslate>yes</xmltranslate> <!-- do not try to translate syncml traffic into XML (DO NOT SET THIS OPTION IN PRODUCTIVE SERVERS!) -->
</debug>
<debug/>
<!-- Note: since 2.1.1.5, clients have a <transport> section to specify <keepconnection> behaviour -->
<transport type="xpt">