You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

301 lines
8.4 KiB

// Module: Log4cplus
// File: clfsappender.cxx
// Created: 5/2012
// Author: Vaclav Zeman
//
//
// Copyright (C) 2012-2013, Vaclav Zeman. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modifica-
// tion, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <log4cplus/config.hxx>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/clfsappender.h>
#include <log4cplus/spi/factory.h>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <log4cplus/config/windowsh-inc.h>
#include <clfsw32.h>
#include <clfsmgmtw32.h>
// Forward Declarations
namespace log4cplus
{
const unsigned CLFS_APPENDER_INITIAL_LOG_SIZE = 512 * 1024;
const ULONG CLFS_APPENDER_DEFAULT_BUFFER_SIZE = 1024 * 64;
namespace
{
static
void
loglog_win32_error (tchar const * msg)
{
DWORD err = GetLastError ();
tostringstream oss;
oss << LOG4CPLUS_TEXT ("CLFSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
<< err << LOG4CPLUS_TEXT (" / 0x")
<< std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
<< err;
helpers::getLogLog ().error (oss.str ());
}
}
struct CLFSAppender::Data
{
Data ()
: log_name ()
, log_handle (INVALID_HANDLE_VALUE)
, buffer (0)
, buffer_size (0)
{ }
tstring log_name;
HANDLE log_handle;
void * buffer;
ULONG buffer_size;
};
CLFSAppender::CLFSAppender (tstring const & logname, unsigned long logsize,
unsigned long buffersize)
: Appender ()
, data (new Data)
{
init (logname, logsize, buffersize);
}
CLFSAppender::CLFSAppender (helpers::Properties const & props)
: Appender (props)
, data (new Data)
{
tstring logname = props.getProperty (LOG4CPLUS_TEXT ("LogName"));
unsigned long logsize = CLFS_APPENDER_INITIAL_LOG_SIZE;
props.getULong (logsize, LOG4CPLUS_TEXT ("LogSize"));
unsigned long buffersize = CLFS_APPENDER_DEFAULT_BUFFER_SIZE;
props.getULong (buffersize, LOG4CPLUS_TEXT ("BufferSize"));
init (logname, logsize, buffersize);
}
CLFSAppender::~CLFSAppender ()
{
destructorImpl ();
delete data;
}
void
CLFSAppender::init (tstring const & logname, unsigned long logsize,
unsigned long buffersize)
{
data->log_name = logname;
data->buffer_size = buffersize;
if (data->log_name.empty ())
helpers::getLogLog ().error (
LOG4CPLUS_TEXT ("CLFSAppender: empty log name"), true);
CLFS_MGMT_POLICY log_policy;
std::memset (&log_policy, 0, sizeof (log_policy));
log_policy.Version = CLFS_MGMT_POLICY_VERSION;
log_policy.LengthInBytes = sizeof (log_policy);
log_policy.PolicyFlags = 0;
CLFS_INFORMATION log_info;
ULONG info_size = sizeof (log_info);
ULONGLONG desired_size;
ULONGLONG resulting_size;
data->log_handle = CreateLogFile (
helpers::towstring (data->log_name).c_str (), GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE);
if (data->log_handle == INVALID_HANDLE_VALUE)
{
loglog_win32_error (LOG4CPLUS_TEXT ("CreateLogFile()"));
goto error;
}
if (! RegisterManageableLogClient (data->log_handle, 0))
{
loglog_win32_error (LOG4CPLUS_TEXT ("RegisterManageableLogClient()"));
goto error;
}
if (! GetLogFileInformation (data->log_handle, &log_info, &info_size))
{
loglog_win32_error (LOG4CPLUS_TEXT ("GetLogFileInformation()"));
goto error;
}
if (log_info.TotalContainers == 0)
{
log_policy.PolicyType = ClfsMgmtPolicyNewContainerSize;
log_policy.PolicyParameters.NewContainerSize.SizeInBytes = logsize;
if (! InstallLogPolicy (data->log_handle, &log_policy))
{
loglog_win32_error (
LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyNewContainerSize)"));
goto error;
}
}
desired_size = 0;
resulting_size = 0;
if (! SetLogFileSizeWithPolicy (data->log_handle, &desired_size,
&resulting_size))
{
loglog_win32_error (LOG4CPLUS_TEXT ("SetLogFileSizeWithPolicy()"));
goto error;
}
log_policy.PolicyType = ClfsMgmtPolicyAutoGrow;
log_policy.PolicyParameters.AutoGrow.Enabled = true;
if (! InstallLogPolicy (data->log_handle, &log_policy))
{
loglog_win32_error (
LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyAutoGrow)"));
goto error;
}
log_policy.PolicyType = ClfsMgmtPolicyGrowthRate;
log_policy.PolicyParameters.GrowthRate.AbsoluteGrowthInContainers = 0;
log_policy.PolicyParameters.GrowthRate.RelativeGrowthPercentage = 10;
if (! InstallLogPolicy (data->log_handle, &log_policy))
{
loglog_win32_error (
LOG4CPLUS_TEXT ("InstallLogPolicy(ClfsMgmtPolicyGrowthRate)"));
goto error;
}
// TODO: Get underlying media sector size using GetDiskFreeSpace().
// TODO: What are reasonable values for cMaxWriteBuffers
// and cMaxReadBuffers?
if (! CreateLogMarshallingArea (data->log_handle, 0, 0, 0,
data->buffer_size, 8, 1, &data->buffer))
{
loglog_win32_error (LOG4CPLUS_TEXT ("CreateLogMarshallingArea"));
goto error;
}
return;
error:
if (data->log_handle != INVALID_HANDLE_VALUE)
{
CloseHandle (data->log_handle);
data->log_handle = INVALID_HANDLE_VALUE;
}
return;
}
void
CLFSAppender::close ()
{
if (data->log_handle != INVALID_HANDLE_VALUE)
{
CloseHandle (data->log_handle);
data->log_handle = INVALID_HANDLE_VALUE;
}
}
void
CLFSAppender::append (spi::InternalLoggingEvent const & ev)
{
if (data->log_handle == INVALID_HANDLE_VALUE)
return;
// TODO: Expose log4cplus' internal TLS to use here.
tostringstream oss;
layout->formatAndAppend(oss, ev);
tstring str;
oss.str ().swap (str);
if ((str.size () + 1) * sizeof (tchar) > data->buffer_size)
str.resize (data->buffer_size / sizeof (tchar));
CLFS_WRITE_ENTRY clfs_write_entry;
clfs_write_entry.Buffer = const_cast<tchar *>(str.c_str ());
clfs_write_entry.ByteLength
= static_cast<ULONG>((str.size () + 1) * sizeof (tchar));
if (! ReserveAndAppendLog (data->buffer, &clfs_write_entry, 1, 0, 0, 0, 0,
CLFS_FLAG_FORCE_APPEND, 0, 0))
loglog_win32_error (LOG4CPLUS_TEXT ("ReserveAndAppendLog"));
}
void
CLFSAppender::registerAppender ()
{
log4cplus::spi::AppenderFactoryRegistry & reg
= log4cplus::spi::getAppenderFactoryRegistry ();
LOG4CPLUS_REG_APPENDER (reg, CLFSAppender);
}
} // namespace log4cplus
extern "C"
BOOL WINAPI DllMain(LOG4CPLUS_DLLMAIN_HINSTANCE, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
{
log4cplus::CLFSAppender::registerAppender ();
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}