You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by sh...@apache.org on 2008/10/16 00:33:35 UTC

svn commit: r705083 - in /incubator/qpid/trunk/qpid/cpp: docs/man/ src/ src/qpid/ src/qpid/log/ src/qpid/log/posix/ src/tests/

Author: shuston
Date: Wed Oct 15 15:33:34 2008
New Revision: 705083

URL: http://svn.apache.org/viewvc?rev=705083&view=rev
Log:
Split logging options into portable options and sink-related options that are platform-specific. Re-did sink options for Posix as discussed on qpid-dev (no more --log-output, but more specific --log-to-<target> options. Allows addition of Windows options without further reorg of Posix code.

Added:
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/SinkOptions.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.h
Modified:
    incubator/qpid/trunk/qpid/cpp/docs/man/qpidd.x
    incubator/qpid/trunk/qpid/cpp/src/Makefile.am
    incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.h
    incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp
    incubator/qpid/trunk/qpid/cpp/src/tests/logging.cpp
    incubator/qpid/trunk/qpid/cpp/src/tests/start_broker
    incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster
    incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster_hosts

Modified: incubator/qpid/trunk/qpid/cpp/docs/man/qpidd.x
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/docs/man/qpidd.x?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/docs/man/qpidd.x (original)
+++ incubator/qpid/trunk/qpid/cpp/docs/man/qpidd.x Wed Oct 15 15:33:34 2008
@@ -28,8 +28,8 @@
   # My qpidd configuration file.
   port=6000
   max-connections=10
-  log-output=stdout
-  log-output=/tmp/qpidd.log
+  log-to-stdout=yes
+  log-to-file=/tmp/qpidd.log
 
 [ENVIRONMENT]
 .I QPID_<option>
@@ -41,6 +41,6 @@
 
   export QPID_PORT=6000
   export QPID_MAX_CONNECTIONS=10
-  export QPID_LOG_OUTPUT=/tmp/qpidd.log
+  export QPID_LOG_TO_FILE=/tmp/qpidd.log
 
 

Modified: incubator/qpid/trunk/qpid/cpp/src/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/Makefile.am?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/Makefile.am Wed Oct 15 15:33:34 2008
@@ -68,6 +68,7 @@
 qpidd_SOURCES = qpidd.cpp
 
 posix_plat_src = \
+  qpid/log/posix/SinkOptions.cpp \
   qpid/sys/posix/IOHandle.cpp \
   qpid/sys/posix/Socket.cpp \
   qpid/sys/posix/AsynchIO.cpp \
@@ -83,6 +84,7 @@
   qpid/sys/posix/PollableCondition.cpp
 
 posix_plat_hdr = \
+  qpid/log/posix/SinkOptions.h \
   qpid/sys/posix/check.h \
   qpid/sys/posix/Condition.h \
   qpid/sys/posix/PrivatePosix.h \
@@ -117,15 +119,6 @@
 include qmf.mk
 include xml.mk
 
-# The logger library uses boost::date_time to format time.
-# We have to disable the unused parameters warning to get around
-# unused parameters in boost::date_time headers. So we build it
-# in a convenience library to link into libqpid_common.
-# 
-noinst_LTLIBRARIES=libLogger.la # libqpidamqp_0_10.la
-libLogger_la_SOURCES=qpid/log/Logger.cpp qpid/log/Logger.h
-libLogger_la_CXXFLAGS=$(AM_CXXFLAGS) -Wno-unused-parameter
-
 if RDMA
 
 # RDMA (Infiniband) protocol code
@@ -222,19 +215,28 @@
   -lboost_program_options \
   -lboost_filesystem \
   -luuid \
-  libLogger.la \
   $(LIB_DLOPEN) \
   $(LIB_CLOCK_GETTIME)
 
 libqpidcommon_la_SOURCES = \
   $(rgen_framing_srcs) \
   $(platform_src) \
-  qpid/amqp_0_10/SessionHandler.h \
-  qpid/amqp_0_10/SessionHandler.cpp \
+  qpid/assert.cpp qpid/assert.h \
+  qpid/pointer_to_other.h \
+  qpid/DataDir.cpp \
+  qpid/Exception.cpp \
+  qpid/Options.cpp \
+  qpid/Plugin.cpp \
+  qpid/RefCountedBuffer.h \
+  qpid/RefCountedBuffer.cpp \
   qpid/Serializer.h \
   qpid/SessionState.h \
   qpid/SessionState.cpp \
   qpid/SessionId.cpp \
+  qpid/StringUtils.cpp \
+  qpid/Url.cpp \
+  qpid/amqp_0_10/SessionHandler.h \
+  qpid/amqp_0_10/SessionHandler.cpp \
   qpid/framing/AccumulatedAck.cpp \
   qpid/framing/AMQBody.cpp \
   qpid/framing/AMQMethodBody.cpp \
@@ -262,11 +264,11 @@
   qpid/framing/Blob.cpp \
   qpid/framing/MaxMethodBodySize.h \
   qpid/framing/TransferContent.cpp \
-  qpid/assert.cpp qpid/assert.h \
-  qpid/Exception.cpp \
-  qpid/Plugin.cpp \
-  qpid/StringUtils.cpp \
-  qpid/Url.cpp \
+  qpid/log/Logger.cpp \
+  qpid/log/Options.cpp \
+  qpid/log/OstreamOutput.cpp \
+  qpid/log/Selector.cpp \
+  qpid/log/Statement.cpp \
   qpid/management/Manageable.cpp \
   qpid/management/ManagementObject.cpp \
   qpid/sys/AggregateOutput.cpp \
@@ -275,15 +277,7 @@
   qpid/sys/PollableCondition.h \
   qpid/sys/PollableQueue.h \
   qpid/sys/Runnable.cpp \
-  qpid/sys/Shlib.cpp \
-  qpid/DataDir.cpp \
-  qpid/Options.cpp \
-  qpid/log/Options.cpp \
-  qpid/RefCountedBuffer.h \
-  qpid/RefCountedBuffer.cpp \
-  qpid/log/Selector.cpp \
-  qpid/log/Statement.cpp \
-  qpid/pointer_to_other.h
+  qpid/sys/Shlib.cpp
 
 libqpidbroker_la_LIBADD = libqpidcommon.la -luuid
 if HAVE_SASL
@@ -578,7 +572,9 @@
   qpid/log/Helpers.h \
   qpid/log/Options.h \
   qpid/log/Logger.h \
+  qpid/log/OstreamOutput.h \
   qpid/log/Selector.h \
+  qpid/log/SinkOptions.h \
   qpid/log/Statement.h \
   qpid/management/Args.h \
   qpid/management/Manageable.h \

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/Plugin.h Wed Oct 15 15:33:34 2008
@@ -28,7 +28,7 @@
 /**@file Generic plug-in framework. */
 
 namespace qpid {
-class Options;
+struct Options;
 
 /**
  * Plug-in base class.

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.cpp?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.cpp Wed Oct 15 15:33:34 2008
@@ -17,18 +17,17 @@
  */
 
 #include "Logger.h"
+#include "Options.h"
+#include "SinkOptions.h"
 #include "qpid/memory.h"
 #include "qpid/sys/Thread.h"
 #include <boost/pool/detail/singleton.hpp>
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
-#include <boost/scoped_ptr.hpp>
 #include <algorithm>
 #include <sstream>
-#include <fstream>
 #include <iomanip>
 #include <stdexcept>
-#include <syslog.h>
 #include <time.h>
 
 
@@ -43,45 +42,6 @@
     s->enabled=selector.isEnabled(s->level, s->function);
 }
 
-struct OstreamOutput : public Logger::Output {
-    OstreamOutput(std::ostream& o) : out(&o) {}
-
-    OstreamOutput(const string& file)
-        : out(new ofstream(file.c_str(), ios_base::out | ios_base::app)),
-          mine(out)
-    {
-        if (!out->good())
-            throw std::runtime_error("Can't open log file: "+file);
-    }
-
-    void log(const Statement&, const std::string& m) {
-        *out << m << flush;
-    }
-    
-    ostream* out;
-    boost::scoped_ptr<ostream> mine;
-};
-
-struct SyslogOutput : public Logger::Output {
-    SyslogOutput(const Options& opts)
-        : name(opts.syslogName), facility(opts.syslogFacility.value)
-    {
-        ::openlog(name.c_str(), LOG_PID, facility);
-    }
-
-    ~SyslogOutput() {
-        ::closelog();
-    }
-    
-    void log(const Statement& s, const std::string& m)
-    {
-        syslog(LevelTraits::priority(s.level), "%s", m.c_str());
-    }
-    
-    std::string name;
-    int facility;
-};
-
 Logger& Logger::instance() {
     return boost::details::pool::singleton_default<Logger>::instance();
 }
@@ -158,25 +118,6 @@
     outputs.push_back(out.release());
 }
 
