Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/sentry/publish/sentry.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
'annotation.result' => false,
'db.result' => false,
'elasticsearch.result' => false,
'response.body' => false,
'http.response.body.contents' => false,
'redis.result' => false,
'rpc.result' => false,
],
Expand Down
32 changes: 19 additions & 13 deletions src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
'baggage' => $span->toBaggage(),
'traceparent' => $span->toW3CTraceparent(),
]);
// Override the headers
$proceedingJoinPoint->arguments['keys']['options']['headers'] = $options['headers'];

if (! $span) {
Expand Down Expand Up @@ -115,22 +116,25 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
];

if ($response = $stats->getResponse()) {
$data['response.status'] = $response->getStatusCode();
$data['response.reason'] = $response->getReasonPhrase();
$data['response.headers'] = $response->getHeaders();
$data['response.body.size'] = $response->getBody()->getSize() ?? 0;
$data = array_merge($data, [
'http.response.status_code' => $response->getStatusCode(),
'http.response.reason' => $response->getReasonPhrase(),
'http.response.headers' => $response->getHeaders(),
'http.response.body.size' => $response->getBody()->getSize() ?? 0,
]);

if ($this->switcher->isTracingExtraTagEnable('response.body')) {
$data['response.body'] = $response->getBody()->getContents();
if ($this->switcher->isTracingExtraTagEnable('http.response.body.contents')) {
$data['http.response.body.contents'] = $response->getBody()->getContents();
$response->getBody()->isSeekable() && $response->getBody()->rewind();
}
Comment on lines +126 to 129
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

读取响应体应限流并按类型白名单,避免内存放大与隐私泄露

当前直接 getContents() 会读完整正文(可能为大文件/二进制)。建议:

  • 仅对白名单类型(text/*、application/json 等)采集;
  • 设定最大读取字节(如 8KB),其余以占位符替代;
  • 仍保留 rewind 逻辑。

可在本段直接替换为(使用完全限定名避免新增 use):

-                if ($this->switcher->isTracingExtraTagEnable('http.response.body.contents')) {
-                    $data['http.response.body.contents'] = $response->getBody()->getContents();
-                    $response->getBody()->isSeekable() && $response->getBody()->rewind();
-                }
+                if ($this->switcher->isTracingExtraTagEnable('http.response.body.contents')) {
+                    $body = $response->getBody();
+                    $contentType = $response->getHeaderLine('Content-Type');
+                    $isTextual = \preg_match('/^(text\/|application\/(json|xml|x-www-form-urlencoded))/i', $contentType) === 1;
+                    $data['http.response.body.contents'] = $isTextual
+                        ? \GuzzleHttp\Psr7\Utils::copyToString($body, 8192)  // 8KB 上限
+                        : '[binary omitted]';
+                    $body->isSeekable() && $body->rewind();
+                }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ($this->switcher->isTracingExtraTagEnable('http.response.body.contents')) {
$data['http.response.body.contents'] = $response->getBody()->getContents();
$response->getBody()->isSeekable() && $response->getBody()->rewind();
}
if ($this->switcher->isTracingExtraTagEnable('http.response.body.contents')) {
$body = $response->getBody();
$contentType = $response->getHeaderLine('Content-Type');
$isTextual = \preg_match('/^(text\/|application\/(json|xml|x-www-form-urlencoded))/i', $contentType) === 1;
$data['http.response.body.contents'] = $isTextual
? \GuzzleHttp\Psr7\Utils::copyToString($body, 8192) // 8KB 上限
: '[binary omitted]';
$body->isSeekable() && $body->rewind();
}
🤖 Prompt for AI Agents
In src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php around lines
126-129, replace the unconditional getContents() with logic that first inspects
the response Content-Type header and only proceeds for a whitelist of safe
text-like types (e.g., text/*, application/json, application/xml,
application/*+json, application/*+xml); for whitelist matches read at most 8192
bytes from the body (use stream read/getContents with a byte limit or
stream->read(8192)), and if the body is larger append a placeholder like
"[TRUNCATED]" (optionally including original size); for non-whitelisted or
binary types do not collect body contents; always preserve the existing rewind
call when the stream is seekable; implement this replacement inline and avoid
adding new use statements (use fully qualified names if needed).


$span->setStatus(SpanStatus::createFromHttpStatusCode($response->getStatusCode()));

if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) {
$span->setStatus(SpanStatus::internalError())
->setTags([
'error' => true,
'response.reason' => $response->getReasonPhrase(),
]);
$span->setTags([
'error' => true,
'http.response.reason' => $response->getReasonPhrase(),
]);
}
}

Expand All @@ -143,8 +147,10 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
'exception.code' => $exception->getCode(),
]);
if ($this->switcher->isTracingExtraTagEnable('exception.stack_trace')) {
$data['exception.message'] = $exception->getMessage();
$data['exception.stack_trace'] = (string) $exception;
$data = array_merge($data, [
'exception.message' => $exception->getMessage(),
'exception.stack_trace' => (string) $exception,
]);
}
}

Expand Down