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

Enhance AWS APM metrics mapping implementation #906

Merged
merged 2 commits into from
Jun 16, 2023

Conversation

mxiamxia
Copy link
Member

@mxiamxia mxiamxia commented Jun 6, 2023

Description:
Enhance AWS APM metrics mapping implementation to resolve a few of the following "Unknown" metric attributes use cases.

  • if span name used in ingress operation is not valid with values of 'null', 'UnknownOperation' and 'HttpMethod valuefor HTTP request use cases. We will try to extract the ingress operation fromhttp.methodandhttp.target` attributes.
  • if the remote service attribute can not be directly derived from the attributes such rpc.name, db.system. We will try to fill it with the net.peer.name and net.sock.peer.addr attribute values and have Collector to do the further resolution on the populated values.
  • if the remote operation attribute is Unknown, We will try to extract the remote operation from http.method and http.url attributes.
  • Add a new aws.remote.target attribute for supporting the following 4 AWS resources when invoking it with Client Spans
    • AWS S3 Bucket Name
    • AWS Queue Name
    • AWS Stream Name
    • AWS DynamoDB table name

Testing:
unit test and adhoc

Documentation:
N/A

Outstanding items:
N/A

@github-actions github-actions bot requested review from srprash and wangzlei June 6, 2023 00:09
@mxiamxia mxiamxia force-pushed the apm_metric branch 2 times, most recently from 7b35c2c to b0837a3 Compare June 6, 2023 22:23

static final AttributeKey<String> AWS_REMOTE_TARGET = AttributeKey.stringKey("aws.remote.target");

static final AttributeKey<String> AWS_BUCKET_NAME = AttributeKey.stringKey("aws.bucket.name");
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add comments to link to the source of these SDK managed fields or split them into a separate file?

sdk 1-1
sdk 2-2

logUnknownAttribute(AWS_REMOTE_OPERATION, span);
builder.put(AWS_REMOTE_OPERATION, UNKNOWN_REMOTE_OPERATION);
// try to derive RemoteService and RemoteOperation from the other un-directive attributes
remoteService = generateRemoteService(span);
Copy link
Contributor

Choose a reason for hiding this comment

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

It's hard to tell the difference between generateRemoteService/Operation and getRemoteService/Operation, only that generate* does some specific to HTTP/NET spans which makes me feel the method name is ambiguous.

I'm thinking if it will be better to assign UNKNOWN* as the initial values to remoteService and remoteOperation, and only do HTTP/NET handling using function like getRemote*FromNETSpan in the else block.

Copy link
Member Author

Choose a reason for hiding this comment

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

Make some updates to split the RemoteService and RemoteOperation generating logic separately on unknown checking.
The method name is general as I thought we could do more to handle unknown besides the http/net span attributes in the future(even I don't have any idea right now what the other attribute we could use)

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! It's much clear now.

@mxiamxia mxiamxia requested a review from bjrara June 7, 2023 18:41
Copy link
Contributor

@bjrara bjrara left a comment

Choose a reason for hiding this comment

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

LGTM

@mxiamxia mxiamxia marked this pull request as ready for review June 8, 2023 16:08
@mxiamxia mxiamxia requested review from a team and bjrara June 8, 2023 16:08
@mxiamxia
Copy link
Member Author

mxiamxia commented Jun 8, 2023

Hi @trask , could you please take a look this PR as code approver when you get the chance? Thanks!

@trask trask added this to the v1.27.0 milestone Jun 9, 2023
@wangzlei
Copy link

LGTM!


static final AttributeKey<String> AWS_REMOTE_TARGET = AttributeKey.stringKey("aws.remote.target");

// use the same AWS Resource attribute name defined by OTel java auto-instr for aws_sdk_v_1_1
Copy link
Contributor

Choose a reason for hiding this comment

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

If we want to use the same name, why not just depend on OTel java auto-instr directly? Why define them separately here? This adds risk to the implementation because if the names change in OTel java auto-instr, we will not know to change them here. This seems possible given that these strings do not seem to align with the OTEL Spec (e.g. aws.s3.bucket)

Copy link

@carolabadeer carolabadeer Jun 12, 2023

Choose a reason for hiding this comment

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

+1. I was going to recommend adding a TODO note here to update these attributes to match the semantic attributes, but I prefer @thpierce's suggestion

Copy link
Member Author

Choose a reason for hiding this comment

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

The listed AWS resource attributes are defined in opentelemetry-java-instrumentation#AwsExperimentalAttributes which is not visible to SDK. I think the long term solution is to move these resource name definitions into semconv#SemanticAttributes.

I think we have to define it again here before we can add it into semconv package.

Copy link
Member Author

Choose a reason for hiding this comment

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

Create an issue for better way to manage AWS specific attributes open-telemetry/opentelemetry-java-instrumentation#8710

setRemoteService(span, builder, MESSAGING_SYSTEM);
setRemoteOperation(span, builder, MESSAGING_OPERATION);
remoteService = getRemoteService(span, MESSAGING_SYSTEM);
remoteOperation = getRemoteOperation(span, MESSAGING_OPERATION);
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought this would be: {messaging.destination.name} {messaging.operation}

Copy link
Member Author

@mxiamxia mxiamxia Jun 13, 2023

Choose a reason for hiding this comment

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

thanks for calling it out. I am thinking moving {messaging.destination.name} to aws.remote.target attribute later and keep remote.operation with messaging.operation.

Synced up with @thpierce offline, we'll keep it with the current impl

}

