Our application stores its data in a MySql database. We can't install the MySql odbc driver on each computer that uses our product so we are forced to use the MySql client library. So, to be able to log to our database, I needed an appender that could log to MySql using the MySql client library - thus, the MySqlAppender was born.
This class derives from the ODBC Appender and just overrides the implementation of execute() to use the Mysql library. It also uses a few more options.
This should be able to work in a non-windows environment, but I haven't tested it anywhere but windows and VC 2003. If it is of use to someone, great. If not, I still needed it.
josh
#include "StdAfx.h" #include "MySqlAppender.h" #include <winsock.h>
#pragma comment(lib, "libmySQL.lib")
#include "MySql.h"
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/transcoder.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::db;
IMPLEMENT_LOG4CXX_OBJECT(MySqlAppender)
MySqlAppender::MySqlAppender(void)
: m_bIsConnectionOpen(false)
{
m_mysql = new MYSQL;
}
MySqlAppender::~MySqlAppender(void)
{
mysql_close(m_mysql);
delete m_mysql;
m_mysql = NULL;
m_bIsConnectionOpen = false;
}
void MySqlAppender::setOption(const LogString& option, const LogString& value)
{
if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SERVER"),
LOG4CXX_STR("server")) )
{
setServer(value);
}
else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("DATABASE"),
LOG4CXX_STR("database")) )
{
setDatabase(value);
}
else
{
ODBCAppender::setOption(option, value);
}
}
void MySqlAppender::execute(const LogString& sql)
{
try
{
if ( m_bIsConnectionOpen == false )
{
OpenConnection();
}
// Execute sql statement...
LOG4CXX_ENCODE_CHAR( strEncodedSql, sql );
if ( strEncodedSql.empty() == true) throw SQLException("Tried
to log an empty sql query.");
int nResult = mysql_real_query( m_mysql, strEncodedSql.c_str(),
strEncodedSql.size() );
// Error Checking
if ( nResult != 0 ) throw SQLException(
mysql_error(m_mysql) );
// Close Connection...
CloseConnection();
}
catch (SQLException& e)
{
throw e;
}
}
void MySqlAppender::OpenConnection()
{
// Initialize MySql
mysql_init(m_mysql);
mysql_options(m_mysql, MYSQL_OPT_LOCAL_INFILE, NULL );
// Open Connection...
LOG4CXX_ENCODE_CHAR( strServer, databaseServer );
LOG4CXX_ENCODE_CHAR( strDatabase, databaseDatabase );
LOG4CXX_ENCODE_CHAR( strUserName, databaseUser );
LOG4CXX_ENCODE_CHAR( strPassword, databasePassword );
MYSQL* pResult = mysql_real_connect(m_mysql,
strServer.c_str(),
strUserName.c_str(),
strPassword.c_str(),
strDatabase.c_str(),
0,NULL, CLIENT_MULTI_STATEMENTS);
if (pResult == NULL)
{
throw SQLException( mysql_error(m_mysql) );
}
m_bIsConnectionOpen = true;
}
void MySqlAppender::CloseConnection()
{
// We don't close the connection here.
// We'll leave it open so we don't keep reconnecting...
// We could call this if needed though...
// mysql_close(m_mysql);
// m_bIsConnectionOpen = false;
}
#ifndef _LOG4CXX_DB_MYSQL_APPENDER_HEADER_
#define _LOG4CXX_DB_MYSQL_APPENDER_HEADER_
#define LOG4CXX_HAVE_ODBC
#include <log4cxx/db/odbcappender.h>
#include <log4cxx/helpers/Object.h>
typedef struct st_mysql MYSQL;
namespace log4cxx
{
namespace db
{
class MySqlAppender;
typedef helpers::ObjectPtrT<MySqlAppender> MySqlAppenderPtr;
class /*LOG4CXX_EXPORT*/ MySqlAppender : public ODBCAppender
{
public:
DECLARE_LOG4CXX_OBJECT(MySqlAppender)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(MySqlAppender)
LOG4CXX_CAST_ENTRY_CHAIN(ODBCAppender)
END_LOG4CXX_CAST_MAP()
MySqlAppender(void);
~MySqlAppender(void);
virtual void setOption(const LogString& option, const
LogString& value);
virtual void execute(const LogString& sql)
/*throw(SQLException)*/;
inline void setServer(const LogString& server)
{ databaseServer = server; }
inline void setDatabase(const LogString& database)
{ databaseDatabase = database; }
protected:
MYSQL* m_mysql;
LogString databaseServer;
LogString databaseDatabase;
bool m_bIsConnectionOpen;
virtual void OpenConnection();
virtual void CloseConnection();
};
}
}
#endif //_LOG4CXX_NT_OUTPUTDEBUGSTRING_APPENDER_HEADER_
