blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Quest Software, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #include "blocxx/BLOCXX_config.h" 00039 #include "blocxx/MultiProcessFileAppender.hpp" 00040 #include "blocxx/Format.hpp" 00041 #include "blocxx/Logger.hpp" 00042 #include "blocxx/LogMessage.hpp" 00043 #include "blocxx/FileSystem.hpp" 00044 00045 #include <fcntl.h> 00046 #ifdef BLOCXX_HAVE_SYS_STAT_H 00047 #include <sys/stat.h> 00048 #endif 00049 00050 namespace BLOCXX_NAMESPACE 00051 { 00052 00053 namespace 00054 { 00055 using namespace blocxx; 00056 00057 class FileLock 00058 { 00059 public: 00060 FileLock(File & file) 00061 : m_file(file) 00062 { 00063 m_ok = file.getLock() == 0; 00064 } 00065 00066 bool ok() const 00067 { 00068 return m_ok; 00069 } 00070 00071 ~FileLock() 00072 { 00073 if (m_ok) 00074 { 00075 m_file.unlock(); // nowhere to report error if unlock fails... 00076 } 00077 } 00078 00079 private: 00080 File & m_file; 00081 bool m_ok; 00082 }; 00083 00084 typedef blocxx::MultiProcessFileAppender app_t; 00085 00086 UInt64 kbytesToBytes(UInt64 max_size) 00087 { 00088 UInt64 const oneK = 1024; 00089 UInt64 const biggest = UInt64(-1); // largest possible UInt64 00090 return( 00091 max_size == app_t::NO_MAX_LOG_SIZE ? biggest 00092 : max_size > biggest / oneK ? biggest 00093 : max_size * oneK 00094 ); 00095 } 00096 00097 } 00098 00099 MultiProcessFileAppender::MultiProcessFileAppender( 00100 const StringArray& components, 00101 const StringArray& categories, 00102 const String & filename, 00103 const String& pattern, 00104 UInt64 maxFileSize, 00105 UInt32 maxBackupIndex 00106 ) 00107 : LogAppender(components, categories, pattern) 00108 , m_filename(filename) 00109 , m_maxFileSize(kbytesToBytes(maxFileSize)) 00110 , m_maxBackupIndex(maxBackupIndex) 00111 { 00112 m_log = FileSystem::openForAppendOrCreateFile(filename); 00113 m_lock = FileSystem::openOrCreateFile(filename + ".lock"); 00114 00115 if (!m_log) 00116 { 00117 String msg = "Cannot create log file " + filename; 00118 BLOCXX_THROW(LoggerException, msg.c_str()); 00119 } 00120 if (!m_lock) 00121 { 00122 String msg = "Cannot create lock file for log file " + filename + ".lock"; 00123 BLOCXX_THROW(LoggerException, msg.c_str()); 00124 } 00125 } 00126 00127 MultiProcessFileAppender::~MultiProcessFileAppender() 00128 { 00129 } 00130 00131 void MultiProcessFileAppender::doProcessLogMessage( 00132 const String& formattedMessage, const LogMessage& message) const 00133 { 00134 // On error, we just return, since doProcessLogMessage should not throw 00135 00136 if (!m_log || !m_lock) 00137 { 00138 return; 00139 } 00140 00141 FileLock lock(m_lock); 00142 if (!lock.ok()) 00143 { 00144 return; 00145 } 00146 00147 UInt64 size = m_log.size(); 00148 00149 if (size >= m_maxFileSize) 00150 { 00151 // Log file has been rotated 00152 File f = FileSystem::openForAppendOrCreateFile(m_filename); 00153 f.swap(m_log); 00154 if (!m_log) 00155 { 00156 return; 00157 } 00158 size = m_log.size(); 00159 } 00160 00161 String s = formattedMessage + "\n"; 00162 m_log.write(s.c_str(), s.length()); 00163 m_log.flush(); 00164 size += s.length(); 00165 00166 // handle log rotation 00167 if (size >= m_maxFileSize) 00168 { 00169 // do the roll over 00170 m_log.close(); 00171 00172 if (m_maxBackupIndex > 0) 00173 { 00174 // delete the oldest file first, if it exists 00175 FileSystem::removeFile(m_filename + '.' + String(m_maxBackupIndex)); 00176 00177 // increment the numbers on all the files, if they exist 00178 for (UInt32 i = m_maxBackupIndex - 1; i >= 1; --i) 00179 { 00180 FileSystem::renameFile(m_filename + '.' + String(i), m_filename + '.' + String(i + 1)); 00181 } 00182 00183 if (!FileSystem::renameFile(m_filename, m_filename + ".1")) 00184 { 00185 // if we can't rename it, at least don't write to it anymore 00186 return; 00187 } 00188 } 00189 00190 // open new log file 00191 File f = FileSystem::openForAppendOrCreateFile(m_filename); 00192 f.swap(m_log); 00193 } 00194 } 00195 00196 } // end namespace BLOCXX_NAMESPACE 00197 00198 00199 00200