1 // Module: Log4cplus
2 // File: clfsappender.cxx
3 // Created: 5/2012
4 // Author: Vaclav Zeman
5 //
6 //
7 // Copyright (C) 2012-2013, Vaclav Zeman. All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without modifica-
10 // tion, are permitted provided that the following conditions are met:
11 //
12 // 1. Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // 2. Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
20 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 // APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
24 // DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include <log4cplus/config.hxx>
31 #include <log4cplus/helpers/loglog.h>
32 #include <log4cplus/helpers/property.h>
33 #include <log4cplus/clfsappender.h>
34 #include <log4cplus/spi/factory.h>
35 #include <sstream>
36 #include <iomanip>
37 #include <cstring>
38 #include <log4cplus/config/windowsh-inc.h>
39 #include <clfsw32.h>
40 #include <clfsmgmtw32.h>
41
42
43 // Forward Declarations
44 namespace log4cplus
45 {
46
47 const unsigned CLFS_APPENDER_INITIAL_LOG_SIZE = 512 * 1024;
48 const ULONG CLFS_APPENDER_DEFAULT_BUFFER_SIZE = 1024 * 64;
49
50
51 namespace
52 {
53
54 static
55 void
loglog_win32_error(tchar const * msg)56 loglog_win32_error (tchar const * msg)
57 {
58 DWORD err = GetLastError ();
59 tostringstream oss;
60 oss << LOG4CPLUS_TEXT ("CLFSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
61 << err << LOG4CPLUS_TEXT (" / 0x")
62 << std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
63 << err;
64 helpers::getLogLog ().error (oss.str ());
65 }
66
67 }
68
69
70 struct CLFSAppender::Data
71 {
Datalog4cplus::CLFSAppender::Data72 Data ()
73 : log_name ()
74 , log_handle (INVALID_HANDLE_VALUE)
75 , buffer (0)
76 , buffer_size (0)
77 { }
78
79 tstring log_name;
80 HANDLE log_handle;
81 void * buffer;
82 ULONG buffer_size;
83 };
84
85
CLFSAppender(tstring const & logname,unsigned long logsize,unsigned long buffersize)86 CLFSAppender::CLFSAppender (tstring const & logname, unsigned long logsize,
87 unsigned long buffersize)
88 : Appender ()
89 , data (new Data)
90 {
91 init (logname, logsize, buffersize);
92 }
93
94
CLFSAppender(helpers::Properties const & props)95 CLFSAppender::CLFSAppender (helpers::Properties const & props)
96 : Appender (props)
97 , data (new Data)
98 {
99 tstring logname = props.getProperty (LOG4CPLUS_TEXT ("LogName"));
100
101 unsigned long logsize = CLFS_APPENDER_INITIAL_LOG_SIZE;
102 props.getULong (logsize, LOG4CPLUS_TEXT ("LogSize"));
103
104 unsigned long buffersize = CLFS_APPENDER_DEFAULT_BUFFER_SIZE;
105 props.getULong (buffersize, LOG4CPLUS_TEXT ("BufferSize"));
106
107 init (logname, logsize, buffersize);
108 }
109
110
~CLFSAppender()111 CLFSAppender::~CLFSAppender ()
112 {
113 destructorImpl ();
114 delete data;
115 }
116
117
118 void
init(tstring const & logname,unsigned long logsize,unsigned long buffersize)119 CLFSAppender::init (tstring const & logname, unsigned long logsize,
120 unsigned long buffersize)
121 {
122 data->log_name = logname;
123 data->buffer_size = buffersize;
124
125 if (data->log_name.empty ())
126 helpers::getLogLog ().error (
127 LOG4CPLUS_TEXT ("CLFSAppender: empty log name"), true);
128
129 CLFS_MGMT_POLICY log_policy;
130 std::memset (&log_policy, 0, sizeof (log_policy));
131 log_policy.Version = CLFS_MGMT_POLICY_VERSION;
132 log_policy.LengthInBytes = sizeof (log_policy);
133 log_policy.PolicyFlags = 0;
134
135 CLFS_INFORMATION log_info;
136 ULONG info_size = sizeof (log_info);
137 ULONGLONG desired_size;
138 ULONGLONG resulting_size;
139
140 data->log_handle = CreateLogFile (
141 helpers::towstring (data->log_name).c_str (), GENERIC_WRITE | GENERIC_READ,
142 FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
143 OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE);
144
145 if (data->log_handle == INVALID_HANDLE_VALUE)
146 {
147 loglog_win32_error (LOG4CPLUS_TEXT ("CreateLogFile()"));
148 goto error;
149 }
150
151 if (! RegisterManageableLogClient (data->log_handle, 0))
152 {
153 loglog_win32_error (LOG4CPLUS_TEXT ("RegisterManageableLogClient()"));
154 goto error;
155 }
156
157
158 if (! GetLogFileInformation (data->log_handle, &log_info, &info_size))
159 {
160 loglog_win32_error (LOG4CPLUS_TEXT ("GetLogFileInformation()"));
161 goto error;
162 }
163
164 if (log_info.TotalContainers == 0)
165 {
166 log_policy.PolicyType = ClfsMgmtPolicyNewContainerSize;
167 log_policy.PolicyParameters.NewContainerSize.SizeInBytes = logsize;
168 if (! InstallLogPolicy (data->log_handle, &log_policy))
169 {
170 loglog_win32_error (
171 LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyNewContainerSize)"));
172 goto error;
173 }
174 }
175
176 desired_size = 0;
177 resulting_size = 0;
178 if (! SetLogFileSizeWithPolicy (data->log_handle, &desired_size,
179 &resulting_size))
180 {
181 loglog_win32_error (LOG4CPLUS_TEXT ("SetLogFileSizeWithPolicy()"));
182 goto error;
183 }
184
185 log_policy.PolicyType = ClfsMgmtPolicyAutoGrow;
186 log_policy.PolicyParameters.AutoGrow.Enabled = true;
187 if (! InstallLogPolicy (data->log_handle, &log_policy))
188 {
189 loglog_win32_error (
190 LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyAutoGrow)"));
191 goto error;
192 }
193
194 log_policy.PolicyType = ClfsMgmtPolicyGrowthRate;
195 log_policy.PolicyParameters.GrowthRate.AbsoluteGrowthInContainers = 0;
196 log_policy.PolicyParameters.GrowthRate.RelativeGrowthPercentage = 10;
197 if (! InstallLogPolicy (data->log_handle, &log_policy))
198 {
199 loglog_win32_error (
200 LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyGrowthRate)"));
201 goto error;
202 }
203
204 // TODO: Get underlying media sector size using GetDiskFreeSpace().
205 // TODO: What are reasonable values for cMaxWriteBuffers
206 // and cMaxReadBuffers?
207 if (! CreateLogMarshallingArea (data->log_handle, 0, 0, 0,
208 data->buffer_size, 8, 1, &data->buffer))
209 {
210 loglog_win32_error (LOG4CPLUS_TEXT ("CreateLogMarshallingArea"));
211 goto error;
212 }
213
214 return;
215
216 error:
217 if (data->log_handle != INVALID_HANDLE_VALUE)
218 {
219 CloseHandle (data->log_handle);
220 data->log_handle = INVALID_HANDLE_VALUE;
221 }
222
223 return;
224 }
225
226
227 void
close()228 CLFSAppender::close ()
229 {
230 if (data->log_handle != INVALID_HANDLE_VALUE)
231 {
232 CloseHandle (data->log_handle);
233 data->log_handle = INVALID_HANDLE_VALUE;
234 }
235 }
236
237
238 void
append(spi::InternalLoggingEvent const & ev)239 CLFSAppender::append (spi::InternalLoggingEvent const & ev)
240 {
241 if (data->log_handle == INVALID_HANDLE_VALUE)
242 return;
243
244 // TODO: Expose log4cplus' internal TLS to use here.
245 tostringstream oss;
246 layout->formatAndAppend(oss, ev);
247
248 tstring str;
249 oss.str ().swap (str);
250 if ((str.size () + 1) * sizeof (tchar) > data->buffer_size)
251 str.resize (data->buffer_size / sizeof (tchar));
252
253 CLFS_WRITE_ENTRY clfs_write_entry;
254 clfs_write_entry.Buffer = const_cast<tchar *>(str.c_str ());
255 clfs_write_entry.ByteLength
256 = static_cast<ULONG>((str.size () + 1) * sizeof (tchar));
257
258 if (! ReserveAndAppendLog (data->buffer, &clfs_write_entry, 1, 0, 0, 0, 0,
259 CLFS_FLAG_FORCE_APPEND, 0, 0))
260 loglog_win32_error (LOG4CPLUS_TEXT ("ReserveAndAppendLog"));
261 }
262
263
264 void
registerAppender()265 CLFSAppender::registerAppender ()
266 {
267 log4cplus::spi::AppenderFactoryRegistry & reg
268 = log4cplus::spi::getAppenderFactoryRegistry ();
269 LOG4CPLUS_REG_APPENDER (reg, CLFSAppender);
270 }
271
272
273 } // namespace log4cplus
274
275
276 extern "C"
DllMain(LOG4CPLUS_DLLMAIN_HINSTANCE,DWORD fdwReason,LPVOID)277 BOOL WINAPI DllMain(LOG4CPLUS_DLLMAIN_HINSTANCE, // handle to DLL module
278 DWORD fdwReason, // reason for calling function
279 LPVOID) // reserved
280 {
281 // Perform actions based on the reason for calling.
282 switch( fdwReason )
283 {
284 case DLL_PROCESS_ATTACH:
285 {
286 log4cplus::CLFSAppender::registerAppender ();
287 break;
288 }
289
290 case DLL_THREAD_ATTACH:
291 break;
292
293 case DLL_THREAD_DETACH:
294 break;
295
296 case DLL_PROCESS_DETACH:
297 break;
298 }
299
300 return TRUE; // Successful DLL_PROCESS_ATTACH.
301 }
302