diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2013-10-01 09:26:41 +0200 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2013-10-25 21:07:27 +0100 |
commit | e7a8f1b456f967323b403ecf543b28a3d52db5a8 (patch) | |
tree | 9ccf373715cc8c4ec03b6c41b8ef9ab4bd4e7c6e | |
parent | 6e47a118da64cccddc6ce3e453f0cf33ec841336 (diff) |
logging: support DLT (FDO #66769)
Diagnostic Log and Trace (DLT) manages a sequence of log messages,
with remote controllable level of detail. SyncEvolution optionally
(can be chosen at compile time and again at runtime) uses DLT instead
of its own syncevolution-log.html files.
-rw-r--r-- | README-DLT.rst | 30 | ||||
-rw-r--r-- | configure.ac | 24 | ||||
-rw-r--r-- | src/dbus/server/main.cpp | 25 | ||||
-rw-r--r-- | src/dbus/server/server.am | 2 | ||||
-rw-r--r-- | src/dbus/server/session-helper.cpp | 28 | ||||
-rw-r--r-- | src/dbus/server/session-helper.h | 3 | ||||
-rw-r--r-- | src/dbus/server/session.cpp | 10 | ||||
-rw-r--r-- | src/dbus/server/sync-helper.cpp | 14 | ||||
-rw-r--r-- | src/syncevo/LocalTransportAgent.cpp | 19 | ||||
-rw-r--r-- | src/syncevo/LogDLT.cpp | 116 | ||||
-rw-r--r-- | src/syncevo/LogDLT.h | 61 | ||||
-rw-r--r-- | src/syncevo/LogRedirect.cpp | 22 | ||||
-rw-r--r-- | src/syncevo/LogStdout.cpp | 10 | ||||
-rw-r--r-- | src/syncevo/Logging.cpp | 6 | ||||
-rw-r--r-- | src/syncevo/Logging.h | 18 | ||||
-rw-r--r-- | src/syncevo/SyncContext.cpp | 99 | ||||
-rw-r--r-- | src/syncevo/syncevo.am | 4 | ||||
-rwxr-xr-x | test/test-dbus.py | 2 |
18 files changed, 447 insertions, 46 deletions
diff --git a/README-DLT.rst b/README-DLT.rst new file mode 100644 index 00000000..16bbc598 --- /dev/null +++ b/README-DLT.rst @@ -0,0 +1,30 @@ +Diagnostic Log and Trace +======================== + +Diagnostic Log and Trace (DLT) is a logging mechanism defined and +implemented by GENIVI: http://projects.genivi.org/diagnostic-log-trace/ + +SyncEvolution optionally supports DLT as follows: + + * syncevo-dbus-server, syncevo-dbus-helper and syncevo-local-sync can + log to DLT. Operations with "syncevolution --daemon=no" never use + DLT. + * Each of the three processes uses a different application ID. By + default, these IDs are "SYNS", "SYNH", "SYNL". These default can be + changed via configure options. All processes use just one context, + with the fixed ID "SYNC". + * syncevo-dbus-helper and syncevo-local-sync only run occasionally. + This makes is hard to adjust their log levels, for example via the + dlt-viewer, because the processes and their contexts are only shown + (known?) while the processes run. To work around this, the initial + log level of these two helpers are inherited from the + log level of the "SYNC" context in syncevo-dbus-helper. + * That log level defaults to "WARN", which ensures that normal runs + produce no output. + * To enable DLT support during compilation, use + "--enable-dlt" and "--with-dlt-syncevolution=SYNS,SYNH,SYNL" where SYNS/H/L + are the actual application IDs. + * To enable DLT support at runtime, run syncevo-dbus-server with + "--dlt". Logging to syslog should be disabled with "--no-syslog". + * The hierarchical log from libsynthesis gets flattened into a flat + stream of messages and no syncevolution-log.html files are written. diff --git a/configure.ac b/configure.ac index 5995cf80..608c9c4e 100644 --- a/configure.ac +++ b/configure.ac @@ -290,6 +290,30 @@ AC_ARG_ENABLE(libsoup, # SoupTransportAgent depends on glib case "$TRANSPORT" in *libsoup*) need_glib=yes;; esac +AC_ARG_ENABLE(dlt, + AS_HELP_STRING([--enable-dlt], + [enable logging via GENIVI Diagnostic Log and Trace (DLT)]), + [enable_dlt=$enableval + test $enable_dlt = "yes" || test $enable_dlt = "no" || AC_ERROR([invalid value of --enable-dlt: $enableval])], + [enable_dlt="no"]) +if test "$enable_dlt" = "yes"; then + PKG_CHECK_MODULES(DLT, automotive-dlt, + [USE_DLT=1], + [AC_ERROR([dlt not found, required for --enable-dlt])]) + AC_DEFINE(USE_DLT, 1, "optionally use GENIVI Diagnostic Log and Trace for logging") + AC_ARG_WITH([dlt-syncevolution], + AS_HELP_STRING([--with-dlt-syncevolution=SYNS,SYNH,SYNL], + [controls the application IDs used by syncevo-dbus-server, syncevo-dbus-helper and syncevo-local-sync]), + [with_dlt_ids="$withval"], + [with_dlt_ids="SYNS,SYNH,SYNL"]) + syns=`echo $with_dlt_ids | cut -d , -f 1` + synh=`echo $with_dlt_ids | cut -d , -f 2` + synl=`echo $with_dlt_ids | cut -d , -f 3` + AC_DEFINE_UNQUOTED(DLT_SYNCEVO_DBUS_SERVER_ID, "$syns", "DLT app ID for syncevo-dbus-server") + AC_DEFINE_UNQUOTED(DLT_SYNCEVO_DBUS_HELPER_ID, "$synh", "DLT app ID for syncevo-dbus-helper") + AC_DEFINE_UNQUOTED(DLT_SYNCEVO_LOCAL_HELPER_ID, "$synl", "DLT app ID for syncevo-local-helper") +fi + bluetooth_disabled=no AC_ARG_ENABLE(bluetooth, AS_HELP_STRING([--enable-bluetooth], diff --git a/src/dbus/server/main.cpp b/src/dbus/server/main.cpp index a8d8c6d9..63c757bd 100644 --- a/src/dbus/server/main.cpp +++ b/src/dbus/server/main.cpp @@ -33,8 +33,13 @@ #include <syncevo/SuspendFlags.h> #include <syncevo/LogRedirect.h> #include <syncevo/LogSyslog.h> +#include <syncevo/LogDLT.h> #include <syncevo/GLibSupport.h> +#ifdef USE_DLT +# include <dlt.h> +#endif + using namespace SyncEvo; using namespace GDBusCXX; @@ -100,6 +105,9 @@ int main(int argc, char **argv, char **envp) int logLevelDBus = 2; gboolean stdoutEnabled = false; gboolean syslogEnabled = true; +#ifdef USE_DLT + gboolean dltEnabled = false; +#endif #ifdef ENABLE_DBUS_PIM gboolean startPIM = false; #endif @@ -115,6 +123,9 @@ int main(int argc, char **argv, char **envp) "Enable printing to stdout (result of operations) and stderr (errors/info/debug).", NULL }, { "no-syslog", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &syslogEnabled, "Disable printing to syslog.", NULL }, +#ifdef USE_DLT + { "dlt", 0, 0, G_OPTION_ARG_NONE, &dltEnabled, "Enable logging via GENIVI Diagnostic Log and Trace.", NULL }, +#endif #ifdef ENABLE_DBUS_PIM { "start-pim", 'p', 0, G_OPTION_ARG_NONE, &startPIM, "Activate the PIM Manager (= unified address book) immediately.", @@ -154,6 +165,20 @@ int main(int argc, char **argv, char **envp) // Redirect output and optionally log to syslog. PushLogger<LogRedirect> redirect(new LogRedirect(LogRedirect::STDERR_AND_STDOUT)); redirect->setLevel(stdoutEnabled ? level : Logger::NONE); +#ifdef USE_DLT + PushLogger<LoggerDLT> loggerdlt; + if (dltEnabled) { + // DLT logging with default log level DLT_LOG_WARN. This + // default was chosen because DLT's own default, + // DLT_LOG_INFO, leads to too much output given that a lot + // of the standard messages in SyncEvolution and + // libsynthesis are labelled informational. + setenv("SYNCEVOLUTION_USE_DLT", StringPrintf("%d", DLT_LOG_WARN).c_str(), true); + loggerdlt.reset(new LoggerDLT(DLT_SYNCEVO_DBUS_SERVER_ID, "SyncEvolution D-Bus server")); + } else { + unsetenv("SYNCEVOLUTION_USE_DLT"); + } +#endif PushLogger<LoggerSyslog> syslogger; if (syslogEnabled && level > Logger::NONE) { syslogger.reset(new LoggerSyslog(execName)); diff --git a/src/dbus/server/server.am b/src/dbus/server/server.am index ab01679d..302754c4 100644 --- a/src/dbus/server/server.am +++ b/src/dbus/server/server.am @@ -82,7 +82,7 @@ nodist_src_dbus_server_libsyncevodbusserver_la_SOURCES += \ src_dbus_server_libsyncevodbusserver_la_LDFLAGS += $(DBUS_PIM_PLUGIN_LDFLAGS) src_dbus_server_libsyncevodbusserver_la_LIBADD += $(FOLKS_LIBS) $(DBUS_PIM_PLUGIN_LIBS) $(PHONENUMBERS_LIBS) -src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS) $(DBUS_PIM_PLUGIN_CFLAGS) $(PHONENUMBERS_CFLAGS) +src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS) $(DBUS_PIM_PLUGIN_CFLAGS) $(PHONENUMBERS_CFLAGS) $(DLT_CFLAGS) endif # Need to list all plugins here and not include the active one in the regular diff --git a/src/dbus/server/session-helper.cpp b/src/dbus/server/session-helper.cpp index 7d233966..19776ea4 100644 --- a/src/dbus/server/session-helper.cpp +++ b/src/dbus/server/session-helper.cpp @@ -42,14 +42,13 @@ static void dumpString(const std::string &output) */ class SessionHelperLogger : public Logger { - boost::shared_ptr<LogRedirect> m_parentLogger; + Handle m_parentLogger; boost::shared_ptr<SessionHelper> m_helper; Level m_dbusLogLevel; public: - SessionHelperLogger(const boost::shared_ptr<LogRedirect> &parentLogger, - const boost::shared_ptr<SessionHelper> &helper): - m_parentLogger(parentLogger), + SessionHelperLogger(const boost::shared_ptr<SessionHelper> &helper): + m_parentLogger(Logger::instance()), m_helper(helper), m_dbusLogLevel(DEBUG) { @@ -84,7 +83,7 @@ public: va_list argsCopy; va_copy(argsCopy, args); if (m_parentLogger) { - m_parentLogger->messagev(options, format, argsCopy); + m_parentLogger.messagev(options, format, argsCopy); } else { formatLines(options.m_level, DEBUG, options.m_processName, @@ -94,10 +93,16 @@ public: } va_end(argsCopy); } else if (m_parentLogger) { - // Only flush parent logger, to capture output sent to - // stdout/stderr by some library and send it via D-Bus - // (recursively!) before printing out own, new output. - m_parentLogger->flush(); + // Pass through to parent, but marked in such a way that + // only the DLT and syslog logger will react to it, but + // not LogStdout. That's necessary because + // syncevo-dbus-server handles stdout for us. + va_list argsCopy; + va_copy(argsCopy, args); + MessageOptions buffer(options); + buffer.m_flags |= MessageOptions::ONLY_GLOBAL_LOG; + m_parentLogger.messagev(buffer, format, argsCopy); + va_end(argsCopy); } if (m_helper && @@ -117,8 +122,7 @@ public: SessionHelper::SessionHelper(GMainLoop *loop, const GDBusCXX::DBusConnectionPtr &conn, - const boost::shared_ptr<ForkExecChild> &forkexec, - const boost::shared_ptr<LogRedirect> &parentLogger) : + const boost::shared_ptr<ForkExecChild> &forkexec) : GDBusCXX::DBusObjectHelper(conn, std::string(SessionCommon::HELPER_PATH) + "/" + forkexec->getInstance(), SessionCommon::HELPER_IFACE, @@ -127,7 +131,7 @@ SessionHelper::SessionHelper(GMainLoop *loop, m_loop(loop), m_conn(conn), m_forkexec(forkexec), - m_logger(new SessionHelperLogger(parentLogger, boost::shared_ptr<SessionHelper>(this, NopDestructor()))), + m_logger(new SessionHelperLogger(boost::shared_ptr<SessionHelper>(this, NopDestructor()))), emitLogOutput(*this, "LogOutput"), emitSyncProgress(*this, "SyncProgress"), emitSourceProgress(*this, "SourceProgress"), diff --git a/src/dbus/server/session-helper.h b/src/dbus/server/session-helper.h index 3c380008..6f9dc0e0 100644 --- a/src/dbus/server/session-helper.h +++ b/src/dbus/server/session-helper.h @@ -85,8 +85,7 @@ class SessionHelper : public GDBusCXX::DBusObjectHelper, public: SessionHelper(GMainLoop *loop, const GDBusCXX::DBusConnectionPtr &conn, - const boost::shared_ptr<ForkExecChild> &forkexec, - const boost::shared_ptr<LogRedirect> &parentLogger); + const boost::shared_ptr<ForkExecChild> &forkexec); ~SessionHelper(); void setDBusLogLevel(Logger::Level level); diff --git a/src/dbus/server/session.cpp b/src/dbus/server/session.cpp index 12b5bb75..03c4ee12 100644 --- a/src/dbus/server/session.cpp +++ b/src/dbus/server/session.cpp @@ -31,6 +31,10 @@ #include <syncevo/SyncContext.h> #include <syncevo/BoostHelper.h> +#ifdef USE_DLT +#include <syncevo/LogDLT.h> +#endif + #include <memory> #include <boost/foreach.hpp> @@ -793,6 +797,11 @@ void Session::useHelperAsync(const SimpleResult &result) args.push_back("--dbus-verbosity"); args.push_back(StringPrintf("%d", m_server.getDBusLogLevel())); m_forkExecParent = SyncEvo::ForkExecParent::create("syncevo-dbus-helper", args); +#ifdef USE_DLT + if (getenv("SYNCEVOLUTION_USE_DLT")) { + m_forkExecParent->addEnvVar("SYNCEVOLUTION_USE_DLT", StringPrintf("%d", LoggerDLT::getCurrentDLTLogLevel())); + } +#endif // We own m_forkExecParent, so the "this" pointer for // onConnect will live longer than the signal in // m_forkExecParent -> no need for resource @@ -884,6 +893,7 @@ static void Logging2Server(Server &server, // there is considered an error. Logger::MessageOptions options(Logger::strToLevel(strLevel.c_str())); options.m_processName = &procname; + options.m_flags = Logger::MessageOptions::ALREADY_LOGGED; Logging2ServerAndStdout(server, path, options, "%s", explanation.c_str()); } } diff --git a/src/dbus/server/sync-helper.cpp b/src/dbus/server/sync-helper.cpp index a564e9a3..8fefb3c0 100644 --- a/src/dbus/server/sync-helper.cpp +++ b/src/dbus/server/sync-helper.cpp @@ -28,6 +28,7 @@ #include <syncevo/SuspendFlags.h> #include <syncevo/SyncContext.h> #include <syncevo/LogRedirect.h> +#include <syncevo/LogDLT.h> using namespace SyncEvo; using namespace GDBusCXX; @@ -45,11 +46,10 @@ namespace { } void onConnect(const DBusConnectionPtr &conn, - const boost::shared_ptr<LogRedirect> &parentLogger, const boost::shared_ptr<ForkExecChild> &forkexec, boost::shared_ptr<SessionHelper> &helper) { - helper.reset(new SessionHelper(loop, conn, forkexec, parentLogger)); + helper.reset(new SessionHelper(loop, conn, forkexec)); helper->activate(); helper->setDBusLogLevel(Logger::Level(logLevelDBus)); } @@ -107,6 +107,14 @@ int main(int argc, char **argv, char **envp) redirect.reset(new LogRedirect(LogRedirect::STDERR_AND_STDOUT)); pushRedirect.reset(redirect); } +#ifdef USE_DLT + // Set by syncevo-dbus-server for us. + bool useDLT = getenv("SYNCEVOLUTION_USE_DLT") != NULL; + PushLogger<LoggerDLT> loggerdlt; + if (useDLT) { + loggerdlt.reset(new LoggerDLT(DLT_SYNCEVO_DBUS_HELPER_ID, "SyncEvolution local sync helper")); + } +#endif setvbuf(stderr, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); @@ -140,7 +148,7 @@ int main(int argc, char **argv, char **envp) boost::shared_ptr<SessionHelper> helper; bool failed = false; - forkexec->m_onConnect.connect(boost::bind(onConnect, _1, redirect, + forkexec->m_onConnect.connect(boost::bind(onConnect, _1, boost::cref(forkexec), boost::ref(helper))); forkexec->m_onFailure.connect(boost::bind(onFailure, _2, boost::ref(failed))); diff --git a/src/syncevo/LocalTransportAgent.cpp b/src/syncevo/LocalTransportAgent.cpp index 3b0ce035..d348878c 100644 --- a/src/syncevo/LocalTransportAgent.cpp +++ b/src/syncevo/LocalTransportAgent.cpp @@ -27,6 +27,7 @@ #include <syncevo/DBusTraits.h> #include <syncevo/SuspendFlags.h> #include <syncevo/LogRedirect.h> +#include <syncevo/LogDLT.h> #include <syncevo/BoostHelper.h> #include <synthesis/syerror.h> @@ -100,6 +101,11 @@ void LocalTransportAgent::start() } m_status = ACTIVE; m_forkexec = ForkExecParent::create("syncevo-local-sync"); +#ifdef USE_DLT + if (getenv("SYNCEVOLUTION_USE_DLT")) { + m_forkexec->addEnvVar("SYNCEVOLUTION_USE_DLT", StringPrintf("%d", LoggerDLT::getCurrentDLTLogLevel())); + } +#endif m_forkexec->m_onConnect.connect(boost::bind(&LocalTransportAgent::onChildConnect, this, _1)); // fatal problems, including quitting child with non-zero status m_forkexec->m_onFailure.connect(boost::bind(&LocalTransportAgent::onFailure, this, _2)); @@ -177,6 +183,9 @@ void LocalTransportAgent::logChildOutput(const std::string &level, const std::st { Logger::MessageOptions options(Logger::strToLevel(level.c_str())); options.m_processName = &m_clientContext; + // Child should have written this into its own log file and/or syslog/dlt already. + // Only pass it on to a user of the command line interface. + options.m_flags = Logger::MessageOptions::ALREADY_LOGGED; SyncEvo::Logger::instance().messageWithOptions(options, "%s", message.c_str()); } @@ -1146,6 +1155,16 @@ int LocalTransportMain(int argc, char **argv) Logger::Handle handle(child->createLogger()); logger.reset(handle); } + +#ifdef USE_DLT + // Set by syncevo-dbus-server for us. + bool useDLT = getenv("SYNCEVOLUTION_USE_DLT") != NULL; + PushLogger<LoggerDLT> loggerdlt; + if (useDLT) { + loggerdlt.reset(new LoggerDLT(DLT_SYNCEVO_LOCAL_HELPER_ID, "SyncEvolution local sync helper")); + } +#endif + child->run(); int ret = child->getReturnCode(); logger.reset(); diff --git a/src/syncevo/LogDLT.cpp b/src/syncevo/LogDLT.cpp new file mode 100644 index 00000000..fd808594 --- /dev/null +++ b/src/syncevo/LogDLT.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <syncevo/LogDLT.h> + +#ifdef USE_DLT + +#include <dlt.h> + +#include <syncevo/declarations.h> +SE_BEGIN_CXX + +static DltLogLevelType SyncEvoLevel2DLTLevel(Logger::Level level) +{ + switch (level) { + case Logger::NONE: return DLT_LOG_OFF; + case Logger::ERROR: return DLT_LOG_ERROR; + case Logger::WARNING: return DLT_LOG_WARN; + case Logger::SHOW: + case Logger::INFO: return DLT_LOG_INFO; + case Logger::DEV: + case Logger::DEBUG: return DLT_LOG_DEBUG; + } + return DLT_LOG_OFF; +} + +static LoggerDLT *LoggerDLTInstance; + +LoggerDLT::LoggerDLT(const char *appid, const char *description) : + m_parentLogger(Logger::instance()), + m_dltContext(calloc(1, sizeof(DltContext))) +{ + DLT_REGISTER_APP(appid, description); + int level = atoi(getEnv("SYNCEVOLUTION_USE_DLT", "-1")); + if (level > 0) { + DLT_REGISTER_CONTEXT_LL_TS(*(DltContext *)m_dltContext, "SYNC", "SyncEvolution messages", + (DltLogLevelType)level, DLT_TRACE_STATUS_OFF); + } else { + DLT_REGISTER_CONTEXT(*(DltContext *)m_dltContext, "SYNC", "SyncEvolution messages"); + } + LoggerDLTInstance = this; +} + +LoggerDLT::~LoggerDLT() +{ + DLT_UNREGISTER_CONTEXT(*(DltContext *)m_dltContext); + DLT_UNREGISTER_APP(); + LoggerDLTInstance = NULL; +} + +void LoggerDLT::messagev(const MessageOptions &options, + const char *format, + va_list args) +{ + // always to parent first (usually stdout): + // if the parent is a LogRedirect instance, then + // it'll flush its own output first, which ensures + // that the new output comes later (as desired) + { + va_list argscopy; + va_copy(argscopy, args); + m_parentLogger.messagev(options, format, argscopy); + va_end(argscopy); + } + + DltContextData log; + if (!(options.m_flags & MessageOptions::ALREADY_LOGGED) && + dlt_user_log_write_start((DltContext *)m_dltContext, &log, SyncEvoLevel2DLTLevel(options.m_level)) > 0) { + std::string buffer = StringPrintfV(format, args); + // Avoid almost empty messages. They are triggered by + // SyncEvolution to format the INFO output and don't add any + // valuable information to the DLT log. + if (!buffer.empty() && + buffer != "\n") { + dlt_user_log_write_string(&log, buffer.c_str()); + dlt_user_log_write_finish(&log); + } + } +} + +int LoggerDLT::getCurrentDLTLogLevel() +{ + if (LoggerDLTInstance) { + for (int level = DLT_LOG_VERBOSE; + level > DLT_LOG_DEFAULT; + --level) { + DltContextData log; + // Emulates DLT_LOG(): logging active if dlt_user_log_write_start() returns something > 0. + // Otherwise discard the DltContextData without doing anything. + if (dlt_user_log_write_start((DltContext *)LoggerDLTInstance->m_dltContext, &log, (DltLogLevelType)level) > 0) { + return level; + } + } + } + return DLT_LOG_DEFAULT; +} + +SE_END_CXX + +#endif // USE_DLT diff --git a/src/syncevo/LogDLT.h b/src/syncevo/LogDLT.h new file mode 100644 index 00000000..f93e1dc0 --- /dev/null +++ b/src/syncevo/LogDLT.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef INCL_LOGDLT +#define INCL_LOGDLT + +#include <config.h> + +#ifdef USE_DLT + +#include <syncevo/Logging.h> +#include <syncevo/util.h> + +#include <syncevo/declarations.h> +SE_BEGIN_CXX + +/** + * A logger which writes to DLT and passes log messages + * through to its parent. + */ +class LoggerDLT : public Logger +{ + Handle m_parentLogger; + // avoid dependency on dlt.h here + void *m_dltContext; + +public: + LoggerDLT(const char *appid, const char *description); + ~LoggerDLT(); + + virtual void messagev(const MessageOptions &options, + const char *format, + va_list args); + + /** + * Extracts current log level from the LoggerDLT which was + * pushed onto the stack, DLT_LOG_DEFAULT if none active. + */ + static int getCurrentDLTLogLevel(); +}; + +SE_END_CXX + +#endif // USE_DLT +#endif // INCL_LOGSYSLOG diff --git a/src/syncevo/LogRedirect.cpp b/src/syncevo/LogRedirect.cpp index ca7666ce..45640cca 100644 --- a/src/syncevo/LogRedirect.cpp +++ b/src/syncevo/LogRedirect.cpp @@ -247,16 +247,18 @@ void LogRedirect::messagev(const MessageOptions &options, // check for other output first process(); - // Choose output channel: SHOW goes to original stdout, - // everything else to stderr. - LoggerStdout::write(options.m_level == SHOW ? - (m_out ? m_out : stdout) : - (m_err ? m_err : stderr), - options.m_level, getLevel(), - options.m_prefix, - options.m_processName, - format, - args); + if (!(options.m_flags & MessageOptions::ONLY_GLOBAL_LOG)) { + // Choose output channel: SHOW goes to original stdout, + // everything else to stderr. + LoggerStdout::write(options.m_level == SHOW ? + (m_out ? m_out : stdout) : + (m_err ? m_err : stderr), + options.m_level, getLevel(), + options.m_prefix, + options.m_processName, + format, + args); + } } void LogRedirect::redirect(int original, FDs &fds) throw() diff --git a/src/syncevo/LogStdout.cpp b/src/syncevo/LogStdout.cpp index f78ff9dc..a2014e2e 100644 --- a/src/syncevo/LogStdout.cpp +++ b/src/syncevo/LogStdout.cpp @@ -84,10 +84,12 @@ void LoggerStdout::messagev(const MessageOptions &options, const char *format, va_list args) { - write(m_file, options.m_level, getLevel(), - options.m_prefix, - options.m_processName, - format, args); + if (!(options.m_flags & MessageOptions::ONLY_GLOBAL_LOG)) { + write(m_file, options.m_level, getLevel(), + options.m_prefix, + options.m_processName, + format, args); + } } SE_END_CXX diff --git a/src/syncevo/Logging.cpp b/src/syncevo/Logging.cpp index 0e80947c..837c8828 100644 --- a/src/syncevo/Logging.cpp +++ b/src/syncevo/Logging.cpp @@ -255,13 +255,15 @@ Logger::MessageOptions::MessageOptions(Level level, const std::string *prefix, const char *file, int line, - const char *function) : + const char *function, + int flags) : m_level(level), m_prefix(prefix), m_file(file), m_line(line), m_function(function), - m_processName(NULL) + m_processName(NULL), + m_flags(flags) { } diff --git a/src/syncevo/Logging.h b/src/syncevo/Logging.h index dde9e325..ce9a2497 100644 --- a/src/syncevo/Logging.h +++ b/src/syncevo/Logging.h @@ -199,13 +199,29 @@ class Logger const char *m_function; /** name of the process which originally created the message, if different from current one */ const std::string *m_processName; + /** additional flags */ + int m_flags; + + enum { + /** + * The message was written into a global log (syslog, dlt, ...) + * already. Such a message must not be logged again. + */ + ALREADY_LOGGED = 1<<0, + /** + * The message must be written into a global log, + * but not to stdout. + */ + ONLY_GLOBAL_LOG = 1<<1 + }; MessageOptions(Level level); MessageOptions(Level level, const std::string *prefix, const char *file, int line, - const char *function); + const char *function, + int flags = 0); }; /** diff --git a/src/syncevo/SyncContext.cpp b/src/syncevo/SyncContext.cpp index d157a19e..13b0aaa6 100644 --- a/src/syncevo/SyncContext.cpp +++ b/src/syncevo/SyncContext.cpp @@ -73,6 +73,10 @@ using namespace std; #include <synthesis/SDK_util.h> #include <synthesis/san.h> +#ifdef USE_DLT +# include <dlt.h> +#endif + #include "test.h" #include <syncevo/declarations.h> @@ -279,6 +283,9 @@ class LogDirLogger : public Logger { Logger::Handle m_parentLogger; /**< the logger which was active before we started to intercept messages */ boost::weak_ptr<LogDir> m_logdir; /**< grants access to report and Synthesis engine */ +#ifdef USE_DLT + bool m_useDLT; /**< SyncEvolution and libsynthesis are logging to DLT */ +#endif public: LogDirLogger(const boost::weak_ptr<LogDir> &logdir); @@ -930,6 +937,9 @@ private: LogDirLogger::LogDirLogger(const boost::weak_ptr<LogDir> &logdir) : m_parentLogger(Logger::instance()), m_logdir(logdir) +#ifdef USE_DLT + , m_useDLT(getenv("SYNCEVOLUTION_USE_DLT") != NULL) +#endif { } @@ -958,8 +968,16 @@ void LogDirLogger::messagev(const MessageOptions &options, m_parentLogger.messagev(options, format, argscopy); va_end(argscopy); - boost::shared_ptr<LogDir> logdir = m_logdir.lock(); - if (logdir) { + // Special handling of our own messages: include in sync report + // (always, because that is how we did it traditionally) and write + // to our own syncevolution-log.html (if not already logged). + // + // The TestLocalSync.testServerFailure and some others check that + // we record the child's error message in our sync report. If we + // don't then it shows up later marked as an "error on the target + // side", which is probably not what we want. + boost::shared_ptr<LogDir> logdir; + if ((bool)(logdir = m_logdir.lock())) { if (logdir->m_report && options.m_level <= ERROR && logdir->m_report->getError().empty()) { @@ -971,7 +989,14 @@ void LogDirLogger::messagev(const MessageOptions &options, logdir->m_report->setError(error); } - if (logdir->m_client.getEngine().get()) { + if (!(options.m_flags & MessageOptions::ALREADY_LOGGED) && +#ifdef USE_DLT + // Don't send to libsynthesis if using DLT, + // because then it would end up getting logged + // in DLT twice. + !m_useDLT && +#endif + logdir->m_client.getEngine().get()) { va_list argscopy; va_copy(argscopy, args); // Once to Synthesis log, with full debugging. @@ -2646,23 +2671,77 @@ void SyncContext::getConfigXML(string &xml, string &configname) stringstream debug; bool logging = !m_sourceListPtr->getLogdir().empty(); int loglevel = getLogLevel(); +#ifdef USE_DLT + const char *useDLT = getenv("SYNCEVOLUTION_USE_DLT"); +#else + static const char *useDLT = NULL; +#endif debug << " <debug>\n" // logpath is a config variable set by SyncContext::doSync() " <logpath>$(logpath)</logpath>\n" - " <filename>" << - LogfileBasename << "</filename>" << + " <filename>" << (useDLT ? "" : LogfileBasename) << "</filename>" << " <logflushmode>flush</logflushmode>\n" - " <logformat>html</logformat>\n" - " <folding>auto</folding>\n" - " <timestamp>yes</timestamp>\n" - " <timestampall>yes</timestampall>\n" + " <logformat>" << (useDLT ? "dlt" : "html") << "</logformat>\n" + " <folding>auto</folding>\n" << + (useDLT ? + " <timestamp>no</timestamp>\n" + " <timestampall>no</timestampall>\n" : + " <timestamp>yes</timestamp>\n" + " <timestampall>yes</timestampall>\n") << " <timedsessionlognames>no</timedsessionlognames>\n" " <subthreadmode>separate</subthreadmode>\n" " <logsessionstoglobal>yes</logsessionstoglobal>\n" " <singlegloballog>yes</singlegloballog>\n"; - if (logging) { +#ifdef USE_DLT + if (useDLT) { + const char *contexts[] = { + "PROT", + "SESS", + "ADMN", + "DATA", + "REMI", + "PARS", + "GEN", + "TRNS", + "SMLT", + "SYS" + }; + BOOST_FOREACH (const char *context, contexts) { + // Help libsynthesis debuglogger.cpp set default log levels, + // based on our own one. + SE_LOG_DEBUG(NULL, "default libsynthesis DLT logging of %s = %s", + context, useDLT); + setenv((std::string("LIBSYNTHESIS_") + context).c_str(), + useDLT, + false); + } + + debug << + // We have to enable all logging inside libsynthesis. + // The actual filtering then takes place inside DLT. + // Message logging is not supported. + " <enable option=\"all\"/>\n" + // Allow logging outside of sessions. + " <globallogs>yes</globallogs>\n" + // Don't try per-session logging, it all goes to DLT anyway. + " <sessionlogs>yes</sessionlogs>\n" + ; + + // Be extra verbose if currently enabled. Cannot be changed later on. + if (atoi(useDLT) > DLT_LOG_DEBUG) { + debug << + " <enable option=\"userdata\"/>\n" + " <enable option=\"scripts\"/>\n"; + } + if (atoi(useDLT) > DLT_LOG_DEBUG) { + debug << + " <enable option=\"exotic\"/>\n"; + } + } else +#endif // USE_DLT + if (logging) { debug << " <sessionlogs>yes</sessionlogs>\n" " <globallogs>yes</globallogs>\n"; diff --git a/src/syncevo/syncevo.am b/src/syncevo/syncevo.am index 5d25ba4f..17940179 100644 --- a/src/syncevo/syncevo.am +++ b/src/syncevo/syncevo.am @@ -49,6 +49,8 @@ src_syncevo_sources = \ \ src/syncevo/Logging.h \ src/syncevo/Logging.cpp \ + src/syncevo/LogDLT.h \ + src/syncevo/LogDLT.cpp \ src/syncevo/LogStdout.h \ src/syncevo/LogStdout.cpp \ src/syncevo/LogRedirect.h \ @@ -212,6 +214,7 @@ src_syncevo_libsyncevolution_la_LIBADD = \ $(TRANSPORT_LIBS) \ @LIBS@ \ $(src_syncevo_ldadd) \ + $(DLT_LIBS) \ $(DBUS_LIBS) \ $(NSS_LIBS) if ENABLE_MODULES @@ -228,6 +231,7 @@ src_syncevo_libsyncevolution_la_CFLAGS = \ $(SYNCEVO_WFLAGS) src_syncevo_libsyncevolution_la_CPPFLAGS = \ $(src_syncevo_cppflags) \ + $(DLT_CFLAGS) \ $(DBUS_CFLAGS) \ -DDATA_DIR=\""$(pkgdatadir)"\" \ -DXML_CONFIG_DIR=\""$(datadir)/syncevolution/xml"\" \ diff --git a/test/test-dbus.py b/test/test-dbus.py index d6165cfa..720fd5d3 100755 --- a/test/test-dbus.py +++ b/test/test-dbus.py @@ -4317,7 +4317,7 @@ END:VCARD''') 'sending message to child failed: The connection is closed')) self.assertSyncStatus('target_+config@client', 22002, 'synchronization process died prematurely') - @timeout(200) + @timeout(600) def testServerFailure(self): """TestLocalSync.testServerFailure - check that D-Bus helper detects when server dies""" self.setUpConfigs(childPassword="-") |