aws / aws-xray-sdk-java

The official AWS X-Ray Recorder SDK for Java.
Apache License 2.0
95 stars 99 forks source link

Can I force subsegments to be the direct child of a segment? #332

Open digithead1011 opened 2 years ago

digithead1011 commented 2 years ago

I am writing an AWS Lambda function in Java that uses Project Reactor and reactive programming paradigms. The methods that I want to trace return Mono or Flux, which is really just a promise to return something in the future. This means that the work isn't "done" when the method exits. Instead, the subsegment should be started when the method is called and ended when the Mono or Flux complete.

More importantly, though, work is being done parallel and any new subsegment should be a direct child of the segment created by the Lambda runtime, and not a child of the "current" subsegment. Is there a way to specify this when creating a subsegment? I don't see that in AWSXRay. All of the methods to begin or create a subsegment ultimately use AWSXRayRecorder.beginSubsegment(String), which delegates the task to the context. In the case of LambdaSegmentContext anyway, the newly created subsegment only seems to be added directly to the segment when it is the first subsegment. After that, newly created subsegments are added as a child of the "current" subsegment.

With the way that subsegments are created by default, a graph of my trace would look like this, where S is the segment and 1, 2, 3, and 4 are the subsegments:

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
   11111111111111111111111111111111111
        222222222222222222222222222
               33333333333333333
                     44444444

By comparison, if I were (am?) able to specify the segment as the parent, the work being done would be graphed more like this instead, which is how it's actually happening:

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
   1111111
        2222222222
               33333333333333333
                               44444444
digithead1011 commented 2 years ago

It's probably worth mentioning that ThreadLocalSegmentContext appears to always create new subsegments as an immediate child of the segment rather than as a child of the currently traced entity, which could be another subsegment. I'm too new here to understand the nuances of why LambdaSegmentContext has different behavior.

I'm guessing that I can't control which type of context is used.

wangzlei commented 2 years ago

Hi,

In theory, user can parent a subsegment to any other segment(or subsegment) by manually create data in low-level API.

We don't officially suggest that because xray segment data model is rigid, that touches some low level logic such as a subsegment has to have a parent segment(not subsegment).

Kurru commented 2 years ago

In my experience Lambda has some slightly different rules for when it creates the segment which was a little confusing for us. IIRC, you cant interact with the lambda segment much, but you can manipulate lambda subsegments fine (but I could be mistaken).

Outside of lambda, we did have good luck with manipulating the X-Ray context using AWSXRay.setTraceEntity(originalSegment); to move the current context around, which allowed us to support async actions and AWSXRay.endSubsegment(otherSegment) to end these floating subsegments.

Using setTraceEntity has been the way we've added support for various async xray segments, but do be wary of #318

Subsegment original = AWSXray.getTraceEntity();
Subsegment asyncSegment = AWSXray.beginSubsegment("concurrent");
ListenableFuture<?> future = beginFuture();
future.addListener(() -> AWSXray.endSubsegment(asyncSegment));
AWSXRay.setTraceEntity(original); // Restore the segment back to the original
twbecker commented 9 months ago

I just hit this issue as well. I'm kicking off a number of asynchronous tasks and want each one to be represented by a subsegment that is a direct child of the current segment at the point where the tasks are submitted. I was able to work around this similarly to how @Kurru described:

    private Subsegment getAsyncSubsegment(String name) {
        Entity previous = AWSXRay.getTraceEntity();
        try {
            return AWSXRay.beginSubsegment(name);
        } finally {
            AWSXRay.setTraceEntity(previous);
        }
    }

This works, but it's clumsy and AWSXRay.setTraceEntity() is deprecated. It would be nice to provide a way to hang subsegments off a segment without updating the context.

Kurru commented 9 months ago

I assumed setTraceEntity() isn't really deprecated, but rather annotated as such to highlight the typically more convenient method: AWSXRay.createSubsegment(). Without it, dunno how these custom flows would be configured