|
| 1 | +// Copyright 2020 New Relic, Inc. All rights reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +using System.Collections.Concurrent; |
| 5 | +using System.Collections.Generic; |
| 6 | +using System.Threading.Tasks; |
| 7 | +using NewRelic.Agent.Api; |
| 8 | +using NewRelic.Agent.Api.Experimental; |
| 9 | +using NewRelic.Agent.Extensions.AwsSdk; |
| 10 | +using NewRelic.Agent.Extensions.Parsing; |
| 11 | +using NewRelic.Agent.Extensions.Providers.Wrapper; |
| 12 | + |
| 13 | +namespace NewRelic.Providers.Wrapper.AwsSdk.RequestHandlers |
| 14 | +{ |
| 15 | + internal static class KinesisRequestHandler |
| 16 | + { |
| 17 | + public const string VendorName = "Kinesis"; |
| 18 | + public static readonly List<string> MessageBrokerRequestTypes = new List<string> { "GetRecordsRequest", "PutRecordsRequest", "PutRecordRequest" }; |
| 19 | + private static ConcurrentDictionary<string, string> _operationNameCache = new(); |
| 20 | + |
| 21 | + |
| 22 | + public static AfterWrappedMethodDelegate HandleKinesisRequest(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction, object request, bool isAsync, ArnBuilder builder) |
| 23 | + { |
| 24 | + var requestType = request.GetType().Name as string; |
| 25 | + |
| 26 | + // Only some Kinesis requests are treated as message queue operations (put records, get records). The rest should be treated as ordinary spans. |
| 27 | + |
| 28 | + // Not all request types have a stream name or a stream ARN |
| 29 | + |
| 30 | + var streamName = KinesisHelper.GetStreamNameFromRequest(request); |
| 31 | + string arn = KinesisHelper.GetStreamArnFromRequest(request); |
| 32 | + if (arn == null && streamName != null) |
| 33 | + { |
| 34 | + arn = builder.Build("kinesis", $"stream/{streamName}"); |
| 35 | + } |
| 36 | + |
| 37 | + var operation = _operationNameCache.GetOrAdd(requestType, requestType.Replace("Request", string.Empty).ToSnakeCase()); |
| 38 | + |
| 39 | + ISegment segment; |
| 40 | + |
| 41 | + if (MessageBrokerRequestTypes.Contains(requestType)) |
| 42 | + { |
| 43 | + var action = requestType.StartsWith("Put") ? MessageBrokerAction.Produce : MessageBrokerAction.Consume; |
| 44 | + |
| 45 | + segment = transaction.StartMessageBrokerSegment(instrumentedMethodCall.MethodCall, MessageBrokerDestinationType.Queue, action, VendorName, destinationName: streamName ?? "Unknown", messagingSystemName: "aws_kinesis_data_streams", cloudAccountId: builder.AccountId, cloudRegion: builder.Region); |
| 46 | + segment.GetExperimentalApi().MakeLeaf(); |
| 47 | + } |
| 48 | + else |
| 49 | + { |
| 50 | + var operationName = requestType.Replace("Request", ""); |
| 51 | + |
| 52 | + if (streamName != null) |
| 53 | + { |
| 54 | + operationName += "/" + streamName; |
| 55 | + } |
| 56 | + |
| 57 | + segment = transaction.StartMethodSegment(instrumentedMethodCall.MethodCall, "Kinesis", operationName, isLeaf: false); |
| 58 | + |
| 59 | + } |
| 60 | + |
| 61 | + if (arn != null) |
| 62 | + { |
| 63 | + segment.AddCloudSdkAttribute("cloud.resource_id", arn); |
| 64 | + } |
| 65 | + segment.AddCloudSdkAttribute("aws.operation", operation); |
| 66 | + segment.AddCloudSdkAttribute("aws.region", builder.Region); |
| 67 | + segment.AddCloudSdkAttribute("cloud.platform", "aws_kinesis_data_streams"); |
| 68 | + |
| 69 | + return isAsync ? |
| 70 | + Delegates.GetAsyncDelegateFor<Task>(agent, segment, true, ProcessResponse, TaskContinuationOptions.ExecuteSynchronously) |
| 71 | + : |
| 72 | + Delegates.GetDelegateFor( |
| 73 | + onComplete: segment.End, |
| 74 | + onSuccess: () => |
| 75 | + { |
| 76 | + return; |
| 77 | + } |
| 78 | + ); |
| 79 | + |
| 80 | + void ProcessResponse(Task responseTask) |
| 81 | + { |
| 82 | + return; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + } |
| 87 | +} |
0 commit comments