| <?php |
| /** |
| * 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. |
| * |
| * @package log4php |
| */ |
| |
| /** |
| * Appends log events to a db table using PDO. |
| * |
| * Configurable parameters of this appender are: |
| * |
| * - dsn - The DSN string for this connection |
| * - user - The user of this database connection |
| * - password - The password of this database connection |
| * - table - Name of the database table into which log entries will be inserted (default: log4php_log) |
| * - insertSQL - Sets the insert statement for a logging event. Defaults |
| * to the correct one - change only if you are sure what you are doing. |
| * - insertPattern - The conversion pattern to use in conjuction with insert |
| * SQL. Must contain the same number of comma separated |
| * conversion patterns as there are question marks in the |
| * insertSQL. |
| * |
| * If $sql is set then $table and $sql are used, else $table, $insertSQL and $insertPattern. |
| * |
| * An example: |
| * |
| * {@example ../../examples/php/appender_pdo.php 19} |
| * |
| * {@example ../../examples/resources/appender_pdo.properties 18} |
| * |
| * @version $Revision$ |
| * @package log4php |
| * @subpackage appenders |
| * @since 2.0 |
| */ |
| class LoggerAppenderPDO extends LoggerAppender { |
| |
| // ****************************************** |
| // *** Configurable parameters *** |
| // ****************************************** |
| |
| /** |
| * DSN string used to connect to the database. |
| * @see http://www.php.net/manual/en/pdo.construct.php |
| */ |
| protected $dsn; |
| |
| /** Database user name. */ |
| protected $user; |
| |
| /** Database password. */ |
| protected $password; |
| |
| /** |
| * The insert query. |
| * |
| * The __TABLE__ placeholder will be replaced by the table name from |
| * {@link $table}. |
| * |
| * The questionmarks are part of the prepared statement, and they must |
| * match the number of conversion specifiers in {@link insertPattern}. |
| */ |
| protected $insertSQL = "INSERT INTO __TABLE__ (timestamp, logger, level, message, thread, file, line) VALUES (?, ?, ?, ?, ?, ?, ?)"; |
| |
| /** |
| * A comma separated list of {@link LoggerPatternLayout} format strings |
| * which replace the "?" in {@link $insertSQL}. |
| * |
| * Must contain the same number of comma separated conversion patterns as |
| * there are question marks in {@link insertSQL}. |
| * |
| * @see LoggerPatternLayout For conversion patterns. |
| */ |
| protected $insertPattern = "%date{Y-m-d H:i:s},%logger,%level,%message,%pid,%file,%line"; |
| |
| /** Name of the table to which to append log events. */ |
| protected $table = 'log4php_log'; |
| |
| /** The number of recconect attempts to make on failed append. */ |
| protected $reconnectAttempts = 3; |
| |
| |
| // ****************************************** |
| // *** Private memebers *** |
| // ****************************************** |
| |
| /** |
| * The PDO instance. |
| * @var PDO |
| */ |
| protected $db; |
| |
| /** |
| * Prepared statement for the insert query. |
| * @var PDOStatement |
| */ |
| protected $preparedInsert; |
| |
| /** This appender does not require a layout. */ |
| protected $requiresLayout = false; |
| |
| |
| // ****************************************** |
| // *** Appender methods *** |
| // ****************************************** |
| |
| /** |
| * Acquires a database connection based on parameters. |
| * Parses the insert pattern to create a chain of converters which will be |
| * used in forming query parameters from logging events. |
| */ |
| public function activateOptions() { |
| try { |
| $this->establishConnection(); |
| } catch (PDOException $e) { |
| $this->warn("Failed connecting to database: " . $e->getMessage()); |
| $this->close(); |
| return; |
| } |
| |
| // Parse the insert patterns; pattern parts are comma delimited |
| $pieces = explode(',', $this->insertPattern); |
| $converterMap = LoggerLayoutPattern::getDefaultConverterMap(); |
| foreach($pieces as $pattern) { |
| $parser = new LoggerPatternParser($pattern, $converterMap); |
| $this->converters[] = $parser->parse(); |
| } |
| |
| $this->closed = false; |
| } |
| |
| /** |
| * Connects to the database, and prepares the insert query. |
| * @throws PDOException If connect or prepare fails. |
| */ |
| protected function establishConnection() { |
| // Acquire database connection |
| $this->db = new PDO($this->dsn, $this->user, $this->password); |
| $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
| |
| // Prepare the insert statement |
| $insertSQL = str_replace('__TABLE__', $this->table, $this->insertSQL); |
| $this->preparedInsert = $this->db->prepare($insertSQL); |
| } |
| |
| /** |
| * Appends a new event to the database. |
| * |
| * If writing to database fails, it will retry by re-establishing the |
| * connection up to $reconnectAttempts times. If writing still fails, |
| * the appender will close. |
| */ |
| public function append(LoggerLoggingEvent $event) { |
| |
| for ($attempt = 1; $attempt <= $this->reconnectAttempts; $attempt++) { |
| try { |
| // If it's a retry, reestablish the connection |
| if ($attempt > 1) { |
| $this->establishConnection(); |
| } |
| |
| // Write to database |
| @$this->preparedInsert->execute($this->format($event)); |
| @$this->preparedInsert->closeCursor(); |
| break; |
| } catch (PDOException $e) { |
| $this->warn("Failed writing to database: ". $e->getMessage()); |
| |
| // Close the appender if it's the last attempt |
| if ($attempt == $this->reconnectAttempts) { |
| $this->warn("Failed after {$this->reconnectAttempts} attempts. Closing appender."); |
| $this->close(); |
| } else { |
| $this->warn("Attempting a reconnect (attempt $attempt of {$this->reconnectAttempts})."); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Converts the logging event to a series of database parameters by using |
| * the converter chain which was set up on activation. |
| */ |
| protected function format(LoggerLoggingEvent $event) { |
| $params = array(); |
| foreach($this->converters as $converter) { |
| $buffer = ''; |
| while ($converter !== null) { |
| $converter->format($buffer, $event); |
| $converter = $converter->next; |
| } |
| $params[] = $buffer; |
| } |
| return $params; |
| } |
| |
| /** |
| * Closes the connection to the logging database |
| */ |
| public function close() { |
| // Close the connection (if any) |
| $this->db = null; |
| |
| // Close the appender |
| $this->closed = true; |
| } |
| |
| // ****************************************** |
| // *** Accessor methods *** |
| // ****************************************** |
| |
| /** |
| * Returns the active database handle or null if not established. |
| * @return PDO |
| */ |
| public function getDatabaseHandle() { |
| return $this->db; |
| } |
| |
| /** Sets the username. */ |
| public function setUser($user) { |
| $this->setString('user', $user); |
| } |
| |
| /** Returns the username. */ |
| public function getUser($user) { |
| return $this->user; |
| } |
| |
| /** Sets the password. */ |
| public function setPassword($password) { |
| $this->setString('password', $password); |
| } |
| |
| /** Returns the password. */ |
| public function getPassword($password) { |
| return $this->password; |
| } |
| |
| /** Sets the insert SQL. */ |
| public function setInsertSQL($sql) { |
| $this->setString('insertSQL', $sql); |
| } |
| |
| /** Returns the insert SQL. */ |
| public function getInsertSQL($sql) { |
| return $this->insertSQL; |
| } |
| |
| /** Sets the insert pattern. */ |
| public function setInsertPattern($pattern) { |
| $this->setString('insertPattern', $pattern); |
| } |
| |
| /** Returns the insert pattern. */ |
| public function getInsertPattern($pattern) { |
| return $this->insertPattern; |
| } |
| |
| /** Sets the table name. */ |
| public function setTable($table) { |
| $this->setString('table', $table); |
| } |
| |
| /** Returns the table name. */ |
| public function getTable($table) { |
| return $this->table; |
| } |
| |
| /** Sets the DSN string. */ |
| public function setDSN($dsn) { |
| $this->setString('dsn', $dsn); |
| } |
| |
| /** Returns the DSN string. */ |
| public function getDSN($dsn) { |
| return $this->setString('dsn', $dsn); |
| } |
| } |
| |