-
Notifications
You must be signed in to change notification settings - Fork 410
Expand file tree
/
Copy pathAWSEC2Detector.cs
More file actions
99 lines (82 loc) · 4 KB
/
Copy pathAWSEC2Detector.cs
File metadata and controls
99 lines (82 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#if NETFRAMEWORK
using System.Net.Http;
#endif
using OpenTelemetry.AWS;
using OpenTelemetry.Resources.AWS.Models;
namespace OpenTelemetry.Resources.AWS;
/// <summary>
/// Resource detector for application running on AWS EC2 instance.
/// </summary>
internal sealed class AWSEC2Detector : IResourceDetector
{
private const string AWSEC2MetadataTokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds";
private const string AWSEC2MetadataTokenHeader = "X-aws-ec2-metadata-token";
private const string AWSEC2MetadataTokenUrl = "http://169.254.169.254/latest/api/token";
private const string AWSEC2HostNameUrl = "http://169.254.169.254/latest/meta-data/hostname";
private const string AWSEC2IdentityDocumentUrl = "http://169.254.169.254/latest/dynamic/instance-identity/document";
private readonly AWSSemanticConventions semanticConventionBuilder;
public AWSEC2Detector(AWSSemanticConventions semanticConventionBuilder)
{
this.semanticConventionBuilder = semanticConventionBuilder;
}
/// <summary>
/// Detector the required and optional resource attributes from AWS EC2.
/// </summary>
/// <returns>Resource with key-value pairs of resource attributes.</returns>
public Resource Detect()
{
try
{
// Prevents EC2 related HTTP calls from being instrumented.
using var scope = SuppressInstrumentationScope.Begin();
var token = GetAWSEC2Token();
var identity = GetAWSEC2Identity(token);
var hostName = GetAWSEC2HostName(token);
return new Resource(
this.ExtractResourceAttributes(identity, hostName),
Internal.SchemaUrls.Get(this.semanticConventionBuilder.Version));
}
catch (Exception ex)
{
AWSResourcesEventSource.Log.ResourceAttributesExtractException(nameof(AWSEC2Detector), ex);
}
return Resource.Empty;
}
internal static AWSEC2IdentityDocumentModel? DeserializeResponse(string response) =>
#if NETFRAMEWORK
ResourceDetectorUtils.DeserializeFromString<AWSEC2IdentityDocumentModel>(response);
#else
ResourceDetectorUtils.DeserializeFromString(response, SourceGenerationContext.Default.AWSEC2IdentityDocumentModel);
#endif
internal List<KeyValuePair<string, object>> ExtractResourceAttributes(AWSEC2IdentityDocumentModel? identity, string hostName)
{
var resourceAttributes =
this.semanticConventionBuilder
.AttributeBuilder
.AddAttributeCloudProviderIsAWS()
.AddAttributeCloudPlatformIsAwsEc2()
.AddAttributeHostName(hostName)
.AddAttributeCloudAccountID(identity?.AccountId)
.AddAttributeCloudAvailabilityZone(identity?.AvailabilityZone)
.AddAttributeHostID(identity?.InstanceId)
.AddAttributeHostImageId(identity?.ImageId)
.AddAttributeHostType(identity?.InstanceType)
.AddAttributeCloudRegion(identity?.Region)
.Build();
return resourceAttributes;
}
private static string GetAWSEC2Token()
=> ResourceDetectorUtils.SendOutRequest(AWSEC2MetadataTokenUrl, HttpMethod.Put, new KeyValuePair<string, string>(AWSEC2MetadataTokenTTLHeader, "60"));
private static AWSEC2IdentityDocumentModel? GetAWSEC2Identity(string token)
{
var identity = GetIdentityResponse(token);
var identityDocument = DeserializeResponse(identity);
return identityDocument;
}
private static string GetIdentityResponse(string token)
=> ResourceDetectorUtils.SendOutRequest(AWSEC2IdentityDocumentUrl, HttpMethod.Get, new KeyValuePair<string, string>(AWSEC2MetadataTokenHeader, token));
private static string GetAWSEC2HostName(string token)
=> ResourceDetectorUtils.SendOutRequest(AWSEC2HostNameUrl, HttpMethod.Get, new KeyValuePair<string, string>(AWSEC2MetadataTokenHeader, token));
}