-void Logger::output(std::ostream& out) {
-    output(make_auto_ptr<Output>(new OstreamOutput(out)));
-}
-
-void Logger::syslog(const Options& opts) {
-    output(make_auto_ptr<Output>(new SyslogOutput(opts)));
-}
-
-void Logger::output(const std::string& name, const Options& opts) {
-    if (name=="stderr")
-        output(clog);
-    else if (name=="stdout")
-        output(cout);
-    else if (name=="syslog")
-        syslog(opts);
-    else 
-        output(make_auto_ptr<Output>(new OstreamOutput(name)));
-}
-
 void Logger::clear() {
     select(Selector());         // locked
     format(0);                  // locked
@@ -218,10 +159,8 @@
         o.selectors.push_back("trace+");
     format(o); 
     select(Selector(o));
-    void (Logger::* outputFn)(const std::string&, const Options&) = &Logger::output;
-    for_each(o.outputs.begin(), o.outputs.end(),
-             boost::bind(outputFn, this, _1, boost::cref(o)));
     setPrefix(opts.prefix);
+    options.sinkOptions->setup(this);
 }
 
 void Logger::setPrefix(const std::string& p) { prefix = p; }

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.h?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/Logger.h Wed Oct 15 15:33:34 2008
@@ -26,15 +26,25 @@
  * Central logging agent.
  *
  * Thread safe, singleton.
