Console: Add log support to network client (every client is a log target)
g0dil [Thu, 27 Mar 2008 01:20:43 +0000 (01:20 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@768 270642c3-0616-0410-b53a-bc976706d245

Console/Doxyfile
Console/Executor.hh
Console/Node.hh
Console/ObjectDirectory.hh
Console/Parse.cc
Console/Server.cc
Console/Server.hh
Utils/Logger/IOStreamTarget.cc
Utils/Logger/IOStreamTarget.hh
Utils/Logger/Target.cc

index 0a359ce..1fd99b4 100644 (file)
@@ -7,4 +7,5 @@ ALPHABETICAL_INDEX = NO
 TAGFILES = \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
     "$(TOPDIR)/Scheduler/doc/Scheduler.tag" \
-    "$(TOPDIR)/Utils/doc/Utils.tag"
+    "$(TOPDIR)/Utils/doc/Utils.tag" \
+    "$(TOPDIR)/Utils/Logger/doc/Logger.tag"
index 93071ac..d089083 100644 (file)
@@ -65,7 +65,8 @@ namespace console {
 
         typedef boost::iterator_range< ParseCommandInfo::argument_iterator> Arguments;
 
-        struct ExitException {};        ///< Thrown by built-in 'exit' command
+        /// Thrown by built-in 'exit' command
+        struct ExitException {};        
 
         ///////////////////////////////////////////////////////////////////////////
         //\/name Structors and default members
index cf48403..c3911ff 100644 (file)
@@ -143,6 +143,7 @@ namespace console {
 
         typedef typename boost::remove_reference<result_type>::type NodeType;
 
+        /// Internal
         struct Creator {
             static NodeType & create(DirectoryNode & node, std::string const & name, 
                                      Object const & ob);
index 1f26bef..bb8008f 100644 (file)
@@ -53,6 +53,7 @@ namespace console {
 
         typedef typename boost::remove_reference<result_type>::type NodeType;
 
+        /// Internal
         struct Creator {
             static NodeType & create(DirectoryNode & node, Owner & owner, 
                                      std::string const & name, Object const & ob);
index bf49f31..c06a2bc 100644 (file)
@@ -41,6 +41,8 @@ namespace senf {
 namespace console {
 namespace detail {
 
+#ifndef DOXYGEN
+
     struct ParserAccess
     {
         static void init(ParseCommandInfo & info)
@@ -149,11 +151,15 @@ namespace detail {
             }
     };
 
+#endif
+
 }}}
 
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo
 
+#ifndef DOXYGEN
+
 struct senf::console::ParseCommandInfo::MakeRange
 {
     typedef ParseCommandInfo::argument_value_type result_type;
@@ -168,6 +174,8 @@ struct senf::console::ParseCommandInfo::MakeRange
     }
 };
 
+#endif
+
 prefix_ void senf::console::ParseCommandInfo::finalize()
 {
     arguments_.resize( tempArguments_.size() );
@@ -211,6 +219,8 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandParser
 
+#ifndef DOXYGEN
+
 struct senf::console::CommandParser::Impl
 {
     typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
@@ -222,6 +232,8 @@ struct senf::console::CommandParser::Impl
     Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
 };
 
+#endif
+
 prefix_ senf::console::CommandParser::CommandParser()
     : impl_ (new Impl())
 {}
index 4e37e68..eb1fac1 100644 (file)
@@ -102,11 +102,13 @@ prefix_ void senf::console::Server::removeClient(Client & client)
 // senf::console::Client
 
 prefix_ senf::console::Client::Client(ClientHandle handle, std::string const & name)
-    : handle_ (handle), name_ (name), out_(::dup(handle.fd()))
+    : out_t(::dup(handle.fd())), senf::log::IOStreamTarget(out_t::member),
+      handle_ (handle), name_ (name), promptLen_(0)
 {
     showPrompt();
     ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
                                         senf::membind(&Client::clientData, this) );
+    route< senf::SenfLog, senf::log::NOTICE >();
 }
 
 prefix_ senf::console::Client::~Client()
@@ -120,6 +122,7 @@ prefix_ void senf::console::Client::stopClient()
 
 prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr helper)
 {
+    promptLen_ = 0;
     if (helper->error() || handle_.eof()) {
         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
         stopClient();
@@ -131,8 +134,9 @@ prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr hel
     boost::trim(data); // Gets rid of superfluous  \r or \n characters
 
     try {
-        if (! parser_.parse(data, boost::bind<void>(boost::ref(executor_), _1, boost::ref(out_))))
-            out_ << "syntax error" << std::endl;
+        if (! parser_.parse(data, boost::bind<void>(boost::ref(executor_), _1, 
+                                                    boost::ref(out_t::member))))
+            out_t::member << "syntax error" << std::endl;
     }
     catch (Executor::ExitException &) {
         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
@@ -140,10 +144,10 @@ prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr hel
         return;
     }
     catch (std::exception & ex) {
-        out_ << ex.what() << std::endl;
+        out_t::member << ex.what() << std::endl;
     }
     catch (...) {
-        out_ << "unidentified error (unknown exception thrown)" << std::endl;
+        out_t::member << "unidentified error (unknown exception thrown)" << std::endl;
     }
 
     showPrompt();
@@ -153,7 +157,21 @@ prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr hel
 
 prefix_ void senf::console::Client::showPrompt()
 {
-    out_ << name_ << ":" << executor_.cwd().path() << "# " << std::flush;
+    std::string path (executor_.cwd().path());
+    out_t::member << name_ << ":" << path << "# " << std::flush;
+    promptLen_ = name_.size() + 1 + path.size() + 1;
+}
+
+prefix_ void senf::console::Client::v_write(boost::posix_time::ptime timestamp,
+                                            std::string const & stream,
+                                            std::string const & area, unsigned level,
+                                            std::string const & message)
+{
+    if (promptLen_)
+        out_t::member << '\r' << std::string(' ', promptLen_) << '\r';
+    IOStreamTarget::v_write(timestamp, stream, area, level, message);
+    if (promptLen_)
+        showPrompt();
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 685eae2..26092fa 100644 (file)
@@ -41,6 +41,7 @@
 #include "Parse.hh"
 #include "Executor.hh"
 #include "../Socket/Protocols/INet/INetAddressing.hh"
+#include "../Utils/Logger.hh"
 
 //#include "Server.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -113,10 +114,17 @@ namespace console {
         \fixme Make output non-blocking (use a non-blocking/discarding streambuf) and possibly set
             socket send buffer size
         \fixme Don't register a new ReadHelper every round
+        \fixme Ensure, that output errors (or any errors) in the console don't terminate the
+            application
      */
     class Client
-        : public senf::intrusive_refcount
+        : public senf::intrusive_refcount, 
+          private boost::base_from_member< boost::iostreams::stream<boost::iostreams::file_descriptor_sink> >,
+          public senf::log::IOStreamTarget
     {
+        typedef boost::base_from_member< 
+            boost::iostreams::stream<boost::iostreams::file_descriptor_sink> > out_t;
+
         SENF_LOG_CLASS_AREA();
         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
     public:
@@ -134,15 +142,17 @@ namespace console {
 
         void clientData(ReadHelper<ClientHandle>::ptr helper);
         void showPrompt();
+
+        virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
+                             std::string const & area, unsigned level, 
+                             std::string const & message);
         
         ClientHandle handle_;
         std::string tail_;
         CommandParser parser_;
         Executor executor_;
         std::string name_;
-
-        typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> fdostream;
-        fdostream out_;
+        unsigned promptLen_;
 
         friend class Server;
     };
index dbf4454..0d798bb 100644 (file)
@@ -73,8 +73,8 @@ prefix_ void senf::log::IOStreamTarget::v_write(boost::posix_time::ptime timesta
         stream_ << timestamp << sep;
         stream_ << "[" << LEVELNAMES_[level] << "]";
         if (area != "senf::log::DefaultArea")
-            stream_ << "[" << area << "] ";
-        stream_ << *i << "\n";
+            stream_ << "[" << area << "]";
+        stream_ << " " << *i << "\n";
         sep = '-';
     }
     stream_ << std::flush;
index 7e4900b..2a2763a 100644 (file)
@@ -73,12 +73,11 @@ namespace log {
         ///////////////////////////////////////////////////////////////////////////
 
     protected:
-
-    private:
         void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
                      std::string const & area, unsigned level, 
                      std::string const & message);
 
+    private:
         std::ostream & stream_;
         static char const * const LEVELNAMES_[8];
     };
index 9740cec..91d231e 100644 (file)
@@ -45,8 +45,8 @@ prefix_ senf::log::Target::Target()
 prefix_ senf::log::Target::~Target()
 {
     while( ! rib_.empty()) {
-        // This is terribly slow but simplifies the area cache handling and removing a target should
-        // be quite seldom
+        // This is slow but simplifies the area cache handling and removing a target should be
+        // relatively seldom
         RIB::reverse_iterator i (rib_.rbegin());
         unroute(i->stream_, i->area_, i->level_, i->action_);
     }