Closed icelava closed 3 years ago
Ok looks like the 'trick' behind it is the PHP layer must add its own sub-segment for the back-end HTTP request.
<?php include 'vendor\autoload.php';?>
<?php
$xrayHeader = "X-Amzn-Trace-Id";
\Pkerrigan\Xray\Trace::getInstance()
->setTraceHeader($_SERVER[$xrayHeader] ?? null)
->setName('XRayFrontPHP')
->setUrl($_SERVER['REQUEST_URI'])
->setMethod($_SERVER['REQUEST_METHOD'])
->begin(100);
// Artificial delay between main segment and sub-segment.
usleep(10000);
// Add separate sub-segment for back-end API tier.
\Pkerrigan\Xray\Trace::getInstance()
->getCurrentSegment()
->addSubsegment(
(new \Pkerrigan\Xray\RemoteSegment())->begin(100)
);
// Use cURL to pass on X-Ray trace ID.
$apiUrl = "http://localhost:8081/api/tier";
$curlyBraces = array("{", "}");
$traceId = \Pkerrigan\Xray\Trace::getInstance()->getTraceId();
$reqHeaders[] = $xrayHeader . ": Root=" . $traceId .";Sampled=1";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER , $reqHeaders);
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
$delayTime = curl_exec($ch);
curl_close($ch);
\Pkerrigan\Xray\Trace::getInstance()
->getCurrentSegment()
->setName('XRayBackApi')
->end();
\Pkerrigan\Xray\Trace::getInstance()
->end()
->setResponseCode(http_response_code())
->setError(http_response_code() >= 400 && http_response_code() < 500)
->setFault(http_response_code() >= 500)
->submit(new \Pkerrigan\Xray\Submission\DaemonSegmentSubmitter());
?>
X-Ray then appears to be able to "jot the dots" between the two service nodes.
It looks like you're pretty much there with this already, but there's a couple of extra things you can do to help make sure X-Ray always links the traces of your two services properly:
The first is to use a HttpSegment
instead of a RemoteSegment
when wrapping the call to your backend service. This allows you to record the URL, request method, and fault/error status of the backend call from the frontend service's perspecitve, which makes the way the trace is shown in the X-Ray console a little richer. More importantly it also allows you to mark the segment as being a call to a traced service by calling the setTraced
method on it. This signals to X-Ray that it should wait for the backend service to submit a trace before it processes the current one, which should mean you can drop the artificial delay you're adding.
The seond thing you can probably add is the ID of the wrapping segment in the header that you pass to the backend service. This lets X-Ray know exactly where to link the two traces together and should help make sure the API call shows up in the correct place in the trace view of the console.
Using your latest code snippet, the above would look something like this:
<?php include 'vendor\autoload.php';?>
<?php
$xrayHeader = "X-Amzn-Trace-Id";
\Pkerrigan\Xray\Trace::getInstance()
->setTraceHeader($_SERVER[$xrayHeader] ?? null)
->setName('XRayFrontPHP')
->setUrl($_SERVER['REQUEST_URI'])
->setMethod($_SERVER['REQUEST_METHOD'])
->begin(100);
$apiUrl = "http://localhost:8081/api/tier";
// Add separate sub-segment for back-end API tier.
$subSegment = (new \Pkerrigan\Xray\HttpSegment())
->setTraced(true)
->setName('XRayBackApi')
->setUrl($apiUrl)
->setMethod('GET');
\Pkerrigan\Xray\Trace::getInstance()
->getCurrentSegment()
->addSubsegment(
$subSegment->begin(100)
);
// Use cURL to pass on X-Ray trace ID.
$curlyBraces = array("{", "}");
$traceId = \Pkerrigan\Xray\Trace::getInstance()->getTraceId();
$reqHeaders[] = $xrayHeader . ": Root=" . $traceId .";Sampled=1;Parent=" . \Pkerrigan\Xray\Trace::getInstance()->getCurrentSegment()->getId();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER , $reqHeaders);
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
$delayTime = curl_exec($ch);
curl_close($ch);
// End HTTP subsegment for API call
\Pkerrigan\Xray\Trace::getInstance()
->getCurrentSegment()
->end()
->setResponseCode(...) // Use the response code from your cURL request to fill in these 3 bits of data
->setError(...)
->setFault(...);
// End trace
\Pkerrigan\Xray\Trace::getInstance()
->end()
->setResponseCode(http_response_code())
->setError(http_response_code() >= 400 && http_response_code() < 500)
->setFault(http_response_code() >= 500)
->submit(new \Pkerrigan\Xray\Submission\DaemonSegmentSubmitter());
?>
Hopefully this helps!
Noted. Thank you!
I'm experimenting with getting a PHP front-end web tier to pass down the trace ID when making web requests to a similarly-instrumented back-end ASP.NET API tier in order to correlate the requests.
Raw cURL hack
The X-Ray console trace UI actually does show the relation, but I can't figure out why the service map does not visualise their relationship? Any ideas what extra actions must be done?