15
15
import static io .opentelemetry .semconv .incubating .OsIncubatingAttributes .OS_TYPE ;
16
16
import static io .opentelemetry .semconv .incubating .OsIncubatingAttributes .OS_VERSION ;
17
17
18
- import com .fasterxml .jackson .core .JsonFactory ;
19
18
import com .fasterxml .jackson .core .JsonParser ;
20
19
import com .fasterxml .jackson .core .JsonToken ;
21
20
import io .opentelemetry .api .common .AttributeKey ;
25
24
import io .opentelemetry .sdk .resources .Resource ;
26
25
import io .opentelemetry .semconv .incubating .CloudIncubatingAttributes ;
27
26
import java .io .IOException ;
28
- import java .net .MalformedURLException ;
29
- import java .net .URL ;
30
- import java .time .Duration ;
31
27
import java .util .HashMap ;
32
28
import java .util .Map ;
33
- import java .util .Objects ;
34
29
import java .util .Optional ;
35
30
import java .util .function .BiConsumer ;
31
+ import java .util .function .Function ;
36
32
import java .util .function .Supplier ;
37
33
import java .util .logging .Level ;
38
34
import java .util .logging .Logger ;
39
- import okhttp3 .OkHttpClient ;
40
- import okhttp3 .Request ;
41
- import okhttp3 .Response ;
42
35
import org .jetbrains .annotations .NotNull ;
43
36
44
37
public class AzureVmResourceProvider extends CloudResourceProvider {
45
38
46
- private static final Map <String , AttributeKey <String >> COMPUTE_MAPPING = new HashMap <>();
39
+ static class Entry {
40
+ final AttributeKey <String > key ;
41
+ final Function <String , String > transform ;
47
42
48
- static {
49
- COMPUTE_MAPPING .put ("location" , CLOUD_REGION );
50
- COMPUTE_MAPPING .put ("resourceId" , CLOUD_RESOURCE_ID );
51
- COMPUTE_MAPPING .put ("vmId" , HOST_ID );
52
- COMPUTE_MAPPING .put ("name" , HOST_NAME );
53
- COMPUTE_MAPPING .put ("vmSize" , HOST_TYPE );
54
- COMPUTE_MAPPING .put ("osType" , OS_TYPE );
55
- COMPUTE_MAPPING .put ("version" , OS_VERSION );
56
- COMPUTE_MAPPING .put ("vmScaleSetName" , AttributeKey .stringKey ("azure.vm.scaleset.name" ));
57
- COMPUTE_MAPPING .put ("sku" , AttributeKey .stringKey ("azure.vm.sku" ));
58
- }
59
-
60
- private static final JsonFactory JSON_FACTORY = new JsonFactory ();
43
+ Entry (AttributeKey <String > key ) {
44
+ this (key , Function .identity ());
45
+ }
61
46
62
- private static final Duration TIMEOUT = Duration .ofSeconds (1 );
47
+ Entry (AttributeKey <String > key , Function <String , String > transform ) {
48
+ this .key = key ;
49
+ this .transform = transform ;
50
+ }
51
+ }
63
52
64
- private static final Logger logger = Logger .getLogger (AzureVmResourceProvider .class .getName ());
65
- private static final URL METADATA_URL ;
53
+ private static final Map <String , Entry > COMPUTE_MAPPING = new HashMap <>();
66
54
67
55
static {
68
- try {
69
- METADATA_URL = new URL ("http://169.254.169.254/metadata/instance?api-version=2021-02-01" );
70
- } catch (MalformedURLException e ) {
71
- throw new IllegalStateException (e );
72
- }
56
+ COMPUTE_MAPPING .put ("location" , new Entry (CLOUD_REGION ));
57
+ COMPUTE_MAPPING .put ("resourceId" , new Entry (CLOUD_RESOURCE_ID ));
58
+ COMPUTE_MAPPING .put ("vmId" , new Entry (HOST_ID ));
59
+ COMPUTE_MAPPING .put ("name" , new Entry (HOST_NAME ));
60
+ COMPUTE_MAPPING .put ("vmSize" , new Entry (HOST_TYPE ));
61
+ COMPUTE_MAPPING .put ("osType" , new Entry (OS_TYPE ));
62
+ COMPUTE_MAPPING .put ("version" , new Entry (OS_VERSION ));
63
+ COMPUTE_MAPPING .put (
64
+ "vmScaleSetName" , new Entry (AttributeKey .stringKey ("azure.vm.scaleset.name" )));
65
+ COMPUTE_MAPPING .put ("sku" , new Entry (AttributeKey .stringKey ("azure.vm.sku" )));
73
66
}
74
67
68
+ private static final Logger logger = Logger .getLogger (AzureVmResourceProvider .class .getName ());
69
+
75
70
private final Supplier <Optional <String >> client ;
76
71
77
72
// SPI
78
73
public AzureVmResourceProvider () {
79
- this (() -> fetchMetadata ( METADATA_URL ));
74
+ this (AzureMetadataService . defaultClient ( ));
80
75
}
81
76
82
77
// visible for testing
@@ -87,20 +82,26 @@ public AzureVmResourceProvider(Supplier<Optional<String>> client) {
87
82
@ Override
88
83
public int order () {
89
84
// run after the fast cloud resource providers that only check environment variables
85
+ // and after the AKS provider
90
86
return 100 ;
91
87
}
92
88
93
89
@ Override
94
90
public Resource createResource (ConfigProperties config ) {
95
- return client .get ().map (AzureVmResourceProvider ::parseMetadata ).orElse (Resource .empty ());
91
+ return client
92
+ .get ()
93
+ .map (
94
+ body ->
95
+ parseMetadata (
96
+ body , COMPUTE_MAPPING , CloudIncubatingAttributes .CloudPlatformValues .AZURE_VM ))
97
+ .orElse (Resource .empty ());
96
98
}
97
99
98
- private static Resource parseMetadata (String body ) {
99
- AttributesBuilder builder =
100
- azureAttributeBuilder (CloudIncubatingAttributes .CloudPlatformValues .AZURE_VM );
101
- try (JsonParser parser = JSON_FACTORY .createParser (body )) {
100
+ static Resource parseMetadata (String body , Map <String , Entry > computeMapping , String platform ) {
101
+ AttributesBuilder builder = azureAttributeBuilder (platform );
102
+ try (JsonParser parser = AzureMetadataService .JSON_FACTORY .createParser (body )) {
102
103
parser .nextToken ();
103
- parseResponse (parser , builder );
104
+ parseResponse (parser , builder , computeMapping );
104
105
} catch (IOException e ) {
105
106
logger .log (Level .FINE , "Can't get Azure VM metadata" , e );
106
107
}
@@ -115,7 +116,9 @@ static AttributesBuilder azureAttributeBuilder(String platform) {
115
116
return builder ;
116
117
}
117
118
118
- static void parseResponse (JsonParser parser , AttributesBuilder builder ) throws IOException {
119
+ static void parseResponse (
120
+ JsonParser parser , AttributesBuilder builder , Map <String , Entry > computeMapping )
121
+ throws IOException {
119
122
if (!parser .isExpectedStartObjectToken ()) {
120
123
logger .log (Level .FINE , "Couldn't parse ECS metadata, invalid JSON" );
121
124
return ;
@@ -126,7 +129,7 @@ static void parseResponse(JsonParser parser, AttributesBuilder builder) throws I
126
129
(name , value ) -> {
127
130
try {
128
131
if (name .equals ("compute" )) {
129
- consumeCompute (parser , builder );
132
+ consumeCompute (parser , builder , computeMapping );
130
133
} else {
131
134
parser .skipChildren ();
132
135
}
@@ -136,14 +139,15 @@ static void parseResponse(JsonParser parser, AttributesBuilder builder) throws I
136
139
});
137
140
}
138
141
139
- private static void consumeCompute (JsonParser parser , AttributesBuilder builder )
142
+ private static void consumeCompute (
143
+ JsonParser parser , AttributesBuilder builder , Map <String , Entry > computeMapping )
140
144
throws IOException {
141
145
consumeJson (
142
146
parser ,
143
147
(computeName , computeValue ) -> {
144
- AttributeKey < String > key = COMPUTE_MAPPING .get (computeName );
145
- if (key != null ) {
146
- builder .put (key , computeValue );
148
+ Entry entry = computeMapping .get (computeName );
149
+ if (entry != null ) {
150
+ builder .put (entry . key , entry . transform . apply ( computeValue ) );
147
151
} else {
148
152
try {
149
153
parser .skipChildren ();
@@ -160,36 +164,4 @@ private static void consumeJson(JsonParser parser, BiConsumer<String, String> co
160
164
consumer .accept (parser .currentName (), parser .nextTextValue ());
161
165
}
162
166
}
163
-
164
- // visible for testing
165
- static Optional <String > fetchMetadata (URL url ) {
166
- OkHttpClient client =
167
- new OkHttpClient .Builder ()
168
- .callTimeout (TIMEOUT )
169
- .connectTimeout (TIMEOUT )
170
- .readTimeout (TIMEOUT )
171
- .build ();
172
-
173
- Request request = new Request .Builder ().url (url ).get ().addHeader ("Metadata" , "true" ).build ();
174
-
175
- try (Response response = client .newCall (request ).execute ()) {
176
- int responseCode = response .code ();
177
- if (responseCode != 200 ) {
178
- logger .log (
179
- Level .FINE ,
180
- "Error response from "
181
- + url
182
- + " code ("
183
- + responseCode
184
- + ") text "
185
- + response .message ());
186
- return Optional .empty ();
187
- }
188
-
189
- return Optional .of (Objects .requireNonNull (response .body ()).string ());
190
- } catch (IOException e ) {
191
- logger .log (Level .FINE , "Failed to fetch Azure VM metadata" , e );
192
- return Optional .empty ();
193
- }
194
- }
195
167
}
0 commit comments