RTT::Logger patch allowing creation with automatic attachment to ostream

Useful in automated unit tests, to create a logger singleton that is associated with an output stream _before_ it starts logging anything. The existing implementation will output a few lines to the console from within the logger constructor, before you can attach the singleton to an ostream.

If the logger singleton already exists, then this patch does not change it. You could modify that behaviour to instead associate the logger with the given stream. Thoughts?

To use the new functionality, do the following before the logger is used. This will sink all logger output to the string stream, instead of to the console.

{{{
...
// stream that Orocos logger is associated with
std::ostringstream str;

// Force creation of the singleton logger, and associate it with the
// above strstream instead of having the logger output to console
// The logger still outputs to the "orocos.log" file.
(void)RTT::Logger::Instance(str);
...
}}}

By the way, how do you attach files to a forum post from a web browser? Just attach it as an image???

Feedback appreciated
S

Index: Logger.hpp
===================================================================
--- Logger.hpp (revision 29209)
+++ Logger.hpp (working copy)
@@ -173,6 +173,17 @@
static Logger* Instance();

/**
+ * Get the singleton logger.
+ * \post If the singleton did not alreay exist then the new
+ * instance is associated with the given stream. Otherwise
+ * no change in the existing instance, and the given stream is
+ * ignored.
+ */
+#ifndef OROSEM_PRINTF_LOGGING
+ static Logger* Instance(std::ostream& str);
+#endif
+
+ /**
* Delete the singleton logger.
*/
static void Release();
@@ -284,6 +295,9 @@
bool mayLog() const;

Logger();
+#ifndef OROSEM_PRINTF_LOGGING
+ Logger(std::ostream& str);
+#endif
~Logger();

static Logger* _instance;
Index: Logger.cpp
===================================================================
--- Logger.cpp (revision 29209)
+++ Logger.cpp (working copy)
@@ -74,6 +74,14 @@
return _instance;
}

+ Logger* Logger::Instance(std::ostream& str) {
+ if (_instance == 0) {
+ _instance = new Logger(str);
+ }
+ // else ignore attempted use of ostream
+ return _instance;
+ }
+
void Logger::Release() {
if (_instance) {
_instance->shutdown();
@@ -118,6 +126,29 @@
#endif
}

+#ifndef OROSEM_PRINTF_LOGGING
+ D(std::ostream& str) :
+#ifndef OROSEM_PRINTF_LOGGING
+ stdoutput(&str),
+#endif
+#ifdef OROSEM_REMOTE_LOGGING
+ messagecnt(0),
+#endif
+#if defined(OROSEM_FILE_LOGGING) && !defined(OROSEM_PRINTF_LOGGING)
+ logfile("orocos.log"),
+#endif
+ inloglevel(Info),
+ outloglevel(Warning),
+ timestamp(0),
+ started(false), showtime(true), allowRT(false),
+ loggermodule("Logger"), moduleptr(loggermodule)
+ {
+#if defined(OROSEM_FILE_LOGGING) && defined(OROSEM_PRINTF_LOGGING)
+ logfile = fopen("orocos.log","w");
+#endif
+ }
+#endif
+
bool maylog() const {
if (!started || (outloglevel == RealTime && allowRT == false))
return false;
@@ -294,6 +325,14 @@
this->startup();
}

+#ifndef OROSEM_PRINTF_LOGGING
+ Logger::Logger(std::ostream& str)
+ :d ( new Logger::D(str) )
+ {
+ this->startup();
+ }
+#endif
+
Logger::~Logger()
{
delete d;

RTT::Logger patch allowing creation with automatic attachment to

On Wednesday 30 April 2008 15:05:38 snrkiwi wrote:
> Useful in automated unit tests, to create a logger singleton that is
> associated with an output stream _before_ it starts logging anything. The
> existing implementation will output a few lines to the console from within
> the logger constructor, before you can attach the singleton to an ostream.
>
> If the logger singleton already exists, then this patch does not change it.
> You could modify that behaviour to instead associate the logger with the
> given stream. Thoughts?

The patch is ok, but could have been smaller. You could have rewritten the
existing 'D' constructor with a default argument like in:

D(std::ostream& outp = &std::cerr) :
#ifndef OROSEM_PRINTF_LOGGING
stdoutput( &outp ),
#endif

instead of duplicating it completely. This actually holds for Instance() and
Logger() as well. You could probably reduce this patch to changing only 3
functions (Instance(), Logger() and D() )

>
> To use the new functionality, do the following before the logger is used.
> This will sink all logger output to the string stream, instead of to the
> console.
>
> {{{
> ...
> // stream that Orocos logger is associated with
> std::ostringstream str;
>
> // Force creation of the singleton logger, and associate it with the
> // above strstream instead of having the logger output to console
> // The logger still outputs to the "orocos.log" file.
> (void)RTT::Logger::Instance(str);
> ...
> }}}
>
> By the way, how do you attach files to a forum post from a web browser?
> Just attach it as an image???

You'd better not use the forum at all to post patches, because they get
filtered and messed up. The patch that arrived (inline) on the orocos-dev
mailinglist was not usable. Maybe this will be possible when we upgrade to
Drupal 6 (after RTT 1.6.0 has been released).

Peter

>
> Feedback appreciated
> S
>
>
> Index: Logger.hpp
> ===================================================================
> --- Logger.hpp (revision 29209)
> +++ Logger.hpp (working copy)
> @@ -173,6 +173,17 @@
> static Logger* Instance();
>
> /**
> + * Get the singleton logger.
> + * \post If the singleton did not alreay exist then the new
> + * instance is associated with the given stream. Otherwise
> + * no change in the existing instance, and the given stream is
> + * ignored.
> + */
> +#ifndef OROSEM_PRINTF_LOGGING
> + static Logger* Instance(std::ostream& str);
> +#endif
> +
> + /**
> * Delete the singleton logger.
> */
> static void Release();
> @@ -284,6 +295,9 @@
> bool mayLog() const;
>
> Logger();
> +#ifndef OROSEM_PRINTF_LOGGING
> + Logger(std::ostream& str);
> +#endif
> ~Logger();
>
> static Logger* _instance;
> Index: Logger.cpp
> ===================================================================
> --- Logger.cpp (revision 29209)
> +++ Logger.cpp (working copy)
> @@ -74,6 +74,14 @@
> return _instance;
> }
>
> + Logger* Logger::Instance(std::ostream& str) {
> + if (_instance == 0) {
> + _instance = new Logger(str);
> + }
> + // else ignore attempted use of ostream
> + return _instance;
> + }
> +
> void Logger::Release() {
> if (_instance) {
> _instance->shutdown();
> @@ -118,6 +126,29 @@
> #endif
> }
>
> +#ifndef OROSEM_PRINTF_LOGGING
> + D(std::ostream& str) :
> +#ifndef OROSEM_PRINTF_LOGGING
> + stdoutput(&str),
> +#endif
> +#ifdef OROSEM_REMOTE_LOGGING
> + messagecnt(0),
> +#endif
> +#if defined(OROSEM_FILE_LOGGING) && !defined(OROSEM_PRINTF_LOGGING)
> + logfile("orocos.log"),
> +#endif
> + inloglevel(Info),
> + outloglevel(Warning),
> + timestamp(0),
> + started(false), showtime(true), allowRT(false),
> + loggermodule("Logger"), moduleptr(loggermodule)
> + {
> +#if defined(OROSEM_FILE_LOGGING) && defined(OROSEM_PRINTF_LOGGING)
> + logfile = fopen("orocos.log","w");
> +#endif
> + }
> +#endif
> +
> bool maylog() const {
> if (!started || (outloglevel == RealTime && allowRT == false))
> return false;
> @@ -294,6 +325,14 @@
> this->startup();
> }
>
> +#ifndef OROSEM_PRINTF_LOGGING
> + Logger::Logger(std::ostream& str)
> + :d ( new Logger::D(str) )
> + {
> + this->startup();
> + }
> +#endif
> +
> Logger::~Logger()
> {
> delete d;

RTT::Logger patch allowing creation with automatic attachment to

>The patch is ok, but could have been smaller. You could have rewritten the
>existing 'D' constructor with a default argument like in:
>
> D(std::ostream& outp = &std::cerr) :
> #ifndef OROSEM_PRINTF_LOGGING
> stdoutput( &outp ),
> #endif
>
>instead of duplicating it completely. This actually holds for Instance() and
>Logger() as well. You could probably reduce this patch to changing only 3
>functions (Instance(), Logger() and D() )

Did not know if that would have been acceptable. Smaller patch below.
S

Index: src/Logger.hpp
===================================================================
--- src/Logger.hpp (revision 29197)
+++ src/Logger.hpp (working copy)
@@ -47,6 +47,9 @@
#include
#endif
#include
+#ifndef OROSEM_PRINTF_LOGGING
+#include // for std::cerr
+#endif

namespace RTT
{
@@ -169,8 +172,12 @@

/**
* Get the singleton logger.
+ * \post If the singleton did not already exist then it is created
+ * and associated with the given ostream. If the singleton already
+ * existed then no change occurs (and the singleton remains associated
+ * with its existing ostream).
*/
- static Logger* Instance();
+ static Logger* Instance(std::ostream& str=std::cerr);

/**
* Delete the singleton logger.
@@ -283,7 +290,7 @@
*/
bool mayLog() const;

- Logger();
+ Logger(std::ostream& str=std::cerr);
~Logger();

static Logger* _instance;
Index: src/Logger.cpp
===================================================================
--- src/Logger.cpp (revision 29197)
+++ src/Logger.cpp (working copy)
@@ -67,9 +67,9 @@

Logger* Logger::_instance = 0;

- Logger* Logger::Instance() {
+ Logger* Logger::Instance(std::ostream& str) {
if (_instance == 0) {
- _instance = new Logger();
+ _instance = new Logger(str);
}
return _instance;
}
@@ -97,9 +97,9 @@
*/
struct Logger::D
{
- D() :
+ D(std::ostream& str) :
#ifndef OROSEM_PRINTF_LOGGING
- stdoutput(&std::cerr),
+ stdoutput(str),
#endif
#ifdef OROSEM_REMOTE_LOGGING
messagecnt(0),

RTT::Logger patch allowing creation with automatic attachment to

On Wednesday 30 April 2008 17:58:19 S Roderick wrote:
> >The patch is ok, but could have been smaller. You could have rewritten the
> >existing 'D' constructor with a default argument like in:
> >
> > D(std::ostream& outp = &std::cerr) :
> > #ifndef OROSEM_PRINTF_LOGGING
> > stdoutput( &outp ),
> > #endif
> >
> >instead of duplicating it completely. This actually holds for Instance()
> > and Logger() as well. You could probably reduce this patch to changing
> > only 3 functions (Instance(), Logger() and D() )
>
> Did not know if that would have been acceptable. Smaller patch below.

$ svn ci src/ -m"Applied patch by S. Roderick: RTT::Logger patch allowing
creation with automatic attachment to ostream."
Sending src/Logger.cpp
Sending src/Logger.hpp
Transmitting file data ..
Committed revision 29225.

Applied, thanks. I had to adjust some whitespace in the Logger.hpp file.

Peter

Incomplete patch

The patch I shipped you appears to have been incomplete. No idea how ... Following are the corrections to make r29230 compile cleanly.

Sorry
S

Index: src/Logger.cpp
===================================================================
--- src/Logger.cpp (revision 29230)
+++ src/Logger.cpp (working copy)
@@ -99,7 +99,7 @@
{
D(std::ostream& str) :
#ifndef OROSEM_PRINTF_LOGGING
- stdoutput(str),
+ stdoutput(&str),
#endif
#ifdef OROSEM_REMOTE_LOGGING
messagecnt(0),
@@ -288,8 +288,8 @@
OS::Mutex startguard;
};

- Logger::Logger()
- :d ( new Logger::D() )
+ Logger::Logger(std::ostream& str)
+ :d ( new Logger::D(str) )
{
this->startup();
}

Incomplete patch

On Monday 05 May 2008 20:53:18 snrkiwi wrote:
> The patch I shipped you appears to have been incomplete. No idea how ...
> Following are the corrections to make r29230 compile cleanly.

Just figured that out myself. So far for 'many eyes catch many bugs' :-)

Peter