+ *
+ * The Logger provides all needed functionality for selecting and
+ * formatting logging output. The actual outputting of log records
+ * is handled by Logger::Output-derived classes instantiated by the
+ * platform's sink-related options.
  */
 class Logger : private boost::noncopyable {
   public:
     /** Flags indicating what to include in the log output */
     enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32};
 
-    /** Interface for log output destination.
-     * 
-     * Implementations must be thread safe.
+    /**
+     * Logging output sink.
+     *
+     * The Output sink provides an interface to direct logging output to.
+     * Logging sinks are primarily platform-specific as provided for on
+     * each platform.
+     *
+     * Implementations of Output must be thread safe.
      */
     class Output {
       public:
@@ -43,7 +53,7 @@
         /** Receives the statemnt of origin and formatted message to log. */
         virtual void log(const Statement&, const std::string&) =0;
     };
-    
+
     static Logger& instance();
 
     Logger();
@@ -69,25 +79,8 @@
     /** Log a message. */
     void log(const Statement&, const std::string&);
 
-    /** Add an ostream to outputs.
-     * 
-     * The ostream must not be destroyed while the Logger might
-     * still be using it. This is the case for std streams cout,
-     * cerr, clog. 
-     */
-    void output(std::ostream&);
-
-    /** Add syslog to outputs. */
-    void syslog(const Options&);
-
-    /** Add an output.
-     *@param name a file name or one of the special tokens:
-     *stdout, stderr, syslog.
-     */
-    void output(const std::string& name, const Options&);
-
     /** Add an output destination for messages */
-    void output(std::auto_ptr<Output> out); 
+    void output(std::auto_ptr<Output> out);
 
     /** Set a prefix for all messages */
     void setPrefix(const std::string& prefix);

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.cpp?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.cpp Wed Oct 15 15:33:34 2008
@@ -17,115 +17,38 @@
  */
 
 #include "Options.h"
+#include "SinkOptions.h"
 #include "Statement.h"
 #include "qpid/Options.h"
 #include <map>
 #include <string>
 #include <algorithm>
-#include <syslog.h>
 
 namespace qpid {
 namespace log {
 
 using namespace std;
 
-namespace {
-
-class SyslogFacilities {
-  public:
-    typedef map<string, int> ByName;
-    typedef map<int, string> ByValue;
-
-    SyslogFacilities() {
-        struct NameValue { const char* name; int value; };
-        NameValue nameValue[] = {
-            { "AUTH", LOG_AUTH },
-            { "AUTHPRIV", LOG_AUTHPRIV },
-            { "CRON", LOG_CRON },
-            { "DAEMON", LOG_DAEMON },
-            { "FTP", LOG_FTP },
-            { "KERN", LOG_KERN },
-            { "LOCAL0", LOG_LOCAL0 },
-            { "LOCAL1", LOG_LOCAL1 },
-            { "LOCAL2", LOG_LOCAL2 },
-            { "LOCAL3", LOG_LOCAL3 },
-            { "LOCAL4", LOG_LOCAL4 },
-            { "LOCAL5", LOG_LOCAL5 },
-            { "LOCAL6", LOG_LOCAL6 },
-            { "LOCAL7", LOG_LOCAL7 },
-            { "LPR", LOG_LPR },
-            { "MAIL", LOG_MAIL },
-            { "NEWS", LOG_NEWS },
-            { "SYSLOG", LOG_SYSLOG },
-            { "USER", LOG_USER },
-            { "UUCP", LOG_UUCP }
-        };
-        for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) {
-            byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value));
-            // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH
-            byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value));
-            byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name));
-        }
-    };
-    
-    int value(const string& name) const {
-        string key(name);
-        transform(key.begin(), key.end(), key.begin(), ::toupper);        
-        ByName::const_iterator i = byName.find(key);
-        if (i == byName.end())
-            throw Exception("Not a valid syslog facility: " + name);
-        return i->second;
-    }
-
-    string name(int value) const {
-        ByValue::const_iterator i = byValue.find(value);
-        if (i == byValue.end())
-            throw Exception("Not a valid syslog value: " + value);
-        return i->second;
-    }
-
-  private:
-    ByName byName;
-    ByValue byValue;
-};
-
-}
-
-ostream& operator<<(ostream& o, const SyslogFacility& f) {
-    return o << SyslogFacilities().name(f.value);
-}
-
-istream& operator>>(istream& i, SyslogFacility& f) {
-    std::string name;
-    i >> name;
-    f.value = SyslogFacilities().value(name);
-    return i;
-}
-
-namespace {
-std::string basename(const std::string path) {
-    size_t i = path.find_last_of('/');
-    return path.substr((i == std::string::npos) ? 0 : i+1);
-}
-}
-
-Options::Options(const std::string& argv0, const std::string& name) :
-    qpid::Options(name),
-    time(true), level(true), thread(false), source(false), function(false), trace(false),
-    syslogName(basename(argv0)), syslogFacility(LOG_DAEMON)
+Options::Options(const std::string& argv0_, const std::string& name_) :
+    qpid::Options(name_),
+    argv0(argv0_),
+    name(name_),
+    time(true),
+    level(true),
+    thread(false),
+    source(false),
+    function(false),
+    trace(false),
+    sinkOptions (SinkOptions::create(argv0_))
 {
-    outputs.push_back("stderr");
     selectors.push_back("error+");
 
     ostringstream levels;
     levels << LevelTraits::name(Level(0));
     for (int i = 1; i < LevelTraits::COUNT; ++i)
         levels << " " << LevelTraits::name(Level(i));
-    
+
     addOptions()
-        ("log-output", optValue(outputs, "FILE"), "Send log output to FILE. "
-         "FILE can be a file name or one of the special values:\n"
-         "stderr, stdout, syslog")
         ("trace,t", optValue(trace), "Enables all logging" )
         ("log-enable", optValue(selectors, "RULE"),
          ("Enables logging for selected levels and components. " 
@@ -143,24 +66,40 @@
         ("log-thread", optValue(thread,"yes|no"), "Include thread ID in log messages")
         ("log-function", optValue(function,"yes|no"), "Include function signature in log messages")
         ("log-prefix", optValue(prefix,"STRING"), "Prefix to append to all log messages")
-        ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages")
-        ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages")
         ;
+    add(*sinkOptions);
+}
+
+Options::Options(const Options &o) :
+    qpid::Options(o.name),
+    argv0(o.argv0),
+    name(o.name),
+    selectors(o.selectors),
+    time(o.time),
+    level(o.level),
+    thread(o.thread),
+    source(o.source),
+    function(o.function),
+    trace(o.trace),
+    prefix(o.prefix),
+    sinkOptions (SinkOptions::create(o.argv0))
+{
+    *sinkOptions = *o.sinkOptions;
 }
 
 Options& Options::operator=(const Options& x) {
     if (this != &x) {
+        argv0 = x.argv0;
+        name = x.name;
         selectors = x.selectors;
-        outputs = x.outputs;
         time = x.time;
         level= x.level;
         thread = x.thread;
         source = x.source;
         function = x.function;
         trace = x.trace;
-        syslogName = x.syslogName;
-        syslogFacility = x.syslogFacility;
         prefix = x.prefix;
+        *sinkOptions = *x.sinkOptions;
     }
     return *this;
 }

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.h?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/Options.h Wed Oct 15 15:33:34 2008
@@ -1,5 +1,5 @@
-#ifndef OPTIONS_H
-#define OPTIONS_H
+#ifndef QPID_LOG_OPTIONS_H
+#define QPID_LOG_OPTIONS_H
 
 /*
  *
@@ -19,40 +19,31 @@
  *
  */
 #include "qpid/Options.h"
+#include "SinkOptions.h"
 #include <iosfwd>
+#include <memory>
 
 namespace qpid {
 namespace log {
 
-/** Provides << and >> operators to convert syslog facility values to/from strings. */
-struct SyslogFacility {
-    int value;
-    SyslogFacility(int i=0) : value(i) {}
-};
-
-std::ostream& operator<<(std::ostream&, const SyslogFacility&);
-std::istream& operator>>(std::istream&, SyslogFacility&);
-
 /** Logging options for config parser. */
 struct Options : public qpid::Options {
     /** Pass argv[0] for use in syslog output */
-    Options(const std::string& argv0=std::string(),
-            const std::string& name="Logging options");
+    Options(const std::string& argv0_=std::string(),
+            const std::string& name_="Logging options");
+    Options(const Options &);
 
     Options& operator=(const Options&);
 
+    std::string argv0;
+    std::string name;
     std::vector<std::string> selectors;
-    std::vector<std::string> outputs;
     bool time, level, thread, source, function;
     bool trace;
-    std::string syslogName;
-    SyslogFacility syslogFacility;
     std::string prefix;
+    std::auto_ptr<SinkOptions> sinkOptions;
 };
 
-
 }} // namespace qpid::log
 
-
-
-#endif  /*!OPTIONS_H*/
+#endif  /*!QPID_LOG_OPTIONS_H*/

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.cpp?rev=705083&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.cpp Wed Oct 15 15:33:34 2008
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "OstreamOutput.h"
+#include <stdexcept>
+
+using namespace std;
+
+namespace qpid {
+namespace log {
+
+OstreamOutput::OstreamOutput(std::ostream& o) : out(&o) {}
+
+OstreamOutput::OstreamOutput(const std::string& file)
+  : out(new ofstream(file.c_str(), ios_base::out | ios_base::app)),
+    mine(out)
+{
+    if (!out->good())
+        throw std::runtime_error("Can't open log file: "+file);
+}
+
+void OstreamOutput::log(const Statement&, const std::string& m) {
+    *out << m << flush;
+}
+
+}} // namespace qpid::log

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.h?rev=705083&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/OstreamOutput.h Wed Oct 15 15:33:34 2008
@@ -0,0 +1,41 @@
+#ifndef QPID_LOG_OSTREAMOUTPUT_H
+#define QPID_LOG_OSTREAMOUTPUT_H
+
+/*
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "Logger.h"
+#include <boost/scoped_ptr.hpp>
+#include <fstream>
+#include <ostream>
+
+namespace qpid {
+namespace log {
+
+/**
+ * OstreamOutput is a reusable logging sink that directs logging to a C++
+ * ostream.
+ */
+class OstreamOutput : public qpid::log::Logger::Output {
+public:
+    OstreamOutput(std::ostream& o);
+    OstreamOutput(const std::string& file);
+
+    virtual void log(const Statement&, const std::string& m);
+
+private:    
+    std::ostream* out;
+    boost::scoped_ptr<std::ostream> mine;
+};
+
+}} // namespace qpid::log
+
+#endif /*!QPID_LOG_OSTREAMOUTPUT_H*/

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/log/SinkOptions.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/SinkOptions.h?rev=705083&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/SinkOptions.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/SinkOptions.h Wed Oct 15 15:33:34 2008
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_SINKOPTIONS_H
+#define QPID_LOG_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/Options.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+
+class Logger;
+
+/**
+ * Logging sink options.
+ *
+ * Most logging sink options will be platform-specific, even if some are
+ * duplicated. The range of platforms to which this code may be ported
+ * can't be assumed to all have C++ iostreams or files. Thus, this class
+ * is primarily for implementing in a platform-specific way.
+ */
+struct SinkOptions : public qpid::Options {
+
+    // Create a platform's SinkOptions. Pass argv0 as the program name,
+    // useful for syslog-type logging.
+    static SinkOptions *create(const std::string& argv0=std::string());
+
+    SinkOptions(const std::string& name="Logging sink options")
+        : qpid::Options(name)
+    {}
+    virtual ~SinkOptions() {}
+
+    virtual SinkOptions& operator=(const SinkOptions&) = 0;
+
+    // This allows the caller to indicate that there's no normal outputs
+    // available. For example, when running as a daemon. In these cases, the
+    // platform's "syslog"-type output should replace the default stderr
+    // unless some other sink has been selected.
+    virtual void detached(void) = 0;
+
+    // The Logger acting on these options calls setup() to request any
+    // Sinks be set up and fed back to the logger.
+    virtual void setup(Logger *logger) = 0;
+};
+
+}} // namespace qpid::log
+
+#endif  /*!QPID_LOG_OPTIONS_H*/

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp?rev=705083&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp Wed Oct 15 15:33:34 2008
@@ -0,0 +1,211 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "SinkOptions.h"
+#include "qpid/log/SinkOptions.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Exception.h"
+#include <iostream>
+#include <map>
+#include <string>
+#include <syslog.h>
+
+using std::string;
+using qpid::Exception;
+
+namespace {
+
+// SyslogFacilities maps from syslog values to the text equivalents.
+class SyslogFacilities {
+public:
+    typedef std::map<string, int> ByName;
+    typedef std::map<int, string> ByValue;
+
+    SyslogFacilities() {
+        struct NameValue { const char* name; int value; };
+        NameValue nameValue[] = {
+            { "AUTH", LOG_AUTH },
+            { "AUTHPRIV", LOG_AUTHPRIV },
+            { "CRON", LOG_CRON },
+            { "DAEMON", LOG_DAEMON },
+            { "FTP", LOG_FTP },
+            { "KERN", LOG_KERN },
+            { "LOCAL0", LOG_LOCAL0 },
+            { "LOCAL1", LOG_LOCAL1 },
+            { "LOCAL2", LOG_LOCAL2 },
+            { "LOCAL3", LOG_LOCAL3 },
+            { "LOCAL4", LOG_LOCAL4 },
+            { "LOCAL5", LOG_LOCAL5 },
+            { "LOCAL6", LOG_LOCAL6 },
+            { "LOCAL7", LOG_LOCAL7 },
+            { "LPR", LOG_LPR },
+            { "MAIL", LOG_MAIL },
+            { "NEWS", LOG_NEWS },
+            { "SYSLOG", LOG_SYSLOG },
+            { "USER", LOG_USER },
+            { "UUCP", LOG_UUCP }
+        };
+        for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) {
+            byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value));
+            // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH
+            byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value));
+            byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name));
+        }
+    }
+    
+    int value(const string& name) const {
+        string key(name);
+        transform(key.begin(), key.end(), key.begin(), ::toupper);        
+        ByName::const_iterator i = byName.find(key);
+        if (i == byName.end())
+            throw Exception("Not a valid syslog facility: " + name);
+        return i->second;
+    }
+
+    string name(int value) const {
+        ByValue::const_iterator i = byValue.find(value);
+        if (i == byValue.end())
+            throw Exception("Not a valid syslog value: " + value);
+        return i->second;
+    }
+
+  private:
+    ByName byName;
+    ByValue byValue;
+};
+
+// 'priorities' maps qpid log levels to syslog priorities. They are in
+// order of qpid log levels and must map to:
+// "trace", "debug", "info", "notice", "warning", "error", "critical"
+static int priorities[qpid::log::LevelTraits::COUNT] = {
+        LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+        LOG_WARNING, LOG_ERR, LOG_CRIT
+};
+
+std::string basename(const std::string path) {
+    size_t i = path.find_last_of('/');
+    return path.substr((i == std::string::npos) ? 0 : i+1);
+}
+
+} // namespace
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+std::ostream& operator<<(std::ostream& o, const SyslogFacility& f) {
+    return o << SyslogFacilities().name(f.value);
+}
+
+std::istream& operator>>(std::istream& i, SyslogFacility& f) {
+    std::string name;
+    i >> name;
+    f.value = SyslogFacilities().value(name);
+    return i;
+}
+
+class SyslogOutput : public qpid::log::Logger::Output {
+public:
+    SyslogOutput(const std::string& logName, const SyslogFacility& logFacility)
+        : name(logName), facility(logFacility.value)
+    {
+        ::openlog(name.c_str(), LOG_PID, facility);
+    }
+
+    virtual ~SyslogOutput() {
+        ::closelog();
+    }
+    
+    virtual void log(const Statement& s, const std::string& m)
+    {
+        syslog(priorities[s.level], "%s", m.c_str());
+    }
+
+private:    
+    std::string name;
+    int facility;
+};
+
+SinkOptions::SinkOptions(const std::string& argv0)
+    : qpid::log::SinkOptions(),
+      logToStderr(true),
+      logToStdout(false),
+      logToSyslog(false),
+      syslogName(basename(argv0)),
+      syslogFacility(LOG_DAEMON) {
+
+    addOptions()
+      ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr")
+      ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout")
+      ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.")
+      ("log-to-syslog", optValue(logToSyslog, "yes|no"), "Send logging output to syslog;\n\tcustomize using --syslog-name and --syslog-facility")
+      ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages")
+      ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages")
+      ;
+
+}
+
+qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) {
+    const SinkOptions *prhs = dynamic_cast<const SinkOptions*>(&rhs);
+    if (this != prhs) {
+        logToStderr = prhs->logToStderr;
+        logToStdout = prhs->logToStdout;
+        logToSyslog = prhs->logToSyslog;
+        logFile = prhs->logFile;
+        syslogName = prhs->syslogName;
+        syslogFacility.value = prhs->syslogFacility.value;
+    }
+    return *this;
+}
+
+void SinkOptions::detached(void) {
+    if (logToStderr && !logToStdout && !logToSyslog) {
+        logToStderr = false;
+        logToSyslog = true;
+    }
+}
+
+// The Logger acting on these options calls setup() to request any
+// Sinks be set up and fed back to the logger.
+void SinkOptions::setup(qpid::log::Logger *logger) {
+    if (logToStderr)
+        logger->output(make_auto_ptr<qpid::log::Logger::Output>
+                         (new qpid::log::OstreamOutput(std::clog)));
+    if (logToStdout)
+        logger->output(make_auto_ptr<qpid::log::Logger::Output>
+                         (new qpid::log::OstreamOutput(std::cout)));
+
+    if (logFile.length() > 0)
+        logger->output(make_auto_ptr<qpid::log::Logger::Output>
+                         (new qpid::log::OstreamOutput(logFile)));
+
+    if (logToSyslog)
+        logger->output(make_auto_ptr<qpid::log::Logger::Output>
+                         (new SyslogOutput(syslogName, syslogFacility)));
+
+}
+
+} // namespace qpid::log::posix
+
+SinkOptions* SinkOptions::create(const std::string& argv0) {
+    return new qpid::log::posix::SinkOptions (argv0);
+}
+
+}} // namespace qpid::log

Added: incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.h
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.h?rev=705083&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.h (added)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/log/posix/SinkOptions.h Wed Oct 15 15:33:34 2008
@@ -0,0 +1,64 @@
+#ifndef QPID_LOG_POSIX_SINKOPTIONS_H
+#define QPID_LOG_POSIX_SINKOPTIONS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/log/SinkOptions.h"
+#include <string>
+
+namespace qpid {
+namespace log {
+namespace posix {
+
+/**
+ * Provides a type that can be passed to << and >> operators to convert
+ * syslog facility values to/from strings.
+ */
+struct SyslogFacility {
+    int value;
+    SyslogFacility(int i=0) : value(i) {}
+};
+
+struct SinkOptions : public qpid::log::SinkOptions {
+    SinkOptions(const std::string& argv0);
+    virtual ~SinkOptions() {}
+
+    virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs);
+
+    // This allows the caller to indicate that there's no normal outputs
+    // available. For example, when running as a daemon. In these cases, the
+    // platform's "syslog"-type output should replace the default stderr
+    // unless some other sink has been selected.
+    virtual void detached(void);
+
+    // The Logger acting on these options calls setup() to request any
+    // Sinks be set up and fed back to the logger.
+    virtual void setup(qpid::log::Logger *logger);
+
+    bool logToStderr;
+    bool logToStdout;
+    bool logToSyslog;
+    std::string logFile;
+    std::string syslogName;
+    SyslogFacility syslogFacility;
+};
+
+}}} // namespace qpid::log::posix
+
+#endif  /*!QPID_LOG_POSIX_SINKOPTIONS_H*/