// try to derive RemoteService and RemoteOperation from the other un-directive attributes
Copy link
Contributor

Choose a reason for hiding this comment

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

What is un-directive?

Copy link
Member Author

Choose a reason for hiding this comment

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

removed it.

Comment on lines 134 to 135
* name.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Please update comment, behaviour has substantially changed. Please review other comments in this code and update accordingly.

if (httpTarget != null) {
operation = extractAPIPathValue(httpTarget);
}
if (isKeyPresent(span, HTTP_METHOD)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

if HTTP_METHOD is not found, are we sure we want to keep just the first part of the target?

Also this code is confusing because in isValidOperation, we are saying that HTTP_METHOD alone is invalid, but here we consider it valid if target is null. A cleaner solution would be to update the if block on line 158 to attempt to append target if only HTTP_METHOD is being used as span name.

Copy link
Member Author

Choose a reason for hiding this comment

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

changed it to: only add http.method as prefix for RemoteOperation when http.target is not null.

Comment on lines +300 to +302
if (remoteOperation.equals(UNKNOWN_REMOTE_OPERATION)) {
logUnknownAttribute(AWS_REMOTE_OPERATION, span);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Not blocking: This doesn't seem appropriate for this method - I would probably keep it in setRemoteServiceAndOperation. Ditto to generateRemoteService

* @return the first part from the http target. Eg, /payment
*/
private static String extractAPIPathValue(String httpTarget) {
if (httpTarget.isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we do null as well?

@@ -5,19 +5,32 @@

package io.opentelemetry.contrib.awsxray;
Copy link
Contributor

Choose a reason for hiding this comment

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

Did not have time to review tests, will rely on reviews from others to cover these.

@@ -152,35 +212,132 @@ private static void setEgressOperation(SpanData span, AttributesBuilder builder)
* and RPC attributes to use here, but this is a sufficient starting point.
*/
private static void setRemoteServiceAndOperation(SpanData span, AttributesBuilder builder) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought we said that remote service/remote operation would be done independently (e.g. could have rpc service and db operation)

Copy link
Member Author

Choose a reason for hiding this comment

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

it could happen in the following blocks which is not restricted by pair of values.

// try to derive RemoteService and RemoteOperation from the other related attributes
    if (remoteService.equals(UNKNOWN_REMOTE_SERVICE)) {
      remoteService = generateRemoteService(span);
    }
    if (remoteOperation.equals(UNKNOWN_REMOTE_OPERATION)) {
      remoteOperation = generateRemoteOperation(span);
    }

Copy link
Contributor

Choose a reason for hiding this comment

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

Discussed offline - not exactly what I was talking about, but we decided this is desirable behaviour.

@mxiamxia
Copy link
Member Author

Hi @trask, kindly follow up if you can help to review this PR and it has been reviewed by AWS reviewers. Thanks!

@trask trask merged commit 047bd89 into open-telemetry:main Jun 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants