Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding hook for adding span links to a lambda instrumentation span #1922

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

peterabbott
Copy link

@peterabbott peterabbott commented Feb 2, 2024

Which problem is this PR solving?

  • With the aws lambda instrumentation, when wrapping a lambda handler adds the ability to add span links. This is useful for batch processing where a message can come from different parent spans.

Short description of the changes

  • Allow links to be added to wrapped lambda spans

@peterabbott peterabbott requested a review from a team February 2, 2024 08:56
Copy link

linux-foundation-easycla bot commented Feb 2, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

@peterabbott peterabbott changed the title adding hook for adding span links to a lambda instrumentation span feat: adding hook for adding span links to a lambda instrumentation span Feb 2, 2024
@@ -208,6 +208,9 @@ export class AwsLambdaInstrumentation extends InstrumentationBase {
context.invokedFunctionArn
),
},
links: config.eventSpanLinksExtractor
Copy link
Author

Choose a reason for hiding this comment

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

somewhat related to the question I have asked over in the main repo about links.

There might be another way, but this allows adding links when dealing with batch processing

@peterabbott
Copy link
Author

@dyladan ping as I can see you did the last release of this module. Is there way to get eyes on a PR? Any reckons / comments here regarding adding links to an instrumented lambda root span?

Copy link

codecov bot commented Feb 22, 2024

Codecov Report

Attention: Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.

Project coverage is 91.01%. Comparing base (cf034c8) to head (c7c211b).
Report is 349 commits behind head on main.

Files with missing lines Patch % Lines
...-instrumentation-aws-lambda/src/instrumentation.ts 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1922      +/-   ##
==========================================
- Coverage   91.02%   91.01%   -0.02%     
==========================================
  Files         146      146              
  Lines        7478     7480       +2     
  Branches     1497     1499       +2     
==========================================
+ Hits         6807     6808       +1     
- Misses        671      672       +1     
Files with missing lines Coverage Δ
...-instrumentation-aws-lambda/src/instrumentation.ts 93.18% <50.00%> (-0.50%) ⬇️

@JamieDanielson
Copy link
Member

Sorry for the delay @peterabbott ! We are catching up on PRs. Generally this seems like a reasonable change, though we’re wondering if this is something generic that doesn't have to be configured multiple times by people with a callback, and instead can be implemented into the instrumentation for everyone to benefit? It may help if you provide the specific usage of this as an example of how it will be used. Also are there tests that can be added to verify this behavior?

As a note, we are also reaching out to get some input from AWS folks and unsure about their response to this as codeowners.

@peterabbott
Copy link
Author

peterabbott commented Jun 22, 2024

@JamieDanielson thanks for the update.

The scenario we have is where a lambda uses an SQS event source mapping where the batch size > 1. The messages on the queue may have come from different parent traces. The current instrumentation looks at the Message for a parent trace id. The parent ID is saved on each message in the batch so when there is more than one unique parent trace id we lose the ability to link to a parent ID with respect to the current trace happening for the lambda invocation.

Using links was going to be our way to associate a message to a parent transaciton in these cases. Using the instrumentation approach is nice as it allows us to separate the code from tracing. Been a few issues with bugs in some of the contributed instrumentatino classes, with the isolated approach of Opentelemetry means it is easy to switch on/off.

On thought is to move the trace code to the handling of a individual message, which in the long run may be better, but we do miss a little bit of execution from when the message is handled and the splitting it out. There are some scenarios where we pre-processing message batches before the main execution so in those scenarios links become more useful.

Hope that makes sense?

I'll try to write some tests for what I am trying to describe

@blumamir
Copy link
Member

@peterabbott can you please share the implementation of the hook that you plan to use in your lambda? is it something specific to your setup or is it a generic logic that is always expected to work?
Since this behavior is part of semantic conventions, I wonder if we should always populate the links in the instrumentation for all users for SQS like aws-sdk instrumentation does, instead of asking to implement hooks as opt-in option.

@peterabbott
Copy link
Author

Using the AwsLambdaInstrumentation and the extractor hook we attempt to extract the propogated trace id from the SQS Records in the batch. This is fixed to SQS and wont apply to many calls. The snippets of relevant code

const sqsEventHandler = (records: SQSRecord[], awsEventContext: AwsContext) => {
  const parsedTraces = records
    .map((r: SQSRecord): Context | undefined => {
      return propagation.extract(ROOT_CONTEXT, r.messageAttributes, getter)
    })
    .reduce<Record<string, Context>>(
      (acc, ctx: Context | undefined) => {
        if (!ctx) {
          return acc
        }

        const spanCtx = trace.getSpanContext(ctx)
        if (!spanCtx) {
          return acc
        }

        // grouping by parent span trace id
        return {...acc, [spanCtx.traceId]: ctx}
      },
      {}
    )

  const parentTraces = Object.values(parsedTraces)

  // if only one event then we can do proper distributed tracing, otherwise a way to do links
  if (parentTraces?.length === 1) {
    diag.debug('single parent trace matched', {
      parentTraces
    })

    return parentTraces[0]
  }


  diag.debug('no or multiple parent traces', {parentTraces})
  // TODO: if > 1 add parent span links or using span link extractor suggestion from PR to add the link regardless 

  return ROOT_CONTEXT
}
///// --------
new AwsLambdaInstrumentation({
   eventContextExtractor: (event, awsEventContext): Context => {
        // Opinianted to SQS event handler
        if (Array.isArray(event?.Records)) {
          return sqsEventHandler(event.Records, awsEventContext)
        }
        // just return the context
        return ROOT_CONTEXT
      }
   }
 })

Copy link
Contributor

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added stale and removed stale labels Aug 22, 2024
@peterabbott
Copy link
Author

@blumamir wondering if there is any movement on this?

Copy link
Contributor

github-actions bot commented Dec 8, 2024

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added stale and removed stale labels Dec 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants