FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Log.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 class Log extends Component{
6 
7  const CUSTOM = 10; //!< Everything above this is only logged when exactly matched.
8  const EMERGENCY = 7; //!< System is unusable.
9  const ALERT = 6; //!< Action must be taken immediately.
10  const CRITICAL = 5; //!< Critical conditions.
11  const ERROR = 4; //!< Error conditions.
12  const WARNING = 3; //!< Warning conditions.
13  const NOTICE = 2; //!< Normal, but significant, condition.
14  const INFO = 1; //!< Informational message.
15  const DEBUG = 0; //!< Debug-level message.
16 
17  public $handlers = []; //!< Array with handlers (key = name, value = config).
18  public $convert = []; //!< Convert the priority of some messages (key = reg-exp's for concatination of IP + '#' + user agent +
19  // '#' + filename + '#' + message to ignore; value = new priority or false to ignore)).
20  public $break = null; //!< Reg-exp for message to throw an Exception on.
21 
22  protected $_busy = false;
23  protected $_timers = [];
24 
25  protected function init(){
26  parent::init();
27  foreach($this->handlers as &$config){
28  if(!$config) $config = [];
29  $prio = $config['prio'] ?? null;
30  if(!array_key_exists('prios',$config) || ($prio !== null))
31  $config['prios'] = array_merge($config['prios'] ?? [],range($prio ?: self::DEBUG,self::CUSTOM - 1));
32  }
33  unset($config);
34  }
35  /**
36  * Get a handler.
37  * @param string $name Name of the handler.
38  * @return Log\\Handler
39  */
40  public function handler($name){
41  if(!is_array($this->handlers[$name])) $this->handlers[$name] = [];
42  if(!array_key_exists(null,$config =& $this->handlers[$name])){
43  $class_name = \Rsi\Record::get($config,'className',__CLASS__ . '\\Handler\\' . ucfirst($name));
44  $config[null] = new $class_name($this,$config,$name);
45  }
46  return $config[null];
47  }
48  /**
49  * Check if the log has a specific handler.
50  * @param string $name Name of the handler.
51  * @return bool True if the log has the specified handler.
52  */
53  public function has($name){
54  return array_key_exists($name,$this->handlers) ? $this->handler($name) : false;
55  }
56 
57  protected function context($filename,$line_no,$trace,$context){
58  return is_array($filename)
59  ? $filename
60  : array_merge(array_filter(['*filename' => $filename,'*lineNo' => $line_no,'*trace' => $trace]),$context ?: []);
61  }
62  /**
63  * Add a message to the log.
64  * @param int $prio Priority of the message. Only if this priority surpasses a handlers minimum priority, the message is
65  * processed by the handler.
66  * @param string|Exception $message Message to add (if this is an Exception all other parameters will be derived from it).
67  * @param string|array $filename File from which the message originated (or context when no specific file).
68  * @param int $line_no Line from which the message originated.
69  * @param array $context Context for the message. If a key is prefixed with an '@' the value has to be a callback function
70  * that returns the real value. This is only done (once) when the message is processed by a handler.
71  */
72  public function add($prio,$message,$filename = null,$line_no = null,$context = null){
73  if($this->break && preg_match($this->break,$message)) throw new \Exception('[break]');
74  if(!$this->_busy) try{
75  $this->_busy = true;
76  $parsed = null;
77  foreach($this->handlers as $name => $config) if(in_array($prio,$config['prios'])) try{
78  if($parsed === null){
79  $trace = null;
80  $parsed = [];
81  if($message instanceof \Exception){
82  $context = $filename ?: [];
83  $filename = $message->getFile();
84  $line_no = $message->getLine();
85  $trace = $message->getTraceAsString();
86  $message = $message->getMessage();
87  }
88  if($this->convert){
89  $subject = implode('#',[
90  \Rsi\Record::get($context,'remoteAddr') ?: $this->component('security')->remoteAddr,
91  $_SERVER['HTTP_USER_AGENT'] ?? null,
92  is_string($filename) ? $filename : null,
93  $message
94  ]);
95  foreach($this->convert as $filter => $convert) if(preg_match($filter,$subject)){
96  if($convert === false) return false;
97  $prio = $convert;
98  break;
99  }
100  }
101  foreach($this->context($filename,$line_no,$trace,$context) as $key => $value){
102  if(substr($key,0,1) == '@') $value = call_user_func($value,$key = substr($key,1));
103  $parsed[$key] = $value;
104  }
105  }
106  $this->handler($name)->add($prio,$message,$parsed);
107  }
108  catch(\Rsi\Fred\Exception $e){
109  if($this->_fred->debug) throw $e;
110  }
111  }
112  finally{
113  $this->_busy = false;
114  }
115  }
116  /**
117  * Add a timer start message to the log.
118  * @param int $prio See add().
119  * @param string|Exception $message See add().
120  * @param string|array $filename See add().
121  * @param int $line_no See add().
122  * @param array $context See add().
123  * @return string Timer ID.
124  */
125  public function start($prio,$message,$filename = null,$line_no = null,$context = null){
126  $context = $this->context($filename,$line_no,null,$context);
127  $this->_timers[$id = \Rsi\Str::random()] = compact('prio','message','context');
128  $this->add($prio,$message,['*start' => $id] + $context);
129  return $id;
130  }
131  /**
132  * Add a message to a timer.
133  * Empty parameters are copied from the start message.
134  * @param string $id Timer ID.
135  * @param int $prio See add().
136  * @param string $message See add().
137  * @param string|array $filename See add().
138  * @param int $line_no See add().
139  * @param array $context See add().
140  * @param string $type Message type.
141  */
142  public function point($id,$prio,$message,$filename = null,$line_no = null,$context = null,$type = '*point'){
143  $timer = $this->_timers[$id] ?? [];
144  $this->add(
145  $prio === null ? $timer['prio'] ?? self::DEBUG : $prio,
146  $message,
147  [$type => $id] + (($filename === null) && ($line_no === null) && ($context === null)
148  ? $timer['context'] ?? []
149  : $this->context($filename,$line_no,null,$context)
150  )
151  );
152  }
153  /**
154  * Stop a timer message.
155  * Empty parameters are copied from the start message.
156  * @param string $id Timer ID.
157  * @param int $prio See add().
158  * @param string $message See add().
159  * @param string|array $filename See add().
160  * @param int $line_no See add().
161  * @param array $context See add().
162  */
163  public function stop($id,$prio = null,$message = null,$filename = null,$line_no = null,$context = null){
164  if($message === null) $message = '[stop] ' . ($timer['message'] ?? null);
165  $this->point($id,$prio,$message,$filename,$line_no,$context,'*stop');
166  }
167 
168  protected function _get($key){
169  return $this->handler($key);
170  }
171 
172  public function __call($func_name,$params){
173  array_unshift($params,constant('self::' . strtoupper($func_name)));
174  call_user_func_array([$this,'add'],$params);
175  }
176 
177  public function __invoke($message,$filename = null,$line_no = null,$context = null){
178  $this->add(self::DEBUG,$message,$filename,$line_no,$context);
179  }
180 
181 }
Rsi\Fred\Log\handler
handler($name)
Get a handler.
Definition: Log.php:40
Rsi\Fred\Log
Definition: Log.php:5
Rsi
Rsi\Fred\Log\NOTICE
const NOTICE
Normal, but significant, condition.
Definition: Log.php:13
Rsi\Fred\Log\stop
stop($id, $prio=null, $message=null, $filename=null, $line_no=null, $context=null)
Stop a timer message.
Definition: Log.php:163
Rsi\Fred\Log\EMERGENCY
const EMERGENCY
System is unusable.
Definition: Log.php:8
Rsi\Fred\Log\$_busy
$_busy
Definition: Log.php:22
Rsi\Fred\Log\CRITICAL
const CRITICAL
Critical conditions.
Definition: Log.php:10
Rsi\Fred\Log\INFO
const INFO
Informational message.
Definition: Log.php:14
Rsi\Fred\Log\$_timers
$_timers
Definition: Log.php:23
Rsi\Fred\Log\$break
$break
Reg-exp for message to throw an Exception on.
Definition: Log.php:20
Rsi\Fred\Component
Basic component class.
Definition: Component.php:8
Rsi\Fred\Log\add
add($prio, $message, $filename=null, $line_no=null, $context=null)
Add a message to the log.
Definition: Log.php:72
Rsi\Fred\Component\component
component($name)
Get a component (local or default).
Definition: Component.php:81
Rsi\Fred\Log\$handlers
$handlers
Array with handlers (key = name, value = config).
Definition: Log.php:17
Rsi\Fred\Log\ALERT
const ALERT
Action must be taken immediately.
Definition: Log.php:9
Rsi\Fred\Log\$convert
$convert
Convert the priority of some messages (key = reg-exp's for concatination of IP + '#' + user agent +.
Definition: Log.php:18
Rsi\Fred\Log\CUSTOM
const CUSTOM
Everything above this is only logged when exactly matched.
Definition: Log.php:7
Rsi\Fred\Log\has
has($name)
Check if the log has a specific handler.
Definition: Log.php:53
Rsi\Fred\Log\context
context($filename, $line_no, $trace, $context)
Definition: Log.php:57
Rsi\Fred\Log\ERROR
const ERROR
Error conditions.
Definition: Log.php:11
Rsi\Fred\Log\__invoke
__invoke($message, $filename=null, $line_no=null, $context=null)
Definition: Log.php:177
Rsi\Fred\Log\point
point($id, $prio, $message, $filename=null, $line_no=null, $context=null, $type=' *point')
Add a message to a timer.
Definition: Log.php:142
Rsi\Fred\Log\WARNING
const WARNING
Warning conditions.
Definition: Log.php:12
Rsi\Fred\Log\start
start($prio, $message, $filename=null, $line_no=null, $context=null)
Add a timer start message to the log.
Definition: Log.php:125
Rsi\Fred\Log\__call
__call($func_name, $params)
Definition: Log.php:172
Rsi\Fred\Log\DEBUG
const DEBUG
Debug-level message.
Definition: Log.php:15
Rsi\Fred\Log\init
init()
Definition: Log.php:25
Rsi\Fred\Exception
Definition: Exception.php:5
Rsi\Fred\Log\_get
_get($key)
Default getter if no specific setter is defined, and the property is also not published (readable).
Definition: Log.php:168
Rsi\Fred
Definition: Alive.php:3