Skip to content
This repository was archived by the owner on Oct 24, 2023. It is now read-only.

Commit 8aa457a

Browse files
ibrahim-abuelalaaJens Schulze
authored andcommitted
feat(Client): add logLevel configuration option
Includes guzzle/log-subscriber with an adjustment for configurable logLevel Closes #300 BREAKING CHANGE: bump minimum version of Guzzle to 5.3.1 BREAKING CHANGE: remove guzzle/log-subscriber as a dependency
1 parent 28ee2cc commit 8aa457a

File tree

12 files changed

+444
-14
lines changed

12 files changed

+444
-14
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ The SDK supports Guzzle6 as well as Guzzle5 as HTTP client. For Guzzle6:
3939
composer require guzzlehttp/guzzle ^6.0
4040
```
4141

42-
When you want to use Guzzle5 you have to add additionally the log subscriber:
42+
When you want to use Guzzle5 you have to ensure react/promise at minimum version 2.2:
4343

4444
```bash
45-
composer require guzzlehttp/guzzle ^5.0
46-
composer require guzzlehttp/log-subscriber ^1.0
45+
composer require guzzlehttp/guzzle ^5.3.1
46+
composer require react/promise ^2.2
4747
```
4848

4949
After installing, you need to require Composer's autoloader if that's not yet the case:

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"require": {
3131
"php": ">=5.6",
3232
"psr/log": "^1.0",
33-
"guzzlehttp/guzzle": "^6.0 || ^5.0",
33+
"guzzlehttp/guzzle": "^6.0 || ^5.3.1",
3434
"guzzlehttp/psr7": "^1.1",
3535
"psr/cache": "^1.0",
3636
"psr/simple-cache": "^1.0",

set_guzzle5.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/bash
22
SRC='"guzzlehttp/guzzle": "^6.0"'
3-
DST='"guzzlehttp/guzzle": "^5.3.1", "guzzlehttp/log-subscriber": "^1.0", "guzzlehttp/ringphp": "^1.0.7", "react/promise": "^2.2.0"'
3+
DST='"guzzlehttp/guzzle": "^5.3.1", "react/promise": "^2.2.0"'
44
sed -ibak -e "s|$SRC|$DST|g" composer.json

src/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public function getHttpClient($options = [])
200200
if (is_null($this->httpClient)) {
201201
$client = parent::getHttpClient($options);
202202
if ($this->logger instanceof LoggerInterface) {
203-
$client->setLogger($this->logger);
203+
$client->setLogger($this->logger, $this->getConfig()->getLogLevel());
204204
}
205205
}
206206

src/Client/Adapter/AdapterInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
use Psr\Http\Message\ResponseInterface;
1010
use Psr\Log\LoggerAwareInterface;
1111
use Psr\Log\LoggerInterface;
12+
use Psr\Log\LogLevel;
1213

1314
interface AdapterInterface extends LoggerAwareInterface
1415
{
15-
public function setLogger(LoggerInterface $logger);
16+
public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO);
1617

1718
public function addHandler($handler);
1819

src/Client/Adapter/Guzzle5Adapter.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
use GuzzleHttp\Pool;
1111
use GuzzleHttp\Psr7\Request;
1212
use GuzzleHttp\Psr7\Response;
13-
use GuzzleHttp\Subscriber\Log\LogSubscriber;
1413
use Psr\Http\Message\RequestInterface;
1514
use Psr\Http\Message\ResponseInterface;
1615
use Psr\Log\LoggerInterface;
16+
use Commercetools\Core\Helper\Subscriber\Log\LogSubscriber;
1717
use Commercetools\Core\Error\ApiException;
18+
use Psr\Log\LogLevel;
1819

1920
class Guzzle5Adapter implements AdapterInterface
2021
{
@@ -54,11 +55,11 @@ public function __construct(array $options = [])
5455
$this->client = new Client($options);
5556
}
5657

57-
public function setLogger(LoggerInterface $logger)
58+
public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO)
5859
{
5960
$this->logger = $logger;
6061
if ($logger instanceof LoggerInterface) {
61-
$this->getEmitter()->attach(new LogSubscriber($logger));
62+
$this->getEmitter()->attach(new LogSubscriber($logger, null, $logLevel));
6263
}
6364
}
6465

src/Client/Adapter/Guzzle6Adapter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ public function __construct(array $options = [])
4343
$this->client = new Client($options);
4444
}
4545

46-
public function setLogger(LoggerInterface $logger)
46+
public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO)
4747
{
4848
$this->logger = $logger;
49-
$this->addHandler(self::log($logger, new MessageFormatter()));
49+
$this->addHandler(self::log($logger, new MessageFormatter(), $logLevel));
5050
}
5151

5252
/**

src/Config.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Commercetools\Core\Error\InvalidArgumentException;
1111
use Commercetools\Core\Model\Common\ContextAwareInterface;
1212
use Commercetools\Core\Model\Common\ContextTrait;
13+
use Psr\Log\LogLevel;
1314

1415
/**
1516
* Client configuration object
@@ -144,6 +145,11 @@ class Config implements ContextAwareInterface
144145
*/
145146
protected $cacheDir;
146147

148+
/**
149+
* @var string
150+
*/
151+
protected $logLevel = LogLevel::INFO;
152+
147153
/**
148154
* @param array $configValues
149155
* @return static
@@ -542,4 +548,23 @@ public function setCacheDir($cacheDir)
542548

543549
return $this;
544550
}
551+
552+
/**
553+
* @return string
554+
*/
555+
public function getLogLevel()
556+
{
557+
return $this->logLevel;
558+
}
559+
560+
/**
561+
* @param string $logLevel
562+
* @return $this
563+
*/
564+
public function setLogLevel($logLevel)
565+
{
566+
$this->logLevel = $logLevel;
567+
568+
return $this;
569+
}
545570
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
/**
3+
* Origin: https://github.com/guzzle/log-subscriber
4+
* Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
namespace Commercetools\Core\Helper\Subscriber\Log;
26+
27+
use GuzzleHttp\Message\MessageInterface;
28+
use GuzzleHttp\Message\RequestInterface;
29+
use GuzzleHttp\Message\ResponseInterface;
30+
31+
/**
32+
* Formats log messages using variable substitutions for requests, responses,
33+
* and other transactional data.
34+
*
35+
* The following variable substitutions are supported:
36+
*
37+
* - {request}: Full HTTP request message
38+
* - {response}: Full HTTP response message
39+
* - {ts}: Timestamp
40+
* - {host}: Host of the request
41+
* - {method}: Method of the request
42+
* - {url}: URL of the request
43+
* - {host}: Host of the request
44+
* - {protocol}: Request protocol
45+
* - {version}: Protocol version
46+
* - {resource}: Resource of the request (path + query + fragment)
47+
* - {hostname}: Hostname of the machine that sent the request
48+
* - {code}: Status code of the response (if available)
49+
* - {phrase}: Reason phrase of the response (if available)
50+
* - {error}: Any error messages (if available)
51+
* - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
52+
* - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
53+
* - {req_headers}: Request headers
54+
* - {res_headers}: Response headers
55+
* - {req_body}: Request body
56+
* - {res_body}: Response body
57+
*/
58+
class Formatter
59+
{
60+
/**
61+
* Apache Common Log Format.
62+
* @link http://httpd.apache.org/docs/1.3/logs.html#common
63+
* @var string
64+
* @codingStandardsIgnoreStart
65+
*/
66+
const CLF = "{hostname} {req_header_User-Agent} - [{ts}] \"{method} {resource} {protocol}/{version}\" {code} {res_header_Content-Length}";
67+
/**
68+
* codingStandardsIgnoreEnd
69+
*/
70+
const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
71+
const SHORT = '[{ts}] "{method} {resource} {protocol}/{version}" {code}';
72+
73+
/** @var string Template used to format log messages */
74+
private $template;
75+
76+
/**
77+
* @param string $template Log message template
78+
*/
79+
public function __construct($template = self::CLF)
80+
{
81+
$this->template = $template ?: self::CLF;
82+
}
83+
84+
/**
85+
* Returns a formatted message
86+
*
87+
* @param RequestInterface $request Request that was sent
88+
* @param ResponseInterface $response Response that was received
89+
* @param \Exception $error Exception that was received
90+
* @param array $customData Associative array of custom template data
91+
*
92+
* @return string
93+
*/
94+
public function format(
95+
RequestInterface $request,
96+
ResponseInterface $response = null,
97+
\Exception $error = null,
98+
array $customData = []
99+
) {
100+
$cache = $customData;
101+
102+
return preg_replace_callback(
103+
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
104+
function (array $matches) use ($request, $response, $error, &$cache) {
105+
106+
if (isset($cache[$matches[1]])) {
107+
return $cache[$matches[1]];
108+
}
109+
110+
$result = '';
111+
switch ($matches[1]) {
112+
case 'request':
113+
$result = $request;
114+
break;
115+
case 'response':
116+
$result = $response;
117+
break;
118+
case 'req_headers':
119+
$result = trim($request->getMethod() . ' '
120+
. $request->getResource()) . ' HTTP/'
121+
. $request->getProtocolVersion() . "\r\n"
122+
. $this->headers($request);
123+
break;
124+
case 'res_headers':
125+
$result = $response ?
126+
sprintf(
127+
'HTTP/%s %d %s',
128+
$response->getProtocolVersion(),
129+
$response->getStatusCode(),
130+
$response->getReasonPhrase()
131+
) . "\r\n" . $this->headers($response)
132+
: 'NULL';
133+
break;
134+
case 'req_body':
135+
$result = $request->getBody();
136+
break;
137+
case 'res_body':
138+
$result = $response ? $response->getBody() : 'NULL';
139+
break;
140+
case 'ts':
141+
$result = gmdate('c');
142+
break;
143+
case 'method':
144+
$result = $request->getMethod();
145+
break;
146+
case 'url':
147+
$result = $request->getUrl();
148+
break;
149+
case 'resource':
150+
$result = $request->getResource();
151+
break;
152+
case 'req_version':
153+
$result = $request->getProtocolVersion();
154+
break;
155+
case 'res_version':
156+
$result = $response
157+
? $response->getProtocolVersion()
158+
: 'NULL';
159+
break;
160+
case 'host':
161+
$result = $request->getHost();
162+
break;
163+
case 'hostname':
164+
$result = gethostname();
165+
break;
166+
case 'code':
167+
$result = $response
168+
? $response->getStatusCode()
169+
: 'NULL';
170+
break;
171+
case 'phrase':
172+
$result = $response
173+
? $response->getReasonPhrase()
174+
: 'NULL';
175+
break;
176+
case 'error':
177+
$result = $error ? $error->getMessage() : 'NULL';
178+
break;
179+
default:
180+
// handle prefixed dynamic headers
181+
if (strpos($matches[1], 'req_header_') === 0) {
182+
$result = $request->getHeader(substr($matches[1], 11));
183+
} elseif (strpos($matches[1], 'res_header_') === 0) {
184+
$result = $response
185+
? $response->getHeader(substr($matches[1], 11))
186+
: 'NULL';
187+
}
188+
}
189+
190+
$cache[$matches[1]] = $result;
191+
return $result;
192+
},
193+
$this->template
194+
);
195+
}
196+
197+
private function headers(MessageInterface $message)
198+
{
199+
$result = '';
200+
foreach ($message->getHeaders() as $name => $values) {
201+
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
202+
}
203+
204+
return trim($result);
205+
}
206+
}

0 commit comments

Comments
 (0)