Skip to content

Commit 70f6393

Browse files
committed
feat: added psr-3 logger implementation
1 parent 7b9d3d7 commit 70f6393

File tree

5 files changed

+124
-4
lines changed

5 files changed

+124
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
/phpunit.xml
44
/.phpunit.result.cache
55
/vendor/
6+
/logs/
67
/.idea
78
/index.php

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
"authors": [
88
{
99
"name": "André Pimpão",
10-
"email": "a.pimpao@programmator.dev",
11-
"homepage": "https://programmator.dev"
10+
"email": "a.pimpao@programmator.dev"
1211
}
1312
],
1413
"require": {
@@ -18,13 +17,15 @@
1817
"psr/cache": "^3.0",
1918
"psr/http-client": "^1.0",
2019
"psr/http-factory": "^1.0",
20+
"psr/log": "^3.0",
2121
"symfony/options-resolver": "^6.3"
2222
},
2323
"provide": {
2424
"psr/http-client-implementation": "^1.0",
2525
"psr/http-factory-implementation": "^1.0"
2626
},
2727
"require-dev": {
28+
"monolog/monolog": "^3.4",
2829
"nyholm/psr7": "^1.8",
2930
"php-http/mock-client": "^1.6",
3031
"phpunit/phpunit": "^10.0",

src/Config.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
namespace ProgrammatorDev\OpenWeatherMap;
44

55
use ProgrammatorDev\OpenWeatherMap\HttpClient\HttpClientBuilder;
6+
use ProgrammatorDev\OpenWeatherMap\HttpClient\Plugin\LoggerPlugin;
67
use ProgrammatorDev\OpenWeatherMap\Validator\BlankValidatorTrait;
78
use ProgrammatorDev\OpenWeatherMap\Validator\ChoiceValidatorTrait;
89
use Psr\Cache\CacheItemPoolInterface;
10+
use Psr\Log\LoggerInterface;
911
use Symfony\Component\OptionsResolver\OptionsResolver;
1012

1113
class Config
@@ -21,6 +23,8 @@ public function __construct(array $options = [])
2123
$this->configureOptions($resolver);
2224

2325
$this->options = $resolver->resolve($options);
26+
27+
$this->configureAdapters();
2428
}
2529

2630
private function configureOptions(OptionsResolver $resolver): void
@@ -29,7 +33,8 @@ private function configureOptions(OptionsResolver $resolver): void
2933
'measurementSystem' => MeasurementSystem::METRIC,
3034
'language' => Language::ENGLISH,
3135
'httpClientBuilder' => new HttpClientBuilder(),
32-
'cache' => null
36+
'cache' => null,
37+
'logger' => null
3338
]);
3439

3540
$resolver->setRequired('applicationKey');
@@ -39,6 +44,7 @@ private function configureOptions(OptionsResolver $resolver): void
3944
$resolver->setAllowedTypes('language', 'string');
4045
$resolver->setAllowedTypes('httpClientBuilder', HttpClientBuilder::class);
4146
$resolver->setAllowedTypes('cache', ['null', CacheItemPoolInterface::class]);
47+
$resolver->setAllowedTypes('logger', ['null', LoggerInterface::class]);
4248