Modified: incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpidd.cpp Wed Oct 15 15:33:34 2008
@@ -229,10 +229,8 @@
         // Starting the broker.
         if (options->daemon.daemon) {
             // For daemon mode replace default stderr with syslog.
-            if (options->log.outputs.size() == 1 && options->log.outputs[0] == "stderr") {
-                options->log.outputs[0] = "syslog";
-                qpid::log::Logger::instance().configure(options->log);
-            }
+            options->log.sinkOptions->detached();
+            qpid::log::Logger::instance().configure(options->log);
             // Fork the daemon
             QpiddDaemon d(options->daemon.piddir);
             d.fork();           // Broker is stared in QpiddDaemon::child()

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/logging.cpp
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/logging.cpp?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/logging.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/logging.cpp Wed Oct 15 15:33:34 2008
@@ -19,8 +19,13 @@
 #include "test_tools.h"
 #include "qpid/log/Logger.h"
 #include "qpid/log/Options.h"
+#include "qpid/log/OstreamOutput.h"
 #include "qpid/memory.h"
 #include "qpid/Options.h"
+#if defined (_WIN32)
+#else
+#  include "qpid/log/posix/SinkOptions.h"
+#endif
 
 #include <boost/test/floating_point_comparison.hpp>
 #include <boost/format.hpp>
@@ -179,7 +184,7 @@
     ScopedSuppressLogging ls(l);
     l.select(Selector(error));
     ostringstream os;
-    l.output(os);
+    l.output(qpid::make_auto_ptr<Logger::Output>(new OstreamOutput(os)));
     QPID_LOG(error, "foo");
     QPID_LOG(error, "bar");
     QPID_LOG(error, "baz");
@@ -257,19 +262,22 @@
         "--log-enable", "error+:foo",
         "--log-enable", "debug:bar",
         "--log-enable", "info",
-        "--log-output", "x",
-        "--log-output", "y",
+        "--log-to-stderr", "no",
+        "--log-to-file", "logout",
         "--log-level", "yes",
         "--log-source", "1",
         "--log-thread", "true",
         "--log-function", "YES"
     };
     qpid::log::Options opts("");
