Skip to content
This repository was archived by the owner on May 2, 2025. It is now read-only.

Commit 84553fe

Browse files
authored
Merge pull request #8 from webinertia/json-db-writer
Json db writer
2 parents ebb967f + 22eba17 commit 84553fe

File tree

7 files changed

+217
-16
lines changed

7 files changed

+217
-16
lines changed

src/ConfigProvider.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ public function getDependencyConfig(): array
2121
public function getLogSettings(): array
2222
{
2323
return [
24-
'log_settings' => [
2524
'log_errors' => true,
2625
'log_exceptions' => true,
2726
'log_table_name' => 'log',
2827
'log_time_format' => 'm-d-Y H:i:s',
29-
],
3028
];
3129
}
3230

@@ -41,10 +39,10 @@ public function getLogProcessorConfig(): array
4139
{
4240
return [
4341
'aliases' => [
44-
'psrplaceholder' => Processors\PsrPlaceholder::class,
42+
'psrplaceholder' => Processor\PsrPlaceholder::class,
4543
],
4644
'factories' => [
47-
Processors\PsrPlaceholder::class => Processors\PsrPlaceholderFactory::class,
45+
Processor\PsrPlaceholder::class => Processor\PsrPlaceholderFactory::class,
4846
],
4947
];
5048
}
@@ -55,7 +53,7 @@ public function getPsrLogConfig(): array
5553
LoggerInterface::class => [
5654
'processors' => [
5755
'psrplaceholder' => [
58-
'name' => Processors\PsrPlaceholder::class,
56+
'name' => Processor\PsrPlaceholder::class,
5957
'priority' => Logger::DEBUG,
6058
],
6159
],

src/LogListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public function log(EventInterface $event)
118118
$logMessage = $event->getTarget();
119119
$params = $event->getParams();
120120

121-
if ($event instanceof LogEvent) {
121+
if (! $event instanceof MvcEvent) {
122122
if ($params !== []) {
123123
$passContext = true;
124124
}

src/LogListenerFactory.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use Laminas\Db\Adapter\Adapter;
88
use Laminas\Db\Adapter\AdapterInterface;
9-
use Laminas\Log\Formatter\Db as Formatter;
109
use Laminas\Log\Formatter\Json;
1110
use Laminas\Log\Writer\Db;
1211
use Laminas\Log\Writer\Stream;
@@ -16,6 +15,7 @@
1615
use Psr\Container\ContainerInterface;
1716
use Psr\Log\LoggerInterface;
1817
use Webinertia\Log\LogListener;
18+
use Webinertia\Log\Writer\JsonDb;
1919

2020
class LogListenerFactory implements FactoryInterface
2121
{
@@ -24,20 +24,18 @@ class LogListenerFactory implements FactoryInterface
2424
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): LogListener
2525
{
2626
$config = $container->get('config');
27-
$logSettings = $config['app_settings']['log_settings'];
27+
$logSettings = $config['log_settings'];
2828
// we need the Laminas Logger instance to setup the writers
2929
/** @var \Laminas\Log\Logger $logger */
3030
$logger = $container->get(LoggerInterface::class)->getLogger();
3131
if (isset($config['db']) && $config['db'] !== [] && $container->has(AdapterInterface::class)) {
3232
$dbAdapter = $container->get(AdapterInterface::class);
33-
if ($dbAdapter instanceof Adapter) { // if this passes we have a configured connection
33+
if ($dbAdapter instanceof Adapter) {
3434
$dbConfig = [
3535
'db' => $dbAdapter,
3636
'table' => $logSettings['log_table_name'] ?? 'log',
3737
];
38-
$dbWriter = new Db($dbConfig);
39-
$dbFormatter = new Formatter($logSettings['log_time_format'] ?? null);
40-
$dbWriter->setFormatter($dbFormatter);
38+
$dbWriter = $logSettings['log_db_entry_as_json'] ? new JsonDb($dbConfig) : new Db($dbConfig);
4139
$logger->addWriter($dbWriter);
4240
}
4341
} else {

src/Module.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public function getConfig(): array
1010
{
1111
$configProvider = new ConfigProvider();
1212
return [
13-
'app_settings' => $configProvider->getLogSettings(),
13+
'log_settings' => $configProvider->getLogSettings(),
1414
'listeners' => $configProvider->getListenerConfig(),
1515
'log_processors' => $configProvider->getLogProcessorConfig(),
1616
'psr_log' => $configProvider->getPsrLogConfig(),

src/Processors/PsrPlaceholder.php renamed to src/Processor/PsrPlaceholder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Webinertia\Log\Processors;
5+
namespace Webinertia\Log\Processor;
66

77
use Laminas\Log\Processor\PsrPlaceholder as Placeholder;
88
use Laminas\I18n\Translator\TranslatorAwareInterface;

src/Processors/PsrPlaceholderFactory.php renamed to src/Processor/PsrPlaceholderFactory.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
declare(strict_types=1);
44

5-
namespace Webinertia\Log\Processors;
5+
namespace Webinertia\Log\Processor;
66

77
use Laminas\ServiceManager\Factory\FactoryInterface;
88
use Psr\Container\ContainerInterface;
9-
use Webinertia\Log\Processors\PsrPlaceholder;
109
use Webinertia\User\Service\UserServiceInterface;
1110

1211
final class PsrPlaceholderFactory implements FactoryInterface

src/Writer/JsonDb.php

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Webinertia\Log\Writer;
6+
7+
use Laminas\Db\Adapter\Adapter;
8+
use Laminas\Log\Writer\AbstractWriter;
9+
use Laminas\Log\Exception;
10+
use Laminas\Log\Formatter\Json;
11+
use Traversable;
12+
13+
use function array_keys;
14+
use function array_map;
15+
use function implode;
16+
use function is_array;
17+
use function is_scalar;
18+
use function iterator_to_array;
19+
use function var_export;
20+
21+
class JsonDb extends AbstractWriter
22+
{
23+
/**
24+
* Db adapter instance
25+
*
26+
* @var Adapter
27+
*/
28+
protected $db;
29+
30+
/**
31+
* Table name
32+
*
33+
* @var string
34+
*/
35+
protected $tableName;
36+
37+
/**
38+
* Relates database columns names to log data field keys.
39+
*
40+
* @var null|array
41+
*/
42+
protected $columnMap;
43+
44+
/**
45+
* Field separator for sub-elements
46+
*
47+
* @var string
48+
*/
49+
protected $separator = '_';
50+
51+
/**
52+
* Constructor
53+
*
54+
* We used the Adapter instead of Laminas\Db for a performance reason.
55+
*
56+
* @param Adapter|array|Traversable $db
57+
* @param string $tableName
58+
* @param array $columnMap
59+
* @param string $separator
60+
* @throws Exception\InvalidArgumentException
61+
*/
62+
public function __construct($db, $tableName = null, ?array $columnMap = null, $separator = null)
63+
{
64+
if ($db instanceof Traversable) {
65+
$db = iterator_to_array($db);
66+
}
67+
68+
if (is_array($db)) {
69+
parent::__construct($db);
70+
$separator = $db['separator'] ?? null;
71+
$columnMap = $db['column'] ?? null;
72+
$tableName = $db['table'] ?? null;
73+
$db = $db['db'] ?? null;
74+
}
75+
76+
if (! $db instanceof Adapter) {
77+
throw new Exception\InvalidArgumentException('You must pass a valid Laminas\Db\Adapter\Adapter');
78+
}
79+
80+
$tableName = (string) $tableName;
81+
if ('' === $tableName) {
82+
throw new Exception\InvalidArgumentException(
83+
'You must specify a table name. Either directly in the constructor, or via options'
84+
);
85+
}
86+
87+
$this->db = $db;
88+
$this->tableName = $tableName;
89+
$this->columnMap = $columnMap;
90+
91+
if (! empty($separator)) {
92+
$this->separator = $separator;
93+
}
94+
95+
if (! $this->hasFormatter()) {
96+
$this->setFormatter(new Json());
97+
}
98+
}
99+
100+
/**
101+
* Remove reference to database adapter
102+
*
103+
* @return void
104+
*/
105+
public function shutdown()
106+
{
107+
$this->db = null;
108+
}
109+
110+
/**
111+
* Write a message to the log.
112+
*
113+
* @param array $event event data
114+
* @return void
115+
* @throws Exception\RuntimeException
116+
*/
117+
protected function doWrite(array $event)
118+
{
119+
if (null === $this->db) {
120+
throw new Exception\RuntimeException('Database adapter is null');
121+
}
122+
123+
$event = $this->formatter->format($event);
124+
$dataToInsert = ['id' => null, 'data' => $event];
125+
126+
$statement = $this->db->query($this->prepareInsert($dataToInsert));
127+
$statement->execute($dataToInsert);
128+
}
129+
130+
/**
131+
* Prepare the INSERT SQL statement
132+
*
133+
* @param array $fields
134+
* @return string
135+
*/
136+
protected function prepareInsert(array $fields)
137+
{
138+
$keys = array_keys($fields);
139+
return 'INSERT INTO ' . $this->db->platform->quoteIdentifier($this->tableName) . ' ('
140+
. implode(",", array_map([$this->db->platform, 'quoteIdentifier'], $keys)) . ') VALUES ('
141+
. implode(",", array_map([$this->db->driver, 'formatParameterName'], $keys)) . ')';
142+
}
143+
144+
/**
145+
* Map event into column using the $columnMap array
146+
*
147+
* @param array $event
148+
* @param array $columnMap
149+
* @return array
150+
*/
151+
protected function mapEventIntoColumn(array $event, ?array $columnMap = null)
152+
{
153+
if (empty($event)) {
154+
return [];
155+
}
156+
157+
$data = [];
158+
foreach ($event as $name => $value) {
159+
if (is_array($value)) {
160+
foreach ($value as $key => $subvalue) {
161+
if (isset($columnMap[$name][$key])) {
162+
if (is_scalar($subvalue)) {
163+
$data[$columnMap[$name][$key]] = $subvalue;
164+
continue;
165+
}
166+
167+
$data[$columnMap[$name][$key]] = var_export($subvalue, true);
168+
}
169+
}
170+
} elseif (isset($columnMap[$name])) {
171+
$data[$columnMap[$name]] = $value;
172+
}
173+
}
174+
return $data;
175+
}
176+
177+
/**
178+
* Transform event into column for the db table
179+
*
180+
* @param array $event
181+
* @return array
182+
*/
183+
protected function eventIntoColumn(array $event)
184+
{
185+
if (empty($event)) {
186+
return [];
187+
}
188+
189+
$data = [];
190+
foreach ($event as $name => $value) {
191+
if (is_array($value)) {
192+
foreach ($value as $key => $subvalue) {
193+
if (is_scalar($subvalue)) {
194+
$data[$name . $this->separator . $key] = $subvalue;
195+
continue;
196+
}
197+
198+
$data[$name . $this->separator . $key] = var_export($subvalue, true);
199+
}
200+
} else {
201+
$data[$name] = $value;
202+
}
203+
}
204+
return $data;
205+
}
206+
}

0 commit comments

Comments
 (0)