      1: <?php
      2: /**
      3:  * Copyright 2012-2014 Rackspace US, Inc.
      4:  *
      5:  * Licensed under the Apache License, Version 2.0 (the "License");
      6:  * you may not use this file except in compliance with the License.
      7:  * 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: namespace OpenCloud\Common\Log;
     19:
     20: use OpenCloud\Common\Exceptions\LoggingException;
     21:
     22: /**
     23:  * Basic logger for OpenCloud which extends FIG's PSR-3 standard logger.
     24:  *
     25:  * @link https://github.com/php-fig/log
     26:  */
     27: class Logger extends AbstractLogger
     28: {
     29:     /**
     30:      * Is this debug class enabled or not?
     31:      *
     32:      * @var bool
     33:      */
     34:     private $enabled;
     35:
     36:     /**
     37:      * These are the levels which will always be outputted - regardless of
     38:      * user-imposed settings.
     39:      *
     40:      * @var array
     41:      */
     42:     private $urgentLevels = array(
     43:         LogLevel::EMERGENCY,
     44:         LogLevel::ALERT,
     45:         LogLevel::CRITICAL
     46:     );
     47:
     48:     /**
     49:      * Logging options.
     50:      *
     51:      * @var array
     52:      */
     53:     private $options = array(
     54:         'outputToFile' => false,
     55:         'logFile'      => null,
     56:         'dateFormat'   => 'd/m/y H:I',
     57:         'delimeter'    => ' - '
     58:     );
     59:
     60:     public function __construct($enabled = false)
     61:     {
     62:         $this->enabled = $enabled;
     63:     }
     64:
     65:     public static function newInstance()
     66:     {
     67:         return new static();
     68:     }
     69:
     70:     /**
     71:      * Determines whether a log level needs to be outputted.
     72:      *
     73:      * @param  string $logLevel
     74:      * @return bool
     75:      */
     76:     private function outputIsUrgent($logLevel)
     77:     {
     78:         return in_array($logLevel, $this->urgentLevels);
     79:     }
     80:
     81:     /**
     82:      * Interpolates context values into the message placeholders.
     83:      *
     84:      * @param string $message
     85:      * @param array  $context
     86:      * @return type
     87:      */
     88:     private function interpolate($message, array $context = array())
     89:     {
     90:         // build a replacement array with braces around the context keys
     91:         $replace = array();
     92:         foreach ($context as $key => $val) {
     93:             $replace['{' . $key . '}'] = $val;
     94:         }
     95:
     96:         // interpolate replacement values into the message and return
     97:         return strtr($message, $replace);
     98:     }
     99:
    100:     /**
    101:      * Enable or disable the debug class.
    102:      *
    103:      * @param  bool $enabled
    104:      * @return self
    105:      */
    106:     public function setEnabled($enabled)
    107:     {
    108:         $this->enabled = $enabled;
    109:
    110:         return $this;
    111:     }
    112:
    113:     /**
    114:      * Is the debug class enabled?
    115:      *
    116:      * @return bool
    117:      */
    118:     public function isEnabled()
    119:     {
    120:         return $this->enabled === true;
    121:     }
    122:
    123:     /**
    124:      * Set an array of options.
    125:      *
    126:      * @param array $options
    127:      */
    128:     public function setOptions(array $options = array())
    129:     {
    130:         foreach ($options as $key => $value) {
    131:             $this->setOption($key, $value);
    132:         }
    133:
    134:         return $this;
    135:     }
    136:
    137:     /**
    138:      * Get all options.
    139:      *
    140:      * @return array
    141:      */
    142:     public function getOptions()
    143:     {
    144:         return $this->options;
    145:     }
    146:
    147:     /**
    148:      * Set an individual option.
    149:      *
    150:      * @param string $key
    151:      * @param string $value
    152:      */
    153:     public function setOption($key, $value)
    154:     {
    155:         if ($this->optionExists($key)) {
    156:             $this->options[$key] = $value;
    157:
    158:             return $this;
    159:         }
    160:     }
    161:
    162:     /**
    163:      * Get an individual option.
    164:      *
    165:      * @param  string $key
    166:      * @return string|null
    167:      */
    168:     public function getOption($key)
    169:     {
    170:         if ($this->optionExists($key)) {
    171:             return $this->options[$key];
    172:         }
    173:     }
    174:
    175:     /**
    176:      * Check whether an individual option exists.
    177:      *
    178:      * @param  string $key
    179:      * @return bool
    180:      */
    181:     private function optionExists($key)
    182:     {
    183:         return array_key_exists($key, $this->getOptions());
    184:     }
    185:
    186:     /**
    187:      * Outputs a log message if necessary.
    188:      *
    189:      * @param string $logLevel
    190:      * @param string $message
    191:      * @param string $context
    192:      */
    193:     public function log($level, $message, array $context = array())
    194:     {
    195:         if ($this->outputIsUrgent($level) || $this->isEnabled()) {
    196:             $this->dispatch($message, $context);
    197:         }
    198:     }
    199:
    200:     /**
    201:      * Used to format the line outputted in the log file.
    202:      *
    203:      * @param  string $string
    204:      * @return string
    205:      */
    206:     private function formatFileLine($string)
    207:     {
    208:         $format = $this->getOption('dateFormat') . $this->getOption('delimeter');
    209:
    210:         return date($format) . $string;
    211:     }
    212:
    213:     /**
    214:      * Dispatch a log output message.
    215:      *
    216:      * @param string $message
    217:      * @param array  $context
    218:      * @throws LoggingException
    219:      */
    220:     private function dispatch($message, $context)
    221:     {
    222:         $output = $this->interpolate($message, $context) . PHP_EOL;
    223:
    224:         if ($this->getOption('outputToFile') === true) {
    225:             $file = $this->getOption('logFile');
    226:
    227:             if (!is_writable($file)) {
    228:                 throw new LoggingException(
    229:                     'The log file either does not exist or is not writeable'
    230:                 );
    231:             }
    232:
    233:             // Output to file
    234:             file_put_contents($file, $this->formatFileLine($output), FILE_APPEND);
    235:         } else {
    236:
    237:             echo $output;
    238:         }
    239:     }
    240:
    241:     public function deprecated($method, $new)
    242:     {
    243:         $string = sprintf('The %s method is deprecated, please use %s instead', $method, $new);
    244:
    245:         return $this->warning($string);
    246:     }
    247: }
    248: