2.4.0 X-Ray Subsegments Solved

0. Learning Materials

Task List


1. Workflow

On AWS X-Ray console, while the traces are coming through, but the specific service we are targeting (UserActivities) is not.

I clicked on home, notifications and usernames (UserActivities) and it is only user_activities that is not coming through.

One of our fellow bootcamper Olga T. found the solution and shared the knowledge with us in her blog post. Andrew implements the suggested solution. The gist is that we did not close the X-Ray segments and subsegments. That is why X-Ray was unable to pick up the traces to send.

1. Instrument @xray_recorder.capture() decorator in app.py

  • @xray_recorder.capture: this decorator marks a particular function as a segment in the trace generated by AWS X-Ray.

    • So our data_handle() function from the user_activities.py service will be marked as a segment.

    • The following is an excerpt from the AWS documentation:

      • To create a subsegment for a synchronous function, use the @xray_recorder.capture decorator. You can pass a name for the subsegment to the capture function or leave it out to use the function name.

app.py
  @app.route("/api/activities/@<string:handle>", methods=['GET'])
+ @xray_recorder.capture("user_activities")
  def data_handle(handle):
    model = UserActivities.run(handle)
    if model['errors'] is not None:
      return model['errors'], 422
    else:
      return model['data'], 200

2. Close segment and subsegment in the target service for tracing.

As it was pointed out by Olga and Andrew, it is important to close the subsegments to ensure that X-Ray works correctly.

  • AWS: "To manage subsegments, use the begin_subsegment and end_subsegment methods."

user_activities.py
class UserActivities:
  def run(user_handle):
    try:
      model = {
        'errors': None,
        'data': None
      }

      now = datetime.now(timezone.utc).astimezone()

      if user_handle == None or len(user_handle) < 1:
        model['errors'] = ['blank_user_handle']
      else:
        now = datetime.now()
        results = [{
          'uuid': '248959df-3079-4947-b847-9e0892d1bab4',
          'handle':  'Andrew Brown',
          'message': 'Cloud is fun!',
          'created_at': (now - timedelta(days=1)).isoformat(),
          'expires_at': (now + timedelta(days=31)).isoformat()
        }]
        model['data'] = results

+     subsegment = xray_recorder.begin_subsegment('user_activities-subsegment-mock-data')
      
      # X-Ray -----
      dict = {
        "now": now.isoformat(),
        "data": model['data'],
        "results-size": len(model['data'])
      }
      subsegment.put_metadata('key', dict, 'namespace')    
+     xray_recorder.end_subsegment()
    finally:
+     xray_recorder.end_subsegment()
    return model

After implementing the closure of the subsegments, the X-ray agent in the X-ray container correctly send the traces over to AWS.

The spans from the target service endpoint are coming through.

In the image below, note that:

  • The segment created by the decorator @xray_recorder.capture("user-activities") was recorded correctly.

  • The subsegment that was labeled in line 24 of the above code user_activities.py also came through safely.

Last updated