1 | <?php |
||||||
2 | declare(strict_types=1); |
||||||
3 | |||||||
4 | /* |
||||||
5 | * This file is part of the php-gelf package. |
||||||
6 | * |
||||||
7 | * (c) Benjamin Zikarsky <http://benjamin-zikarsky.de> |
||||||
8 | * |
||||||
9 | * For the full copyright and license information, please view the LICENSE |
||||||
10 | * file that was distributed with this source code. |
||||||
11 | */ |
||||||
12 | |||||||
13 | namespace Gelf\Test; |
||||||
14 | |||||||
15 | use Gelf\Logger; |
||||||
16 | use Gelf\MessageInterface; |
||||||
17 | use Gelf\PublisherInterface; |
||||||
18 | use PHPUnit\Framework\MockObject\MockObject; |
||||||
19 | use PHPUnit\Framework\TestCase; |
||||||
20 | use Psr\Log\LogLevel; |
||||||
21 | use Exception; |
||||||
22 | use Closure; |
||||||
23 | use Stringable; |
||||||
24 | |||||||
25 | class LoggerTest extends TestCase |
||||||
26 | { |
||||||
27 | private MockObject|PublisherInterface $publisher; |
||||||
28 | private Logger $logger; |
||||||
29 | |||||||
30 | public function setUp(): void |
||||||
31 | { |
||||||
32 | $this->publisher = $this->createMock(PublisherInterface::class); |
||||||
33 | $this->logger = new Logger($this->publisher); |
||||||
34 | } |
||||||
35 | |||||||
36 | public function testPublisher(): void |
||||||
37 | { |
||||||
38 | self::assertEquals($this->publisher, $this->logger->getPublisher()); |
||||||
39 | |||||||
40 | $newPublisher = $this->createMock(PublisherInterface::class); |
||||||
41 | $this->logger->setPublisher($newPublisher); |
||||||
42 | self::assertEquals($newPublisher, $this->logger->getPublisher()); |
||||||
43 | } |
||||||
44 | |||||||
45 | public function testSimpleLog(): void |
||||||
46 | { |
||||||
47 | $this->validatePublish( |
||||||
48 | function (MessageInterface $message) { |
||||||
49 | self::assertEquals("test", $message->getShortMessage()); |
||||||
50 | self::assertEquals(LogLevel::ALERT, $message->getLevel()); |
||||||
51 | } |
||||||
52 | ); |
||||||
53 | |||||||
54 | $this->logger->log(LogLevel::ALERT, "test"); |
||||||
55 | } |
||||||
56 | |||||||
57 | public function testLogContext(): void |
||||||
58 | { |
||||||
59 | $additional = ['test' => 'bar', 'abc' => 'buz']; |
||||||
60 | $this->validatePublish( |
||||||
61 | function (MessageInterface $message) use ($additional) { |
||||||
62 | self::assertEquals("foo bar", $message->getShortMessage()); |
||||||
63 | self::assertEquals($additional, $message->getAllAdditionals()); |
||||||
64 | } |
||||||
65 | ); |
||||||
66 | |||||||
67 | $this->logger->log(LogLevel::NOTICE, "foo {test}", $additional); |
||||||
68 | } |
||||||
69 | |||||||
70 | /** |
||||||
71 | * @see https://github.com/bzikarsky/gelf-php/issues/50 |
||||||
72 | * @dataProvider providerLogContextWithStructuralValues |
||||||
73 | */ |
||||||
74 | public function testLogContextWithStructuralValues(mixed $contextValue, mixed $expected): void |
||||||
75 | { |
||||||
76 | $additional = ['context' => $contextValue]; |
||||||
77 | $this->validatePublish( |
||||||
78 | function (MessageInterface $message) use ($expected) { |
||||||
79 | // Use Message::toArray() as it filters invalid values |
||||||
80 | $final = $message->toArray(); |
||||||
81 | if (!isset($final['_context'])) { |
||||||
82 | self::fail("Expected context key missing"); |
||||||
83 | } |
||||||
84 | $actual = $final['_context']; |
||||||
85 | // Only scalar values are allowed, with exception of boolean |
||||||
86 | self::assertTrue( |
||||||
87 | is_scalar($actual) && !is_bool($actual), |
||||||
88 | 'Unexpected context value of type: ' . gettype($actual) |
||||||
89 | ); |
||||||
90 | self::assertSame($expected, $actual); |
||||||
91 | } |
||||||
92 | ); |
||||||
93 | |||||||
94 | // Log message length must exceed longest context key length + 2 |
||||||
95 | // to cause strtr() in Logger::interpolate() to throw notices for nested arrays |
||||||
96 | $this->logger->log(LogLevel::NOTICE, 'test message', $additional); |
||||||
97 | } |
||||||
98 | |||||||
99 | public static function providerLogContextWithStructuralValues(): array |
||||||
100 | { |
||||||
101 | $stdClass = new \stdClass(); |
||||||
102 | $stdClass->prop1 = 'val1'; |
||||||
103 | |||||||
104 | $toString = new class implements Stringable { |
||||||
105 | public function __toString(): string |
||||||
106 | { |
||||||
107 | return 'toString'; |
||||||
108 | } |
||||||
109 | }; |
||||||
110 | |||||||
111 | return [ |
||||||
112 | 'array' => [['bar' => 'buz'], '{"bar":"buz"}'], |
||||||
113 | 'boolTrue' => [true, 'true'], |
||||||
114 | 'boolFalse' => [false, 'false'], |
||||||
115 | 'integer' => [123, 123], |
||||||
116 | 'float' => [123.456, 123.456], |
||||||
117 | 'object' => [$stdClass, '[object (stdClass)]'], |
||||||
118 | 'toString' => [$toString, 'toString'], |
||||||
119 | 'resource' => [fopen('php://memory', 'r'), '[resource]'], |
||||||
120 | 'null' => [null, 'NULL'] |
||||||
121 | ]; |
||||||
122 | } |
||||||
123 | |||||||
124 | public function testLogException(): void |
||||||
125 | { |
||||||
126 | // offset is the line-distance to the throw statement! |
||||||
127 | $line = __LINE__ + 3; |
||||||
128 | |||||||
129 | try { |
||||||
130 | throw new Exception("test-message", 123); |
||||||
131 | } catch (Exception $e) { |
||||||
132 | $this->validatePublish( |
||||||
133 | function (MessageInterface $message) use ($e, $line) { |
||||||
134 | self::assertStringContainsString( |
||||||
135 | $e->getMessage(), |
||||||
136 | $message->getFullMessage() |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
137 | ); |
||||||
138 | self::assertStringContainsString( |
||||||
139 | get_class($e), |
||||||
140 | $message->getFullMessage() |
||||||
141 | ); |
||||||
142 | self::assertEquals($line, $message->getAdditional('line')); |
||||||
143 | self::assertEquals(__FILE__, $message->getAdditional('file')); |
||||||
144 | } |
||||||
145 | ); |
||||||
146 | |||||||
147 | $this->logger->log( |
||||||
148 | LogLevel::ALERT, |
||||||
149 | $e->getMessage(), |
||||||
150 | context: ['exception' => $e] |
||||||
151 | ); |
||||||
152 | } |
||||||
153 | } |
||||||
154 | |||||||
155 | // @see https://github.com/bzikarsky/gelf-php/issues/9 |
||||||
156 | public function testStringZeroMessage(): void |
||||||
157 | { |
||||||
158 | $this->validatePublish( |
||||||
159 | function (MessageInterface $message) { |
||||||
160 | self::assertEquals("0", $message->getShortMessage()); |
||||||
161 | } |
||||||
162 | ); |
||||||
163 | |||||||
164 | $this->logger->info('0'); |
||||||
165 | } |
||||||
166 | |||||||
167 | private function validatePublish(Closure $validator): void |
||||||
168 | { |
||||||
169 | $this->publisher->expects($this->once())->method('publish')->will( |
||||||
0 ignored issues
–
show
The method
expects() does not exist on Gelf\PublisherInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
170 | $this->returnCallback($validator) |
||||||
171 | ); |
||||||
172 | } |
||||||
173 | |||||||
174 | public function testDefaultContext(): void |
||||||
175 | { |
||||||
176 | $this->logger->setDefaultContext(['defaultFoo' => 'bar', 'defaultBar' => 'foo']); |
||||||
177 | $this->validatePublish( |
||||||
178 | function (MessageInterface $message) { |
||||||
179 | self::assertEquals("bar", $message->getAdditional('defaultFoo')); |
||||||
180 | self::assertEquals("baz", $message->getAdditional('defaultBar')); |
||||||
181 | } |
||||||
182 | ); |
||||||
183 | |||||||
184 | $this->logger->log(5, 'test', [ |
||||||
185 | 'defaultBar' => 'baz' |
||||||
186 | ]); |
||||||
187 | } |
||||||
188 | } |
||||||
189 |