blocxx

FileAppender.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, 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 *       Vintela, 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/FileAppender.hpp"
00040 #include "blocxx/Format.hpp"
00041 #include "blocxx/Logger.hpp"
00042 #include "blocxx/LogMessage.hpp"
00043 #include "blocxx/Mutex.hpp"
00044 #include "blocxx/MutexLock.hpp"
00045 #include "blocxx/FileSystem.hpp"
00046 #include "blocxx/GlobalMutex.hpp"
00047 
00048 #include <fstream>
00049 
00050 namespace BLOCXX_NAMESPACE
00051 {
00052 
00054 FileAppender::FileAppender(const StringArray& components,
00055    const StringArray& categories,
00056    const char* filename,
00057    const String& pattern,
00058    UInt64 maxFileSize,
00059    unsigned int maxBackupIndex,
00060    bool flushLog)
00061    : LogAppender(components, categories, pattern)
00062    , m_filename(filename)
00063    , m_maxFileSize(maxFileSize)
00064    , m_maxBackupIndex(maxBackupIndex)
00065    , m_flushLog(flushLog)
00066 {
00067    m_log.open(m_filename.c_str(), std::ios::out | std::ios::app);
00068    if (!m_log)
00069    {
00070       BLOCXX_THROW(LoggerException, Format("FileAppender: Unable to open file: %1", m_filename).toString().c_str() );
00071    }
00072 }
00073 
00075 FileAppender::~FileAppender()
00076 {
00077 }
00078 
00080 namespace
00081 {
00082    GlobalMutex fileGuard = BLOCXX_GLOBAL_MUTEX_INIT();
00083 }
00084 void
00085 FileAppender::doProcessLogMessage(const String& formattedMessage, const LogMessage& message) const
00086 {
00087    MutexLock lock(fileGuard);
00088 
00089    // take into account external log rotators, if the file we have open no longer exists, then reopen it.
00090    if (!FileSystem::exists(m_filename.c_str()))
00091    {
00092       // make sure we can re-open the log file before we close it
00093       std::ofstream temp;
00094       temp.open(m_filename.c_str(), std::ios::out | std::ios::app);
00095       if (temp)
00096       {
00097          temp.close();
00098          m_log.close();
00099          m_log.open(m_filename.c_str(), std::ios::out | std::ios::app);
00100       }
00101       else
00102       {
00103          m_log << "FileAppender::doProcessLogMessage(): " << m_filename << " no longer exists and re-opening it failed!\n";
00104       }
00105    }
00106 
00107    if (!m_log)
00108    {
00109       // hmm, not much we can do here.  doProcessLogMessage can't throw.
00110       return;
00111    }
00112 
00113    m_log.write(formattedMessage.c_str(), formattedMessage.length());
00114    m_log << '\n';
00115 
00116    if (m_flushLog)
00117    {
00118       m_log.flush();
00119    }
00120 
00121    // handle log rotation
00122    if (m_maxFileSize != NO_MAX_LOG_SIZE && m_log.tellp() >= static_cast<std::streampos>(m_maxFileSize * 1024))
00123    {
00124       // do the roll over
00125 
00126       if (m_maxBackupIndex > 0)
00127       {
00128          // Delete the oldest file first - this may or may not exist; we try anyway.
00129          FileSystem::removeFile(m_filename + '.' + String(m_maxBackupIndex));
00130 
00131          // increment the numbers on all the files - some may exist or not, but try anyway.
00132          for (unsigned int i = m_maxBackupIndex - 1; i >= 1; --i)
00133          {
00134             FileSystem::renameFile(m_filename + '.' + String(i), m_filename + '.' + String(i + 1));
00135          }
00136 
00137          if (!FileSystem::renameFile(m_filename, m_filename + ".1"))
00138          {
00139             // if we can't rename it, avoid truncating it.
00140             m_log << "FileAppender::doProcessLogMessage(): Failed to rename " << m_filename << " to " << m_filename + ".1! Logging to this file STOPPED!\n";
00141             m_log.close();
00142             return;
00143          }
00144       }
00145 
00146       // make sure we can re-open the log file before we close it
00147       std::ofstream temp;
00148       temp.open(m_filename.c_str(), std::ios::out | std::ios::app);
00149       if (temp)
00150       {
00151          temp.close();
00152          m_log.close();
00153          // truncate the existing one
00154          m_log.open(m_filename.c_str(), std::ios_base::out | std::ios_base::trunc);
00155       }
00156       else
00157       {
00158          m_log << "FileAppender::doProcessLogMessage(): Failed to open " << m_filename << "! Logging to this file STOPPED!\n";
00159          m_log.close();
00160       }
00161    }
00162 }
00163 
00165 const GlobalString FileAppender::STR_DEFAULT_MESSAGE_PATTERN = BLOCXX_GLOBAL_STRING_INIT("%d{%a %b %d %H:%M:%S %Y} [%t]: %m");
00166 
00167 } // end namespace BLOCXX_NAMESPACE
00168 
00169 
00170 
00171