FileLogHandler.cpp 4.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

17
#include <ndb_global.h>
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
18
#include <FileLogHandler.hpp>
19 20 21 22 23 24 25 26 27 28 29 30 31
#include <File.hpp>

//
// PUBLIC
//

FileLogHandler::FileLogHandler() : 
  LogHandler(),
  m_maxNoFiles(MAX_NO_FILES), 
  m_maxFileSize(MAX_FILE_SIZE),
  m_maxLogEntries(MAX_LOG_ENTRIES)

{
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
32
  m_pLogFile = new File_class("logger.log", "a+");
33 34 35 36 37 38 39 40 41 42 43
}

FileLogHandler::FileLogHandler(const char* aFileName, 
			       int maxNoFiles, 
			       long maxFileSize,
			       unsigned int maxLogEntries) : 
  LogHandler(),
  m_maxNoFiles(maxNoFiles), 
  m_maxFileSize(maxFileSize),
  m_maxLogEntries(maxLogEntries)
{
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
44
  m_pLogFile = new File_class(aFileName, "a+");
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
}

FileLogHandler::~FileLogHandler()
{
  delete m_pLogFile;
}

bool
FileLogHandler::open()
{
  bool rc = true;

  if (m_pLogFile->open())
  {
    if (isTimeForNewFile())
    {
      if (!createNewFile())
      {
	setErrorCode(errno);
	rc = false; 
      }
    }
  }
  else
  {
    setErrorCode(errno);
    rc = false;
  }

  return rc;
}

bool
FileLogHandler::close()
{
  bool rc = true;
  if (!m_pLogFile->close())
  {
    setErrorCode(errno);
    rc = false;
  }	

  return rc;
}

void 
FileLogHandler::writeHeader(const char* pCategory, Logger::LoggerLevel level)
{
  char str[LogHandler::MAX_HEADER_LENGTH];
  m_pLogFile->writeChar(getDefaultHeader(str, pCategory, level));
}

void 
FileLogHandler::writeMessage(const char* pMsg)
{
  m_pLogFile->writeChar(pMsg);
}

void 
FileLogHandler::writeFooter()
{
  static int callCount = 0;
  m_pLogFile->writeChar(getDefaultFooter());
  /**
   * The reason I also check the number of log entries instead of
   * only the log size, is that I do not want to check the file size
   * after each log entry which requires system calls and is quite slow.
   * TODO: Any better way?
   */
  if (callCount % m_maxLogEntries != 0) // Check every m_maxLogEntries
  {
    if (isTimeForNewFile())
    {
      if (!createNewFile())
      {
	// Baby one more time...
	createNewFile();
      }
    }	
    callCount = 0;
  }
  callCount++;

  m_pLogFile->flush();
}


//
// PRIVATE
//

bool 
FileLogHandler::isTimeForNewFile()
{
  return (m_pLogFile->size() >= m_maxFileSize); 
}

bool
FileLogHandler::createNewFile()
{
  bool rc = true;	
  int fileNo = 1;
147
  char newName[PATH_MAX];
148
  time_t newMtime, preMtime = 0;
149 150 151 152 153 154

  do
  {
    if (fileNo >= m_maxNoFiles)
    {
      fileNo = 1;
155
      BaseString::snprintf(newName, sizeof(newName),
156 157 158
		 "%s.%d", m_pLogFile->getName(), fileNo);
      break;
    }		
159
    BaseString::snprintf(newName, sizeof(newName),
160
	       "%s.%d", m_pLogFile->getName(), fileNo++); 
161 162 163 164 165 166 167 168 169
    newMtime = File_class::mtime(newName);
    if (newMtime < preMtime) 
    {
      break;
    }
    else
    {
      preMtime = newMtime;
    }
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
170
  } while (File_class::exists(newName));
171 172
  
  m_pLogFile->close();	
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
173
  if (!File_class::rename(m_pLogFile->getName(), newName))
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  {		
    setErrorCode(errno);
    rc = false;
  }

  // Open again
  if (!m_pLogFile->open())
  {
    setErrorCode(errno);
    rc = false;
  }				
  
  return rc;
}

bool
FileLogHandler::setParam(const BaseString &param, const BaseString &value){
  if(param == "filename")
    return setFilename(value);
  if(param == "maxsize")
    return setMaxSize(value);
  if(param == "maxfiles")
    return setMaxFiles(value);
197
  setErrorStr("Invalid parameter");
198 199 200 201 202 203 204 205
  return false;
}

bool
FileLogHandler::setFilename(const BaseString &filename) {
  close();
  if(m_pLogFile)
    delete m_pLogFile;
tomas@mc05.(none)'s avatar
tomas@mc05.(none) committed
206
  m_pLogFile = new File_class(filename.c_str(), "a+");
207
  return open();
208
}
209 210 211 212 213

bool
FileLogHandler::setMaxSize(const BaseString &size) {
  char *end;
  long val = strtol(size.c_str(), &end, 0); /* XXX */
214 215 216
  if(size.c_str() == end || val < 0)
  {
    setErrorStr("Invalid file size");
217
    return false;
218
  }
joreland@mysql.com's avatar
joreland@mysql.com committed
219
  if(end[0] == 'M')
220
    val *= 1024*1024;
joreland@mysql.com's avatar
joreland@mysql.com committed
221
  if(end[0] == 'k')
222 223 224 225 226
    val *= 1024;

  m_maxFileSize = val;

  return true;
227
}
228 229 230 231 232

bool
FileLogHandler::setMaxFiles(const BaseString &files) {
  char *end;
  long val = strtol(files.c_str(), &end, 0);
233 234 235
  if(files.c_str() == end || val < 1)
  {
    setErrorStr("Invalid maximum number of files");
236
    return false;
237
  }
238 239 240
  m_maxNoFiles = val;

  return true;
241
}
242 243 244 245

bool
FileLogHandler::checkParams() {
  if(m_pLogFile == NULL)
246 247
  {
    setErrorStr("Log file cannot be null.");
248
    return false;
249
  }
250 251
  return true;
}