1 // Module: Log4cplus
2 // File: clfsappender.cxx
3 // Created: 5/2012
4 // Author: Vaclav Zeman
5 //
6 //
7 // Copyright (C) 2012, 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 "dcmtk/oflog/config.h"
31 #include "dcmtk/oflog/helpers/loglog.h"
32 #include "dcmtk/oflog/helpers/property.h"
33 #include "dcmtk/oflog/clfsap.h"
34 #include "dcmtk/oflog/spi/factory.h"
35 #include <sstream>
36 #include <iomanip>
37 #include <cstring>
38 #include "dcmtk/oflog/config/windowsh.h"
39 #include <clfsw32.h>
40 #include <clfsmgmtw32.h>
41
42
43 // Forward Declarations
44 namespace dcmtk
45 {
46 namespace log4cplus
47 {
48
49 const unsigned CLFS_APPENDER_INITIAL_LOG_SIZE = 512 * 1024;
50 const ULONG CLFS_APPENDER_DEFAULT_BUFFER_SIZE = 1024 * 64;
51
52
53 namespace
54 {
55
56 static
57 void
loglog_win32_error(tchar const * msg)58 loglog_win32_error (tchar const * msg)
59 {
60 DWORD err = GetLastError ();
61 tostringstream oss;
62 oss << DCMTK_LOG4CPLUS_TEXT ("CLFSAppender: ") << msg << DCMTK_LOG4CPLUS_TEXT(": ")
63 << err << DCMTK_LOG4CPLUS_TEXT (" / 0x")
64 << STD_NAMESPACE setw (8) << STD_NAMESPACE setfill (DCMTK_LOG4CPLUS_TEXT ('0')) << STD_NAMESPACE hex
65 << err;
66 helpers::getLogLog ().error(OFString(oss.str().c_str(), oss.str().length()));
67 }
68
69 }
70
71
72 struct CLFSAppender::Data
73 {
Datadcmtk::log4cplus::CLFSAppender::Data74 Data ()
75 : log_name ()
76 , log_handle (INVALID_HANDLE_VALUE)
77 , buffer (0)
78 , buffer_size (0)
79 { }
80
81 tstring log_name;
82 HANDLE log_handle;
83 void * buffer;
84 ULONG buffer_size;
85 };
86
87
CLFSAppender(tstring const & logname,unsigned long logsize,unsigned long buffersize)88 CLFSAppender::CLFSAppender (tstring const & logname, unsigned long logsize,
89 unsigned long buffersize)
90 : Appender ()
91 , data (new Data)
92 {
93 init (logname, logsize, buffersize);
94 }
95
96
CLFSAppender(helpers::Properties const & props)97 CLFSAppender::CLFSAppender (helpers::Properties const & props)
98 : Appender (props)
99 , data (new Data)
100 {
101 tstring logname = props.getProperty (DCMTK_LOG4CPLUS_TEXT ("LogName"));
102
103 unsigned long logsize = CLFS_APPENDER_INITIAL_LOG_SIZE;
104 props.getULong (logsize, DCMTK_LOG4CPLUS_TEXT ("LogSize"));
105
106 unsigned long buffersize = CLFS_APPENDER_DEFAULT_BUFFER_SIZE;
107 props.getULong (buffersize, DCMTK_LOG4CPLUS_TEXT ("BufferSize"));
108
109 init (logname, logsize, buffersize);
110 }
111
112
~CLFSAppender()113 CLFSAppender::~CLFSAppender ()
114 {
115 destructorImpl ();
116 delete data;
117 }
118
119
120 void
init(tstring const & logname,unsigned long logsize,unsigned long buffersize)121 CLFSAppender::init (tstring const & logname, unsigned long logsize,
122 unsigned long buffersize)
123 {
124 data->log_name = logname;
125 data->buffer_size = buffersize;
126
127 if (data->log_name.empty ())
128 helpers::getLogLog ().error (
129 DCMTK_LOG4CPLUS_TEXT ("CLFSAppender: empty log name"), true);
130
131 CLFS_MGMT_POLICY log_policy;
132 memset (&log_policy, 0, sizeof (log_policy));
133 log_policy.Version = CLFS_MGMT_POLICY_VERSION;
134 log_policy.LengthInBytes = sizeof (log_policy);
135 log_policy.PolicyFlags = 0;
136
137 CLFS_INFORMATION log_info;
138 ULONG info_size = sizeof (log_info);
139 ULONGLONG desired_size;
140 ULONGLONG resulting_size;
141
142 data->log_handle = CreateLogFile (
143 helpers::towstring (data->log_name).c_str (), GENERIC_WRITE | GENERIC_READ,
144 FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
145 OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE);
146
147 if (data->log_handle == INVALID_HANDLE_VALUE)
148 {
149 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("CreateLogFile()"));
150 goto error;
151 }
152
153 if (! RegisterManageableLogClient (data->log_handle, 0))
154 {
155 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("RegisterManageableLogClient()"));
156 goto error;
157 }
158
159
160 if (! GetLogFileInformation (data->log_handle, &log_info, &info_size))
161 {
162 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("GetLogFileInformation()"));
163 goto error;
164 }
165
166 if (log_info.TotalContainers == 0)
167 {
168 log_policy.PolicyType = ClfsMgmtPolicyNewContainerSize;
169 log_policy.PolicyParameters.NewContainerSize.SizeInBytes = logsize;
170 if (! InstallLogPolicy (data->log_handle, &log_policy))
171 {
172 loglog_win32_error (
173 DCMTK_LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyNewContainerSize)"));
174 goto error;
175 }
176 }
177
178 desired_size = 0;
179 resulting_size = 0;
180 if (! SetLogFileSizeWithPolicy (data->log_handle, &desired_size,
181 &resulting_size))
182 {
183 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("SetLogFileSizeWithPolicy()"));
184 goto error;
185 }
186
187 log_policy.PolicyType = ClfsMgmtPolicyAutoGrow;
188 log_policy.PolicyParameters.AutoGrow.Enabled = true;
189 if (! InstallLogPolicy (data->log_handle, &log_policy))
190 {
191 loglog_win32_error (
192 DCMTK_LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyAutoGrow)"));
193 goto error;
194 }
195
196 log_policy.PolicyType = ClfsMgmtPolicyGrowthRate;
197 log_policy.PolicyParameters.GrowthRate.AbsoluteGrowthInContainers = 0;
198 log_policy.PolicyParameters.GrowthRate.RelativeGrowthPercentage = 10;
199 if (! InstallLogPolicy (data->log_handle, &log_policy))
200 {
201 loglog_win32_error (
202 DCMTK_LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyGrowthRate)"));
203 goto error;
204 }
205
206 // TODO: Get underlying media sector size using GetDiskFreeSpace().
207 // TODO: What are reasonable values for cMaxWriteBuffers
208 // and cMaxReadBuffers?
209 if (! CreateLogMarshallingArea (data->log_handle, 0, 0, 0,
210 data->buffer_size, 8, 1, &data->buffer))
211 {
212 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("CreateLogMarshallingArea"));
213 goto error;
214 }
215
216 return;
217
218 error:
219 if (data->log_handle != INVALID_HANDLE_VALUE)
220 {
221 CloseHandle (data->log_handle);
222 data->log_handle = INVALID_HANDLE_VALUE;
223 }
224
225 return;
226 }
227
228
229 void
close()230 CLFSAppender::close ()
231 {
232 if (data->log_handle != INVALID_HANDLE_VALUE)
233 {
234 CloseHandle (data->log_handle);
235 data->log_handle = INVALID_HANDLE_VALUE;
236 }
237 }
238
239
240 void
append(spi::InternalLoggingEvent const & ev)241 CLFSAppender::append (spi::InternalLoggingEvent const & ev)
242 {
243 if (data->log_handle == INVALID_HANDLE_VALUE)
244 return;
245
246 // TODO: Expose log4cplus' internal TLS to use here.
247 tostringstream oss;
248 layout->formatAndAppend(oss, ev);
249
250 tstring str = OFString(oss.str().c_str(), oss.str().length());
251 //oss.str ().swap (str);
252 if ((str.size () + 1) * sizeof (tchar) > data->buffer_size)
253 str.resize (data->buffer_size / sizeof (tchar));
254
255 CLFS_WRITE_ENTRY clfs_write_entry;
256 clfs_write_entry.Buffer = OFconst_cast(tchar *, str.c_str ());
257 clfs_write_entry.ByteLength
258 = OFstatic_cast(ULONG, (str.size () + 1) * sizeof (tchar));
259
260 if (! ReserveAndAppendLog (data->buffer, &clfs_write_entry, 1, 0, 0, 0, 0,
261 CLFS_FLAG_FORCE_APPEND, 0, 0))
262 loglog_win32_error (DCMTK_LOG4CPLUS_TEXT ("ReserveAndAppendLog"));
263 }
264
265
266 void
registerAppender()267 CLFSAppender::registerAppender ()
268 {
269 dcmtk::log4cplus::spi::AppenderFactoryRegistry & reg
270 = dcmtk::log4cplus::spi::getAppenderFactoryRegistry ();
271 DCMTK_LOG4CPLUS_REG_APPENDER (reg, CLFSAppender);
272 }
273
274
275 } // namespace log4cplus
276 } // end namespace dcmtk
277
278
279 extern "C"
DllMain(DCMTK_LOG4CPLUS_DLLMAIN_HINSTANCE,DWORD fdwReason,LPVOID)280 BOOL WINAPI DllMain(DCMTK_LOG4CPLUS_DLLMAIN_HINSTANCE, // handle to DLL module
281 DWORD fdwReason, // reason for calling function
282 LPVOID) // reserved
283 {
284 // Perform actions based on the reason for calling.
285 switch( fdwReason )
286 {
287 case DLL_PROCESS_ATTACH:
288 {
289 dcmtk::log4cplus::CLFSAppender::registerAppender ();
290 break;
291 }
292
293 case DLL_THREAD_ATTACH:
294 break;
295
296 case DLL_THREAD_DETACH:
297 break;
298
299 case DLL_PROCESS_DETACH:
300 break;
301 }
302
303 return TRUE; // Successful DLL_PROCESS_ATTACH.
304 }
305