-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
MongoDBFormatter.php
159 lines (135 loc) · 4.81 KB
/
MongoDBFormatter.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?php declare(strict_types=1);
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use MongoDB\BSON\Type;
use MongoDB\BSON\UTCDateTime;
use Monolog\Utils;
use Monolog\LogRecord;
/**
* Formats a record for use with the MongoDBHandler.
*
* @author Florian Plattner <[email protected]>
*/
class MongoDBFormatter implements FormatterInterface
{
private bool $exceptionTraceAsString;
private int $maxNestingLevel;
private bool $isLegacyMongoExt;
/**
* @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record->context is 2
* @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
*/
public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsString = true)
{
$this->maxNestingLevel = max($maxNestingLevel, 0);
$this->exceptionTraceAsString = $exceptionTraceAsString;
$this->isLegacyMongoExt = \extension_loaded('mongodb') && version_compare((string) phpversion('mongodb'), '1.1.9', '<=');
}
/**
* @inheritDoc
*
* @return mixed[]
*/
public function format(LogRecord $record): array
{
/** @var mixed[] $res */
$res = $this->formatArray($record->toArray());
return $res;
}
/**
* @inheritDoc
*
* @return array<mixed[]>
*/
public function formatBatch(array $records): array
{
$formatted = [];
foreach ($records as $key => $record) {
$formatted[$key] = $this->format($record);
}
return $formatted;
}
/**
* @param mixed[] $array
* @return mixed[]|string Array except when max nesting level is reached then a string "[...]"
*/
protected function formatArray(array $array, int $nestingLevel = 0)
{
if ($this->maxNestingLevel > 0 && $nestingLevel > $this->maxNestingLevel) {
return '[...]';
}
foreach ($array as $name => $value) {
if ($value instanceof \DateTimeInterface) {
$array[$name] = $this->formatDate($value, $nestingLevel + 1);
} elseif ($value instanceof \Throwable) {
$array[$name] = $this->formatException($value, $nestingLevel + 1);
} elseif (\is_array($value)) {
$array[$name] = $this->formatArray($value, $nestingLevel + 1);
} elseif (\is_object($value) && !$value instanceof Type) {
$array[$name] = $this->formatObject($value, $nestingLevel + 1);
}
}
return $array;
}
/**
* @param mixed $value
* @return mixed[]|string
*/
protected function formatObject($value, int $nestingLevel)
{
$objectVars = get_object_vars($value);
$objectVars['class'] = Utils::getClass($value);
return $this->formatArray($objectVars, $nestingLevel);
}
/**
* @return mixed[]|string
*/
protected function formatException(\Throwable $exception, int $nestingLevel)
{
$formattedException = [
'class' => Utils::getClass($exception),
'message' => $exception->getMessage(),
'code' => (int) $exception->getCode(),
'file' => $exception->getFile() . ':' . $exception->getLine(),
];
if ($this->exceptionTraceAsString === true) {
$formattedException['trace'] = $exception->getTraceAsString();
} else {
$formattedException['trace'] = $exception->getTrace();
}
return $this->formatArray($formattedException, $nestingLevel);
}
protected function formatDate(\DateTimeInterface $value, int $nestingLevel): UTCDateTime
{
if ($this->isLegacyMongoExt) {
return $this->legacyGetMongoDbDateTime($value);
}
return $this->getMongoDbDateTime($value);
}
private function getMongoDbDateTime(\DateTimeInterface $value): UTCDateTime
{
return new UTCDateTime((int) floor(((float) $value->format('U.u')) * 1000));
}
/**
* This is needed to support MongoDB Driver v1.19 and below
*
* See https://github.com/mongodb/mongo-php-driver/issues/426
*
* It can probably be removed in 2.1 or later once MongoDB's 1.2 is released and widely adopted
*/
private function legacyGetMongoDbDateTime(\DateTimeInterface $value): UTCDateTime
{
$milliseconds = floor(((float) $value->format('U.u')) * 1000);
$milliseconds = (PHP_INT_SIZE === 8) //64-bit OS?
? (int) $milliseconds
: (string) $milliseconds;
return new UTCDateTime($milliseconds);
}
}