4349
$resolver->setAllowedValues('applicationKey', function($value) {
4450
return !empty($value);
@@ -47,6 +53,15 @@ private function configureOptions(OptionsResolver $resolver): void
4753
$resolver->setAllowedValues('language', Language::getList());
4854
}
4955

56+
private function configureAdapters(): void
57+
{
58+
if ($this->getLogger() !== null) {
59+
$this->getHttpClientBuilder()->addPlugin(
60+
new LoggerPlugin($this->getLogger())
61+
);
62+
}
63+
}
64+
5065
public function getApplicationKey(): string
5166
{
5267
return $this->options['applicationKey'];
@@ -112,4 +127,16 @@ public function setCache(?CacheItemPoolInterface $cache): self
112127

113128
return $this;
114129
}
130+
131+
public function getLogger(): ?LoggerInterface
132+
{
133+
return $this->options['logger'];
134+
}
135+
136+
public function setLogger(?LoggerInterface $logger): self
137+
{
138+
$this->options['logger'] = $logger;
139+
140+
return $this;
141+
}
115142
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\OpenWeatherMap\HttpClient\Plugin;
4+
5+
use Http\Client\Common\Plugin;
6+
use Http\Client\Exception;
7+
use Http\Message\Formatter;
8+
use Http\Message\Formatter\SimpleFormatter;
9+
use Psr\Http\Message\RequestInterface;
10+
use Psr\Http\Message\ResponseInterface;
11+
use Psr\Log\LoggerInterface;
12+
13+
class LoggerPlugin implements Plugin
14+
{
15+
use Plugin\VersionBridgePlugin;
16+
17+
private LoggerInterface $logger;
18+
19+
private Formatter $formatter;
20+
21+
public function __construct(LoggerInterface $logger, Formatter $formatter = null)
22+
{
23+
$this->logger = $logger;
24+
$this->formatter = $formatter ?: new SimpleFormatter();
25+
}
26+
27+
/**
28+
* @throws Exception
29+
*/
30+
protected function doHandleRequest(RequestInterface $request, callable $next, callable $first)
31+
{
32+
$start = hrtime(true) / 1E6;
33+
$this->logger->info(
34+
\sprintf('Sending request: %s', $this->formatter->formatRequest($request))
35+
);
36+
37+
return $next($request)->then(function (ResponseInterface $response) use ($start, $request) {
38+
$milliseconds = (int) round(hrtime(true) / 1E6 - $start);
39+
$formattedResponse = $this->formatter->formatResponseForRequest($response, $request);
40+
41+
$this->logger->info(
42+
\sprintf('Received response: %s', $formattedResponse), [
43+
'milliseconds' => $milliseconds
44+
]
45+
);
46+
47+
return $response;
48+
}, function (Exception $exception) use ($request, $start) {
49+
$milliseconds = (int) round((hrtime(true) / 1E6 - $start));
50+
51+
if ($exception instanceof Exception\HttpException) {
52+
$formattedResponse = $this->formatter->formatResponseForRequest(
53+
$exception->getResponse(),
54+
$exception->getRequest()
55+
);
56+
57+
$this->logger->error(
58+
\sprintf('Error: %s with response: %s', $exception->getMessage(), $formattedResponse), [
59+
'exception' => $exception,
60+
'milliseconds' => $milliseconds
61+
]
62+
);
63+
}
64+
else {
65+
$this->logger->error(
66+
\sprintf(
67+
'Error: %s when sending request: %s',
68+
$exception->getMessage(),
69+
$this->formatter->formatRequest($request)
70+
), [
71+
'exception' => $exception,
72+
'milliseconds' => $milliseconds
73+
]
74+
);
75+
}
76+
77+
throw $exception;
78+
});
79+
}
80+
}

tests/ConfigTest.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
namespace ProgrammatorDev\OpenWeatherMap\Test;
44

5+
use Monolog\Logger;
56
use PHPUnit\Framework\Attributes\DataProvider;
67
use PHPUnit\Framework\Attributes\DataProviderExternal;
78
use ProgrammatorDev\OpenWeatherMap\Config;
89
use ProgrammatorDev\OpenWeatherMap\HttpClient\HttpClientBuilder;
910
use ProgrammatorDev\OpenWeatherMap\Test\DataProvider\InvalidParamDataProvider;
1011
use Psr\Cache\CacheItemPoolInterface;
12+
use Psr\Log\LoggerInterface;
1113
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
1214
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
1315
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
@@ -32,6 +34,7 @@ public function testConfigDefaultOptions()
3234
$this->assertSame('en', $this->config->getLanguage());
3335
$this->assertInstanceOf(HttpClientBuilder::class, $this->config->getHttpClientBuilder());
3436
$this->assertSame(null, $this->config->getCache());
37+
$this->assertSame(null, $this->config->getLogger());
3538
}
3639

3740
public function testConfigWithOptions()
@@ -41,14 +44,16 @@ public function testConfigWithOptions()
4144
'measurementSystem' => 'imperial',
4245
'language' => 'pt',
4346
'httpClientBuilder' => new HttpClientBuilder(),
44-
'cache' => new FilesystemAdapter()
47+
'cache' => new FilesystemAdapter(),
48+
'logger' => new Logger('test')
4549
]);
4650

4751
$this->assertSame('newtestappkey', $config->getApplicationKey());
4852
$this->assertSame('imperial', $config->getMeasurementSystem());
4953
$this->assertSame('pt', $config->getLanguage());
5054
$this->assertInstanceOf(HttpClientBuilder::class, $config->getHttpClientBuilder());
5155
$this->assertInstanceOf(CacheItemPoolInterface::class, $config->getCache());
56+
$this->assertInstanceOf(LoggerInterface::class, $config->getLogger());
5257
}
5358

5459
#[DataProvider('provideInvalidConfigOptionsData')]
@@ -136,4 +141,10 @@ public function testConfigSetCache()
136141
$this->config->setCache(new FilesystemAdapter());
137142
$this->assertInstanceOf(CacheItemPoolInterface::class, $this->config->getCache());
138143
}
144+
145+
public function testConfigSetLogger()
146+
{
147+
$this->config->setLogger(new Logger('test'));
148+
$this->assertInstanceOf(LoggerInterface::class, $this->config->getLogger());
149+
}
139150
}

0 commit comments

Comments
 (0)