]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
logging: DoutStreambuf: Implement log-to-file
authorColin Patrick McCabe <cmccabe@alumni.cmu.edu>
Tue, 7 Dec 2010 21:55:54 +0000 (13:55 -0800)
committerColin Patrick McCabe <cmccabe@alumni.cmu.edu>
Tue, 7 Dec 2010 21:55:54 +0000 (13:55 -0800)
Signed-off-by: Colin McCabe <colinm@hq.newdream.net>
src/common/DoutStreambuf.cc
src/common/DoutStreambuf.h
src/test/TestDoutStreambuf.cc

index 7d6d967c2b021b55140727e77b6e7e5547c16c8f..447f42ade707c770ad453659305b58779eb9cec9 100644 (file)
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <fstream>
 #include <iostream>
+#include <memory>
 #include <sstream>
 #include <streambuf>
 #include <string.h>
@@ -33,7 +34,36 @@ extern Mutex _dout_lock;
 /* True if we should output high-priority messages to stderr */
 static bool use_stderr = true;
 
-///////////////////////////// Helper functions /////////////////////////////
+//////////////////////// Helper functions //////////////////////////
+static bool empty(const char *str)
+{
+  if (!str)
+    return true;
+  if (!str[0])
+    return true;
+  return false;
+}
+
+static string cpp_str(const char *str)
+{
+  if (!str)
+    return "(NULL)";
+  if (str[0] == '\0')
+    return "(empty)";
+  return str;
+}
+
+static std::string normalize_relative(const char *from)
+{
+  if (from[0] == '/')
+    return string(from);
+
+  std::auto_ptr <char> cwd(get_current_dir_name());
+  ostringstream oss;
+  oss << "/" << *cwd << "/" << from;
+  return oss.str();
+}
+
 /* Complain about errors even without a logfile */
 static void primitive_log(const std::string &str)
 {
@@ -89,6 +119,7 @@ static int safe_write(int fd, const char *buf, signed int len)
 ///////////////////////////// DoutStreambuf /////////////////////////////
 template <typename charT, typename traits>
 DoutStreambuf<charT, traits>::DoutStreambuf()
+  : flags(0), ofd(-1)
 {
   // Initialize get pointer to zero so that underflow is called on the first read.
   this->setg(0, 0, 0);
@@ -159,6 +190,10 @@ DoutStreambuf<charT, traits>::overflow(DoutStreambuf<charT, traits>::int_type c)
          flags &= ~DOUTSB_FLAG_STDERR;
       }
     }
+    if (flags & DOUTSB_FLAG_OFILE) {
+      if (safe_write(ofd, start, len))
+       flags &= ~DOUTSB_FLAG_OFILE;
+    }
 
     *(end+1) = next;
     start = end + 1;
@@ -185,7 +220,7 @@ void DoutStreambuf<charT, traits>::set_use_stderr(bool val)
 }
 
 template <typename charT, typename traits>
-void DoutStreambuf<charT, traits>::read_global_configuration()
+void DoutStreambuf<charT, traits>::read_global_config()
 {
   assert(_dout_lock.is_locked());
   flags = 0;
@@ -199,11 +234,11 @@ void DoutStreambuf<charT, traits>::read_global_configuration()
   if (use_stderr) {
     flags |= DOUTSB_FLAG_STDERR;
   }
-//  if (g_conf.log_to_file) {
-//    if (read_log_to_file_configuration()) {
-//      flags |= DOUTSB_FLAG_FILE;
-//    }
-//  }
+  if (g_conf.log_to_file) {
+    if (_read_ofile_config()) {
+      flags |= DOUTSB_FLAG_OFILE;
+    }
+  }
 }
 
 template <typename charT, typename traits>
@@ -225,6 +260,53 @@ set_prio(int prio)
   this->pbump(2);
 }
 
+// call after calling daemon()
+template <typename charT, typename traits>
+int DoutStreambuf<charT, traits>::rename_output_file()
+{
+  Mutex::Locker l(_dout_lock);
+  if (!(flags & DOUTSB_FLAG_OFILE))
+    return 0;
+
+  string new_opath(_calculate_opath());
+  if (opath == new_opath)
+    return 0;
+
+  int ret = ::rename(opath.c_str(), new_opath.c_str());
+  if (ret) {
+    int err = errno;
+    ostringstream oss;
+    oss << __func__ << ": failed to rename '" << opath << "' to "
+        << "'" << new_opath << "': " << cpp_strerror(err) << "\n";
+    primitive_log(oss.str());
+    return err;
+  }
+
+//  // $type.$id symlink
+//  if (g_conf.log_per_instance && _dout_name_symlink_path[0])
+//    create_symlink(_dout_name_symlink_path);
+//  if (_dout_rank_symlink_path[0])
+//    create_symlink(_dout_rank_symlink_path);
+
+  return 0;
+}
+
+template <typename charT, typename traits>
+std::string DoutStreambuf<charT, traits>::config_to_str() const
+{
+  assert(_dout_lock.is_locked());
+  ostringstream oss;
+  oss << "g_conf.log_to_syslog = " << g_conf.log_to_syslog << "\n";
+  oss << "g_conf.log_to_stdout = " << g_conf.log_to_stdout << "\n";
+  oss << "use_stderr = " << use_stderr << "\n";
+  oss << "g_conf.log_to_file = " << g_conf.log_to_file << "\n";
+  oss << "g_conf.log_file = '" << cpp_str(g_conf.log_file) << "'\n";
+  oss << "flags = 0x" << std::hex << flags << std::dec << "\n";
+  oss << "ofd = " << ofd << "\n";
+  oss << "opath = '" << opath << "'\n";
+  return oss.str();
+}
+
 // This is called to flush the buffer.
 // This is called when we're done with the file stream (or when .flush() is called).
 template <typename charT, typename traits>
