1: <?php
2: /**
3: * Horde Log package
4: *
5: * This package is based on Zend_Log from the Zend Framework
6: * (http://framework.zend.com). Both that package and this
7: * one were written by Mike Naberezny and Chuck Hagenbuch.
8: *
9: * @author Mike Naberezny <mike@maintainable.com>
10: * @author Chuck Hagenbuch <chuck@horde.org>
11: * @category Horde
12: * @license http://www.horde.org/licenses/bsd BSD
13: * @package Log
14: */
15:
16: /**
17: * @author Mike Naberezny <mike@maintainable.com>
18: * @author Chuck Hagenbuch <chuck@horde.org>
19: * @category Horde
20: * @license http://www.horde.org/licenses/bsd BSD
21: * @package Log
22: *
23: * @method void LOGLEVEL() LOGLEVEL($event) Log an event at LOGLEVEL, where LOGLEVEL has been added with addLevel() or already exists
24: * @method void emerg() emerg($event) Log an event at the EMERG log level
25: * @method void alert() alert($event) Log an event at the ALERT log level
26: * @method void crit() crit($event) Log an event at the CRIT log level
27: * @method void err() err($event) Log an event at the ERR log level
28: * @method void warn() warn($event) Log an event at the WARN log level
29: * @method void notice() notice($event) Log an event at the NOTICE log level
30: * @method void info() info($event) Log an event at the INFO log level
31: * @method void debug() debug($event) Log an event at the DEBUG log level
32: */
33: class Horde_Log_Logger implements Serializable
34: {
35: /* Serialize version. */
36: const VERSION = 1;
37:
38: /**
39: * Log levels where the keys are the level priorities and the values are
40: * the level names.
41: *
42: * @var array
43: */
44: private $_levels = array();
45:
46: /**
47: * Horde_Log_Handler_Base objects.
48: *
49: * @var array
50: */
51: private $_handlers = array();
52:
53: /**
54: * Horde_Log_Filter objects.
55: *
56: * @var array
57: */
58: private $_filters = array();
59:
60: /**
61: * Constructor.
62: *
63: * @param Horde_Log_Handler_Base|null $handler Default handler.
64: */
65: public function __construct($handler = null)
66: {
67: if (!is_null($handler)) {
68: $this->addHandler($handler);
69: }
70:
71: $this->_init();
72: }
73:
74: /**
75: * Serialize.
76: *
77: * @return string Serialized representation of this object.
78: */
79: public function serialize()
80: {
81: return serialize(array(
82: self::VERSION,
83: $this->_filters,
84: $this->_handlers
85: ));
86: }
87:
88: /**
89: * Unserialize.
90: *
91: * @param string $data Serialized data.
92: *
93: * @throws Exception
94: */
95: public function unserialize($data)
96: {
97: $data = @unserialize($data);
98: if (!is_array($data) ||
99: !isset($data[0]) ||
100: ($data[0] != self::VERSION)) {
101: throw new Exception('Cache version change');
102: }
103:
104: $this->_filters = $data[1];
105: $this->_handlers = $data[2];
106:
107: $this->_init();
108: }
109:
110: /**
111: * Initialization tasks.
112: */
113: protected function _init()
114: {
115: $r = new ReflectionClass('Horde_Log');
116: $this->_levels = array_flip($r->getConstants());
117: }
118:
119: /**
120: * Undefined method handler allows a shortcut:
121: * <pre>
122: * $log->levelName('message');
123: * instead of
124: * $log->log('message', Horde_Log_LEVELNAME);
125: * </pre>
126: *
127: * @param string $method Log level name.
128: * @param string $params Message to log.
129: */
130: public function __call($method, $params)
131: {
132: $levelName = strtoupper($method);
133: if (($level = array_search($levelName, $this->_levels)) !== false) {
134: $this->log(array_shift($params), $level);
135: } else {
136: throw new Horde_Log_Exception('Bad log level ' . $levelName);
137: }
138: }
139:
140: /**
141: * Log a message at a level
142: *
143: * @param mixed $event Message to log, either an array or a string.
144: * @param integer $level Log level of message, required if $message is a
145: * string.
146: */
147: public function log($event, $level = null)
148: {
149: if (empty($this->_handlers)) {
150: throw new Horde_Log_Exception('No handlers were added');
151: }
152:
153: // Create an event array from the given arguments.
154: if (is_array($event)) {
155: // If we are passed an array, it must contain 'message'
156: // and 'level' indices.
157: if (!isset($event['message'])) {
158: throw new Horde_Log_Exception('Event array did not contain a message');
159: }
160: if (!isset($event['level'])) {
161: if (is_null($level)) {
162: throw new Horde_Log_Exception('Event array did not contain a log level');
163: }
164: $event['level'] = $level;
165: }
166: } else {
167: // Create an event array from the message and level
168: // arguments.
169: $event = array('message' => $event, 'level' => $level);
170: }
171:
172: if (!isset($this->_levels[$event['level']]) ||
173: !is_string($this->_levels[$event['level']])) {
174: throw new Horde_Log_Exception('Bad log level: ' . $event['level']);
175: }
176:
177: // Fill in the level name and timestamp for filters, formatters,
178: // handlers.
179: $event['levelName'] = $this->_levels[$event['level']];
180:
181: if (!isset($event['timestamp'])) {
182: $event['timestamp'] = date('c');
183: }
184:
185: // If any global filter rejects the event, don't log it.
186: foreach ($this->_filters as $filter) {
187: if (!$filter->accept($event)) {
188: return;
189: }
190: }
191:
192: foreach ($this->_handlers as $handler) {
193: $handler->log($event);
194: }
195: }
196:
197: /**
198: * Does this logger have the level $name already?
199: *
200: * @param string $name The level name to check for.
201: *
202: * @return boolean Whether the logger already has the specific level
203: * name.
204: */
205: public function hasLevel($name)
206: {
207: return (boolean)array_search($name, $this->_levels);
208: }
209:
210: /**
211: * Add a custom log level
212: *
213: * @param string $name Name of level.
214: * @param integer $level Numeric level.
215: */
216: public function addLevel($name, $level)
217: {
218: // Log level names must be uppercase for predictability.
219: $name = strtoupper($name);
220:
221: if (isset($this->_levels[$level]) || $this->hasLevel($name)) {
222: throw new Horde_Log_Exception('Existing log levels cannot be overwritten');
223: }
224:
225: $this->_levels[$level] = $name;
226: }
227:
228: /**
229: * Add a filter that will be applied before all log handlers.
230: * Before a message will be received by any of the handlers, it
231: * must be accepted by all filters added with this method.
232: *
233: * @param Horde_Log_Filter $filter Filter to add.
234: */
235: public function addFilter($filter)
236: {
237: $this->_filters[] = is_integer($filter)
238: ? new Horde_Log_Filter_Level($filter)
239: : $filter;
240: }
241:
242: /**
243: * Add a handler. A handler is responsible for taking a log
244: * message and writing it out to storage.
245: *
246: * @param Horde_Log_Handler_Base $handler Handler to add.
247: */
248: public function addHandler($handler)
249: {
250: $this->_handlers[] = $handler;
251: }
252:
253: }
254: