Azure resource providers (#1228)
Co-authored-by: heyams <heya@microsoft.com>
This commit is contained in:
parent
1b006501c0
commit
c19a97334a
|
|
@ -19,6 +19,9 @@ components:
|
|||
aws-xray-propagator:
|
||||
- wangzlei
|
||||
- srprash
|
||||
azure-resources:
|
||||
- trask
|
||||
- zeitlinger
|
||||
baggage-processor:
|
||||
- mikegoldsmith
|
||||
- zeitlinger
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
# Azure Resource Detectors for OpenTelemetry
|
||||
|
||||
This module provides Azure resource detectors for OpenTelemetry.
|
||||
|
||||
The following OpenTelemetry semantic conventions will be detected:
|
||||
|
||||
| Resource attribute | VM | Functions | App Service | Containers |
|
||||
|-------------------------|----------|-----------------|-------------------|----------------------|
|
||||
| cloud.platform | azure_vm | azure_functions | azure_app_service | azure_container_apps |
|
||||
| cloud.provider | azure | azure | azure | azure |
|
||||
| cloud.resource.id | auto | | auto | |
|
||||
| cloud.region | auto | auto | auto | |
|
||||
| deployment.environment | | | auto | |
|
||||
| host.id | auto | | auto | |
|
||||
| host.name | auto | | | |
|
||||
| host.type | auto | | | |
|
||||
| os.type | auto | | | |
|
||||
| os.version | auto | | | |
|
||||
| azure.vm.scaleset.name | auto | | | |
|
||||
| azure.vm.sku | auto | | | |
|
||||
| service.name | | | auto | auto |
|
||||
| service.version | | | | auto |
|
||||
| service.instance.id | | | auto | auto |
|
||||
| azure.app.service.stamp | | | auto | |
|
||||
| faas.name | | auto | | |
|
||||
| faas.version | | auto | | |
|
||||
| faas.instance | | auto | | |
|
||||
| faas.faas.max_memory | | auto | | |
|
||||
|
||||
## Component Owners
|
||||
|
||||
- [Trask Stalnaker](https://github.com/trask), Microsoft
|
||||
- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana
|
||||
|
||||
Learn more about component owners in [component_owners.yml](../.github/component_owners.yml).
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
plugins {
|
||||
id("otel.java-conventions")
|
||||
|
||||
id("otel.publish-conventions")
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
description = "OpenTelemetry GCP Resources Support"
|
||||
otelJava.moduleName.set("io.opentelemetry.contrib.gcp.resource")
|
||||
|
||||
// enable publishing to maven local
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("io.opentelemetry:opentelemetry-api")
|
||||
api("io.opentelemetry:opentelemetry-sdk")
|
||||
|
||||
implementation("io.opentelemetry.semconv:opentelemetry-semconv")
|
||||
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
|
||||
implementation("com.fasterxml.jackson.core:jackson-core")
|
||||
implementation("com.squareup.okhttp3:okhttp")
|
||||
|
||||
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
|
||||
// testImplementation("org.mockito:mockito-core")
|
||||
testImplementation("com.google.guava:guava")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
testImplementation("org.assertj:assertj-core")
|
||||
testImplementation("com.linecorp.armeria:armeria-junit5")
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudPlatformIncubatingValues.AZURE_AKS;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.K8S_CLUSTER_NAME;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class AzureAksResourceProvider extends CloudResourceProvider {
|
||||
|
||||
private static final Map<String, AzureVmResourceProvider.Entry> COMPUTE_MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
COMPUTE_MAPPING.put(
|
||||
"resourceGroupName",
|
||||
new AzureVmResourceProvider.Entry(
|
||||
K8S_CLUSTER_NAME, AzureAksResourceProvider::parseClusterName));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
static String parseClusterName(String resourceGroup) {
|
||||
// Code inspired by
|
||||
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/datadogexporter/internal/hostmetadata/internal/azure/provider.go#L36
|
||||
String[] splitAll = resourceGroup.split("_");
|
||||
if (splitAll.length == 4 && splitAll[0].equalsIgnoreCase("mc")) {
|
||||
return splitAll[splitAll.length - 2];
|
||||
}
|
||||
return resourceGroup;
|
||||
}
|
||||
|
||||
// Environment variable that is set when running on Kubernetes
|
||||
static final String KUBERNETES_SERVICE_HOST = "KUBERNETES_SERVICE_HOST";
|
||||
private final Supplier<Optional<String>> client;
|
||||
private final Map<String, String> environment;
|
||||
|
||||
// SPI
|
||||
public AzureAksResourceProvider() {
|
||||
this(AzureMetadataService.defaultClient(), System.getenv());
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
AzureAksResourceProvider(Supplier<Optional<String>> client, Map<String, String> environment) {
|
||||
this.client = client;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
// run after the fast cloud resource providers that only check environment variables
|
||||
// and before the AKS provider
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties configProperties) {
|
||||
if (environment.get(KUBERNETES_SERVICE_HOST) == null) {
|
||||
return Resource.empty();
|
||||
}
|
||||
return client
|
||||
.get()
|
||||
.map(body -> AzureVmResourceProvider.parseMetadata(body, COMPUTE_MAPPING, AZURE_AKS))
|
||||
.orElse(Resource.empty());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_REGION;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_RESOURCE_ID;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudPlatformIncubatingValues.AZURE_APP_SERVICE;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.DEPLOYMENT_ENVIRONMENT_NAME;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.HOST_ID;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.SERVICE_INSTANCE_ID;
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import io.opentelemetry.api.internal.StringUtils;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AzureAppServiceResourceProvider extends CloudResourceProvider {
|
||||
|
||||
static final AttributeKey<String> AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE =
|
||||
AttributeKey.stringKey("azure.app.service.stamp");
|
||||
static final String REGION_NAME = "REGION_NAME";
|
||||
private static final String WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME";
|
||||
private static final String WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME";
|
||||
static final String WEBSITE_INSTANCE_ID = "WEBSITE_INSTANCE_ID";
|
||||
private static final String WEBSITE_OWNER_NAME = "WEBSITE_OWNER_NAME";
|
||||
private static final String WEBSITE_RESOURCE_GROUP = "WEBSITE_RESOURCE_GROUP";
|
||||
static final String WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME";
|
||||
private static final String WEBSITE_SLOT_NAME = "WEBSITE_SLOT_NAME";
|
||||
|
||||
private static final Map<AttributeKey<String>, String> ENV_VAR_MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
ENV_VAR_MAPPING.put(CLOUD_REGION, REGION_NAME);
|
||||
ENV_VAR_MAPPING.put(DEPLOYMENT_ENVIRONMENT_NAME, WEBSITE_SLOT_NAME);
|
||||
ENV_VAR_MAPPING.put(HOST_ID, WEBSITE_HOSTNAME);
|
||||
ENV_VAR_MAPPING.put(SERVICE_INSTANCE_ID, WEBSITE_INSTANCE_ID);
|
||||
ENV_VAR_MAPPING.put(AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE, WEBSITE_HOME_STAMPNAME);
|
||||
}
|
||||
|
||||
private final Map<String, String> env;
|
||||
|
||||
// SPI
|
||||
public AzureAppServiceResourceProvider() {
|
||||
this(System.getenv());
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
AzureAppServiceResourceProvider(Map<String, String> env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties config) {
|
||||
return Resource.create(getAttributes());
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
AzureEnvVarPlatform detect = AzureEnvVarPlatform.detect(env);
|
||||
if (detect != AzureEnvVarPlatform.APP_SERVICE) {
|
||||
return Attributes.empty();
|
||||
}
|
||||
String name = Objects.requireNonNull(env.get(WEBSITE_SITE_NAME));
|
||||
AttributesBuilder builder = AzureVmResourceProvider.azureAttributeBuilder(AZURE_APP_SERVICE);
|
||||
builder.put(SERVICE_NAME, name);
|
||||
|
||||
String resourceUri = resourceUri(name);
|
||||
if (resourceUri != null) {
|
||||
builder.put(CLOUD_RESOURCE_ID, resourceUri);
|
||||
}
|
||||
|
||||
AzureEnvVarPlatform.addAttributesFromEnv(ENV_VAR_MAPPING, env, builder);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String resourceUri(String websiteName) {
|
||||
String websiteResourceGroup = env.get(WEBSITE_RESOURCE_GROUP);
|
||||
String websiteOwnerName = env.get(WEBSITE_OWNER_NAME);
|
||||
|
||||
String subscriptionId;
|
||||
if (websiteOwnerName != null && websiteOwnerName.contains("+")) {
|
||||
subscriptionId = websiteOwnerName.substring(0, websiteOwnerName.indexOf("+"));
|
||||
} else {
|
||||
subscriptionId = websiteOwnerName;
|
||||
}
|
||||
|
||||
if (StringUtils.isNullOrEmpty(websiteResourceGroup)
|
||||
|| StringUtils.isNullOrEmpty(subscriptionId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return String.format(
|
||||
"/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s",
|
||||
subscriptionId, websiteResourceGroup, websiteName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.SERVICE_INSTANCE_ID;
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_VERSION;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AzureContainersResourceProvider extends CloudResourceProvider {
|
||||
|
||||
static final String CONTAINER_APP_NAME = "CONTAINER_APP_NAME";
|
||||
|
||||
private static final String CONTAINER_APP_REPLICA_NAME = "CONTAINER_APP_REPLICA_NAME";
|
||||
private static final String CONTAINER_APP_REVISION = "CONTAINER_APP_REVISION";
|
||||
|
||||
private static final Map<AttributeKey<String>, String> ENV_VAR_MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
ENV_VAR_MAPPING.put(SERVICE_NAME, CONTAINER_APP_NAME);
|
||||
ENV_VAR_MAPPING.put(SERVICE_INSTANCE_ID, CONTAINER_APP_REPLICA_NAME);
|
||||
ENV_VAR_MAPPING.put(SERVICE_VERSION, CONTAINER_APP_REVISION);
|
||||
}
|
||||
|
||||
private final Map<String, String> env;
|
||||
|
||||
// SPI
|
||||
public AzureContainersResourceProvider() {
|
||||
this(System.getenv());
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
AzureContainersResourceProvider(Map<String, String> env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties config) {
|
||||
return Resource.create(getAttributes());
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
AzureEnvVarPlatform detect = AzureEnvVarPlatform.detect(env);
|
||||
if (detect != AzureEnvVarPlatform.CONTAINER_APP) {
|
||||
return Attributes.empty();
|
||||
}
|
||||
|
||||
AttributesBuilder builder =
|
||||
AzureVmResourceProvider.azureAttributeBuilder("azure_container_apps");
|
||||
|
||||
AzureEnvVarPlatform.addAttributesFromEnv(ENV_VAR_MAPPING, env, builder);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import java.util.Map;
|
||||
|
||||
public enum AzureEnvVarPlatform {
|
||||
APP_SERVICE,
|
||||
FUNCTIONS,
|
||||
CONTAINER_APP,
|
||||
NONE;
|
||||
|
||||
public static AzureEnvVarPlatform detect(Map<String, String> env) {
|
||||
String appName = env.get(AzureContainersResourceProvider.CONTAINER_APP_NAME);
|
||||
if (appName != null) {
|
||||
return CONTAINER_APP;
|
||||
}
|
||||
String name = env.get(AzureAppServiceResourceProvider.WEBSITE_SITE_NAME);
|
||||
if (name == null) {
|
||||
return NONE;
|
||||
}
|
||||
if (env.get(AzureFunctionsResourceProvider.FUNCTIONS_VERSION) != null) {
|
||||
return FUNCTIONS;
|
||||
}
|
||||
return APP_SERVICE;
|
||||
}
|
||||
|
||||
static void addAttributesFromEnv(
|
||||
Map<AttributeKey<String>, String> mapping,
|
||||
Map<String, String> env,
|
||||
AttributesBuilder builder) {
|
||||
mapping.forEach(
|
||||
(key, value) -> {
|
||||
String envValue = env.get(value);
|
||||
if (envValue != null) {
|
||||
builder.put(key, envValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_REGION;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudPlatformIncubatingValues.AZURE_FUNCTIONS;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.FAAS_INSTANCE;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.FAAS_MAX_MEMORY;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.FAAS_NAME;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.FAAS_VERSION;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AzureFunctionsResourceProvider extends CloudResourceProvider {
|
||||
|
||||
static final String FUNCTIONS_VERSION = "FUNCTIONS_EXTENSION_VERSION";
|
||||
private static final String FUNCTIONS_MEM_LIMIT = "WEBSITE_MEMORY_LIMIT_MB";
|
||||
|
||||
private static final Map<AttributeKey<String>, String> ENV_VAR_MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
ENV_VAR_MAPPING.put(CLOUD_REGION, AzureAppServiceResourceProvider.REGION_NAME);
|
||||
ENV_VAR_MAPPING.put(FAAS_NAME, AzureAppServiceResourceProvider.WEBSITE_SITE_NAME);
|
||||
ENV_VAR_MAPPING.put(FAAS_VERSION, FUNCTIONS_VERSION);
|
||||
ENV_VAR_MAPPING.put(FAAS_INSTANCE, AzureAppServiceResourceProvider.WEBSITE_INSTANCE_ID);
|
||||
}
|
||||
|
||||
private final Map<String, String> env;
|
||||
|
||||
// SPI
|
||||
public AzureFunctionsResourceProvider() {
|
||||
this(System.getenv());
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
AzureFunctionsResourceProvider(Map<String, String> env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties config) {
|
||||
return Resource.create(getAttributes());
|
||||
}
|
||||
|
||||
public Attributes getAttributes() {
|
||||
AzureEnvVarPlatform detect = AzureEnvVarPlatform.detect(env);
|
||||
if (detect != AzureEnvVarPlatform.FUNCTIONS) {
|
||||
return Attributes.empty();
|
||||
}
|
||||
|
||||
AttributesBuilder builder = AzureVmResourceProvider.azureAttributeBuilder(AZURE_FUNCTIONS);
|
||||
|
||||
String limit = env.get(FUNCTIONS_MEM_LIMIT);
|
||||
if (limit != null) {
|
||||
builder.put(FAAS_MAX_MEMORY, Long.parseLong(limit));
|
||||
}
|
||||
|
||||
AzureEnvVarPlatform.addAttributesFromEnv(ENV_VAR_MAPPING, env, builder);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class AzureMetadataService {
|
||||
static final JsonFactory JSON_FACTORY = new JsonFactory();
|
||||
private static final URL METADATA_URL;
|
||||
|
||||
static {
|
||||
try {
|
||||
METADATA_URL = new URL("http://169.254.169.254/metadata/instance?api-version=2021-02-01");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private AzureMetadataService() {}
|
||||
|
||||
private static final Duration TIMEOUT = Duration.ofSeconds(1);
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AzureMetadataService.class.getName());
|
||||
|
||||
static Supplier<Optional<String>> defaultClient() {
|
||||
return () -> fetchMetadata(METADATA_URL);
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
static Optional<String> fetchMetadata(URL url) {
|
||||
OkHttpClient client =
|
||||
new OkHttpClient.Builder()
|
||||
.callTimeout(TIMEOUT)
|
||||
.connectTimeout(TIMEOUT)
|
||||
.readTimeout(TIMEOUT)
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder().url(url).get().addHeader("Metadata", "true").build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
int responseCode = response.code();
|
||||
if (responseCode != 200) {
|
||||
logger.log(
|
||||
Level.FINE,
|
||||
"Error response from "
|
||||
+ url
|
||||
+ " code ("
|
||||
+ responseCode
|
||||
+ ") text "
|
||||
+ response.message());
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(Objects.requireNonNull(response.body()).string());
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "Failed to fetch Azure VM metadata", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_REGION;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_RESOURCE_ID;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudPlatformIncubatingValues.AZURE_VM;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudProviderIncubatingValues.AZURE;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.HOST_ID;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.HOST_NAME;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.HOST_TYPE;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.OS_TYPE;
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.OS_VERSION;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AzureVmResourceProvider extends CloudResourceProvider {
|
||||
|
||||
static class Entry {
|
||||
final AttributeKey<String> key;
|
||||
final Function<String, String> transform;
|
||||
|
||||
Entry(AttributeKey<String> key) {
|
||||
this(key, Function.identity());
|
||||
}
|
||||
|
||||
Entry(AttributeKey<String> key, Function<String, String> transform) {
|
||||
this.key = key;
|
||||
this.transform = transform;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String, Entry> COMPUTE_MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
COMPUTE_MAPPING.put("location", new Entry(CLOUD_REGION));
|
||||
COMPUTE_MAPPING.put("resourceId", new Entry(CLOUD_RESOURCE_ID));
|
||||
COMPUTE_MAPPING.put("vmId", new Entry(HOST_ID));
|
||||
COMPUTE_MAPPING.put("name", new Entry(HOST_NAME));
|
||||
COMPUTE_MAPPING.put("vmSize", new Entry(HOST_TYPE));
|
||||
COMPUTE_MAPPING.put("osType", new Entry(OS_TYPE));
|
||||
COMPUTE_MAPPING.put("version", new Entry(OS_VERSION));
|
||||
COMPUTE_MAPPING.put(
|
||||
"vmScaleSetName", new Entry(AttributeKey.stringKey("azure.vm.scaleset.name")));
|
||||
COMPUTE_MAPPING.put("sku", new Entry(AttributeKey.stringKey("azure.vm.sku")));
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AzureVmResourceProvider.class.getName());
|
||||
|
||||
private final Supplier<Optional<String>> client;
|
||||
|
||||
// SPI
|
||||
public AzureVmResourceProvider() {
|
||||
this(AzureMetadataService.defaultClient());
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
AzureVmResourceProvider(Supplier<Optional<String>> client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
// run after the fast cloud resource providers that only check environment variables
|
||||
// and after the AKS provider
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createResource(ConfigProperties config) {
|
||||
return client
|
||||
.get()
|
||||
.map(body -> parseMetadata(body, COMPUTE_MAPPING, AZURE_VM))
|
||||
.orElse(Resource.empty());
|
||||
}
|
||||
|
||||
static Resource parseMetadata(String body, Map<String, Entry> computeMapping, String platform) {
|
||||
AttributesBuilder builder = azureAttributeBuilder(platform);
|
||||
try (JsonParser parser = AzureMetadataService.JSON_FACTORY.createParser(body)) {
|
||||
parser.nextToken();
|
||||
parseResponse(parser, builder, computeMapping);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "Can't get Azure VM metadata", e);
|
||||
}
|
||||
return Resource.create(builder.build());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static AttributesBuilder azureAttributeBuilder(String platform) {
|
||||
AttributesBuilder builder = Attributes.builder();
|
||||
builder.put(CLOUD_PROVIDER, AZURE);
|
||||
builder.put(CLOUD_PLATFORM, platform);
|
||||
return builder;
|
||||
}
|
||||
|
||||
static void parseResponse(
|
||||
JsonParser parser, AttributesBuilder builder, Map<String, Entry> computeMapping)
|
||||
throws IOException {
|
||||
if (!parser.isExpectedStartObjectToken()) {
|
||||
logger.log(Level.FINE, "Couldn't parse ECS metadata, invalid JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
consumeJson(
|
||||
parser,
|
||||
(name, value) -> {
|
||||
try {
|
||||
if (name.equals("compute")) {
|
||||
consumeCompute(parser, builder, computeMapping);
|
||||
} else {
|
||||
parser.skipChildren();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void consumeCompute(
|
||||
JsonParser parser, AttributesBuilder builder, Map<String, Entry> computeMapping)
|
||||
throws IOException {
|
||||
consumeJson(
|
||||
parser,
|
||||
(computeName, computeValue) -> {
|
||||
Entry entry = computeMapping.get(computeName);
|
||||
if (entry != null) {
|
||||
builder.put(entry.key, entry.transform.apply(computeValue));
|
||||
} else {
|
||||
try {
|
||||
parser.skipChildren();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void consumeJson(JsonParser parser, BiConsumer<String, String> consumer)
|
||||
throws IOException {
|
||||
while (parser.nextToken() != JsonToken.END_OBJECT) {
|
||||
consumer.accept(parser.currentName(), parser.nextTextValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CLOUD_PROVIDER;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
|
||||
public abstract class CloudResourceProvider implements ConditionalResourceProvider {
|
||||
|
||||
@Override
|
||||
public final boolean shouldApply(ConfigProperties config, Resource existing) {
|
||||
return existing.getAttribute(CLOUD_PROVIDER) == null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
|
||||
// copied from opentelemetry-semconv-incubating
|
||||
final class IncubatingAttributes {
|
||||
|
||||
// service attributes
|
||||
public static final AttributeKey<String> SERVICE_INSTANCE_ID =
|
||||
AttributeKey.stringKey("service.instance.id");
|
||||
|
||||
// cloud attributes
|
||||
public static final AttributeKey<String> CLOUD_PLATFORM =
|
||||
AttributeKey.stringKey("cloud.platform");
|
||||
public static final AttributeKey<String> CLOUD_PROVIDER =
|
||||
AttributeKey.stringKey("cloud.provider");
|
||||
public static final AttributeKey<String> CLOUD_REGION = AttributeKey.stringKey("cloud.region");
|
||||
public static final AttributeKey<String> CLOUD_RESOURCE_ID =
|
||||
AttributeKey.stringKey("cloud.resource_id");
|
||||
|
||||
public static final class CloudPlatformIncubatingValues {
|
||||
public static final String AZURE_VM = "azure_vm";
|
||||
public static final String AZURE_AKS = "azure_aks";
|
||||
public static final String AZURE_FUNCTIONS = "azure_functions";
|
||||
public static final String AZURE_APP_SERVICE = "azure_app_service";
|
||||
|
||||
private CloudPlatformIncubatingValues() {}
|
||||
}
|
||||
|
||||
public static final class CloudProviderIncubatingValues {
|
||||
public static final String AZURE = "azure";
|
||||
|
||||
private CloudProviderIncubatingValues() {}
|
||||
}
|
||||
|
||||
// deployment attributes
|
||||
public static final AttributeKey<String> DEPLOYMENT_ENVIRONMENT_NAME =
|
||||
AttributeKey.stringKey("deployment.environment.name");
|
||||
|
||||
// host attributes
|
||||
public static final AttributeKey<String> HOST_ID = AttributeKey.stringKey("host.id");
|
||||
public static final AttributeKey<String> HOST_NAME = AttributeKey.stringKey("host.name");
|
||||
public static final AttributeKey<String> HOST_TYPE = AttributeKey.stringKey("host.type");
|
||||
|
||||
// faas attributes
|
||||
public static final AttributeKey<String> FAAS_INSTANCE = AttributeKey.stringKey("faas.instance");
|
||||
public static final AttributeKey<Long> FAAS_MAX_MEMORY = AttributeKey.longKey("faas.max_memory");
|
||||
public static final AttributeKey<String> FAAS_NAME = AttributeKey.stringKey("faas.name");
|
||||
public static final AttributeKey<String> FAAS_VERSION = AttributeKey.stringKey("faas.version");
|
||||
|
||||
// host attributes
|
||||
static final AttributeKey<String> K8S_CLUSTER_NAME = AttributeKey.stringKey("k8s.cluster.name");
|
||||
|
||||
// OS attributes
|
||||
public static final AttributeKey<String> OS_TYPE = AttributeKey.stringKey("os.type");
|
||||
public static final AttributeKey<String> OS_VERSION = AttributeKey.stringKey("os.version");
|
||||
|
||||
private IncubatingAttributes() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
io.opentelemetry.contrib.azure.resource.AzureAppServiceResourceProvider
|
||||
io.opentelemetry.contrib.azure.resource.AzureFunctionsResourceProvider
|
||||
io.opentelemetry.contrib.azure.resource.AzureVmResourceProvider
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||
import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.K8sIncubatingAttributes;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AzureAksResourceProviderTest extends MetadataBasedResourceProviderTest {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ResourceProvider getResourceProvider(Supplier<Optional<String>> client) {
|
||||
return new AzureAksResourceProvider(
|
||||
client,
|
||||
Collections.singletonMap(AzureAksResourceProvider.KUBERNETES_SERVICE_HOST, "localhost"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPlatform() {
|
||||
return CloudIncubatingAttributes.CloudPlatformIncubatingValues.AZURE_AKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertDefaultAttributes(AttributesAssert attributesAssert) {
|
||||
attributesAssert
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(
|
||||
CLOUD_PLATFORM, CloudIncubatingAttributes.CloudPlatformIncubatingValues.AZURE_AKS)
|
||||
.containsEntry(K8sIncubatingAttributes.K8S_CLUSTER_NAME, "macikgo-test-may-23");
|
||||
}
|
||||
|
||||
@Test
|
||||
void notOnK8s() {
|
||||
AzureAksResourceProvider provider =
|
||||
new AzureAksResourceProvider(() -> Optional.of(okResponse()), Collections.emptyMap());
|
||||
Attributes attributes = provider.createResource(null).getAttributes();
|
||||
OpenTelemetryAssertions.assertThat(attributes).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseClusterName() {
|
||||
String clusterName =
|
||||
AzureAksResourceProvider.parseClusterName(
|
||||
"mc_macikgo-test-may-23_macikgo-test-may-23_eastus");
|
||||
assertThat(clusterName).isEqualTo("macikgo-test-may-23");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_REGION;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_RESOURCE_ID;
|
||||
import static io.opentelemetry.semconv.incubating.DeploymentIncubatingAttributes.DEPLOYMENT_ENVIRONMENT_NAME;
|
||||
import static io.opentelemetry.semconv.incubating.HostIncubatingAttributes.HOST_ID;
|
||||
import static io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes.SERVICE_INSTANCE_ID;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AzureAppServiceResourceProviderTest {
|
||||
|
||||
private static final String TEST_WEBSITE_SITE_NAME = "TEST_WEBSITE_SITE_NAME";
|
||||
private static final String TEST_REGION_NAME = "TEST_REGION_NAME";
|
||||
private static final String TEST_WEBSITE_SLOT_NAME = "TEST_WEBSITE_SLOT_NAME";
|
||||
private static final String TEST_WEBSITE_HOSTNAME = "TEST_WEBSITE_HOSTNAME";
|
||||
private static final String TEST_WEBSITE_INSTANCE_ID = "TEST_WEBSITE_INSTANCE_ID";
|
||||
private static final String TEST_WEBSITE_HOME_STAMPNAME = "TEST_WEBSITE_HOME_STAMPNAME";
|
||||
private static final String TEST_WEBSITE_RESOURCE_GROUP = "TEST_WEBSITE_RESOURCE_GROUP";
|
||||
private static final String TEST_WEBSITE_OWNER_NAME = "TEST_WEBSITE_OWNER_NAME";
|
||||
private static final ImmutableMap<String, String> DEFAULT_ENV_VARS =
|
||||
ImmutableMap.of(
|
||||
"WEBSITE_SITE_NAME", TEST_WEBSITE_SITE_NAME,
|
||||
"REGION_NAME", TEST_REGION_NAME,
|
||||
"WEBSITE_SLOT_NAME", TEST_WEBSITE_SLOT_NAME,
|
||||
"WEBSITE_HOSTNAME", TEST_WEBSITE_HOSTNAME,
|
||||
"WEBSITE_INSTANCE_ID", TEST_WEBSITE_INSTANCE_ID,
|
||||
"WEBSITE_HOME_STAMPNAME", TEST_WEBSITE_HOME_STAMPNAME,
|
||||
"WEBSITE_RESOURCE_GROUP", TEST_WEBSITE_RESOURCE_GROUP,
|
||||
"WEBSITE_OWNER_NAME", TEST_WEBSITE_OWNER_NAME);
|
||||
|
||||
@Test
|
||||
void defaultValues() {
|
||||
createResource(DEFAULT_ENV_VARS)
|
||||
.containsEntry(SERVICE_NAME, TEST_WEBSITE_SITE_NAME)
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(CLOUD_PLATFORM, "azure_app_service")
|
||||
.containsEntry(
|
||||
CLOUD_RESOURCE_ID,
|
||||
"/subscriptions/TEST_WEBSITE_OWNER_NAME/resourceGroups/TEST_WEBSITE_RESOURCE_GROUP/providers/Microsoft.Web/sites/TEST_WEBSITE_SITE_NAME")
|
||||
.containsEntry(CLOUD_REGION, TEST_REGION_NAME)
|
||||
.containsEntry(DEPLOYMENT_ENVIRONMENT_NAME, TEST_WEBSITE_SLOT_NAME)
|
||||
.containsEntry(HOST_ID, TEST_WEBSITE_HOSTNAME)
|
||||
.containsEntry(SERVICE_INSTANCE_ID, TEST_WEBSITE_INSTANCE_ID)
|
||||
.containsEntry(
|
||||
AzureAppServiceResourceProvider.AZURE_APP_SERVICE_STAMP_RESOURCE_ATTRIBUTE,
|
||||
TEST_WEBSITE_HOME_STAMPNAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void subscriptionFromOwner() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.put("WEBSITE_OWNER_NAME", "foo+bar");
|
||||
|
||||
createResource(map)
|
||||
.containsEntry(
|
||||
CLOUD_RESOURCE_ID,
|
||||
"/subscriptions/foo/resourceGroups/TEST_WEBSITE_RESOURCE_GROUP/providers/Microsoft.Web/sites/TEST_WEBSITE_SITE_NAME");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noResourceId() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.remove("WEBSITE_RESOURCE_GROUP");
|
||||
|
||||
createResource(map).doesNotContainKey(CLOUD_RESOURCE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void noWebsite() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.remove("WEBSITE_SITE_NAME");
|
||||
|
||||
createResource(map).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isFunction() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.put("FUNCTIONS_EXTENSION_VERSION", "3.0");
|
||||
|
||||
createResource(map).isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static AttributesAssert createResource(Map<String, String> map) {
|
||||
return OpenTelemetryAssertions.assertThat(
|
||||
new AzureAppServiceResourceProvider(map).createResource(null).getAttributes());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME;
|
||||
import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_VERSION;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes.SERVICE_INSTANCE_ID;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AzureContainersResourceProviderTest {
|
||||
private static final String TEST_APP_NAME = "TEST_APP_NAME";
|
||||
private static final String TEST_REPLICA_NAME = "TEST_REPLICA_NAME";
|
||||
private static final String TEST_REVISION = "TEST_REVISION";
|
||||
|
||||
private static final ImmutableMap<String, String> DEFAULT_ENV_VARS =
|
||||
ImmutableMap.of(
|
||||
"CONTAINER_APP_NAME", TEST_APP_NAME,
|
||||
"CONTAINER_APP_REPLICA_NAME", TEST_REPLICA_NAME,
|
||||
"CONTAINER_APP_REVISION", TEST_REVISION);
|
||||
|
||||
@Test
|
||||
void defaultValues() {
|
||||
createResource(DEFAULT_ENV_VARS)
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(CLOUD_PLATFORM, "azure_container_apps")
|
||||
.containsEntry(SERVICE_NAME, TEST_APP_NAME)
|
||||
.containsEntry(SERVICE_INSTANCE_ID, TEST_REPLICA_NAME)
|
||||
.containsEntry(SERVICE_VERSION, TEST_REVISION);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNotContainer() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.remove("CONTAINER_APP_NAME");
|
||||
|
||||
createResource(map).isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static AttributesAssert createResource(Map<String, String> map) {
|
||||
return OpenTelemetryAssertions.assertThat(
|
||||
new AzureContainersResourceProvider(map).createResource(null).getAttributes());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static io.opentelemetry.semconv.incubating.FaasIncubatingAttributes.FAAS_INSTANCE;
|
||||
import static io.opentelemetry.semconv.incubating.FaasIncubatingAttributes.FAAS_MAX_MEMORY;
|
||||
import static io.opentelemetry.semconv.incubating.FaasIncubatingAttributes.FAAS_NAME;
|
||||
import static io.opentelemetry.semconv.incubating.FaasIncubatingAttributes.FAAS_VERSION;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AzureFunctionsResourceProviderTest {
|
||||
private static final String TEST_WEBSITE_SITE_NAME = "TEST_WEBSITE_SITE_NAME";
|
||||
private static final String TEST_REGION_NAME = "TEST_REGION_NAME";
|
||||
private static final String TEST_FUNCTION_VERSION = "TEST_VERSION";
|
||||
private static final String TEST_WEBSITE_INSTANCE_ID = "TEST_WEBSITE_INSTANCE_ID";
|
||||
private static final String TEST_MEM_LIMIT = "1024";
|
||||
private static final ImmutableMap<String, String> DEFAULT_ENV_VARS =
|
||||
ImmutableMap.of(
|
||||
"WEBSITE_SITE_NAME", TEST_WEBSITE_SITE_NAME,
|
||||
"REGION_NAME", TEST_REGION_NAME,
|
||||
"WEBSITE_MEMORY_LIMIT_MB", TEST_MEM_LIMIT,
|
||||
"FUNCTIONS_EXTENSION_VERSION", TEST_FUNCTION_VERSION,
|
||||
"WEBSITE_INSTANCE_ID", TEST_WEBSITE_INSTANCE_ID);
|
||||
|
||||
@Test
|
||||
void defaultValues() {
|
||||
createResource(DEFAULT_ENV_VARS)
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(CLOUD_PLATFORM, "azure_functions")
|
||||
.containsEntry(FAAS_NAME, TEST_WEBSITE_SITE_NAME)
|
||||
.containsEntry(FAAS_VERSION, TEST_FUNCTION_VERSION)
|
||||
.containsEntry(FAAS_INSTANCE, TEST_WEBSITE_INSTANCE_ID)
|
||||
.containsEntry(FAAS_MAX_MEMORY, Long.parseLong(TEST_MEM_LIMIT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNotFunction() {
|
||||
HashMap<String, String> map = new HashMap<>(DEFAULT_ENV_VARS);
|
||||
map.remove("FUNCTIONS_EXTENSION_VERSION");
|
||||
|
||||
createResource(map).isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static AttributesAssert createResource(Map<String, String> map) {
|
||||
return OpenTelemetryAssertions.assertThat(
|
||||
new AzureFunctionsResourceProvider(map).createResource(null).getAttributes());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_REGION;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_RESOURCE_ID;
|
||||
import static io.opentelemetry.semconv.incubating.HostIncubatingAttributes.HOST_ID;
|
||||
import static io.opentelemetry.semconv.incubating.HostIncubatingAttributes.HOST_NAME;
|
||||
import static io.opentelemetry.semconv.incubating.HostIncubatingAttributes.HOST_TYPE;
|
||||
import static io.opentelemetry.semconv.incubating.OsIncubatingAttributes.OS_TYPE;
|
||||
import static io.opentelemetry.semconv.incubating.OsIncubatingAttributes.OS_VERSION;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class AzureVmResourceProviderTest extends MetadataBasedResourceProviderTest {
|
||||
@NotNull
|
||||
@Override
|
||||
protected ResourceProvider getResourceProvider(Supplier<Optional<String>> client) {
|
||||
return new AzureVmResourceProvider(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPlatform() {
|
||||
return CloudIncubatingAttributes.CloudPlatformIncubatingValues.AZURE_VM;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertDefaultAttributes(AttributesAssert attributesAssert) {
|
||||
attributesAssert
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(
|
||||
CLOUD_PLATFORM, CloudIncubatingAttributes.CloudPlatformIncubatingValues.AZURE_VM)
|
||||
.containsEntry(CLOUD_REGION, "westus")
|
||||
.containsEntry(
|
||||
CLOUD_RESOURCE_ID,
|
||||
"/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname")
|
||||
.containsEntry(HOST_ID, "02aab8a4-74ef-476e-8182-f6d2ba4166a6")
|
||||
.containsEntry(HOST_NAME, "examplevmname")
|
||||
.containsEntry(HOST_TYPE, "Standard_A3")
|
||||
.containsEntry(OS_TYPE, "Linux")
|
||||
.containsEntry(OS_VERSION, "15.05.22")
|
||||
.containsEntry("azure.vm.scaleset.name", "crpteste9vflji9")
|
||||
.containsEntry("azure.vm.sku", "18.04-LTS");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.azure.resource;
|
||||
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
|
||||
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.linecorp.armeria.common.HttpResponse;
|
||||
import com.linecorp.armeria.common.HttpStatus;
|
||||
import com.linecorp.armeria.common.MediaType;
|
||||
import com.linecorp.armeria.testing.junit5.server.mock.MockWebServerExtension;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
public abstract class MetadataBasedResourceProviderTest {
|
||||
@RegisterExtension
|
||||
public static final MockWebServerExtension server = new MockWebServerExtension();
|
||||
|
||||
@NotNull
|
||||
private AttributesAssert mockServerResponse() {
|
||||
return createResource(
|
||||
() -> {
|
||||
try {
|
||||
return AzureMetadataService.fetchMetadata(server.httpUri().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AttributesAssert createResource(Supplier<Optional<String>> client) {
|
||||
Resource resource = getResourceProvider(client).createResource(null);
|
||||
return OpenTelemetryAssertions.assertThat(resource.getAttributes());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract ResourceProvider getResourceProvider(Supplier<Optional<String>> client);
|
||||
|
||||
private void assertOnlyProvider(AttributesAssert attributesAssert) {
|
||||
attributesAssert
|
||||
.hasSize(2)
|
||||
.containsEntry(CLOUD_PROVIDER, "azure")
|
||||
.containsEntry(CLOUD_PLATFORM, getPlatform());
|
||||
}
|
||||
|
||||
protected abstract String getPlatform();
|
||||
|
||||
protected abstract void assertDefaultAttributes(AttributesAssert attributesAssert);
|
||||
|
||||
protected static String okResponse() {
|
||||
try {
|
||||
return CharStreams.toString(
|
||||
new InputStreamReader(
|
||||
Objects.requireNonNull(
|
||||
AzureVmResourceProviderTest.class
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("response.json")),
|
||||
StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successFromFile() {
|
||||
assertDefaultAttributes(createResource(() -> Optional.of(okResponse())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successFromMockServer() {
|
||||
server.enqueue(HttpResponse.of(MediaType.JSON, okResponse()));
|
||||
assertDefaultAttributes(mockServerResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseNotFound() {
|
||||
server.enqueue(HttpResponse.of(HttpStatus.NOT_FOUND));
|
||||
mockServerResponse().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseEmpty() {
|
||||
server.enqueue(HttpResponse.of(""));
|
||||
assertOnlyProvider(mockServerResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseEmptyJson() {
|
||||
server.enqueue(HttpResponse.of("{}"));
|
||||
assertOnlyProvider(mockServerResponse());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
{
|
||||
"compute": {
|
||||
"azEnvironment": "AZUREPUBLICCLOUD",
|
||||
"additionalCapabilities": {
|
||||
"hibernationEnabled": "true"
|
||||
},
|
||||
"hostGroup": {
|
||||
"id": "testHostGroupId"
|
||||
},
|
||||
"extendedLocation": {
|
||||
"type": "edgeZone",
|
||||
"name": "microsoftlosangeles"
|
||||
},
|
||||
"evictionPolicy": "",
|
||||
"isHostCompatibilityLayerVm": "true",
|
||||
"licenseType": "",
|
||||
"location": "westus",
|
||||
"name": "examplevmname",
|
||||
"offer": "UbuntuServer",
|
||||
"osProfile": {
|
||||
"adminUsername": "admin",
|
||||
"computerName": "examplevmname",
|
||||
"disablePasswordAuthentication": "true"
|
||||
},
|
||||
"osType": "Linux",
|
||||
"placementGroupId": "f67c14ab-e92c-408c-ae2d-da15866ec79a",
|
||||
"plan": {
|
||||
"name": "planName",
|
||||
"product": "planProduct",
|
||||
"publisher": "planPublisher"
|
||||
},
|
||||
"platformFaultDomain": "36",
|
||||
"platformSubFaultDomain": "",
|
||||
"platformUpdateDomain": "42",
|
||||
"priority": "Regular",
|
||||
"publicKeys": [{
|
||||
"keyData": "ssh-rsa 0",
|
||||
"path": "/home/user/.ssh/authorized_keys0"
|
||||
},
|
||||
{
|
||||
"keyData": "ssh-rsa 1",
|
||||
"path": "/home/user/.ssh/authorized_keys1"
|
||||
}
|
||||
],
|
||||
"publisher": "Canonical",
|
||||
"resourceGroupName": "macikgo-test-may-23",
|
||||
"resourceId": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname",
|
||||
"securityProfile": {
|
||||
"secureBootEnabled": "true",
|
||||
"virtualTpmEnabled": "false",
|
||||
"encryptionAtHost": "true",
|
||||
"securityType": "TrustedLaunch"
|
||||
},
|
||||
"sku": "18.04-LTS",
|
||||
"storageProfile": {
|
||||
"dataDisks": [{
|
||||
"bytesPerSecondThrottle": "979202048",
|
||||
"caching": "None",
|
||||
"createOption": "Empty",
|
||||
"diskCapacityBytes": "274877906944",
|
||||
"diskSizeGB": "1024",
|
||||
"image": {
|
||||
"uri": ""
|
||||
},
|
||||
"isSharedDisk": "false",
|
||||
"isUltraDisk": "true",
|
||||
"lun": "0",
|
||||
"managedDisk": {
|
||||
"id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampledatadiskname",
|
||||
"storageAccountType": "StandardSSD_LRS"
|
||||
},
|
||||
"name": "exampledatadiskname",
|
||||
"opsPerSecondThrottle": "65280",
|
||||
"vhd": {
|
||||
"uri": ""
|
||||
},
|
||||
"writeAcceleratorEnabled": "false"
|
||||
}],
|
||||
"imageReference": {
|
||||
"id": "",
|
||||
"offer": "UbuntuServer",
|
||||
"publisher": "Canonical",
|
||||
"sku": "16.04.0-LTS",
|
||||
"version": "latest",
|
||||
"communityGalleryImageId": "/CommunityGalleries/testgallery/Images/1804Gen2/Versions/latest",
|
||||
"sharedGalleryImageId": "/SharedGalleries/1P/Images/gen2/Versions/latest",
|
||||
"exactVersion": "1.1686127202.30113"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"diskSizeGB": "30",
|
||||
"diffDiskSettings": {
|
||||
"option": "Local"
|
||||
},
|
||||
"encryptionSettings": {
|
||||
"enabled": "false",
|
||||
"diskEncryptionKey": {
|
||||
"sourceVault": {
|
||||
"id": "/subscriptions/test-source-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv"
|
||||
},
|
||||
"secretUrl": "https://test-disk.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
|
||||
},
|
||||
"keyEncryptionKey": {
|
||||
"sourceVault": {
|
||||
"id": "/subscriptions/test-key-guid/resourceGroups/testrg/providers/Microsoft.KeyVault/vaults/test-kv"
|
||||
},
|
||||
"keyUrl": "https://test-key.vault.azure.net/secrets/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
|
||||
}
|
||||
},
|
||||
"image": {
|
||||
"uri": ""
|
||||
},
|
||||
"managedDisk": {
|
||||
"id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/disks/exampleosdiskname",
|
||||
"storageAccountType": "StandardSSD_LRS"
|
||||
},
|
||||
"name": "exampleosdiskname",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": ""
|
||||
},
|
||||
"writeAcceleratorEnabled": "false"
|
||||
},
|
||||
"resourceDisk": {
|
||||
"size": "4096"
|
||||
}
|
||||
},
|
||||
"subscriptionId": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
|
||||
"tags": "baz:bash;foo:bar",
|
||||
"version": "15.05.22",
|
||||
"virtualMachineScaleSet": {
|
||||
"id": "/subscriptions/xxxxxxxx-xxxxx-xxx-xxx-xxxx/resourceGroups/resource-group-name/providers/Microsoft.Compute/virtualMachineScaleSets/virtual-machine-scale-set-name"
|
||||
},
|
||||
"vmId": "02aab8a4-74ef-476e-8182-f6d2ba4166a6",
|
||||
"vmScaleSetName": "crpteste9vflji9",
|
||||
"vmSize": "Standard_A3",
|
||||
"zone": ""
|
||||
},
|
||||
"network": {
|
||||
"interface": [{
|
||||
"ipv4": {
|
||||
"ipAddress": [{
|
||||
"privateIpAddress": "10.144.133.132",
|
||||
"publicIpAddress": ""
|
||||
}],
|
||||
"subnet": [{
|
||||
"address": "10.144.133.128",
|
||||
"prefix": "26"
|
||||
}]
|
||||
},
|
||||
"ipv6": {
|
||||
"ipAddress": [
|
||||
]
|
||||
},
|
||||
"macAddress": "0011AAFFBB22"
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ include(":all")
|
|||
include(":aws-resources")
|
||||
include(":aws-xray")
|
||||
include(":aws-xray-propagator")
|
||||
include(":azure-resources")
|
||||
include(":baggage-processor")
|
||||
include(":compressors:compressor-zstd")
|
||||
include(":consistent-sampling")
|
||||
|
|
|
|||
Loading…
Reference in New Issue