+    qpid::log::posix::SinkOptions sinks("test");
     opts.parse(ARGC(argv), const_cast<char**>(argv));
+    sinks = *opts.sinkOptions;
     vector<string> expect=list_of("error+:foo")("debug:bar")("info");
     BOOST_CHECK_EQUAL(expect, opts.selectors);
-    expect=list_of("x")("y");
-    BOOST_CHECK_EQUAL(expect, opts.outputs);
+    BOOST_CHECK(!sinks.logToStderr);
+    BOOST_CHECK(!sinks.logToStdout);
+    BOOST_CHECK(sinks.logFile == "logout");
     BOOST_CHECK(opts.level);
     BOOST_CHECK(opts.source);
     BOOST_CHECK(opts.function);
@@ -278,9 +286,12 @@
 
 QPID_AUTO_TEST_CASE(testOptionsDefault) {
     Options opts("");
-    vector<string> expect=list_of("stderr");
-    BOOST_CHECK_EQUAL(expect, opts.outputs);
-    expect=list_of("error+");
+    qpid::log::posix::SinkOptions sinks("test");
+    sinks = *opts.sinkOptions;
+    BOOST_CHECK(sinks.logToStderr);
+    BOOST_CHECK(!sinks.logToStdout);
+    BOOST_CHECK(sinks.logFile.length() == 0);
+    vector<string> expect=list_of("error+");
     BOOST_CHECK_EQUAL(expect, opts.selectors);
     BOOST_CHECK(opts.time && opts.level);
     BOOST_CHECK(!(opts.source || opts.function || opts.thread));
@@ -313,7 +324,8 @@
         0,
         "--log-time", "no", 
         "--log-source", "yes",
-        "--log-output", "logging.tmp",
+        "--log-to-stderr", "no",
+        "--log-to-file", "logging.tmp",
         "--log-enable", "critical"
     };
     opts.parse(ARGC(argv), const_cast<char**>(argv));
