// -*- c++ -*- //------------------------------------------------------------------------------ // FileLogger.cpp //------------------------------------------------------------------------------ // $Id: FileLogger.cpp,v 1.10 2006/07/20 02:30:53 vlg Exp $ //------------------------------------------------------------------------------ // Copyright (C) 1997-2002,2005 Vladislav Grinchenko // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. //------------------------------------------------------------------------------ #include #include // vsprintf(3) #include // stat(2) #include // stat(2) #include // stat(2) #include #include #include #include #include using namespace ASSA; int FileLogger:: log_open (const char* logfname_, u_long groups_, u_long maxsize_) { // std::cout << "Enter: FileLogger::log_open(fname=\"" // << logfname_ << "\"" // << " groups=0x" << std::setw(8) << std::hex << groups_ // << " maxsize=" << std::dec << maxsize_ << ")\n"; if (logfname_ == NULL || maxsize_ <= 0) { // std::cout << "FileLogger::log_open() failed 1\n"; errno = EINVAL; return -1; } if (m_state == opened) { // std::cout << "FileLogger::log_open() already open\n"; errno = EEXIST; return -1; } m_logfname = logfname_; m_groups = groups_; m_maxsize = maxsize_; m_sink.open (m_logfname.c_str (), std::ios::out | std::ios::app); if (!m_sink) { // std::cout << "FileLogger::log_open() failed to open()!\n"; return -1; } // std::cout << "Success on FileLogger::log_open()\n"; m_state = opened; return 0; } int FileLogger:: log_close (void) { if (m_state != closed) { m_sink << std::flush; m_sink.close (); m_state = closed; if (m_groups == 0) { ::unlink (m_logfname.c_str ()); } m_logfname.empty (); m_maxsize = 0; m_bytecount = 0; } return 0; } /** * If output string is longer then LOGGER_MAXLINE-1, it is truncated * to that size. * * From printf(3) manpage: * * "Upon successful return, these functions return the number of * characters printed (not including the trailing '\\0' used to * end output to strings). * * If the output was truncated due to this limit then the return * value is the number of characters (not including the trailing * '\\0') which would have been written to the final string * if enough space had been available. * * Thus, a return value of size or more means that the output * was truncated. * * If an output error is encountered, a negative value is returned." * * In other words, if you have attempted to write more then buffer can * hold, the output is truncated by buffer size - 1, and the return * value would be the number of bytes you have tried to write to the buffer. * * If buffer size is 256, and you tried to write 340 bytes to it, the * first 255 bytes are written to the buffer, and 340 is returns as the * return value. */ int FileLogger:: log_msg (Group g_, size_t indent_level_, const string& func_name_, size_t expected_sz_, const char* fmt_, va_list msg_list_) { // std::cout << "FileLogger::log_msg() enter\n" // << "group__=0x" << std::setw(8) << std::hex << (u_long)g_ << "\n"; if (m_state == closed) { // std::cout << "FileLogger::log_msg() sink closed!\n"; errno = EPERM; return -1; } if (! group_enabled (g_)) { // std::cout << "FileLogger::log_msg() group is not enabled!\n" // << "m_groups=0x" // << std::setw(8) << std::hex << m_groups << "\n"; return 0; } m_bytecount += add_timestamp (m_sink); m_bytecount += indent_func_name (m_sink, func_name_,indent_level_,FUNC_MSG); bool release = false; char* msgbuf_ptr = format_msg (expected_sz_, fmt_, msg_list_, release); if (msgbuf_ptr == NULL) { // std::cout << "FileLogger::log_msg() call to format_msg() failed!" // << " fmt_= \"" << fmt_ << "\"\n" << std::flush; return -1; // failed to format } m_sink << msgbuf_ptr << std::flush; m_bytecount += strlen (msgbuf_ptr); if (release) { delete [] msgbuf_ptr; } return handle_rollover (); } int FileLogger:: log_func (Group g_, size_t indent_level_, const string& func_name_, marker_t type_) { if (m_state == closed) { errno = EPERM; return -1; } if (! group_enabled (g_)) { return 0; } m_bytecount += add_timestamp (m_sink); m_bytecount += indent_func_name (m_sink, func_name_, indent_level_, type_); m_sink << ((type_ == FUNC_ENTRY) ? "---v---\n" : "---^---\n") << std::flush; m_bytecount += ::strlen ("---v---\n"); return handle_rollover (); } int FileLogger:: log_raw_msg (const string& msg_) { if (m_state == closed) { errno = EPERM; return -1; } m_sink << msg_ << std::flush; m_bytecount += msg_.length (); return handle_rollover (); } int FileLogger:: handle_rollover () { if (m_bytecount >= m_maxsize) { struct stat fst; if (::stat (m_logfname.c_str(), &fst) == 0) { if (S_ISREG (fst.st_mode)) { m_sink << "\nReached maximum allowable size\n" << "m_bytecount = " << m_bytecount << ", m_maxsize = " << m_maxsize << std::endl; m_sink.close (); m_state = closed; m_bytecount = 0; string newname = m_logfname + ".0"; unlink (newname.c_str ()); rename (m_logfname.c_str (), newname.c_str ()); m_sink.open (m_logfname.c_str (), std::ios::app | std::ios::out); if (!m_sink) { return -1; } m_state = opened; } else if (S_ISCHR (fst.st_mode)) { // It is /dev/null m_bytecount = 0; } else { Assure_exit (1); } } } return 0; } void FileLogger:: dump (void) { #ifdef BUG_HUNTING if (m_state == opened) { m_sink << "m_logfname = \"" << m_logfname << "\"\n" << "m_groups = 0x"; char oldfill = m_sink.fill ('0'); m_sink << std::setw(8) << std::hex << m_groups << '\n' << std::dec; m_sink.fill (oldfill); m_sink << "m_indent_step = " << m_indent_step << '\n' << "m_tmflg = " << m_tmflg << '\n' << "m_maxsize = " << m_maxsize << '\n' << "m_state = opened\n" << "m_bytecount = " << m_bytecount << std::endl; } #endif }