patrickkerrigan / php-xray

A PHP instrumentation library for AWS X-Ray
BSD 3-Clause "New" or "Revised" License
63 stars 26 forks source link

ECS logs being flooded with ErrorCode: "MissingTraceId" #16

Closed Marco-Ca closed 1 year ago

Marco-Ca commented 1 year ago

Hello, I am using your package for php and my ECS is getting flooded with ErrorCode: "MissingTraceId", I tried adding a condition like isset($_SERVER['HTTP_X_AMZN_TRACE_ID']) so that it only enables xray tracing if there is trace id but didnt work. Any idea, solution?

patrickkerrigan commented 1 year ago

Hi Marco,

That definitely sounds strange. Even when the X-Amzn-Trace-Id header isn't present (e.g when not using an ALB), the Trace object should generate its own ID to work with, so you shouldn't need to be checking for it yourself.

I don't suppose you'd have a minimal script that reproduces this issue that you could post would you?

If not, no worries, I think I should be able to spot any immediate problems if you could post the following with any sensitive information removed/replaced:

Thanks

Marco-Ca commented 1 year ago

Hello @patrickkerrigan , thank you for your response! I can post some snippets here

index.php

<?php

use Pkerrigan\Xray\Trace;
use Pkerrigan\Xray\Submission\DaemonSegmentSubmitter;

if (Functions::isXrayTracingEnabled()) {
    Trace::getInstance()
        ->setTraceHeader($_SERVER["HTTP_X_AMZN_TRACE_ID"] ?? null)
        ->setName("nucleus_backend")
        ->setUrl($_SERVER["REQUEST_URI"])
        ->setMethod($_SERVER["REQUEST_METHOD"])
        ->begin(10);
}

Service::handleRequest();

if (Functions::isXrayTracingEnabled()) {
    Trace::getInstance()
        ->end()
        ->setResponseCode(http_response_code())
        ->setError(http_response_code() >= 400 && http_response_code() < 500)
        ->setFault(http_response_code() >= 500)
        ->submit(new DaemonSegmentSubmitter("XRay"));
}

?>
Subsegment for sql queries

if (Functions::isXrayTracingEnabled()) {
    $sanitized_query = substr($sql, 0, strpos($sql, "WHERE"));
    Trace::getInstance()
        ->getCurrentSegment()
        ->addSubsegment(
            (new SqlSegment())->begin()
            ->setName("mysqlii_query")
            ->setDatabaseType("MySQL")
            ->setQuery($sanitized_query)
        );
}

$this->query_count++;

if (Functions::isXrayTracingEnabled()) {
    Trace::getInstance()
        ->getCurrentSegment()
        ->end()
        ->submit(new DaemonSegmentSubmitter("XRay"));
}
Helper function

public static function isXrayTracingEnabled(): bool {
    if (
        function_exists('socket_create') &&
        isset($_SERVER['HTTP_X_AMZN_TRACE_ID'])
    ) {
        return true;
    }
    return false;
}
patrickkerrigan commented 1 year ago

Thanks for the code snippets!

I think I can see what's going wrong now. It looks like you're submitting each of your subsegments individually in this part of your code:

$this->query_count++;

if (Functions::isXrayTracingEnabled()) {
    Trace::getInstance()
        ->getCurrentSegment()
        ->end()
        ->submit(new DaemonSegmentSubmitter("XRay"));
}

While this is possible to do in x-ray, it's not needed in the vast majority of cases and comes with a bunch of additional work, such as manually assigning trace IDs to each subsegment.

If you remove the submit call here, and only submit the Trace object at the end of your request, then I think your issue should go away. When the Trace is submitted, all subsegements that were created under it will be submitted for you and will be automatically linked to the correct trace ID

Marco-Ca commented 1 year ago

Great info! So you mean only have the submit call in the index file? Will try and thanks a lot!

patrickkerrigan commented 1 year ago

Yep, that's correct. Only the submit call in the index file should be needed :+1: