MonologFileLogger.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\core\impl;
12 
13 use Monolog\Formatter\LineFormatter;
14 use Monolog\Handler\RotatingFileHandler;
15 use Monolog\Handler\StreamHandler;
16 use Monolog\Logger;
17 use Monolog\Processor\IntrospectionProcessor;
22 
23 /**
24  * MonologFileLogger is a wrapper for the Monolog library that logs to files.
25  *
26  * Loggers may be configured by passing configuration file name to the first
27  * created logger instance. The file must have INI file format. The following
28  * sectiona are supported:
29  * - _Root_:
30  * - _level_: default log level
31  * - _target_: location of rotating log files relative to WCMF_BASE or stream resource e.g. php://stdout
32  * - _Logger_: Keys are the logger names, values the levels (_DEBUG_, _WARN_, ...)
33  *
34  * @author ingo herwig <ingo@wemove.com>
35  */
37 
38  const ROOT_SECTION_NAME = 'Root';
39  const LOGGER_SECTION_NAME = 'Logger';
40 
41  private $monologLogger = null;
42  private $level = Logger::ERROR;
43 
44  private static $defaultLevel = Logger::ERROR;
45  private static $logTarget = '';
46  private static $levels = [];
47 
48  /**
49  * Constructor
50  * @param $name The logger name (channel in Monolog)
51  * @param $configFile A configuration file name
52  */
53  public function __construct($name, $configFile='') {
54  if (strlen($configFile) > 0) {
55  self::configure($configFile);
56  if (!$this->isStreamTarget(self::$logTarget)) {
57  $fileUtil = new FileUtil();
58  self::$logTarget = $fileUtil->realpath(WCMF_BASE.self::$logTarget).'/';
59  $fileUtil->mkdirRec(self::$logTarget);
60  }
61  }
62  $level = isset(self::$levels[$name]) ? self::$levels[$name] : self::$defaultLevel;
63  $this->level = $level;
64 
65  $output = "[%datetime%] %level_name%: %channel%:%extra.line%: %message%\n";
66  $formatter = new LineFormatter($output, null, true);
67  $processor = new IntrospectionProcessor($level, [__CLASS__]);
68  if ($this->isStreamTarget(self::$logTarget)) {
69  $handler = new StreamHandler(self::$logTarget, $level);
70  }
71  else {
72  $handler = new RotatingFileHandler(self::$logTarget.'.log', 0, $level);
73  $handler->setFilenameFormat('{date}', 'Y-m-d');
74  }
75  $handler->setFormatter($formatter);
76  $handler->pushProcessor($processor);
77 
78  $this->monologLogger = new Logger($name, [$handler]);
79  }
80 
81  /**
82  * @see Logger::debug()
83  */
84  public function debug($message) {
85  $this->monologLogger->addDebug($this->prepareMessage($message));
86  }
87 
88  /**
89  * @see Logger::info()
90  */
91  public function info($message) {
92  $this->monologLogger->addInfo($this->prepareMessage($message));
93  }
94 
95  /**
96  * @see Logger::warn()
97  */
98  public function warn($message) {
99  $this->monologLogger->addWarning($this->prepareMessage($message));
100  }
101 
102  /**
103  * @see Logger::error()
104  */
105  public function error($message) {
106  $this->monologLogger->addError($this->prepareMessage($message));
107  }
108 
109  /**
110  * @see Logger::fatal()
111  */
112  public function fatal($message) {
113  $this->monologLogger->addCritical($this->prepareMessage($message));
114  }
115 
116  /**
117  * @see Logger::isDebugEnabled()
118  */
119  public function isDebugEnabled() {
120  return $this->level <= Logger::DEBUG;
121  }
122 
123  /**
124  * @see Logger::isInfoEnabled()
125  */
126  public function isInfoEnabled() {
127  return $this->level <= Logger::INFO;
128  }
129 
130  /**
131  * @see Logger::isWarnEnabled()
132  */
133  public function isWarnEnabled() {
134  return $this->level <= Logger::WARNING;
135  }
136 
137  /**
138  * @see Logger::isErrorEnabled()
139  */
140  public function isErrorEnabled() {
141  return $this->level <= Logger::ERROR;
142  }
143 
144  /**
145  * @see Logger::isFatalEnabled()
146  */
147  public function isFatalEnabled() {
148  return $this->level <= Logger::CRITICAL;
149  }
150 
151  /**
152  * @see Logger::getLogger()
153  */
154  public static function getLogger($name) {
155  return new MonologFileLogger($name);
156  }
157 
158  /**
159  * Configure logging
160  * @param $configFile
161  */
162  private function configure($configFile) {
163  if (!file_exists($configFile)) {
164  throw new ConfigurationException('Configuration file '.$configFile.' not found');
165  }
166  $config = parse_ini_file($configFile, true);
167 
168  // default settings
169  if (isset($config[self::ROOT_SECTION_NAME])) {
170  $rootConfig = $config[self::ROOT_SECTION_NAME];
171  self::$defaultLevel = isset($rootConfig['level']) ?
172  constant('Monolog\Logger::'.strtoupper($rootConfig['level'])) :
173  self::$defaultLevel;
174  self::$logTarget = isset($rootConfig['target']) ?
175  $rootConfig['target'] : WCMF_BASE.self::$logTarget;
176  }
177 
178  // log levels
179  self::$levels = isset($config[self::LOGGER_SECTION_NAME]) ?
180  $config[self::LOGGER_SECTION_NAME] : [];
181  foreach (self::$levels as $key => $val) {
182  self::$levels[$key] = constant('Monolog\Logger::'.strtoupper($val));
183  }
184  }
185 
186  /**
187  * Prepare a message to be used with the internal logger
188  * @param $message
189  * @return String
190  */
191  private function prepareMessage($message) {
192  return is_string($message) ? $message :
193  (is_object($message) && method_exists($message, '__toString') ? $message->__toString() :
194  StringUtil::getDump($message));
195  }
196 
197  /**
198  * Check if the given target is a stream resource
199  * @param $target
200  * @return Boolean
201  */
202  private function isStreamTarget($target) {
203  return preg_match('/^.+?:\/\//', $target);
204  }
205 }
206 ?>
static getDump($variable, $strlen=100, $width=25, $depth=10, $i=0, &$objects=[])
Get the dump of a variable as string.
Definition: StringUtil.php:29
MonologFileLogger is a wrapper for the Monolog library that logs to files.
__construct($name, $configFile='')
Constructor.
StringUtil provides support for string manipulation.
Definition: StringUtil.php:18
ConfigurationException signals an exception in the configuration.
AbstractLogger is the abstract base class for Logger implementations.
Interface for logger implementations.
Definition: Logger.php:18
FileUtil provides basic support for file functionality like HTTP file upload.
Definition: FileUtil.php:22