blob: e1b8fd5187f62ce8552977a9ca04994efee8223f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef _LOG4CXX_DB_ODBC_APPENDER_H
#define _LOG4CXX_DB_ODBC_APPENDER_H
#if defined(_MSC_VER)
#pragma warning ( push )
#pragma warning ( disable: 4231 4251 4275 4786 )
#endif
#include <log4cxx/log4cxx.h>
#include <log4cxx/helpers/exception.h>
#include <log4cxx/appenderskeleton.h>
#include <log4cxx/spi/loggingevent.h>
#include <list>
namespace log4cxx
{
namespace db
{
class LOG4CXX_EXPORT SQLException : public log4cxx::helpers::Exception {
public:
SQLException(short fHandleType,
void* hInput, const char* prolog,
log4cxx::helpers::Pool& p);
SQLException(const char* msg);
SQLException(const SQLException& src);
private:
const char* formatMessage(short fHandleType,
void* hInput, const char* prolog,
log4cxx::helpers::Pool& p);
};
/**
<p><b>WARNING: This version of ODBCAppender
is very likely to be completely replaced in the future. Moreoever,
it does not log exceptions.</b> </p>
The ODBCAppender provides for sending log events to a database.
<p>Each append call adds to an <code>ArrayList</code> buffer. When
the buffer is filled each log event is placed in a sql statement
(configurable) and executed.
<b>BufferSize</b>, <b>db URL</b>, <b>User</b>, & <b>Password</b> are
configurable options in the standard log4j ways.
<p>The <code>setSql(String sql)</code> sets the SQL statement to be
used for logging -- this statement is sent to a
<code>PatternLayout</code> (either created automaticly by the
appender or added by the user). Therefore by default all the
conversion patterns in <code>PatternLayout</code> can be used
inside of the statement. (see the test cases for examples)
<p>Overriding the {@link #getLogStatement} method allows more
explicit control of the statement used for logging.
<p>For use as a base class:
<ul>
<li>Override getConnection() to pass any connection
you want. Typically this is used to enable application wide
connection pooling.
<li>Override closeConnection -- if
you override getConnection make sure to implement
<code>closeConnection</code> to handle the connection you
generated. Typically this would return the connection to the
pool it came from.
<li>Override getLogStatement to
produce specialized or dynamic statements. The default uses the
sql option value.
</ul>
*/
class LOG4CXX_EXPORT ODBCAppender : public AppenderSkeleton
{
protected:
/**
* URL of the DB for default connection handling
*/
LogString databaseURL;
/**
* User to connect as for default connection handling
*/
LogString databaseUser;
/**
* User to use for default connection handling
*/
LogString databasePassword;
typedef void* SQLHDBC;
typedef void* SQLHENV;
typedef void* SQLHANDLE;
typedef short SQLSMALLINT;
/**
* Connection used by default. The connection is opened the first time it
* is needed and then held open until the appender is closed (usually at
* garbage collection). This behavior is best modified by creating a
* sub-class and overriding the <code>getConnection</code> and
* <code>closeConnection</code> methods.
*/
SQLHDBC connection;
SQLHENV env;
/**
* Stores the string given to the pattern layout for conversion into a SQL
* statement, eg: insert into LogTable (Thread, File, Message) values
* ("%t", "%F", "%m")
*
* Be careful of quotes in your messages!
*
* Also see PatternLayout.
*/
LogString sqlStatement;
/**
* size of LoggingEvent buffer before writing to the database.
* Default is 1.
*/
size_t bufferSize;
/**
* ArrayList holding the buffer of Logging Events.
*/
std::list<spi::LoggingEventPtr> buffer;
public:
DECLARE_LOG4CXX_OBJECT(ODBCAppender)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(ODBCAppender)
LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
END_LOG4CXX_CAST_MAP()
ODBCAppender();
virtual ~ODBCAppender();
/**
Set options
*/
virtual void setOption(const LogString& option, const LogString& value);
/**
Activate the specified options.
*/
virtual void activateOptions(log4cxx::helpers::Pool& p);
/**
* Adds the event to the buffer. When full the buffer is flushed.
*/
void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool&);
/**
* By default getLogStatement sends the event to the required Layout object.
* The layout will format the given pattern into a workable SQL string.
*
* Overriding this provides direct access to the LoggingEvent
* when constructing the logging statement.
*
*/
protected:
LogString getLogStatement(const spi::LoggingEventPtr& event,
helpers::Pool& p) const;
/**
*
* Override this to provide an alertnate method of getting
* connections (such as caching). One method to fix this is to open
* connections at the start of flushBuffer() and close them at the
* end. I use a connection pool outside of ODBCAppender which is
* accessed in an override of this method.
* */
virtual void execute(const LogString& sql,
log4cxx::helpers::Pool& p) /*throw(SQLException)*/;
/**
* Override this to return the connection to a pool, or to clean up the
* resource.
*
* The default behavior holds a single connection open until the appender
* is closed (typically when garbage collected).
*/
virtual void closeConnection(SQLHDBC con);
/**
* Override this to link with your connection pooling system.
*
* By default this creates a single connection which is held open
* until the object is garbage collected.
*/
virtual SQLHDBC getConnection(log4cxx::helpers::Pool& p) /*throw(SQLException)*/;
/**
* Closes the appender, flushing the buffer first then closing the default
* connection if it is open.
*/
public:
virtual void close();
/**
* loops through the buffer of LoggingEvents, gets a
* sql string from getLogStatement() and sends it to execute().
* Errors are sent to the errorHandler.
*
* If a statement fails the LoggingEvent stays in the buffer!
*/
virtual void flushBuffer(log4cxx::helpers::Pool& p);
/**
* ODBCAppender requires a layout.
* */
virtual bool requiresLayout() const
{ return true; }
/**
* Set pre-formated statement eg: insert into LogTable (msg) values ("%m")
*/
void setSql(const LogString& s);
/**
* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
*/
inline const LogString& getSql() const
{ return sqlStatement; }
inline void setUser(const LogString& user)
{ databaseUser = user; }
inline void setURL(const LogString& url)
{ databaseURL = url; }
inline void setPassword(const LogString& password)
{ databasePassword = password; }
inline void setBufferSize(size_t newBufferSize)
{ bufferSize = newBufferSize; }
inline const LogString& getUser() const
{ return databaseUser; }
inline const LogString& getURL() const
{ return databaseURL; }
inline const LogString& getPassword() const
{ return databasePassword; }
inline size_t getBufferSize() const
{ return bufferSize; }
private:
ODBCAppender(const ODBCAppender&);
ODBCAppender& operator=(const ODBCAppender&);
static void encode(wchar_t** dest, const LogString& src,
log4cxx::helpers::Pool& p);
static void encode(unsigned short** dest, const LogString& src,
log4cxx::helpers::Pool& p);
}; // class ODBCAppender
LOG4CXX_PTR_DEF(ODBCAppender);
} // namespace db
} // namespace log4cxx
#if defined(_MSC_VER)
#pragma warning ( pop )
#endif
#endif // _LOG4CXX_DB_ODBC_APPENDER_H