|
1 <?php |
|
2 /** |
|
3 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
4 * contributor license agreements. See the NOTICE file distributed with |
|
5 * this work for additional information regarding copyright ownership. |
|
6 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
7 * (the "License"); you may not use this file except in compliance with |
|
8 * the License. You may obtain a copy of the License at |
|
9 * |
|
10 * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 * |
|
12 * Unless required by applicable law or agreed to in writing, software |
|
13 * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 * See the License for the specific language governing permissions and |
|
16 * limitations under the License. |
|
17 */ |
|
18 |
|
19 /** |
|
20 * Appender for writing to MongoDB. |
|
21 * |
|
22 * This class was originally contributed by Vladimir Gorej. |
|
23 * |
|
24 * ## Configurable parameters: ## |
|
25 * |
|
26 * - **host** - Server on which mongodb instance is located. |
|
27 * - **port** - Port on which the instance is bound. |
|
28 * - **databaseName** - Name of the database to which to log. |
|
29 * - **collectionName** - Name of the target collection within the given database. |
|
30 * - **username** - Username used to connect to the database. |
|
31 * - **password** - Password used to connect to the database. |
|
32 * - **timeout** - For how long the driver should try to connect to the database (in milliseconds). |
|
33 * |
|
34 * @version $Revision: 1346363 $ |
|
35 * @package log4php |
|
36 * @subpackage appenders |
|
37 * @since 2.1 |
|
38 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
|
39 * @link http://logging.apache.org/log4php/docs/appenders/mongodb.html Appender documentation |
|
40 * @link http://github.com/log4mongo/log4mongo-php Vladimir Gorej's original submission. |
|
41 * @link http://www.mongodb.org/ MongoDB website. |
|
42 */ |
|
43 class LoggerAppenderMongoDB extends LoggerAppender { |
|
44 |
|
45 // ****************************************** |
|
46 // ** Constants ** |
|
47 // ****************************************** |
|
48 |
|
49 /** Default prefix for the {@link $host}. */ |
|
50 const DEFAULT_MONGO_URL_PREFIX = 'mongodb://'; |
|
51 |
|
52 /** Default value for {@link $host}, without a prefix. */ |
|
53 const DEFAULT_MONGO_HOST = 'localhost'; |
|
54 |
|
55 /** Default value for {@link $port} */ |
|
56 const DEFAULT_MONGO_PORT = 27017; |
|
57 |
|
58 /** Default value for {@link $databaseName} */ |
|
59 const DEFAULT_DB_NAME = 'log4php_mongodb'; |
|
60 |
|
61 /** Default value for {@link $collectionName} */ |
|
62 const DEFAULT_COLLECTION_NAME = 'logs'; |
|
63 |
|
64 /** Default value for {@link $timeout} */ |
|
65 const DEFAULT_TIMEOUT_VALUE = 3000; |
|
66 |
|
67 // ****************************************** |
|
68 // ** Configurable parameters ** |
|
69 // ****************************************** |
|
70 |
|
71 /** Server on which mongodb instance is located. */ |
|
72 protected $host; |
|
73 |
|
74 /** Port on which the instance is bound. */ |
|
75 protected $port; |
|
76 |
|
77 /** Name of the database to which to log. */ |
|
78 protected $databaseName; |
|
79 |
|
80 /** Name of the collection within the given database. */ |
|
81 protected $collectionName; |
|
82 |
|
83 /** Username used to connect to the database. */ |
|
84 protected $userName; |
|
85 |
|
86 /** Password used to connect to the database. */ |
|
87 protected $password; |
|
88 |
|
89 /** Timeout value used when connecting to the database (in milliseconds). */ |
|
90 protected $timeout; |
|
91 |
|
92 // ****************************************** |
|
93 // ** Member variables ** |
|
94 // ****************************************** |
|
95 |
|
96 /** |
|
97 * Connection to the MongoDB instance. |
|
98 * @var Mongo |
|
99 */ |
|
100 protected $connection; |
|
101 |
|
102 /** |
|
103 * The collection to which log is written. |
|
104 * @var MongoCollection |
|
105 */ |
|
106 protected $collection; |
|
107 |
|
108 public function __construct($name = '') { |
|
109 parent::__construct($name); |
|
110 $this->host = self::DEFAULT_MONGO_URL_PREFIX . self::DEFAULT_MONGO_HOST; |
|
111 $this->port = self::DEFAULT_MONGO_PORT; |
|
112 $this->databaseName = self::DEFAULT_DB_NAME; |
|
113 $this->collectionName = self::DEFAULT_COLLECTION_NAME; |
|
114 $this->timeout = self::DEFAULT_TIMEOUT_VALUE; |
|
115 $this->requiresLayout = false; |
|
116 } |
|
117 |
|
118 /** |
|
119 * Setup db connection. |
|
120 * Based on defined options, this method connects to the database and |
|
121 * creates a {@link $collection}. |
|
122 */ |
|
123 public function activateOptions() { |
|
124 try { |
|
125 $this->connection = new Mongo(sprintf('%s:%d', $this->host, $this->port), array('timeout' => $this->timeout)); |
|
126 $db = $this->connection->selectDB($this->databaseName); |
|
127 if ($this->userName !== null && $this->password !== null) { |
|
128 $authResult = $db->authenticate($this->userName, $this->password); |
|
129 if ($authResult['ok'] == floatval(0)) { |
|
130 throw new Exception($authResult['errmsg'], $authResult['ok']); |
|
131 } |
|
132 } |
|
133 $this->collection = $db->selectCollection($this->collectionName); |
|
134 } catch (MongoConnectionException $ex) { |
|
135 $this->closed = true; |
|
136 $this->warn(sprintf('Failed to connect to mongo deamon: %s', $ex->getMessage())); |
|
137 } catch (InvalidArgumentException $ex) { |
|
138 $this->closed = true; |
|
139 $this->warn(sprintf('Error while selecting mongo database: %s', $ex->getMessage())); |
|
140 } catch (Exception $ex) { |
|
141 $this->closed = true; |
|
142 $this->warn('Invalid credentials for mongo database authentication'); |
|
143 } |
|
144 } |
|
145 |
|
146 /** |
|
147 * Appends a new event to the mongo database. |
|
148 * |
|
149 * @param LoggerLoggingEvent $event |
|
150 */ |
|
151 public function append(LoggerLoggingEvent $event) { |
|
152 try { |
|
153 if ($this->collection != null) { |
|
154 $this->collection->insert($this->format($event)); |
|
155 } |
|
156 } catch (MongoCursorException $ex) { |
|
157 $this->warn(sprintf('Error while writing to mongo collection: %s', $ex->getMessage())); |
|
158 } |
|
159 } |
|
160 |
|
161 /** |
|
162 * Converts the logging event into an array which can be logged to mongodb. |
|
163 * |
|
164 * @param LoggerLoggingEvent $event |
|
165 * @return array The array representation of the logging event. |
|
166 */ |
|
167 protected function format(LoggerLoggingEvent $event) { |
|
168 $timestampSec = (int)$event->getTimestamp(); |
|
169 $timestampUsec = (int)(($event->getTimestamp() - $timestampSec) * 1000000); |
|
170 |
|
171 $document = array( |
|
172 'timestamp' => new MongoDate($timestampSec, $timestampUsec), |
|
173 'level' => $event->getLevel()->toString(), |
|
174 'thread' => (int)$event->getThreadName(), |
|
175 'message' => $event->getMessage(), |
|
176 'loggerName' => $event->getLoggerName() |
|
177 ); |
|
178 |
|
179 $locationInfo = $event->getLocationInformation(); |
|
180 if ($locationInfo != null) { |
|
181 $document['fileName'] = $locationInfo->getFileName(); |
|
182 $document['method'] = $locationInfo->getMethodName(); |
|
183 $document['lineNumber'] = ($locationInfo->getLineNumber() == 'NA') ? 'NA' : (int)$locationInfo->getLineNumber(); |
|
184 $document['className'] = $locationInfo->getClassName(); |
|
185 } |
|
186 |
|
187 $throwableInfo = $event->getThrowableInformation(); |
|
188 if ($throwableInfo != null) { |
|
189 $document['exception'] = $this->formatThrowable($throwableInfo->getThrowable()); |
|
190 } |
|
191 |
|
192 return $document; |
|
193 } |
|
194 |
|
195 /** |
|
196 * Converts an Exception into an array which can be logged to mongodb. |
|
197 * |
|
198 * Supports innner exceptions (PHP >= 5.3) |
|
199 * |
|
200 * @param Exception $ex |
|
201 * @return array |
|
202 */ |
|
203 protected function formatThrowable(Exception $ex) { |
|
204 $array = array( |
|
205 'message' => $ex->getMessage(), |
|
206 'code' => $ex->getCode(), |
|
207 'stackTrace' => $ex->getTraceAsString(), |
|
208 ); |
|
209 |
|
210 if (method_exists($ex, 'getPrevious') && $ex->getPrevious() !== null) { |
|
211 $array['innerException'] = $this->formatThrowable($ex->getPrevious()); |
|
212 } |
|
213 |
|
214 return $array; |
|
215 } |
|
216 |
|
217 /** |
|
218 * Closes the connection to the logging database |
|
219 */ |
|
220 public function close() { |
|
221 if ($this->closed != true) { |
|
222 $this->collection = null; |
|
223 if ($this->connection !== null) { |
|
224 $this->connection->close(); |
|
225 $this->connection = null; |
|
226 } |
|
227 $this->closed = true; |
|
228 } |
|
229 } |
|
230 |
|
231 /** |
|
232 * Sets the value of {@link $host} parameter. |
|
233 * @param string $host |
|
234 */ |
|
235 public function setHost($host) { |
|
236 if (!preg_match('/^mongodb\:\/\//', $host)) { |
|
237 $host = self::DEFAULT_MONGO_URL_PREFIX . $host; |
|
238 } |
|
239 $this->host = $host; |
|
240 } |
|
241 |
|
242 /** |
|
243 * Returns the value of {@link $host} parameter. |
|
244 * @return string |
|
245 */ |
|
246 public function getHost() { |
|
247 return $this->host; |
|
248 } |
|
249 |
|
250 /** |
|
251 * Sets the value of {@link $port} parameter. |
|
252 * @param int $port |
|
253 */ |
|
254 public function setPort($port) { |
|
255 $this->setPositiveInteger('port', $port); |
|
256 } |
|
257 |
|
258 /** |
|
259 * Returns the value of {@link $port} parameter. |
|
260 * @return int |
|
261 */ |
|
262 public function getPort() { |
|
263 return $this->port; |
|
264 } |
|
265 |
|
266 /** |
|
267 * Sets the value of {@link $databaseName} parameter. |
|
268 * @param string $databaseName |
|
269 */ |
|
270 public function setDatabaseName($databaseName) { |
|
271 $this->setString('databaseName', $databaseName); |
|
272 } |
|
273 |
|
274 /** |
|
275 * Returns the value of {@link $databaseName} parameter. |
|
276 * @return string |
|
277 */ |
|
278 public function getDatabaseName() { |
|
279 return $this->databaseName; |
|
280 } |
|
281 |
|
282 /** |
|
283 * Sets the value of {@link $collectionName} parameter. |
|
284 * @param string $collectionName |
|
285 */ |
|
286 public function setCollectionName($collectionName) { |
|
287 $this->setString('collectionName', $collectionName); |
|
288 } |
|
289 |
|
290 /** |
|
291 * Returns the value of {@link $collectionName} parameter. |
|
292 * @return string |
|
293 */ |
|
294 public function getCollectionName() { |
|
295 return $this->collectionName; |
|
296 } |
|
297 |
|
298 /** |
|
299 * Sets the value of {@link $userName} parameter. |
|
300 * @param string $userName |
|
301 */ |
|
302 public function setUserName($userName) { |
|
303 $this->setString('userName', $userName, true); |
|
304 } |
|
305 |
|
306 /** |
|
307 * Returns the value of {@link $userName} parameter. |
|
308 * @return string |
|
309 */ |
|
310 public function getUserName() { |
|
311 return $this->userName; |
|
312 } |
|
313 |
|
314 /** |
|
315 * Sets the value of {@link $password} parameter. |
|
316 * @param string $password |
|
317 */ |
|
318 public function setPassword($password) { |
|
319 $this->setString('password', $password, true); |
|
320 } |
|
321 |
|
322 /** |
|
323 * Returns the value of {@link $password} parameter. |
|
324 * @return string |
|
325 */ |
|
326 public function getPassword() { |
|
327 return $this->password; |
|
328 } |
|
329 |
|
330 /** |
|
331 * Sets the value of {@link $timeout} parameter. |
|
332 * @param int $timeout |
|
333 */ |
|
334 public function setTimeout($timeout) { |
|
335 $this->setPositiveInteger('timeout', $timeout); |
|
336 } |
|
337 |
|
338 /** |
|
339 * Returns the value of {@link $timeout} parameter. |
|
340 * @return int |
|
341 */ |
|
342 public function getTimeout() { |
|
343 return $this->timeout; |
|
344 } |
|
345 |
|
346 /** |
|
347 * Returns the mongodb connection. |
|
348 * @return Mongo |
|
349 */ |
|
350 public function getConnection() { |
|
351 return $this->connection; |
|
352 } |
|
353 |
|
354 /** |
|
355 * Returns the active mongodb collection. |
|
356 * @return MongoCollection |
|
357 */ |
|
358 public function getCollection() { |
|
359 return $this->collection; |
|
360 } |
|
361 } |