Hi michael,
I already send the source code as attachment. Also, the following code:
//////////
> > if(evaluator->isTriggeringEvent(event))
> > {
> > sendBuffer();
> > }
> > //////////
is fine and dosen't need to be comment. I debugged it and found out that
this snippet sends the log immediately if the level is Error/Fatal. If it's
Debug, it waits for the buffer to get filled before shooting the email. So
everything's working fine.
The major changes in the classes are, i commented everything related to
libsmtp and used CDO (downloaded from MSDN-exchange sdk along with samples)
which is a com object. I initialize the com object and assign the email
details.
Following are the changes:
1. Import the dependencies:
#import "C:\Program Files\Common Files\system\ado\msado25.tlb" no_namespace
rename("EOF","adoEOF"), named_guids
#import "C:\Program Files\Exchange SDK\SDK\Support\CDO\cdoex.tlb"
no_namespace
//initialize the com
hr = CoInitialize(NULL);
//modify the send buffer method
IMessagePtr iMsg(__uuidof(Message));
// Set up a reply.
iMsg->From = bstrFrom;
// Set the recipient to the sender of the message that caused the event.
iMsg->To = bstrTo;
LogLog::debug(bstrTo);
// Set up the subject string to contain the subject of the message that
caused the event.
iMsg->Subject = bstrSubject;//ansiSubject;
// Set up the text of the message to contain the URL to the message that
caused the event.
iMsg->TextBody = _com_util::ConvertStringToBSTR(T2A((TCHAR
*)s.c_str()));//T2A((TCHAR *)s.c_str());
LogLog::debug(_com_util::ConvertStringToBSTR(T2A((TCHAR *)s.c_str())));
// Send the message.
try{
LogLog::error(_T("Sending Email"));
hr = iMsg->Send();
}catch (_com_error err){
LogLog::error(err.ErrorMessage());
}
/////////////////////////////////////////////////////////////////
thats it. here's the entire copy/paste of the source file:
/*
* Copyright 2003,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <log4cxx/config.h>
#include <comutil.h>
#ifdef HAVE_SMTP
#include <log4cxx/net/smtpappender.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/stringtokenizer.h>
#import "C:\Program Files\Common Files\system\ado\msado25.tlb" no_namespace
rename("EOF","adoEOF"), named_guids
#import "C:\Program Files\Exchange SDK\SDK\Support\CDO\cdoex.tlb"
no_namespace
extern "C" {
//#include <libsmtp.h>
//#include <libsmtp_mime.h>
}
using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::net;
using namespace log4cxx::spi;
int ReadyCOM();
char * ansiFrom;
char * ansiSubject;
char * ansiTo;
BSTR bstrFrom;
BSTR bstrTo;
BSTR bstrSubject;
int error_code = 0;
char buffer [sizeof(int)*8+1];
IMPLEMENT_LOG4CXX_OBJECT(DefaultEvaluator)
IMPLEMENT_LOG4CXX_OBJECT(SMTPAppender)
bool DefaultEvaluator::isTriggeringEvent(const spi::LoggingEventPtr& event)
{
return event->getLevel()->isGreaterOrEqual(Level::ERROR);
}
SMTPAppender::SMTPAppender()
: bufferSize(512), locationInfo(false), cb(bufferSize),
evaluator(new DefaultEvaluator()), session(0),
encoding(_T("7bit")), charset(_T("us-ascii"))
{
if (ReadyCOM() == 1) {
LogLog::error(_T("Could not initialize CDO com"));
}
}
/**
Use <code>evaluator</code> passed as parameter as the
TriggeringEventEvaluator for this SMTPAppender. */
SMTPAppender::SMTPAppender(spi::TriggeringEventEvaluatorPtr evaluator)
: bufferSize(512), locationInfo(false), cb(bufferSize),
evaluator(evaluator), session(0),
encoding(_T("7bit")), charset(_T("us-ascii"))
{
}
SMTPAppender::~SMTPAppender()
{
finalize();
}
void SMTPAppender::setOption(const String& option,
const String& value)
{
if (StringHelper::equalsIgnoreCase(option, _T("buffersize")))
{
setBufferSize(OptionConverter::toInt(value, 512));
}
else if (StringHelper::equalsIgnoreCase(option,
_T("evaluatorclass")))
{
setEvaluatorClass(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("from")))
{
setFrom(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("smtphost")))
{
setSMTPHost(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("subject")))
{
setSubject(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("to")))
{
setTo(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("charset")))
{
setCharset(value);
}
else if (StringHelper::equalsIgnoreCase(option, _T("encoding")))
{
setEncoding(value);
}
else
{
AppenderSkeleton::setOption(name, value);
}
}
/**
Activate the specified options, such as the smtp host, the
recipient, from, etc. */
void SMTPAppender::activateOptions()
{
USES_CONVERSION;
// session = ::libsmtp_session_initialize();
// if (session == 0)
// {
// LogLog::error(_T("Could not intialize session."));
// return;
// }
ansiFrom = T2A((TCHAR *)from.c_str());
LogLog::error(_T("from:"));
bstrFrom = _com_util::ConvertStringToBSTR(ansiFrom);
LogLog::error(bstrFrom);
LogLog::error(_T("subject:"));
ansiSubject = T2A((TCHAR *)subject.c_str());
bstrSubject = _com_util::ConvertStringToBSTR(ansiSubject);
LogLog::error(bstrSubject);
/*
::libsmtp_set_environment(
ansiFrom,
ansiSubject,
0,
(libsmtp_session_struct *)session);
*/
std::vector<String> recipients = parseAddress(to);
std::vector<String>::iterator i;
for (i = recipients.begin(); i != recipients.end(); i++)
{
/*
if (::libsmtp_add_recipient(LIBSMTP_REC_TO,
(TCHAR *)T2A(i->c_str()),
(libsmtp_session_struct *)session) != 0)
{
LogLog::error(_T("Could not add recipient
")+*i+_T("."));
return;
}
*/
// ansiTo = (TCHAR *)T2A(i->c_str());
// char * thisVal = A2W(i->c_str());
ansiTo = T2A((TCHAR *)i->c_str());
bstrTo = _com_util::ConvertStringToBSTR(ansiTo);
LogLog::error(_T("To:"));
LogLog::error(bstrTo);
}
// MIMEPART
if (layout != 0)
{
int mimeType = 0;
String contentType = layout->getContentType();
if (contentType == _T("text/plain"))
{
// mimeType = LIBSMTP_MIME_SUB_PLAIN;
}
else if (contentType == _T("text/html"))
{
// mimeType = LIBSMTP_MIME_SUB_HTML;
}
else
{
LogLog::error(_T("invalid layout content type:
")+contentType+_T("."));
return;
}
int charset = 0;
/*
if (this->charset == _T("us-ascii"))
{
charset = LIBSMTP_CHARSET_USASCII;
}
else if (this->charset == _T("iso8859_1"))
{
charset = LIBSMTP_CHARSET_ISO8859_1;
}
else if (this->charset == _T("iso8859_2"))
{
charset = LIBSMTP_CHARSET_ISO8859_2;
}
else if (this->charset == _T("iso8859_3"))
{
charset = LIBSMTP_CHARSET_ISO8859_3;
}
else
{
LogLog::error(_T("invalid charset:
")+this->charset+_T("."));
return;
}
*/
int encoding = 0;
/*
if (this->encoding == _T("7bit"))
{
encoding = LIBSMTP_ENC_7BIT;
}
else if (this->encoding == _T("8bit"))
{
encoding = LIBSMTP_ENC_8BIT;
}
else if (this->encoding == _T("binary"))
{
encoding = LIBSMTP_ENC_BINARY;
}
else if (this->encoding == _T("base64"))
{
encoding = LIBSMTP_ENC_BASE64;
}
else if (this->encoding == _T("quoted"))
{
encoding = LIBSMTP_ENC_QUOTED;
}
else
{
LogLog::error(_T("invalid encoding:
")+this->encoding+_T("."));
return;
}
*/
/*
libsmtp_part_struct * part = 0;
part = ::libsmtp_part_new(
0,
LIBSMTP_MIME_TEXT,
mimeType,
encoding,
charset,
"content",
(libsmtp_session_struct *)session);
if (part == 0)
{
LogLog::error(_T("Error adding part."));
}
*/
}
else
{
LogLog::error(_T("Layout not set !"));
}
}
/**
Perform SMTPAppender specific appending actions, mainly adding
the event to a cyclic buffer and checking if the event triggers
an e-mail to be sent. */
void SMTPAppender::append(const spi::LoggingEventPtr& event)
{
if(!checkEntryConditions())
{
return;
}
event->getNDC();
/* if(locationInfo)
{
event.getLocationInformation();
}*/
cb.add(event);
if(evaluator->isTriggeringEvent(event))
{
sendBuffer();
}
}
/**
This method determines if there is a sense in attempting to append.
<p>It checks whether there is a set output target and also if
there is a set layout. If these checks fail, then the boolean
value <code>false</code> is returned. */
bool SMTPAppender::checkEntryConditions()
{
if(to.empty() || from.empty() || subject.empty() ||
smtpHost.empty())
{
errorHandler->error(_T("Message not configured."));
return false;
}
if(evaluator == 0)
{
errorHandler->error(_T("No TriggeringEventEvaluator is set
for appender [")+
name+_T("]."));
return false;
}
/*
if(layout == 0)
{
errorHandler->error(_T("No layout set for appender named
[")+name+_T("]."));
return false;
}
*/
return true;
}
void SMTPAppender::close()
{
synchronized sync(this);
/*
if (!this->closed && session != 0)
{
::libsmtp_free((libsmtp_session_struct *)session);
session = 0;
}
*/
this->closed = true;
}
std::vector<String> SMTPAppender::parseAddress(const String& addressStr)
{
std::vector<String> addresses;
StringTokenizer st(addressStr, _T(","));
while (st.hasMoreTokens())
{
addresses.push_back(st.nextToken());
}
return addresses;
}
/**
Send the contents of the cyclic buffer as an e-mail message.
*/
void SMTPAppender::sendBuffer()
{
// Note: this code already owns the monitor for this
// appender. This frees us from needing to synchronize on 'cb'.
try
{
USES_CONVERSION;
StringBuffer sbuf;
layout->appendHeader(sbuf);
int len = cb.length();
for(int i = 0; i < len; i++)
{
//sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
LoggingEventPtr event = cb.get();
layout->format(sbuf, event);
}
layout->appendFooter(sbuf);
/* This starts the SMTP connection */
/*
if (::libsmtp_connect(
T2A((TCHAR *)smtpHost.c_str()),
0,
0,
(libsmtp_session_struct *)session) != 0)
{
LogLog::error(_T("Error occured while starting the
SMTP connection."));
return;
}
*/
/* This will conduct the SMTP dialogue */
/*
if (::libsmtp_dialogue((libsmtp_session_struct *)session) !=
0)
{
LogLog::error(_T("Error occured while conducting the
SMTP dialogue."));
return;
}
*/
/* Now lets send the headers */
/*
if (::libsmtp_headers((libsmtp_session_struct *)session) !=
0)
{
LogLog::error(_T("Error occured while sending the
headers."));
return;
}
*/
/* Now lets send the MIME headers */
/*
if (::libsmtp_mime_headers((libsmtp_session_struct
*)session) != 0)
{
LogLog::error(_T("Error occured while sending the
MIME headers."));
return;
}
*/
String s = sbuf.str();
HRESULT hr;
// Create a new message.
IMessagePtr iMsg(__uuidof(Message));
// Set up a reply.
iMsg->From = bstrFrom;
// Set the recipient to the sender of the message that
caused the event.
iMsg->To = bstrTo;
LogLog::debug(bstrTo);
// Set up the subject string to contain the subject of the
message that caused the event.
iMsg->Subject = bstrSubject;//ansiSubject;
// Set up the text of the message to contain the URL to the
message that caused the event.
iMsg->TextBody = _com_util::ConvertStringToBSTR(T2A((TCHAR
*)s.c_str()));//T2A((TCHAR *)s.c_str());
LogLog::debug(_com_util::ConvertStringToBSTR(T2A((TCHAR
*)s.c_str())));
// Send the message.
try{
LogLog::error(_T("Sending Email"));
hr = iMsg->Send();
}catch (_com_error err){
LogLog::error(err.ErrorMessage());
}
// LogLog::error(_T("Don't know if error occured while sending
the message body."));
/*
if (::libsmtp_part_send(
T2A((TCHAR *)s.c_str()),
s.length(),
(libsmtp_session_struct *)session) != 0)
{
LogLog::error(_T("Error occured while sending the
message body."));
}
*/
/* This ends the body part */
/*
if (::libsmtp_body_end((libsmtp_session_struct *)session) !=
0)
{
LogLog::error(_T("Error occured while ending the
body part."));
return;
}
*/
/* This ends the connection gracefully */
/*
if (::libsmtp_quit((libsmtp_session_struct *)session) != 0)
{
LogLog::error(_T("Error occured while ending the
connection."));
return;
}
*/
}
catch(Exception& e)
{
LogLog::error(_T("Error occured while sending e-mail
notification."), e);
}
}
/**
Returns value of the <b>EvaluatorClass</b> option.
*/
String SMTPAppender::getEvaluatorClass()
{
return evaluator == 0 ? String() : evaluator->getClass().getName();
}
/**
The <b>BufferSize</b> option takes a positive integer
representing the maximum number of logging events to collect in a
cyclic buffer. When the <code>BufferSize</code> is reached,
oldest events are deleted as new events are added to the
buffer. By default the size of the cyclic buffer is 512 events.
*/
void SMTPAppender::setBufferSize(int bufferSize)
{
this->bufferSize = bufferSize;
cb.resize(bufferSize);
}
/**
The <b>EvaluatorClass</b> option takes a string value
representing the name of the class implementing the [EMAIL PROTECTED]
TriggeringEventEvaluator} interface. A corresponding object will
be instantiated and assigned as the triggering event evaluator
for the SMTPAppender.
*/
void SMTPAppender::setEvaluatorClass(const String& value)
{
evaluator = OptionConverter::instantiateByClassName(value,
TriggeringEventEvaluator::getStaticClass(), evaluator);
}
#endif //HAVE_SMTP
int ReadyCOM()
{
HRESULT hr;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
//cout << "COM Initialization Failed." << endl;
return 1;
}
return 0;
}