mirror of
https://github.com/boostorg/log.git
synced 2026-02-10 11:32:32 +00:00
On compilers without support for unreachable code or noreturn hints generate dummy return statements to silence warnings.
624 lines
21 KiB
C++
624 lines
21 KiB
C++
/*
|
|
* Copyright Andrey Semashev 2007 - 2014.
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
/*!
|
|
* \file event_log_backend.cpp
|
|
* \author Andrey Semashev
|
|
* \date 07.11.2008
|
|
*
|
|
* \brief A logging sink backend that uses Windows NT event log API
|
|
* for signalling application events.
|
|
*/
|
|
|
|
#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
|
|
|
|
#include "windows_version.hpp"
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <ostream>
|
|
#include <stdexcept>
|
|
#include <boost/scoped_array.hpp>
|
|
#include <boost/log/exceptions.hpp>
|
|
#include <boost/log/sinks/event_log_backend.hpp>
|
|
#include <boost/log/sinks/event_log_constants.hpp>
|
|
#include <boost/log/utility/once_block.hpp>
|
|
#include <boost/log/detail/cleanup_scope_guard.hpp>
|
|
#include <boost/log/detail/attachable_sstream_buf.hpp>
|
|
#include <boost/log/detail/code_conversion.hpp>
|
|
#include <boost/log/utility/formatting_ostream.hpp>
|
|
#include "event_log_registry.hpp"
|
|
#include <windows.h>
|
|
#include <psapi.h>
|
|
#include "simple_event_log.h"
|
|
#include <boost/log/detail/header.hpp>
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma comment(lib, "psapi.lib")
|
|
#pragma comment(lib, "advapi32.lib")
|
|
#endif
|
|
|
|
|
|
namespace boost {
|
|
|
|
BOOST_LOG_OPEN_NAMESPACE
|
|
|
|
namespace sinks {
|
|
|
|
namespace event_log {
|
|
|
|
//! The function constructs log record level from an integer
|
|
BOOST_LOG_API event_type make_event_type(unsigned short lev)
|
|
{
|
|
switch (lev)
|
|
{
|
|
case success: return success;
|
|
case warning: return warning;
|
|
case error: return error;
|
|
default:
|
|
BOOST_THROW_EXCEPTION(std::out_of_range("Windows NT event type is out of range"));
|
|
BOOST_LOG_UNREACHABLE_RETURN(info);
|
|
case info: return info;
|
|
}
|
|
}
|
|
|
|
} // namespace event_log
|
|
|
|
BOOST_LOG_ANONYMOUS_NAMESPACE {
|
|
|
|
#ifdef BOOST_LOG_USE_CHAR
|
|
//! A simple forwarder to the ReportEvent API
|
|
inline BOOL report_event(
|
|
HANDLE hEventLog,
|
|
WORD wType,
|
|
WORD wCategory,
|
|
DWORD dwEventID,
|
|
PSID lpUserSid,
|
|
WORD wNumStrings,
|
|
DWORD dwDataSize,
|
|
const char** lpStrings,
|
|
LPVOID lpRawData)
|
|
{
|
|
return ReportEventA(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
|
|
}
|
|
//! A simple forwarder to the GetModuleFileName API
|
|
inline DWORD get_module_file_name(HMODULE hModule, char* lpFilename, DWORD nSize)
|
|
{
|
|
return GetModuleFileNameA(hModule, lpFilename, nSize);
|
|
}
|
|
//! A simple forwarder to the RegisterEventSource API
|
|
inline HANDLE register_event_source(const char* lpUNCServerName, const char* lpSourceName)
|
|
{
|
|
return RegisterEventSourceA(lpUNCServerName, lpSourceName);
|
|
}
|
|
//! The function completes default source name for the sink backend
|
|
inline void complete_default_simple_event_log_source_name(std::string& name)
|
|
{
|
|
name += " simple event source";
|
|
}
|
|
//! The function completes default source name for the sink backend
|
|
inline void complete_default_event_log_source_name(std::string& name)
|
|
{
|
|
name += " event source";
|
|
}
|
|
#endif // BOOST_LOG_USE_CHAR
|
|
|
|
#ifdef BOOST_LOG_USE_WCHAR_T
|
|
//! A simple forwarder to the ReportEvent API
|
|
inline BOOL report_event(
|
|
HANDLE hEventLog,
|
|
WORD wType,
|
|
WORD wCategory,
|
|
DWORD dwEventID,
|
|
PSID lpUserSid,
|
|
WORD wNumStrings,
|
|
DWORD dwDataSize,
|
|
const wchar_t** lpStrings,
|
|
LPVOID lpRawData)
|
|
{
|
|
return ReportEventW(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
|
|
}
|
|
//! A simple forwarder to the GetModuleFileName API
|
|
inline DWORD get_module_file_name(HMODULE hModule, wchar_t* lpFilename, DWORD nSize)
|
|
{
|
|
return GetModuleFileNameW(hModule, lpFilename, nSize);
|
|
}
|
|
//! A simple forwarder to the RegisterEventSource API
|
|
inline HANDLE register_event_source(const wchar_t* lpUNCServerName, const wchar_t* lpSourceName)
|
|
{
|
|
return RegisterEventSourceW(lpUNCServerName, lpSourceName);
|
|
}
|
|
//! The function completes default source name for the sink backend
|
|
inline void complete_default_simple_event_log_source_name(std::wstring& name)
|
|
{
|
|
name += L" simple event source";
|
|
}
|
|
//! The function completes default source name for the sink backend
|
|
inline void complete_default_event_log_source_name(std::wstring& name)
|
|
{
|
|
name += L" event source";
|
|
}
|
|
#endif // BOOST_LOG_USE_WCHAR_T
|
|
|
|
//! The function finds the handle for the current module
|
|
void init_self_module_handle(HMODULE& handle)
|
|
{
|
|
// Acquire all modules of the current process
|
|
HANDLE hProcess = GetCurrentProcess();
|
|
std::vector< HMODULE > modules;
|
|
DWORD module_count = 1024;
|
|
do
|
|
{
|
|
modules.resize(module_count, HMODULE(0));
|
|
BOOL res = EnumProcessModules(
|
|
hProcess,
|
|
&modules[0],
|
|
static_cast< DWORD >(modules.size() * sizeof(HMODULE)),
|
|
&module_count);
|
|
module_count /= sizeof(HMODULE);
|
|
|
|
if (!res)
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not enumerate process modules");
|
|
}
|
|
while (module_count > modules.size());
|
|
modules.resize(module_count, HMODULE(0));
|
|
|
|
// Now find the current module among them
|
|
void* p = (void*)&init_self_module_handle;
|
|
for (std::size_t i = 0, n = modules.size(); i < n; ++i)
|
|
{
|
|
MODULEINFO info;
|
|
if (!GetModuleInformation(hProcess, modules[i], &info, sizeof(info)))
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not acquire module information");
|
|
|
|
if (info.lpBaseOfDll <= p && (static_cast< unsigned char* >(info.lpBaseOfDll) + info.SizeOfImage) > p)
|
|
{
|
|
// Found it
|
|
handle = modules[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!handle)
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not find self module information");
|
|
}
|
|
|
|
//! Retrieves the full name of the current module (be that dll or exe)
|
|
template< typename CharT >
|
|
std::basic_string< CharT > get_current_module_name()
|
|
{
|
|
static HMODULE hSelfModule = 0;
|
|
|
|
BOOST_LOG_ONCE_BLOCK()
|
|
{
|
|
init_self_module_handle(hSelfModule);
|
|
}
|
|
|
|
// Get the module file name
|
|
CharT buf[MAX_PATH];
|
|
DWORD size = get_module_file_name(hSelfModule, buf, sizeof(buf) / sizeof(*buf));
|
|
if (size == 0)
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not get module file name");
|
|
|
|
return std::basic_string< CharT >(buf, buf + size);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Simple event log backend implementation
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//! Sink backend implementation
|
|
template< typename CharT >
|
|
struct basic_simple_event_log_backend< CharT >::implementation
|
|
{
|
|
//! A handle for the registered event provider
|
|
HANDLE m_SourceHandle;
|
|
//! A level mapping functor
|
|
event_type_mapper_type m_LevelMapper;
|
|
|
|
implementation() : m_SourceHandle(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
//! Default constructor. Registers event source Boost.Log <Boost version> in the Application log.
|
|
template< typename CharT >
|
|
BOOST_LOG_API basic_simple_event_log_backend< CharT >::basic_simple_event_log_backend()
|
|
{
|
|
construct(log::aux::empty_arg_list());
|
|
}
|
|
|
|
//! Destructor
|
|
template< typename CharT >
|
|
BOOST_LOG_API basic_simple_event_log_backend< CharT >::~basic_simple_event_log_backend()
|
|
{
|
|
DeregisterEventSource(m_pImpl->m_SourceHandle);
|
|
delete m_pImpl;
|
|
}
|
|
|
|
//! Constructs backend implementation
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_simple_event_log_backend< CharT >::construct(
|
|
string_type const& target, string_type const& log_name, string_type const& source_name, event_log::registration_mode reg_mode)
|
|
{
|
|
if (reg_mode != event_log::never)
|
|
{
|
|
aux::registry_params< char_type > reg_params;
|
|
reg_params.event_message_file = get_current_module_name< char_type >();
|
|
reg_params.types_supported = DWORD(
|
|
EVENTLOG_SUCCESS |
|
|
EVENTLOG_INFORMATION_TYPE |
|
|
EVENTLOG_WARNING_TYPE |
|
|
EVENTLOG_ERROR_TYPE);
|
|
aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params);
|
|
}
|
|
|
|
std::auto_ptr< implementation > p(new implementation());
|
|
|
|
const char_type* target_unc = NULL;
|
|
if (!target.empty())
|
|
target_unc = target.c_str();
|
|
|
|
HANDLE hSource = register_event_source(target_unc, source_name.c_str());
|
|
if (!hSource)
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not register event source");
|
|
|
|
p->m_SourceHandle = hSource;
|
|
|
|
m_pImpl = p.release();
|
|
}
|
|
|
|
//! Returns default log name
|
|
template< typename CharT >
|
|
BOOST_LOG_API typename basic_simple_event_log_backend< CharT >::string_type
|
|
basic_simple_event_log_backend< CharT >::get_default_log_name()
|
|
{
|
|
return aux::registry_traits< char_type >::make_default_log_name();
|
|
}
|
|
|
|
//! Returns default source name
|
|
template< typename CharT >
|
|
BOOST_LOG_API typename basic_simple_event_log_backend< CharT >::string_type
|
|
basic_simple_event_log_backend< CharT >::get_default_source_name()
|
|
{
|
|
string_type source_name = aux::registry_traits< char_type >::make_default_source_name();
|
|
complete_default_simple_event_log_source_name(source_name);
|
|
return source_name;
|
|
}
|
|
|
|
//! The method installs the function object that maps application severity levels to WinAPI event types
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_simple_event_log_backend< CharT >::set_event_type_mapper(event_type_mapper_type const& mapper)
|
|
{
|
|
m_pImpl->m_LevelMapper = mapper;
|
|
}
|
|
|
|
//! The method puts the formatted message to the event log
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_simple_event_log_backend< CharT >::consume(record_view const& rec, string_type const& formatted_message)
|
|
{
|
|
const char_type* message = formatted_message.c_str();
|
|
event_log::event_type evt_type = event_log::info;
|
|
if (!m_pImpl->m_LevelMapper.empty())
|
|
evt_type = m_pImpl->m_LevelMapper(rec);
|
|
|
|
DWORD event_id;
|
|
switch (evt_type)
|
|
{
|
|
case event_log::success:
|
|
event_id = BOOST_LOG_MSG_DEBUG; break;
|
|
case event_log::warning:
|
|
event_id = BOOST_LOG_MSG_WARNING; break;
|
|
case event_log::error:
|
|
event_id = BOOST_LOG_MSG_ERROR; break;
|
|
default:
|
|
event_id = BOOST_LOG_MSG_INFO; break;
|
|
}
|
|
|
|
report_event(
|
|
m_pImpl->m_SourceHandle, // Event log handle.
|
|
static_cast< WORD >(evt_type), // Event type.
|
|
0, // Event category.
|
|
event_id, // Event identifier.
|
|
NULL, // No user security identifier.
|
|
1, // Number of substitution strings.
|
|
0, // No data.
|
|
&message, // Pointer to strings.
|
|
NULL); // No data.
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Customizable event log backend implementation
|
|
//////////////////////////////////////////////////////////////////////////
|
|
namespace event_log {
|
|
|
|
template< typename CharT >
|
|
class basic_event_composer< CharT >::insertion_composer
|
|
{
|
|
public:
|
|
//! Function object result type
|
|
typedef void result_type;
|
|
|
|
private:
|
|
//! The list of insertion composers (in backward order)
|
|
typedef std::vector< formatter_type > formatters;
|
|
|
|
private:
|
|
//! The insertion string composers
|
|
formatters m_Formatters;
|
|
|
|
public:
|
|
//! Default constructor
|
|
insertion_composer() {}
|
|
//! Composition operator
|
|
void operator() (record_view const& rec, insertion_list& insertions) const
|
|
{
|
|
std::size_t size = m_Formatters.size();
|
|
insertions.resize(size);
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
{
|
|
typename formatter_type::stream_type strm(insertions[i]);
|
|
m_Formatters[i](rec, strm);
|
|
strm.flush();
|
|
}
|
|
}
|
|
//! Adds a new formatter to the list
|
|
void add_formatter(formatter_type const& fmt)
|
|
{
|
|
m_Formatters.push_back(formatter_type(fmt));
|
|
}
|
|
};
|
|
|
|
//! Default constructor
|
|
template< typename CharT >
|
|
basic_event_composer< CharT >::basic_event_composer(event_id_mapper_type const& id_mapper) :
|
|
m_EventIDMapper(id_mapper)
|
|
{
|
|
}
|
|
//! Copy constructor
|
|
template< typename CharT >
|
|
basic_event_composer< CharT >::basic_event_composer(basic_event_composer const& that) :
|
|
m_EventIDMapper(that.m_EventIDMapper),
|
|
m_EventMap(that.m_EventMap)
|
|
{
|
|
}
|
|
//! Destructor
|
|
template< typename CharT >
|
|
basic_event_composer< CharT >::~basic_event_composer()
|
|
{
|
|
}
|
|
|
|
//! Assignment
|
|
template< typename CharT >
|
|
basic_event_composer< CharT >& basic_event_composer< CharT >::operator= (basic_event_composer that)
|
|
{
|
|
swap(that);
|
|
return *this;
|
|
}
|
|
//! Swapping
|
|
template< typename CharT >
|
|
void basic_event_composer< CharT >::swap(basic_event_composer& that)
|
|
{
|
|
m_EventIDMapper.swap(that.m_EventIDMapper);
|
|
m_EventMap.swap(that.m_EventMap);
|
|
}
|
|
//! Creates a new entry for a message
|
|
template< typename CharT >
|
|
typename basic_event_composer< CharT >::event_map_reference
|
|
basic_event_composer< CharT >::operator[] (event_id id)
|
|
{
|
|
return event_map_reference(id, *this);
|
|
}
|
|
//! Creates a new entry for a message
|
|
template< typename CharT >
|
|
typename basic_event_composer< CharT >::event_map_reference
|
|
basic_event_composer< CharT >::operator[] (int id)
|
|
{
|
|
return event_map_reference(make_event_id(id), *this);
|
|
}
|
|
|
|
//! Event composition operator
|
|
template< typename CharT >
|
|
event_id basic_event_composer< CharT >::operator() (record_view const& rec, insertion_list& insertions) const
|
|
{
|
|
event_id id = m_EventIDMapper(rec);
|
|
typename event_map::const_iterator it = m_EventMap.find(id);
|
|
if (it != m_EventMap.end())
|
|
it->second(rec, insertions);
|
|
return id;
|
|
}
|
|
|
|
//! Adds a formatter to the insertion composers list
|
|
template< typename CharT >
|
|
typename basic_event_composer< CharT >::insertion_composer*
|
|
basic_event_composer< CharT >::add_formatter(event_id id, insertion_composer* composer, formatter_type const& fmt)
|
|
{
|
|
if (!composer)
|
|
composer = &m_EventMap[id];
|
|
composer->add_formatter(fmt);
|
|
return composer;
|
|
}
|
|
|
|
#ifdef BOOST_LOG_USE_CHAR
|
|
template class BOOST_LOG_API basic_event_composer< char >;
|
|
#endif
|
|
#ifdef BOOST_LOG_USE_WCHAR_T
|
|
template class BOOST_LOG_API basic_event_composer< wchar_t >;
|
|
#endif
|
|
|
|
} // namespace event_log
|
|
|
|
|
|
//! Backend implementation
|
|
template< typename CharT >
|
|
struct basic_event_log_backend< CharT >::implementation
|
|
{
|
|
// NOTE: This order of data members is critical for MSVC 9.0 in debug mode,
|
|
// as it ICEs if boost::functions are not the first members. Doh!
|
|
|
|
//! An event category mapper
|
|
event_category_mapper_type m_CategoryMapper;
|
|
//! A level mapping functor
|
|
event_type_mapper_type m_LevelMapper;
|
|
|
|
//! A handle for the registered event provider
|
|
HANDLE m_SourceHandle;
|
|
//! A functor that composes an event
|
|
event_composer_type m_EventComposer;
|
|
//! An array of formatted insertions
|
|
insertion_list m_Insertions;
|
|
|
|
implementation() : m_SourceHandle(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
//! Destructor
|
|
template< typename CharT >
|
|
BOOST_LOG_API basic_event_log_backend< CharT >::~basic_event_log_backend()
|
|
{
|
|
DeregisterEventSource(m_pImpl->m_SourceHandle);
|
|
delete m_pImpl;
|
|
}
|
|
|
|
//! Constructs backend implementation
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_event_log_backend< CharT >::construct(
|
|
filesystem::path const& message_file_name,
|
|
string_type const& target,
|
|
string_type const& log_name,
|
|
string_type const& source_name,
|
|
event_log::registration_mode reg_mode)
|
|
{
|
|
if (reg_mode != event_log::never)
|
|
{
|
|
aux::registry_params< char_type > reg_params;
|
|
string_type file_name;
|
|
log::aux::code_convert(message_file_name.string(), file_name);
|
|
reg_params.event_message_file = file_name;
|
|
reg_params.types_supported = DWORD(
|
|
EVENTLOG_SUCCESS |
|
|
EVENTLOG_INFORMATION_TYPE |
|
|
EVENTLOG_WARNING_TYPE |
|
|
EVENTLOG_ERROR_TYPE);
|
|
aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params);
|
|
}
|
|
|
|
std::auto_ptr< implementation > p(new implementation());
|
|
|
|
const char_type* target_unc = NULL;
|
|
if (!target.empty())
|
|
target_unc = target.c_str();
|
|
|
|
HANDLE hSource = register_event_source(target_unc, source_name.c_str());
|
|
if (!hSource)
|
|
BOOST_LOG_THROW_DESCR(system_error, "Could not register event source");
|
|
|
|
p->m_SourceHandle = hSource;
|
|
|
|
m_pImpl = p.release();
|
|
}
|
|
|
|
//! The method puts the formatted message to the event log
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_event_log_backend< CharT >::consume(record_view const& rec)
|
|
{
|
|
if (!m_pImpl->m_EventComposer.empty())
|
|
{
|
|
log::aux::cleanup_guard< insertion_list > cleaner(m_pImpl->m_Insertions);
|
|
|
|
// Get event ID and construct insertions
|
|
DWORD id = m_pImpl->m_EventComposer(rec, m_pImpl->m_Insertions);
|
|
WORD string_count = static_cast< WORD >(m_pImpl->m_Insertions.size());
|
|
scoped_array< const char_type* > strings(new const char_type*[string_count]);
|
|
for (WORD i = 0; i < string_count; ++i)
|
|
strings[i] = m_pImpl->m_Insertions[i].c_str();
|
|
|
|
// Get event type
|
|
WORD event_type = EVENTLOG_INFORMATION_TYPE;
|
|
if (!m_pImpl->m_LevelMapper.empty())
|
|
event_type = static_cast< WORD >(m_pImpl->m_LevelMapper(rec));
|
|
|
|
WORD event_category = 0;
|
|
if (!m_pImpl->m_CategoryMapper.empty())
|
|
event_category = static_cast< WORD >(m_pImpl->m_CategoryMapper(rec));
|
|
|
|
report_event(
|
|
m_pImpl->m_SourceHandle, // Event log handle.
|
|
event_type, // Event type.
|
|
event_category, // Event category.
|
|
id, // Event identifier.
|
|
NULL, // No user security identifier.
|
|
string_count, // Number of substitution strings.
|
|
0, // No data.
|
|
strings.get(), // Pointer to strings.
|
|
NULL); // No data.
|
|
}
|
|
}
|
|
|
|
//! Returns default log name
|
|
template< typename CharT >
|
|
BOOST_LOG_API typename basic_event_log_backend< CharT >::string_type
|
|
basic_event_log_backend< CharT >::get_default_log_name()
|
|
{
|
|
return aux::registry_traits< char_type >::make_default_log_name();
|
|
}
|
|
|
|
//! Returns default source name
|
|
template< typename CharT >
|
|
BOOST_LOG_API typename basic_event_log_backend< CharT >::string_type
|
|
basic_event_log_backend< CharT >::get_default_source_name()
|
|
{
|
|
string_type source_name = aux::registry_traits< char_type >::make_default_source_name();
|
|
complete_default_event_log_source_name(source_name);
|
|
return source_name;
|
|
}
|
|
|
|
//! The method installs the function object that maps application severity levels to WinAPI event types
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_type_mapper(event_type_mapper_type const& mapper)
|
|
{
|
|
m_pImpl->m_LevelMapper = mapper;
|
|
}
|
|
|
|
//! The method installs the function object that extracts event category from attribute values
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_category_mapper(event_category_mapper_type const& mapper)
|
|
{
|
|
m_pImpl->m_CategoryMapper = mapper;
|
|
}
|
|
|
|
/*!
|
|
* The method installs the function object that extracts event identifier from the attributes and creates
|
|
* insertion strings that will replace placeholders in the event message.
|
|
*/
|
|
template< typename CharT >
|
|
BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_composer(event_composer_type const& composer)
|
|
{
|
|
m_pImpl->m_EventComposer = composer;
|
|
}
|
|
|
|
|
|
#ifdef BOOST_LOG_USE_CHAR
|
|
template class basic_simple_event_log_backend< char >;
|
|
template class basic_event_log_backend< char >;
|
|
#endif
|
|
#ifdef BOOST_LOG_USE_WCHAR_T
|
|
template class basic_simple_event_log_backend< wchar_t >;
|
|
template class basic_event_log_backend< wchar_t >;
|
|
#endif
|
|
|
|
} // namespace sinks
|
|
|
|
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
|
|
|
} // namespace boost
|
|
|
|
#include <boost/log/detail/footer.hpp>
|
|
|
|
#endif // !defined(BOOST_LOG_WITHOUT_EVENT_LOG)
|