blocxx
MultiProcessFileAppender.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Quest Software, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Quest Software, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
38 #include "blocxx/BLOCXX_config.h"
40 #include "blocxx/Format.hpp"
41 #include "blocxx/Logger.hpp"
42 #include "blocxx/LogMessage.hpp"
43 #include "blocxx/FileSystem.hpp"
44 
45 #include <fcntl.h>
46 #ifdef BLOCXX_HAVE_SYS_STAT_H
47 #include <sys/stat.h>
48 #endif
49 
50 namespace BLOCXX_NAMESPACE
51 {
52 
53 namespace
54 {
55  using namespace blocxx;
56 
57  class FileLock
58  {
59  public:
60  FileLock(File & file)
61  : m_file(file)
62  {
63  m_ok = file.getLock() == 0;
64  }
65 
66  bool ok() const
67  {
68  return m_ok;
69  }
70 
71  ~FileLock()
72  {
73  if (m_ok)
74  {
75  m_file.unlock(); // nowhere to report error if unlock fails...
76  }
77  }
78 
79  private:
80  File & m_file;
81  bool m_ok;
82  };
83 
84  typedef blocxx::MultiProcessFileAppender app_t;
85 
86  UInt64 kbytesToBytes(UInt64 max_size)
87  {
88  UInt64 const oneK = 1024;
89  UInt64 const biggest = UInt64(-1); // largest possible UInt64
90  return(
91  max_size == app_t::NO_MAX_LOG_SIZE ? biggest
92  : max_size > biggest / oneK ? biggest
93  : max_size * oneK
94  );
95  }
96 
97 }
98 
100  const StringArray& components,
101  const StringArray& categories,
102  const String & filename,
103  const String& pattern,
104  UInt64 maxFileSize,
105  UInt32 maxBackupIndex
106 )
107  : LogAppender(components, categories, pattern)
108  , m_filename(filename)
109  , m_maxFileSize(kbytesToBytes(maxFileSize))
110  , m_maxBackupIndex(maxBackupIndex)
111 {
113  m_lock = FileSystem::openOrCreateFile(filename + ".lock");
114 
115  if (!m_log)
116  {
117  String msg = "Cannot create log file " + filename;
119  }
120  if (!m_lock)
121  {
122  String msg = "Cannot create lock file for log file " + filename + ".lock";
124  }
125 }
126 
128 {
129 }
130 
132  const String& formattedMessage, const LogMessage& message) const
133 {
134  // On error, we just return, since doProcessLogMessage should not throw
135 
136  if (!m_log || !m_lock)
137  {
138  return;
139  }
140 
141  FileLock lock(m_lock);
142  if (!lock.ok())
143  {
144  return;
145  }
146 
147  UInt64 size = m_log.size();
148 
149  if (size >= m_maxFileSize)
150  {
151  // Log file has been rotated
153  f.swap(m_log);
154  if (!m_log)
155  {
156  return;
157  }
158  size = m_log.size();
159  }
160 
161  String s = formattedMessage + "\n";
162  m_log.write(s.c_str(), s.length());
163  m_log.flush();
164  size += s.length();
165 
166  // handle log rotation
167  if (size >= m_maxFileSize)
168  {
169  // do the roll over
170  m_log.close();
171 
172  if (m_maxBackupIndex > 0)
173  {
174  // delete the oldest file first, if it exists
176 
177  // increment the numbers on all the files, if they exist
178  for (UInt32 i = m_maxBackupIndex - 1; i >= 1; --i)
179  {
180  FileSystem::renameFile(m_filename + '.' + String(i), m_filename + '.' + String(i + 1));
181  }
182 
184  {
185  // if we can't rename it, at least don't write to it anymore
186  return;
187  }
188  }
189 
190  // open new log file
192  f.swap(m_log);
193  }
194 }
195 
196 } // end namespace BLOCXX_NAMESPACE
197 
198 
199 
200 
MultiProcessFileAppender(const StringArray &components, const StringArray &categories, const String &filename, const String &pattern, UInt64 maxFileSize, UInt32 maxBackupIndex)
All processes that log to filename must use the same values for maxFileSize and maxBackupIndex.
Taken from RFC 1321.
UInt64 size() const
Current size of file.
Definition: File.hpp:163
BLOCXX_COMMON_API File openForAppendOrCreateFile(const String &path)
Opens the file for the given name to append data or create if it does not exist.
BLOCXX_COMMON_API File openOrCreateFile(const String &path)
Opens or creates the file for the given name.
This String class is an abstract data type that represents as NULL terminated string of characters...
Definition: String.hpp:66
virtual void doProcessLogMessage(const String &formattedMessage, const LogMessage &message) const
const char * c_str() const
Definition: String.cpp:905
BLOCXX_COMMON_API bool renameFile(const String &oldFileName, const String &newFileName)
Rename the given file to the new name.
BLOCXX_COMMON_API bool removeFile(const String &path)
Remove the given file.
size_t length() const
Definition: String.cpp:354
int close()
Close the underlying file object.
Definition: File.hpp:171
The purpose of the File class is to provide an abstraction layer over the platform dependant function...
Definition: File.hpp:54
void swap(File &x)
Definition: File.hpp:98
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
Definition: Exception.hpp:263
File & m_file
size_t write(const void *bfr, size_t numberOfBytes, Int64 offset=-1L)
Write to the underlying file.
Definition: File.hpp:127
int flush()
Flush any buffered data to the file.
Definition: File.hpp:185