/src/logging-log4cxx/src/main/include/log4cxx/db/odbcappender.h
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
| 3 |  |  * contributor license agreements.  See the NOTICE file distributed with | 
| 4 |  |  * this work for additional information regarding copyright ownership. | 
| 5 |  |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
| 6 |  |  * (the "License"); you may not use this file except in compliance with | 
| 7 |  |  * the License.  You may obtain a copy of the License at | 
| 8 |  |  * | 
| 9 |  |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  |  * | 
| 11 |  |  * Unless required by applicable law or agreed to in writing, software | 
| 12 |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 13 |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 14 |  |  * See the License for the specific language governing permissions and | 
| 15 |  |  * limitations under the License. | 
| 16 |  |  */ | 
| 17 |  |  | 
| 18 |  | #ifndef _LOG4CXX_DB_ODBC_APPENDER_H | 
| 19 |  | #define _LOG4CXX_DB_ODBC_APPENDER_H | 
| 20 |  |  | 
| 21 |  | #include <log4cxx/log4cxx.h> | 
| 22 |  |  | 
| 23 |  | #include <log4cxx/helpers/exception.h> | 
| 24 |  | #include <log4cxx/appenderskeleton.h> | 
| 25 |  | #include <log4cxx/spi/loggingevent.h> | 
| 26 |  |  | 
| 27 |  | #if LOG4CXX_EVENTS_AT_EXIT | 
| 28 |  | #include <log4cxx/private/atexitregistry.h> | 
| 29 |  | #endif | 
| 30 |  |  | 
| 31 |  | #include <list> | 
| 32 |  | #include <memory> | 
| 33 |  |  | 
| 34 |  | namespace LOG4CXX_NS | 
| 35 |  | { | 
| 36 |  | namespace db | 
| 37 |  | { | 
| 38 |  | class LOG4CXX_EXPORT SQLException : public LOG4CXX_NS::helpers::Exception | 
| 39 |  | { | 
| 40 |  |   public: | 
| 41 |  |     SQLException(short fHandleType, | 
| 42 |  |       void* hInput, const char* prolog, | 
| 43 |  |       LOG4CXX_NS::helpers::Pool& p); | 
| 44 |  |     SQLException(const char* msg); | 
| 45 |  |     SQLException(const SQLException& src); | 
| 46 |  |   private: | 
| 47 |  |     const char* formatMessage(short fHandleType, | 
| 48 |  |       void* hInput, const char* prolog, | 
| 49 |  |       LOG4CXX_NS::helpers::Pool& p); | 
| 50 |  | }; | 
| 51 |  |  | 
| 52 |  | /** | 
| 53 |  | The ODBCAppender sends log events to a database. | 
| 54 |  |  | 
| 55 |  | <p>Each append call adds the spi::LoggingEvent to a buffer. | 
| 56 |  | When the buffer is full, values are extracted from each spi::LoggingEvent | 
| 57 |  | and the sql insert statement executed. | 
| 58 |  |  | 
| 59 |  | The SQL insert statement pattern must be provided | 
| 60 |  | either in the Log4cxx configuration file | 
| 61 |  | using the <b>sql</b> parameter element | 
| 62 |  | or programatically by calling the <code>setSql(String sql)</code> method. | 
| 63 |  |  | 
| 64 |  | The following <b>param</b> elements are optional: | 
| 65 |  | - one of <b>DSN</b>, <b>URL</b>, <b>ConnectionString</b> - | 
| 66 |  |   The <b>serverName</b> parameter value in the <a href="https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function">SQLConnect</a> call. | 
| 67 |  | - <b>User</b> - | 
| 68 |  |   The <b>UserName</b> parameter value in the <a href="https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function">SQLConnect</a> call. | 
| 69 |  | - <b>Password</b> - | 
| 70 |  |   The <b>Authentication</b> parameter value in the <a href="https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function">SQLConnect</a> call. | 
| 71 |  | - <b>BufferSize</b> - | 
| 72 |  |   Delay executing the sql until this many logging events are available. | 
| 73 |  |   One by default, meaning an sql statement is executed | 
| 74 |  |   whenever a logging event is appended. | 
| 75 |  | - <b>ColumnMapping</b> - | 
| 76 |  |   One element for each "?" in the <b>sql</b> statement | 
| 77 |  |   in a sequence corresponding to the columns in the insert statement. | 
| 78 |  |   The following values are supported: | 
| 79 |  |   - <b>logger</b> - the name of the logger that generated the logging event | 
| 80 |  |   - <b>level</b> - the level of the logging event | 
| 81 |  |   - <b>thread</b> - the thread number as a hex string that generated the logging event | 
| 82 |  |   - <b>threadname</b> - the name assigned to the thread that generated the logging event | 
| 83 |  |   - <b>time</b> - a datetime or datetime2 SQL field type at which the event was generated | 
| 84 |  |   - <b>shortfilename</b> - the basename of the file containing the logging statement | 
| 85 |  |   - <b>fullfilename</b> - the path of the file containing the logging statement | 
| 86 |  |   - <b>line</b> - the position in the file at which the logging event was generated | 
| 87 |  |   - <b>class</b> - the class from which the logging event was generated (\ref usingMacros "1") | 
| 88 |  |   - <b>method</b> - the function in which the logging event was generated (\ref usingMacros "1") | 
| 89 |  |   - <b>message</b> - the data sent by the logging statement | 
| 90 |  |   - <b>mdc</b> - A JSON format string of all entries in the logging thread's mapped diagnostic context | 
| 91 |  |   - <b>mdc{key}</b> - the value associated with the <b>key</b> entry in the logging thread's mapped diagnostic context | 
| 92 |  |   - <b>ndc</b> - the last entry the logging thread's nested diagnostic context | 
| 93 |  |  | 
| 94 |  | \anchor usingMacros (1) Only available when the LOG4CXX_* macros are used to issue the logging request. | 
| 95 |  |  | 
| 96 |  | <p>For use as a base class: | 
| 97 |  |  | 
| 98 |  | <ul> | 
| 99 |  |  | 
| 100 |  | <li>Override getConnection() to pass any connection | 
| 101 |  | you want.  Typically this is used to enable application wide | 
| 102 |  | connection pooling. | 
| 103 |  |  | 
| 104 |  | <li>Override closeConnection -- if | 
| 105 |  | you override getConnection make sure to implement | 
| 106 |  | <code>closeConnection</code> to handle the connection you | 
| 107 |  | generated.  Typically this would return the connection to the | 
| 108 |  | pool it came from. | 
| 109 |  |  | 
| 110 |  | </ul> | 
| 111 |  |  | 
| 112 |  | An example configuration that writes to the data source named "LoggingDSN" is: | 
| 113 |  | ~~~{.xml} | 
| 114 |  | <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> | 
| 115 |  | <appender name="PreparedAppender" class="ODBCAppender"> | 
| 116 |  |  <param name="DSN" value="LoggingDSN"/> | 
| 117 |  |  <param name="sql" value="INSERT INTO [SomeDatabaseName].[SomeUserName].[SomeTableName] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message],[MappedContext]) VALUES (?,?,?,?,?,?,?,?)" /> | 
| 118 |  |  <param name="ColumnMapping" value="thread"/> | 
| 119 |  |  <param name="ColumnMapping" value="logger"/> | 
| 120 |  |  <param name="ColumnMapping" value="time"/> | 
| 121 |  |  <param name="ColumnMapping" value="level"/> | 
| 122 |  |  <param name="ColumnMapping" value="shortfilename"/> | 
| 123 |  |  <param name="ColumnMapping" value="line"/> | 
| 124 |  |  <param name="ColumnMapping" value="message"/> | 
| 125 |  |  <param name="ColumnMapping" value="mdc"/> | 
| 126 |  | </appender> | 
| 127 |  | <appender name="ASYNC" class="AsyncAppender"> | 
| 128 |  |   <param name="BufferSize" value="1000"/> | 
| 129 |  |   <param name="Blocking" value="false"/> | 
| 130 |  |   <appender-ref ref="PreparedAppender"/> | 
| 131 |  | </appender> | 
| 132 |  | <root> | 
| 133 |  |   <priority value ="INFO" /> | 
| 134 |  |   <appender-ref ref="ASYNC" /> | 
| 135 |  | </root> | 
| 136 |  | </log4j:configuration> | 
| 137 |  | ~~~ | 
| 138 |  |  | 
| 139 |  | You may also want to consider the DBAppender class, which uses APR in order to support logging to databases apart from ODBC. | 
| 140 |  | */ | 
| 141 |  |  | 
| 142 |  | class LOG4CXX_EXPORT ODBCAppender : public AppenderSkeleton | 
| 143 |  | { | 
| 144 |  |   public: | 
| 145 |  |     DECLARE_LOG4CXX_OBJECT(ODBCAppender) | 
| 146 | 0 |     BEGIN_LOG4CXX_CAST_MAP() | 
| 147 | 0 |     LOG4CXX_CAST_ENTRY(ODBCAppender) | 
| 148 | 0 |     LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton) | 
| 149 | 0 |     END_LOG4CXX_CAST_MAP() | 
| 150 |  |  | 
| 151 |  |     typedef void* SQLHDBC; | 
| 152 |  |     typedef void* SQLHENV; | 
| 153 |  |     typedef void* SQLHANDLE; | 
| 154 |  |     typedef short SQLSMALLINT; | 
| 155 |  |  | 
| 156 |  |     ODBCAppender(); | 
| 157 |  |     virtual ~ODBCAppender(); | 
| 158 |  |  | 
| 159 |  |     /** | 
| 160 |  |     \copybrief AppenderSkeleton::setOption() | 
| 161 |  |  | 
| 162 |  |     Supported options | Supported values | Default value | | 
| 163 |  |     :-------------- | :----------------: | :---------------: | | 
| 164 |  |     BufferSize | {int} | 1 | | 
| 165 |  |     ConnectionString | {any} | - | | 
| 166 |  |     URL | {any} | - | | 
| 167 |  |     DSN | {any} | - | | 
| 168 |  |     User | {any} | - | | 
| 169 |  |     Password | {any} | - | | 
| 170 |  |     SQL | {any} | - | 
| 171 |  |     ColumnMapping | (\ref colName "^") | - | 
| 172 |  |  | 
| 173 |  |     \anchor colName (^) One value for each '?' character in the SQL value. | 
| 174 |  |  | 
| 175 |  |     \sa AppenderSkeleton::setOption() | 
| 176 |  |     */ | 
| 177 |  |     void setOption(const LogString& option, const LogString& value) override; | 
| 178 |  |  | 
| 179 |  |     /** | 
| 180 |  |     Activate the specified options. | 
| 181 |  |     */ | 
| 182 |  |     void activateOptions(helpers::Pool& p) override; | 
| 183 |  |  | 
| 184 |  |     /** | 
| 185 |  |     * Adds the event to the buffer.  When full the buffer is flushed. | 
| 186 |  |     */ | 
| 187 |  |     void append(const spi::LoggingEventPtr& event, helpers::Pool&) override; | 
| 188 |  |  | 
| 189 |  |   protected: | 
| 190 |  |     /** | 
| 191 |  |     * To be removed. | 
| 192 |  |     */ | 
| 193 |  |     LogString getLogStatement(const spi::LoggingEventPtr& event, | 
| 194 |  |       helpers::Pool& p) const; | 
| 195 |  |  | 
| 196 |  |     /** | 
| 197 |  |     * | 
| 198 |  |     * To be removed. | 
| 199 |  |     * */ | 
| 200 |  |     virtual void execute(const LogString& sql, | 
| 201 |  |       LOG4CXX_NS::helpers::Pool& p) /*throw(SQLException)*/; | 
| 202 |  |  | 
| 203 |  |     /** | 
| 204 |  |     * Override this to return the connection to a pool, or to clean up the | 
| 205 |  |     * resource. | 
| 206 |  |     * | 
| 207 |  |     * The default behavior holds a single connection open until the appender | 
| 208 |  |     * is closed (typically when garbage collected). | 
| 209 |  |     */ | 
| 210 |  |     virtual void closeConnection(SQLHDBC con); | 
| 211 |  |  | 
| 212 |  |     /** | 
| 213 |  |     * Override this to link with your connection pooling system. | 
| 214 |  |     * | 
| 215 |  |     * By default this creates a single connection which is held open | 
| 216 |  |     * until the object is garbage collected. | 
| 217 |  |     */ | 
| 218 |  |     virtual SQLHDBC getConnection(LOG4CXX_NS::helpers::Pool& p) /*throw(SQLException)*/; | 
| 219 |  |  | 
| 220 |  |     /** | 
| 221 |  |     * Closes the appender, flushing the buffer first then closing the default | 
| 222 |  |     * connection if it is open. | 
| 223 |  |     */ | 
| 224 |  |   public: | 
| 225 |  |     void close() override; | 
| 226 |  |  | 
| 227 |  |     /** | 
| 228 |  |     * loops through the buffer of LoggingEvents, gets a | 
| 229 |  |     * sql string from getLogStatement() and sends it to execute(). | 
| 230 |  |     * Errors are sent to the errorHandler. | 
| 231 |  |     * | 
| 232 |  |     * If a statement fails the LoggingEvent stays in the buffer! | 
| 233 |  |     */ | 
| 234 |  |     virtual void flushBuffer(LOG4CXX_NS::helpers::Pool& p); | 
| 235 |  |  | 
| 236 |  |     /** | 
| 237 |  |     * Does this appender require a layout? | 
| 238 |  |     * */ | 
| 239 |  |     bool requiresLayout() const override; | 
| 240 |  |  | 
| 241 |  |     /** | 
| 242 |  |     * Set pre-formated statement eg: insert into LogTable (msg) values ("%m") | 
| 243 |  |     */ | 
| 244 |  |     void setSql(const LogString& s); | 
| 245 |  |  | 
| 246 |  |     /** | 
| 247 |  |     * Returns pre-formated statement eg: insert into LogTable (msg) values ("%m") | 
| 248 |  |     */ | 
| 249 |  |     const LogString& getSql() const; | 
| 250 |  |  | 
| 251 |  |  | 
| 252 |  |     void setUser(const LogString& user); | 
| 253 |  |  | 
| 254 |  |     void setURL(const LogString& url); | 
| 255 |  |  | 
| 256 |  |     void setPassword(const LogString& password); | 
| 257 |  |  | 
| 258 |  |     void setBufferSize(size_t newBufferSize); | 
| 259 |  |  | 
| 260 |  |     const LogString& getUser() const; | 
| 261 |  |  | 
| 262 |  |     const LogString& getURL() const; | 
| 263 |  |  | 
| 264 |  |     const LogString& getPassword() const; | 
| 265 |  |  | 
| 266 |  |     size_t getBufferSize() const; | 
| 267 |  |   private: | 
| 268 |  |     ODBCAppender(const ODBCAppender&); | 
| 269 |  |     ODBCAppender& operator=(const ODBCAppender&); | 
| 270 |  | #if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR_T || defined(WIN32) || defined(_WIN32) | 
| 271 |  |     static void encode(wchar_t** dest, const LogString& src, | 
| 272 |  |       LOG4CXX_NS::helpers::Pool& p); | 
| 273 |  | #endif | 
| 274 |  |     static void encode(unsigned short** dest, const LogString& src, | 
| 275 |  |       LOG4CXX_NS::helpers::Pool& p); | 
| 276 |  |  | 
| 277 |  |   protected: | 
| 278 |  |     struct ODBCAppenderPriv; | 
| 279 |  | }; // class ODBCAppender | 
| 280 |  | LOG4CXX_PTR_DEF(ODBCAppender); | 
| 281 |  |  | 
| 282 |  | } // namespace db | 
| 283 |  | } // namespace log4cxx | 
| 284 |  |  | 
| 285 |  | #endif // _LOG4CXX_DB_ODBC_APPENDER_H |