@@ -332,10 +344,13 @@
     Logger& l=Logger::instance();
     ScopedSuppressLogging ls(l);
     Options opts("test");
-    opts.outputs.clear();
-    opts.outputs.push_back("logging.tmp");
     opts.time=false;
+    qpid::log::posix::SinkOptions *sinks =
+      dynamic_cast<qpid::log::posix::SinkOptions *>(opts.sinkOptions.get());
+    sinks->logToStderr = false;
+    sinks->logFile = "logging.tmp";
     l.configure(opts);
+
     char s[] = "null\0tab\tspace newline\nret\r\x80\x99\xff";
     string str(s, sizeof(s));
     QPID_LOG(critical, str); 

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/start_broker
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/start_broker?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/start_broker (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/start_broker Wed Oct 15 15:33:34 2008
@@ -1,4 +1,4 @@
 #!/bin/sh
 # Start a test broker.
 srcdir=`dirname $0`
-exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-output qpidd.log "$@" > qpidd.port
+exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-to-file qpidd.log "$@" > qpidd.port

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster Wed Oct 15 15:33:34 2008
@@ -16,10 +16,10 @@
 
 if test "$SIZE" = "one"; then	# Special case of singleton cluster, use default port.
     ../qpidd -q
-    with_ais_group ../qpidd $OPTS --log-output=cluster.log || exit 1
+    with_ais_group ../qpidd $OPTS --log-to-file=cluster.log || exit 1
 else
     for (( i=0; i<SIZE; ++i )); do
-	PORT=`with_ais_group ../qpidd  -p0 --log-output=cluster$i.log $OPTS`  || exit 1
+	PORT=`with_ais_group ../qpidd  -p0 --log-to-file=cluster$i.log $OPTS`  || exit 1
 	echo $PORT >> cluster.ports
     done
 fi

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster_hosts
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster_hosts?rev=705083&r1=705082&r2=705083&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster_hosts (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/start_cluster_hosts Wed Oct 15 15:33:34 2008
@@ -37,7 +37,7 @@
 test -z "$CLUSTER" && { echo Must specify at least one host; exit 1; }
 
 
-OPTS="-d $PORTOPT --load-module $LIBQPIDCLUSTER --cluster-name=$NAME --no-data-dir --auth=no --log-output=syslog --log-enable=info+"
+OPTS="-d $PORTOPT --load-module $LIBQPIDCLUSTER --cluster-name=$NAME --no-data-dir --auth=no --log-to-syslog --log-enable=info+"
 
 num=0
 for h in $CLUSTER; do