@@ -257,5 +339,58 @@ void DoutStreambuf<charT, traits>::_clear_output_buffer()
   this->setp(obuf, obuf + OBUF_SZ - 5);
 }
 
+template <typename charT, typename traits>
+std::string DoutStreambuf<charT, traits>::_calculate_opath() const
+{
+  assert(_dout_lock.is_locked());
+  if (!empty(g_conf.log_file)) {
+    return normalize_relative(g_conf.log_file);
+  }
+
+  if (g_conf.log_per_instance) {
+    char hostname[255];
+    memset(hostname, 0, sizeof(hostname));
+    int ret = gethostname(hostname, sizeof(hostname));
+    if (ret) {
+      int err = errno;
+      ostringstream oss;
+      oss << __func__ << ": error calling gethostname: " << cpp_strerror(err) << "\n";
+      primitive_log(oss.str());
+      return "";
+    }
+    ostringstream oss;
+    oss << hostname << "." << getpid();
+    return oss.str();
+  }
+  else {
+    ostringstream oss;
+    oss << g_conf.type << "." << g_conf.id << ".log";
+    return oss.str();
+  }
+}
+
+template <typename charT, typename traits>
+bool DoutStreambuf<charT, traits>::_read_ofile_config()
+{
+  opath = _calculate_opath();
+  if (opath.empty()) {
+    primitive_log("_calculate_opath failed.\n");
+    return false;
+  }
+
+  assert(ofd == -1);
+  ofd = open(opath.c_str(),
+           O_CREAT | O_WRONLY | O_CLOEXEC | O_APPEND, S_IWUSR | S_IRUSR);
+  if (ofd < 0) {
+    int err = errno;
+    ostringstream oss;
+    oss << "failed to open log file '" << opath << "': "
+       << cpp_strerror(err) << "\n";
+    primitive_log(oss.str());
+    return false;
+  }
+  return true;
+}
+
 // Explicit template instantiation
 template class DoutStreambuf <char>;
index 2f4e87aaea0afaefab1ab4ea98ef6b8e5f8057d8..386485ec1dbdb61c217a977656780aa83b36723a 100644 (file)
@@ -21,6 +21,7 @@
 #define CEPH_DOUT_STREAMBUF_H
 
 #include <iosfwd>
+#include <string>
 
 template <typename charT, typename traits = std::char_traits<charT> >
 class DoutStreambuf : public std::basic_streambuf<charT, traits>
@@ -30,6 +31,7 @@ public:
     DOUTSB_FLAG_SYSLOG =          0x01,
     DOUTSB_FLAG_STDOUT =          0x02,
     DOUTSB_FLAG_STDERR =          0x04,
+    DOUTSB_FLAG_OFILE =           0x08,
   };
 
   typedef traits traits_ty;
@@ -49,7 +51,7 @@ public:
   void set_use_stderr(bool val);
 
   // Set the flags based on the global configuration
-  void read_global_configuration();
+  void read_global_config();
 
   // Set the flags directly (for debug use only)
   void set_flags(int flags_);
@@ -57,6 +59,10 @@ public:
   // Set the priority of the messages being put into the stream
   void set_prio(int prio);
 
+  int rename_output_file();
+
+  std::string config_to_str() const;
+
 protected:
   // Called when the buffer fills up
   virtual int_type overflow(int_type c);
@@ -69,11 +75,18 @@ protected:
 
 private:
   void _clear_output_buffer();
+  std::string _calculate_opath() const;
+  bool _read_ofile_config();
 
   // Output buffer
   charT obuf[OBUF_SZ];
 
+  // Output flags
   int flags;
+
+  // ofile stuff
+  int ofd;
+  std::string opath;
 };
 
 #endif
index 50d49a7d6c21a2a4d971eaec9e08cb0e60eeb0e6..18eec24051e9a856cd2d8cf56a17efd5e69335cb 100644 (file)
@@ -44,9 +44,11 @@ int main(int argc, const char **argv)
   DoutStreambuf<char> *dos = new DoutStreambuf<char>();
 
   _dout_lock.Lock();
-  dos->set_flags(DoutStreambuf<char>::DOUTSB_FLAG_SYSLOG |
-                 DoutStreambuf<char>::DOUTSB_FLAG_STDOUT |
-                DoutStreambuf<char>::DOUTSB_FLAG_STDERR);
+  dos->read_global_config();
+//  dos->set_flags(DoutStreambuf<char>::DOUTSB_FLAG_SYSLOG |
+//                 DoutStreambuf<char>::DOUTSB_FLAG_STDOUT |
+//              DoutStreambuf<char>::DOUTSB_FLAG_STDERR);
+  std::cout << "using configuration: " << dos->config_to_str() << std::endl;
   _dout_lock.Unlock();
 
   std::ostream oss(dos);