1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Guzzle\Log; |
4
|
|
|
|
5
|
|
|
use Guzzle\Http\Curl\CurlHandle; |
6
|
|
|
use Guzzle\Http\Message\RequestInterface; |
7
|
|
|
use Guzzle\Http\Message\EntityEnclosingRequestInterface; |
8
|
|
|
use Guzzle\Http\Message\Response; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Message formatter used in various places in the framework |
12
|
|
|
* |
13
|
|
|
* Format messages using a template that can contain the the following variables: |
14
|
|
|
* |
15
|
|
|
* - {request}: Full HTTP request message |
16
|
|
|
* - {response}: Full HTTP response message |
17
|
|
|
* - {ts}: Timestamp |
18
|
|
|
* - {host}: Host of the request |
19
|
|
|
* - {method}: Method of the request |
20
|
|
|
* - {url}: URL of the request |
21
|
|
|
* - {host}: Host of the request |
22
|
|
|
* - {protocol}: Request protocol |
23
|
|
|
* - {version}: Protocol version |
24
|
|
|
* - {resource}: Resource of the request (path + query + fragment) |
25
|
|
|
* - {port}: Port of the request |
26
|
|
|
* - {hostname}: Hostname of the machine that sent the request |
27
|
|
|
* - {code}: Status code of the response (if available) |
28
|
|
|
* - {phrase}: Reason phrase of the response (if available) |
29
|
|
|
* - {curl_error}: Curl error message (if available) |
30
|
|
|
* - {curl_code}: Curl error code (if available) |
31
|
|
|
* - {curl_stderr}: Curl standard error (if available) |
32
|
|
|
* - {connect_time}: Time in seconds it took to establish the connection (if available) |
33
|
|
|
* - {total_time}: Total transaction time in seconds for last transfer (if available) |
34
|
|
|
* - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message |
35
|
|
|
* - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message |
36
|
|
|
* - {req_body}: Request body |
37
|
|
|
* - {res_body}: Response body |
38
|
|
|
*/ |
39
|
|
|
class MessageFormatter |
40
|
|
|
{ |
41
|
|
|
const DEFAULT_FORMAT = "{hostname} {req_header_User-Agent} - [{ts}] \"{method} {resource} {protocol}/{version}\" {code} {res_header_Content-Length}"; |
42
|
|
|
const DEBUG_FORMAT = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{curl_stderr}"; |
43
|
|
|
const SHORT_FORMAT = '[{ts}] "{method} {resource} {protocol}/{version}" {code}'; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var string Template used to format log messages |
47
|
|
|
*/ |
48
|
|
|
protected $template; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @param string $template Log message template |
52
|
|
|
*/ |
53
|
|
|
public function __construct($template = self::DEFAULT_FORMAT) |
54
|
|
|
{ |
55
|
|
|
$this->template = $template ?: self::DEFAULT_FORMAT; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Set the template to use for logging |
60
|
|
|
* |
61
|
|
|
* @param string $template Log message template |
62
|
|
|
* |
63
|
|
|
* @return self |
64
|
|
|
*/ |
65
|
|
|
public function setTemplate($template) |
66
|
|
|
{ |
67
|
|
|
$this->template = $template; |
68
|
|
|
|
69
|
|
|
return $this; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Returns a formatted message |
74
|
|
|
* |
75
|
|
|
* @param RequestInterface $request Request that was sent |
76
|
|
|
* @param Response $response Response that was received |
77
|
|
|
* @param CurlHandle $handle Curl handle associated with the message |
78
|
|
|
* @param array $customData Associative array of custom template data |
79
|
|
|
* |
80
|
|
|
* @return string |
81
|
|
|
*/ |
82
|
|
|
public function format( |
83
|
|
|
RequestInterface $request, |
84
|
|
|
Response $response = null, |
85
|
|
|
CurlHandle $handle = null, |
86
|
|
|
array $customData = array() |
87
|
|
|
) { |
88
|
|
|
$cache = $customData; |
89
|
|
|
|
90
|
|
|
return preg_replace_callback( |
91
|
|
|
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/', |
92
|
|
|
function (array $matches) use ($request, $response, $handle, &$cache) { |
93
|
|
|
|
94
|
|
|
if (array_key_exists($matches[1], $cache)) { |
95
|
|
|
return $cache[$matches[1]]; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$result = ''; |
99
|
|
|
switch ($matches[1]) { |
100
|
|
|
case 'request': |
101
|
|
|
$result = (string) $request; |
102
|
|
|
break; |
103
|
|
|
case 'response': |
104
|
|
|
$result = (string) $response; |
105
|
|
|
break; |
106
|
|
|
case 'req_body': |
107
|
|
|
$result = $request instanceof EntityEnclosingRequestInterface |
108
|
|
|
? (string) $request->getBody() : ''; |
109
|
|
|
break; |
110
|
|
|
case 'res_body': |
111
|
|
|
$result = $response ? $response->getBody(true) : ''; |
112
|
|
|
break; |
113
|
|
|
case 'ts': |
114
|
|
|
$result = gmdate('c'); |
115
|
|
|
break; |
116
|
|
|
case 'method': |
117
|
|
|
$result = $request->getMethod(); |
118
|
|
|
break; |
119
|
|
|
case 'url': |
120
|
|
|
$result = (string) $request->getUrl(); |
121
|
|
|
break; |
122
|
|
|
case 'resource': |
123
|
|
|
$result = $request->getResource(); |
124
|
|
|
break; |
125
|
|
|
case 'protocol': |
126
|
|
|
$result = 'HTTP'; |
127
|
|
|
break; |
128
|
|
|
case 'version': |
129
|
|
|
$result = $request->getProtocolVersion(); |
130
|
|
|
break; |
131
|
|
|
case 'host': |
132
|
|
|
$result = $request->getHost(); |
133
|
|
|
break; |
134
|
|
|
case 'hostname': |
135
|
|
|
$result = gethostname(); |
136
|
|
|
break; |
137
|
|
|
case 'port': |
138
|
|
|
$result = $request->getPort(); |
139
|
|
|
break; |
140
|
|
|
case 'code': |
141
|
|
|
$result = $response ? $response->getStatusCode() : ''; |
142
|
|
|
break; |
143
|
|
|
case 'phrase': |
144
|
|
|
$result = $response ? $response->getReasonPhrase() : ''; |
145
|
|
|
break; |
146
|
|
View Code Duplication |
case 'connect_time': |
|
|
|
|
147
|
|
|
$result = $handle && $handle->getInfo(CURLINFO_CONNECT_TIME) |
148
|
|
|
? $handle->getInfo(CURLINFO_CONNECT_TIME) |
149
|
|
|
: ($response ? $response->getInfo('connect_time') : ''); |
150
|
|
|
break; |
151
|
|
View Code Duplication |
case 'total_time': |
|
|
|
|
152
|
|
|
$result = $handle && $handle->getInfo(CURLINFO_TOTAL_TIME) |
153
|
|
|
? $handle->getInfo(CURLINFO_TOTAL_TIME) |
154
|
|
|
: ($response ? $response->getInfo('total_time') : ''); |
155
|
|
|
break; |
156
|
|
|
case 'curl_error': |
157
|
|
|
$result = $handle ? $handle->getError() : ''; |
158
|
|
|
break; |
159
|
|
|
case 'curl_code': |
160
|
|
|
$result = $handle ? $handle->getErrorNo() : ''; |
161
|
|
|
break; |
162
|
|
|
case 'curl_stderr': |
163
|
|
|
$result = $handle ? $handle->getStderr() : ''; |
164
|
|
|
break; |
165
|
|
|
default: |
166
|
|
|
if (strpos($matches[1], 'req_header_') === 0) { |
167
|
|
|
$result = $request->getHeader(substr($matches[1], 11)); |
168
|
|
|
} elseif ($response && strpos($matches[1], 'res_header_') === 0) { |
169
|
|
|
$result = $response->getHeader(substr($matches[1], 11)); |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
$cache[$matches[1]] = $result; |
174
|
|
|
return $result; |
175
|
|
|
}, |
176
|
|
|
$this->template |
177
|
|
|
); |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.