Skip to content

Commit d80b94d

Browse files
committed
V.1.0.0 🔖 - Added more config options. Added max_rows logic. More unit tests. Set Travis to php7.2 and added code coverage testing.
1 parent 03609f9 commit d80b94d

File tree

10 files changed

+239
-71
lines changed

10 files changed

+239
-71
lines changed

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Homestead.yaml
1111
.env
1212
.vagrant
1313
composer.lock
14+
coverage.xml
1415
.phpstorm.meta.php
1516
_ide_helper.php
1617
_ide_helper_models.php.php

‎.travis.yml‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
language: php
22
php:
3-
- 7.1
3+
- 7.2
44
services:
55
- mysql
66
- mongodb
77
before_script:
88
- pecl install mongodb
99
- mysql -e 'CREATE DATABASE testing;'
10+
- composer self-update
1011
- composer install --no-interaction
1112
script:
12-
- vendor/bin/phpunit
13+
- vendor/bin/phpunit --coverage-clover=coverage.xml
14+
after_success:
15+
- bash <(curl -s https://codecov.io/bash)

‎phpunit.xml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,12 @@
1212
<directory suffix=".php">./tests/</directory>
1313
</testsuite>
1414
</testsuites>
15+
<filter>
16+
<whitelist processUncoveredFilesFromWhitelist="true">
17+
<directory suffix=".php">./src</directory>
18+
<exclude>
19+
<directory>./vendor</directory>
20+
</exclude>
21+
</whitelist>
22+
</filter>
1523
</phpunit>

‎readme.md‎

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,57 @@
11
# Laravel Log-to-DB
2-
Custom Larvel 5.6+ Log channel handler that can store log events to SQL or MongoDB databases.
3-
Uses Laravel native logging functionality.
4-
52
[![Travis (.org)](https://img.shields.io/travis/danielme85/laravel-log-to-db.svg?style=flat-square)](https://travis-ci.org/danielme85/laravel-log-to-db)
63
[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/danielme85/laravel-log-to-db)
74

5+
Custom Larvel 5.6+ Log channel handler that can store log events to SQL or MongoDB databases.
6+
Uses Laravel native logging functionality.
7+
88
### Installation
9-
```php
9+
```
1010
require danielme85/laravel-log-to-db
1111
```
1212

13+
If you are going to be using SQL database server to store log events you would need to run the migrations first. The MongoDB driver does not require the migration.
14+
```
15+
php artisan migrate
16+
```
17+
1318
### Configuration
1419
Starting with Laravel 5.6 you will have a new settings file: "config/logging.php".
1520
You will need to add an array under 'channels' for Log-to-DB here like so:
1621
```php
17-
'database' => [
18-
'driver' => 'custom',
19-
'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
20-
'level' => env('APP_LOG_LEVEL', 'debug'),
21-
]
22+
'database' => [
23+
'driver' => 'custom',
24+
'via' => danielme85\LaravelLogToDB\LogToDbHandler::class,
25+
'level' => env('APP_LOG_LEVEL', 'debug'),
26+
'name' => 'My DB Log',
27+
'connection' => 'default',
28+
'collection' => 'log',
29+
'detailed' => true,
30+
'max_rows' => false
31+
]
32+
```
33+
* driver = Required to trigger the log driver.
34+
* via = The Log handler class.
35+
* level = The minimum error level to trigger this Log Channel.
36+
* name = The channel name that will be stored with the Log event.
37+
* connection = The DB connection from config/database.php to use (default: 'default').
38+
* collection = The DB table or collection name. (Default: log).
39+
* detailed = Store detailed log on Exceptions like stack-trace (default: true).
40+
* max_rows = The number of rows/objects to allow before automatically removing the oldest (default: false).
41+
42+
More info about some of these options: https://laravel.com/docs/5.6/logging#customizing-monolog-for-channels
43+
44+
There are some default settings and more information about configuring the logger in the 'logtodb.php' config file.
45+
This can be copied to your project so you can edit it with the vendor publish command.
46+
```
47+
php artisan vendor:publish
48+
```
49+
You can give the logging channels whatever name you want instead of: 'database', as well as the log levels.
50+
The naming can be used later if you want to send a Log event to a specific channel:
51+
```php
52+
Log::channel('database')->info("This thing just happened");
53+
Log::channel('mongodb')->info("This thing just happened");
2254
```
23-
You can give it whatever name you want as the array index instead of: 'database', as well as the log levels.
2455
This logger works the same as any other across Laravel, for example you can add it to a stack.
2556
You can log multiple levels to multiple DB connections... the possibilities are ENDLESS! 😎
2657
```php
@@ -61,27 +92,27 @@ You can log multiple levels to multiple DB connections... the possibilities are
6192
Since this is a custom log channel for Laravel, all "standard" ways of generating log events etc should work with
6293
the Laravel Log Facade. See https://laravel.com/docs/5.6/logging for more information.
6394

64-
#### Viewing/Getting The Log
65-
The logging by this channel is done trough the Eloquent Model builder. To get access to the underlying models use:
95+
#### Fetching Logs
96+
The logging by this channel is done trough the Eloquent Model builder.
97+
LogToDB::model($channel, $connection, $collection);
98+
You can skip all function variables and the default settings from the config/logtodb.php will be used.
6699
```php
67-
$log = danielme85\LaravelLogToDB\LogToDB::model();
100+
$model = LogToDB::model();
101+
$model->all(); //All logs for defualt channel/connection
68102
```
69103

70-
Some examples of getting logs
104+
Some more examples of getting logs
71105
```php
72-
//LogToDB::model() = The Eloquent model;
73-
74106
$logs = LogToDB::model()->all();
75107
$logs = LogToDB::model()->where('id' = $id)->first();
76-
77-
//or
78-
79-
$log = danielme85\LaravelLogToDB\LogToDB::model();
80-
$log->all();
81108
```
82109

83-
Getting log for specific DB connection when using multiple DB storage methods.
110+
When getting logs for specific channel or DB connection and collection you can either use the channel name matching
111+
config/logging.php or connection name from config/databases.php. You can also specify collection/table name if needed as
112+
the third function variable when fetching the model.
84113
```php
85-
$logsFromDatabase = LogToDB::model('mysql')->all();
86-
$logsFromMongoDB = LogToDB::model('mongodb')->all();
114+
$logsFromDefault = LogDB::model()->all();
115+
$logsFromChannel = LogDB::model('database')->all();
116+
$logsFromMysql = LogToDB::model(null, 'mysql')->all();
117+
$logsFromMongoDB = LogToDB::model(null, 'mongodb', 'log')->all();
87118
```

‎src/LogToDB.php‎

Lines changed: 112 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,79 @@
99
*/
1010
class LogToDB
1111
{
12+
/**
13+
* Connection referenced in logging config.
14+
* @var null
15+
*/
1216
public $channelConnection;
13-
14-
public $detailed = false;
15-
16-
public $maxRows = false;
17-
18-
//DB Connection to use
19-
public $connection = 'default';
20-
17+
/**
18+
* Store detailed log
19+
* @var string
20+
*/
21+
public $detailed;
22+
/**
23+
* Max number of allowed rows
24+
* @var bool
25+
*/
26+
public $maxRows;
27+
/**
28+
* Connection reference in databases config.
29+
* @var string
30+
*/
31+
public $connection;
32+
/**
33+
* The table in SQL or Collection in noSQL.
34+
* @var string
35+
*/
2136
public $collection;
22-
23-
private $database = null;
37+
/**
38+
* The DB config details
39+
* @var null
40+
*/
41+
private $database;
2442

2543
/**
2644
* LogToDB constructor.
45+
*
46+
* @param null $channelConnection
47+
* @param null $collection
48+
* @param null $detailed
49+
* @param null $maxRows
2750
*/
28-
function __construct($channelConnection = null, $collection = 'log')
51+
function __construct($channelConnection = null, $collection = null, $detailed = null, $maxRows = null)
2952
{
30-
$this->channelConnection = $channelConnection;
31-
$this->collection = $collection;
32-
33-
//Set config data
53+
//Log default config if present
3454
$config = config('logtodb');
3555
if (!empty($config)) {
3656
if (isset($config['connection'])) {
3757
$this->connection = $config['connection'];
3858
}
59+
if (isset($config['collection'])) {
60+
$this->collection = $config['collection'];
61+
}
3962
if (isset($config['detailed'])) {
4063
$this->detailed = $config['detailed'];
4164
}
4265
if (isset($config['max_rows'])) {
43-
$this->maxRows = $config['max_rows'];
66+
$this->maxRows = (int)$config['max_rows'];
4467
}
4568
}
4669

70+
//Set config based on specified config from the Log handler
71+
if (!empty($channelConnection)) {
72+
$this->channelConnection = $channelConnection;
73+
}
74+
if (!empty($collection)) {
75+
$this->collection = $collection;
76+
}
77+
if (!empty($detailed)) {
78+
$this->detailed = $detailed;
79+
}
80+
if (!empty($maxRows)) {
81+
$this->maxRows = (int)$maxRows;
82+
}
83+
84+
//Get the DB connections
4785
$dbconfig = config('database.connections');
4886

4987
if (!empty($this->channelConnection)) {
@@ -67,10 +105,42 @@ function __construct($channelConnection = null, $collection = 'log')
67105
}
68106

69107
/**
70-
* @return string
108+
* Return a new LogToDB Module instance.
109+
*
110+
* @param string|null $channel
111+
* @param string|null $connection
112+
* @param string|null $collection
113+
*
114+
* @return DBLog|DBLogMongoDB
71115
*/
72-
public static function model($channelConnection = null) {
73-
$model = new self($channelConnection);
116+
public static function model(string $channel = null, string $connection = null, string $collection = null)
117+
{
118+
$conn = null;
119+
$coll = null;
120+
121+
if (!empty($channel)) {
122+
$channels = config('logging.channels');
123+
if (isset($channels[$channel])) {
124+
if (isset($channels[$channel]['connection']) and !empty($channels[$channel]['connection'])) {
125+
$conn = $channels[$channel]['connection'];
126+
}
127+
if (isset($channels[$channel]['collection']) and !empty($channels[$channel]['collection'])) {
128+
$coll = $channels[$channel]['collection'];
129+
}
130+
}
131+
}
132+
else {
133+
if (!empty($connection)) {
134+
$conn = $connection;
135+
}
136+
if (!empty($collection)) {
137+
$coll = $collection;
138+
}
139+
}
140+
141+
//Return new instance of this model
142+
$model = new self($conn, $coll);
143+
74144
return $model->getModel();
75145
}
76146

@@ -96,7 +166,6 @@ private function getModel() {
96166
*/
97167
public function newFromMonolog(array $record) : self
98168
{
99-
100169
if ($this->database['driver'] === 'mongodb') {
101170
//MongoDB has its own Model
102171
$log = new DBLogMongoDB($this->connection, $this->collection);
@@ -109,10 +178,6 @@ public function newFromMonolog(array $record) : self
109178
if (isset($record['message'])) {
110179
$log->message = $record['message'];
111180
}
112-
/**
113-
* Storing the error log details takes quite a bit of space in sql database compared to a log file,
114-
* so this can be disabled in the config.
115-
*/
116181
if ($this->detailed) {
117182
if (isset($record['context'])) {
118183
if (!empty($record['context'])) {
@@ -139,9 +204,31 @@ public function newFromMonolog(array $record) : self
139204
}
140205
$log->unix_time = time();
141206

142-
$log->save();
207+
if ($log->save()) {
208+
if (!empty($this->maxRows)) {
209+
$this->removeOldestIfMaxRows();
210+
}
211+
}
143212

144213
return $this;
145214
}
146215

216+
/**
217+
* Delete the oldest record based on unix_time
218+
*
219+
* @return bool success
220+
*/
221+
private function removeOldestIfMaxRows() {
222+
$model = $this->model();
223+
$current = $model->count();
224+
if ($current > $this->maxRows) {
225+
$oldest = $model->orderBy('unix_time', 'ASC')->first();
226+
if ($oldest->delete()) {
227+
return true;
228+
}
229+
}
230+
231+
return false;
232+
}
233+
147234
}

‎src/LogToDbCustomLoggingHandler.php‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,25 @@ class LogToDbCustomLoggingHandler extends AbstractProcessingHandler
1414
{
1515
private $connection;
1616
private $collection;
17+
private $detailed;
18+
private $maxRows;
1719

1820
/**
1921
* LogToDbHandler constructor.
2022
*
23+
* @param string $connection The DB connection.
24+
* @param string $collection The Collection/Table name for DB.
25+
* @param bool $detailed Detailed error logging.
26+
* @param int $maxRows The Maximum number of rows/objects before auto purge.
2127
* @param int $level The minimum logging level at which this handler will be triggered
2228
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
2329
*/
24-
function __construct($connection = 'default', $level = Logger::DEBUG, $collection = 'log', bool $bubble = true)
30+
function __construct($connection, $collection, $detailed, $maxRows, $level = Logger::DEBUG, bool $bubble = true)
2531
{
2632
$this->connection = $connection;
2733
$this->collection = $collection;
34+
$this->detailed = $detailed;
35+
$this->maxRows = $maxRows;
2836

2937
parent::__construct($level, $bubble);
3038
}
@@ -38,7 +46,7 @@ protected function write(array $record): void
3846
{
3947
if (!empty($record)) {
4048
try {
41-
$log = new LogToDB($this->connection, $this->collection);
49+
$log = new LogToDB($this->connection, $this->collection, $this->detailed, $this->maxRows);
4250
$log->newFromMonolog($record);
4351
} catch (\Exception $e) {
4452
//

0 commit comments

Comments
 (0)