PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / ClientSideMonitoring / AbstractMonitoringMiddleware.php
transferito / vendor / aws / aws-sdk-php / src / ClientSideMonitoring Last commit date
Exception 10 months ago AbstractMonitoringMiddleware.php 10 months ago ApiCallAttemptMonitoringMiddleware.php 10 months ago ApiCallMonitoringMiddleware.php 10 months ago Configuration.php 10 months ago ConfigurationInterface.php 10 months ago ConfigurationProvider.php 10 months ago MonitoringMiddlewareInterface.php 10 months ago
AbstractMonitoringMiddleware.php
289 lines
1 <?php
2
3 namespace Aws\ClientSideMonitoring;
4
5 use Aws\CommandInterface;
6 use Aws\Exception\AwsException;
7 use Aws\MonitoringEventsInterface;
8 use Aws\ResponseContainerInterface;
9 use Aws\ResultInterface;
10 use GuzzleHttp\Promise;
11 use Psr\Http\Message\RequestInterface;
12 use Psr\Http\Message\ResponseInterface;
13
14 /**
15 * @internal
16 */
17 abstract class AbstractMonitoringMiddleware
18 implements MonitoringMiddlewareInterface
19 {
20 private static $socket;
21
22 private $nextHandler;
23 private $options;
24 protected $credentialProvider;
25 protected $region;
26 protected $service;
27
28 protected static function getAwsExceptionHeader(AwsException $e, $headerName)
29 {
30 $response = $e->getResponse();
31 if ($response !== null) {
32 $header = $response->getHeader($headerName);
33 if (!empty($header[0])) {
34 return $header[0];
35 }
36 }
37 return null;
38 }
39
40 protected static function getResultHeader(ResultInterface $result, $headerName)
41 {
42 if (isset($result['@metadata']['headers'][$headerName])) {
43 return $result['@metadata']['headers'][$headerName];
44 }
45 return null;
46 }
47
48 protected static function getExceptionHeader(\Exception $e, $headerName)
49 {
50 if ($e instanceof ResponseContainerInterface) {
51 $response = $e->getResponse();
52 if ($response instanceof ResponseInterface) {
53 $header = $response->getHeader($headerName);
54 if (!empty($header[0])) {
55 return $header[0];
56 }
57 }
58 }
59 return null;
60 }
61
62 /**
63 * Constructor stores the passed in handler and options.
64 *
65 * @param callable $handler
66 * @param callable $credentialProvider
67 * @param $options
68 * @param $region
69 * @param $service
70 */
71 public function __construct(
72 callable $handler,
73 callable $credentialProvider,
74 $options,
75 $region,
76 $service
77 ) {
78 $this->nextHandler = $handler;
79 $this->credentialProvider = $credentialProvider;
80 $this->options = $options;
81 $this->region = $region;
82 $this->service = $service;
83 }
84
85 /**
86 * Standard invoke pattern for middleware execution to be implemented by
87 * child classes.
88 *
89 * @param CommandInterface $cmd
90 * @param RequestInterface $request
91 * @return Promise\PromiseInterface
92 */
93 public function __invoke(CommandInterface $cmd, RequestInterface $request)
94 {
95 $handler = $this->nextHandler;
96 $eventData = null;
97 $enabled = $this->isEnabled();
98
99 if ($enabled) {
100 $cmd['@http']['collect_stats'] = true;
101 $eventData = $this->populateRequestEventData(
102 $cmd,
103 $request,
104 $this->getNewEvent($cmd, $request)
105 );
106 }
107
108 $g = function ($value) use ($eventData, $enabled) {
109 if ($enabled) {
110 $eventData = $this->populateResultEventData(
111 $value,
112 $eventData
113 );
114 $this->sendEventData($eventData);
115
116 if ($value instanceof MonitoringEventsInterface) {
117 $value->appendMonitoringEvent($eventData);
118 }
119 }
120 if ($value instanceof \Exception || $value instanceof \Throwable) {
121 return Promise\Create::rejectionFor($value);
122 }
123 return $value;
124 };
125
126 return Promise\Create::promiseFor($handler($cmd, $request))->then($g, $g);
127 }
128
129 private function getClientId()
130 {
131 return $this->unwrappedOptions()->getClientId();
132 }
133
134 private function getNewEvent(
135 CommandInterface $cmd,
136 RequestInterface $request
137 ) {
138 $event = [
139 'Api' => $cmd->getName(),
140 'ClientId' => $this->getClientId(),
141 'Region' => $this->getRegion(),
142 'Service' => $this->getService(),
143 'Timestamp' => (int) floor(microtime(true) * 1000),
144 'UserAgent' => substr(
145 $request->getHeaderLine('User-Agent') . ' ' . \Aws\default_user_agent(),
146 0,
147 256
148 ),
149 'Version' => 1
150 ];
151 return $event;
152 }
153
154 private function getHost()
155 {
156 return $this->unwrappedOptions()->getHost();
157 }
158
159 private function getPort()
160 {
161 return $this->unwrappedOptions()->getPort();
162 }
163
164 private function getRegion()
165 {
166 return $this->region;
167 }
168
169 private function getService()
170 {
171 return $this->service;
172 }
173
174 /**
175 * Returns enabled flag from options, unwrapping options if necessary.
176 *
177 * @return bool
178 */
179 private function isEnabled()
180 {
181 return $this->unwrappedOptions()->isEnabled();
182 }
183
184 /**
185 * Returns $eventData array with information from the request and command.
186 *
187 * @param CommandInterface $cmd
188 * @param RequestInterface $request
189 * @param array $event
190 * @return array
191 */
192 protected function populateRequestEventData(
193 CommandInterface $cmd,
194 RequestInterface $request,
195 array $event
196 ) {
197 $dataFormat = static::getRequestData($request);
198 foreach ($dataFormat as $eventKey => $value) {
199 if ($value !== null) {
200 $event[$eventKey] = $value;
201 }
202 }
203 return $event;
204 }
205
206 /**
207 * Returns $eventData array with information from the response, including
208 * the calculation for attempt latency.
209 *
210 * @param ResultInterface|\Exception $result
211 * @param array $event
212 * @return array
213 */
214 protected function populateResultEventData(
215 $result,
216 array $event
217 ) {
218 $dataFormat = static::getResponseData($result);
219 foreach ($dataFormat as $eventKey => $value) {
220 if ($value !== null) {
221 $event[$eventKey] = $value;
222 }
223 }
224 return $event;
225 }
226
227 /**
228 * Creates a UDP socket resource and stores it with the class, or retrieves
229 * it if already instantiated and connected. Handles error-checking and
230 * re-connecting if necessary. If $forceNewConnection is set to true, a new
231 * socket will be created.
232 *
233 * @param bool $forceNewConnection
234 * @return Resource
235 */
236 private function prepareSocket($forceNewConnection = false)
237 {
238 if (!is_resource(self::$socket)
239 || $forceNewConnection
240 || socket_last_error(self::$socket)
241 ) {
242 self::$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
243 socket_clear_error(self::$socket);
244 socket_connect(self::$socket, $this->getHost(), $this->getPort());
245 }
246
247 return self::$socket;
248 }
249
250 /**
251 * Sends formatted monitoring event data via the UDP socket connection to
252 * the CSM agent endpoint.
253 *
254 * @param array $eventData
255 * @return int
256 */
257 private function sendEventData(array $eventData)
258 {
259 $socket = $this->prepareSocket();
260 $datagram = json_encode($eventData);
261 $result = socket_write($socket, $datagram, strlen($datagram));
262 if ($result === false) {
263 $this->prepareSocket(true);
264 }
265 return $result;
266 }
267
268 /**
269 * Unwraps options, if needed, and returns them.
270 *
271 * @return ConfigurationInterface
272 */
273 private function unwrappedOptions()
274 {
275 if (!($this->options instanceof ConfigurationInterface)) {
276 try {
277 $this->options = ConfigurationProvider::unwrap($this->options);
278 } catch (\Exception $e) {
279 // Errors unwrapping CSM config defaults to disabling it
280 $this->options = new Configuration(
281 false,
282 ConfigurationProvider::DEFAULT_HOST,
283 ConfigurationProvider::DEFAULT_PORT
284 );
285 }
286 }
287 return $this->options;
288 }
289 }