Skip to content

Commit 3cd567d

Browse files
committed
feat: add request and trace id to http requests and responses
1 parent 3e0b602 commit 3cd567d

8 files changed

Lines changed: 614 additions & 11 deletions

File tree

phpstan-baseline.neon

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ parameters:
3737
path: src/Lambda/Response/Http/AbstractErrorHttpResponse.php
3838

3939
-
40-
message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#'
41-
identifier: function.alreadyNarrowedType
40+
message: '#^Method Ymir\\Runtime\\Lambda\\Response\\Http\\HttpResponse\:\:withHeader\(\) has parameter \$value with no type specified\.$#'
41+
identifier: missingType.parameter
4242
count: 1
43-
path: src/Lambda/Response/Http/StaticFileResponse.php
43+
path: src/Lambda/Response/Http/HttpResponse.php
4444

4545
-
4646
message: '#^Method Ymir\\Runtime\\Logger\:\:__construct\(\) has parameter \$level with no type specified\.$#'

src/FastCgi/FastCgiRequest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,32 @@ public function __construct(string $content = '', array $parameters = [])
5050
public static function createFromInvocationEvent(HttpRequestEvent $event, string $scriptFilename): self
5151
{
5252
$content = $event->getBody();
53+
$context = $event->getContext();
5354
$documentRoot = getcwd() ?: '';
5455
$headers = $event->getHeaders();
5556
$method = strtoupper($event->getMethod());
5657
$path = $event->getPath();
5758
$pathInfo = '';
5859
$port = $headers['x-forwarded-port'][0] ?? 80;
5960
$queryString = $event->getQueryString();
61+
$requestId = $context->getRequestId();
6062
$scriptName = str_replace($documentRoot, '', $scriptFilename);
6163
$self = $scriptName.$path;
64+
$traceId = $context->getTraceId();
6265

6366
// Parse path information using same regex for nginx with "fastcgi_split_path_info"
6467
if (1 === preg_match('%^(.+\.php)(/.+)$%i', $path, $matches)) {
6568
$pathInfo = $matches[2];
6669
$self = $matches[0];
6770
}
6871

72+
$headers['x-request-id'] = $headers['x-request-id'] ?? [$requestId];
73+
$headers['x-trace-id'] = $headers['x-trace-id'] ?? [$traceId];
74+
$headers['x-amzn-request-id'] = $headers['x-amzn-request-id'] ?? [$requestId];
75+
$headers['x-amzn-trace-id'] = $headers['x-amzn-trace-id'] ?? [$traceId];
76+
6977
$parameters = [
78+
'AWS_REQUEST_ID' => $requestId,
7079
'DOCUMENT_ROOT' => $documentRoot,
7180
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
7281
'PATH_INFO' => $pathInfo,
@@ -84,6 +93,7 @@ public static function createFromInvocationEvent(HttpRequestEvent $event, string
8493
'SERVER_PORT' => $port,
8594
'SERVER_PROTOCOL' => $event->getProtocol(),
8695
'SERVER_SOFTWARE' => 'ymir',
96+
'_X_AMZN_TRACE_ID' => $traceId,
8797
];
8898

8999
$parameters['REQUEST_URI'] = empty($queryString) ? $path : $path.'?'.$queryString;

src/Lambda/Response/Http/HttpResponse.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,16 @@ public function isCompressible(): bool
129129
return $this->compressible;
130130
}
131131

132+
/**
133+
* Return an instance with the given value replacing the given header.
134+
*/
135+
public function withHeader(string $name, $value): self
136+
{
137+
$this->headers[$name] = (array) $value;
138+
139+
return $this;
140+
}
141+
132142
/**
133143
* Get the HTTP response headers properly formatted for a Lambda response.
134144
*/

src/RuntimeApiClient.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Ymir\Runtime\Lambda\InvocationEvent\InvocationEventFactory;
1919
use Ymir\Runtime\Lambda\InvocationEvent\InvocationEventInterface;
2020
use Ymir\Runtime\Lambda\Response\Http\ForbiddenHttpResponse;
21+
use Ymir\Runtime\Lambda\Response\Http\HttpResponse;
2122
use Ymir\Runtime\Lambda\Response\ResponseInterface;
2223

2324
/**
@@ -104,12 +105,23 @@ public function sendInitializationError(\Throwable $error): void
104105
*/
105106
public function sendResponse(InvocationEventInterface $event, ResponseInterface $response): void
106107
{
108+
$requestId = $event->getContext()->getRequestId();
109+
110+
if ($response instanceof HttpResponse) {
111+
$response
112+
->withHeader('X-Request-ID', $requestId)
113+
->withHeader('X-Amzn-RequestId', $requestId);
114+
}
115+
107116
$data = $response->getResponseData();
108117

109118
// Lambda has a 6MB response payload limit. Send an error if we hit this limit instead of getting an
110119
// error from the API gateway.
111120
if (!empty($data['body']) && mb_strlen((string) $data['body']) >= 6000000) {
112-
$data = (new ForbiddenHttpResponse('Response Too Large'))->getResponseData();
121+
$data = (new ForbiddenHttpResponse('Response Too Large'))
122+
->withHeader('X-Request-ID', $requestId)
123+
->withHeader('X-Amzn-RequestId', $requestId)
124+
->getResponseData();
113125
}
114126

115127
$this->sendData($data, sprintf('invocation/%s/response', $event->getContext()->getRequestId()));

0 commit comments

Comments
 (0)