From: Colin Patrick McCabe Date: Tue, 7 Dec 2010 21:55:54 +0000 (-0800) Subject: logging: DoutStreambuf: Implement log-to-file X-Git-Tag: v0.25~463^2~17 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d70851ef019aef3b62c1edf7a7a7c063066e367c;p=ceph.git logging: DoutStreambuf: Implement log-to-file Signed-off-by: Colin McCabe --- diff --git a/src/common/DoutStreambuf.cc b/src/common/DoutStreambuf.cc index 7d6d967c2b02..447f42ade707 100644 --- a/src/common/DoutStreambuf.cc +++ b/src/common/DoutStreambuf.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -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 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 DoutStreambuf::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::overflow(DoutStreambuf::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::set_use_stderr(bool val) } template -void DoutStreambuf::read_global_configuration() +void DoutStreambuf::read_global_config() { assert(_dout_lock.is_locked()); flags = 0; @@ -199,11 +234,11 @@ void DoutStreambuf::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 @@ -225,6 +260,53 @@ set_prio(int prio) this->pbump(2); } +// call after calling daemon() +template +int DoutStreambuf::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 +std::string DoutStreambuf::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 @@ -257,5 +339,58 @@ void DoutStreambuf::_clear_output_buffer() this->setp(obuf, obuf + OBUF_SZ - 5); } +template +std::string DoutStreambuf::_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 +bool DoutStreambuf::_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 ; diff --git a/src/common/DoutStreambuf.h b/src/common/DoutStreambuf.h index 2f4e87aaea0a..386485ec1dbd 100644 --- a/src/common/DoutStreambuf.h +++ b/src/common/DoutStreambuf.h @@ -21,6 +21,7 @@ #define CEPH_DOUT_STREAMBUF_H #include +#include template > class DoutStreambuf : public std::basic_streambuf @@ -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 diff --git a/src/test/TestDoutStreambuf.cc b/src/test/TestDoutStreambuf.cc index 50d49a7d6c21..18eec24051e9 100644 --- a/src/test/TestDoutStreambuf.cc +++ b/src/test/TestDoutStreambuf.cc @@ -44,9 +44,11 @@ int main(int argc, const char **argv) DoutStreambuf *dos = new DoutStreambuf(); _dout_lock.Lock(); - dos->set_flags(DoutStreambuf::DOUTSB_FLAG_SYSLOG | - DoutStreambuf::DOUTSB_FLAG_STDOUT | - DoutStreambuf::DOUTSB_FLAG_STDERR); + dos->read_global_config(); +// dos->set_flags(DoutStreambuf::DOUTSB_FLAG_SYSLOG | +// DoutStreambuf::DOUTSB_FLAG_STDOUT | +// DoutStreambuf::DOUTSB_FLAG_STDERR); + std::cout << "using configuration: " << dos->config_to_str() << std::endl; _dout_lock.Unlock(); std::ostream oss(dos);