Add telemetry mode for spring cloud azure autoconfiguration, #38. (#39)

* Add telemetry mode for spring cloud azure autoconfiguration.

* track version, installId, subsId, resourcGroup and serviceName.

* Add Unit test for telemetry bean.

Signed-off-by: Pan Li <panli@microsoft.com>
Signed-off-by: Warren Zhu <Zhongwei.Zhu@microsoft.com>
This commit is contained in:
Pan Li 2018-07-05 11:31:09 +08:00 коммит произвёл GitHub
Родитель 6436ca5c4f
Коммит a18b4ffe3d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 235 добавлений и 40 удалений

Просмотреть файл

@ -79,7 +79,6 @@
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -112,6 +111,14 @@
<artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope>
</dependency>
<!-- Project Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

Просмотреть файл

@ -82,7 +82,7 @@
<artifactId>applicationinsights-core</artifactId>
<version>${azure.applicationinsights.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
@ -92,15 +92,22 @@
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
<resources>
<!-- Filtering Resource -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>META-INF/project.properties</include>
</includes>
</resource>
<!-- Raw Resource -->
<resource>
<directory>src/main/resources</directory>

Просмотреть файл

@ -10,6 +10,9 @@ import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.redis.RedisCache;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoConfiguration;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureProperties;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -21,6 +24,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.annotation.PostConstruct;
import java.io.IOException;
/**
@ -35,6 +39,14 @@ import java.io.IOException;
@EnableConfigurationProperties(AzureRedisProperties.class)
public class AzureRedisAutoConfiguration {
@Autowired(required = false)
private TelemetryTracker telemetryTracker;
@PostConstruct
public void triggerTelemetry() {
TelemetryUtils.telemetryTriggerEvent(telemetryTracker, getClass().getSimpleName());
}
@ConditionalOnMissingBean
@Primary
@Bean

Просмотреть файл

@ -7,6 +7,7 @@
package com.microsoft.azure.spring.cloud.autoconfigure.context;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
import com.microsoft.azure.spring.cloud.context.core.CredentialsProvider;
import com.microsoft.azure.spring.cloud.context.core.DefaultCredentialsProvider;
@ -53,4 +54,10 @@ public class AzureContextAutoConfiguration {
public Azure azure() throws IOException {
return Azure.authenticate(credentialsProvider().getCredentials()).withDefaultSubscription();
}
@Bean
@ConditionalOnProperty(name = "spring.cloud.azure.telemetryAllowed", havingValue = "true", matchIfMissing = true)
public TelemetryTracker telemetryTracker(Azure azure, AzureProperties azureProperties) {
return new TelemetryTracker(azure, azureProperties.getResourceGroup());
}
}

Просмотреть файл

@ -7,36 +7,20 @@
package com.microsoft.azure.spring.cloud.autoconfigure.context;
import com.microsoft.azure.spring.cloud.context.core.CredentialSupplier;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Getter
@Setter
@ConfigurationProperties("spring.cloud.azure")
public class AzureProperties implements CredentialSupplier {
private String credentialFilePath;
private String resourceGroup;
private String region;
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getCredentialFilePath() {
return this.credentialFilePath;
}
public void setCredentialFilePath(String credentialFilePath) {
this.credentialFilePath = credentialFilePath;
}
public String getResourceGroup() {
return this.resourceGroup;
}
public void setResourceGroup(String resourceGroup) {
this.resourceGroup = resourceGroup;
}
private boolean telemetryAllowed = true;
}

Просмотреть файл

@ -6,14 +6,15 @@
package com.microsoft.azure.spring.cloud.autoconfigure.eventhub;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.eventhub.AuthorizationRule;
import com.microsoft.azure.management.eventhub.EventHub;
import com.microsoft.azure.management.eventhub.EventHubAuthorizationKey;
import com.microsoft.azure.management.eventhub.EventHubNamespace;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoConfiguration;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureProperties;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryUtils;
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -26,6 +27,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.annotation.PostConstruct;
import java.util.Arrays;
/**
@ -50,6 +52,14 @@ public class AzureEventHubAutoConfiguration {
private static final String SASL_MECHANISM_PLAIN = "PLAIN";
private static final int PORT = 9093;
@Autowired(required = false)
private TelemetryTracker telemetryTracker;
@PostConstruct
public void triggerTelemetry() {
TelemetryUtils.telemetryTriggerEvent(telemetryTracker, getClass().getSimpleName());
}
@ConditionalOnMissingBean
@Primary
@Bean

Просмотреть файл

@ -7,7 +7,10 @@
package com.microsoft.azure.spring.cloud.autoconfigure.sql;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoConfiguration;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryUtils;
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -25,6 +28,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
/**
@ -42,6 +46,14 @@ import javax.sql.DataSource;
@AutoConfigureAfter(AzureContextAutoConfiguration.class)
public class AzureSqlAutoConfiguration {
@Autowired(required = false)
private TelemetryTracker telemetryTracker;
@PostConstruct
public void triggerTelemetry() {
TelemetryUtils.telemetryTriggerEvent(telemetryTracker, getClass().getSimpleName());
}
/**
* The Sql Server Configuration for the {@link SqlServerJdbcDataSourcePropertiesUpdater}
* based on the {@link DatabaseType#SQLSERVER}.
@ -53,6 +65,7 @@ public class AzureSqlAutoConfiguration {
@Bean
public JdbcDataSourcePropertiesUpdater defaultSqlServerJdbcInfoProvider(AzureSqlProperties
azureSqlProperties, AzureAdmin azureAdmin) {
return new SqlServerJdbcDataSourcePropertiesUpdater(azureSqlProperties, azureAdmin);
}
}

Просмотреть файл

@ -6,16 +6,18 @@
package com.microsoft.azure.spring.cloud.autoconfigure.storage;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.storage.StorageAccount;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoConfiguration;
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureProperties;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryUtils;
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
import com.microsoft.azure.spring.cloud.context.core.AzureUtil;
import com.microsoft.azure.spring.cloud.storage.AzureStorageProtocolResolver;
import com.microsoft.azure.storage.CloudStorageAccount;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -25,6 +27,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import javax.annotation.PostConstruct;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
@ -42,6 +45,14 @@ import java.security.InvalidKeyException;
public class AzureStorageAutoConfiguration {
private static final Log LOGGER = LogFactory.getLog(AzureStorageAutoConfiguration.class);
@Autowired(required = false)
private TelemetryTracker telemetryTracker;
@PostConstruct
public void triggerTelemetry() {
TelemetryUtils.telemetryTriggerEvent(telemetryTracker, getClass().getSimpleName());
}
@Bean
@ConditionalOnMissingBean
public CloudStorageAccount storage(AzureAdmin azureAdmin, AzureProperties azureProperties,

Просмотреть файл

@ -0,0 +1,59 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.cloud.autoconfigure.telemetry;
import com.microsoft.applicationinsights.TelemetryClient;
import com.microsoft.azure.management.Azure;
import org.springframework.lang.NonNull;
import java.util.HashMap;
import java.util.Map;
public class TelemetryTracker {
private static final String PROJECT_VERSION = TelemetryTracker.class.getPackage().getImplementationVersion();
private static final String PROJECT_INFO = "spring-cloud-azure" + "/" + PROJECT_VERSION;
private static final String PROPERTY_VERSION = "version";
private static final String PROPERTY_INSTALLATION_ID = "installationId";
private static final String PROPERTY_SUBSCRIPTION_ID = "subscriptionId";
private static final String PROPERTY_RESOURCE_GROUP = "resourceGroup";
private static final String PROPERTY_SERVICE_NAME = "serviceName";
private final TelemetryClient client;
private final Map<String, String> defaultProperties;
public TelemetryTracker(Azure azure, String resourceGroup) {
this.client = new TelemetryClient();
this.defaultProperties = new HashMap<>();
this.defaultProperties.put(PROPERTY_SUBSCRIPTION_ID, azure.getCurrentSubscription().subscriptionId());
this.defaultProperties.put(PROPERTY_RESOURCE_GROUP, resourceGroup);
this.defaultProperties.put(PROPERTY_VERSION, PROJECT_INFO);
this.defaultProperties.put(PROPERTY_INSTALLATION_ID, TelemetryUtils.getHashMac());
}
private void trackEvent(@NonNull String name, @NonNull Map<String, String> customProperties) {
this.defaultProperties.forEach(customProperties::putIfAbsent);
this.client.trackEvent(name, customProperties, null);
this.client.flush();
}
public void trackEventWithServiceName(@NonNull String eventName, @NonNull String serviceName) {
final Map<String, String> properties = new HashMap<>();
properties.put(PROPERTY_SERVICE_NAME, serviceName);
this.trackEvent(eventName, properties);
}
}

Просмотреть файл

@ -0,0 +1,52 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.cloud.autoconfigure.telemetry;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import static com.microsoft.applicationinsights.core.dependencies.apachecommons.codec.digest.DigestUtils.sha256Hex;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TelemetryUtils {
private static final String UNKNOWN_MAC = "Unknown-Mac-Address";
private static final String EVENT_NAME = "spring-cloud-azure";
private static String getMacAddress() {
try {
final InetAddress host = InetAddress.getLocalHost();
final byte[] macBytes = NetworkInterface.getByInetAddress(host).getHardwareAddress();
return new String(macBytes);
} catch (UnknownHostException | SocketException e) { // Ignore
return UNKNOWN_MAC;
}
}
public static String getHashMac() {
final String mac = getMacAddress();
if (mac.equals(UNKNOWN_MAC)) {
return UNKNOWN_MAC;
}
return sha256Hex(mac);
}
public static void telemetryTriggerEvent(TelemetryTracker tracker, String serviceName) {
if (tracker != null) {
tracker.trackEventWithServiceName(EVENT_NAME, serviceName);
}
}
}

Просмотреть файл

@ -7,6 +7,8 @@
package com.microsoft.azure.spring.cloud.autoconfigure.context;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.resources.Subscription;
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
import com.microsoft.azure.spring.cloud.context.core.CredentialsProvider;
import org.junit.Test;
@ -17,6 +19,7 @@ import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
public class AzureContextAutoConfigurationTest {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
@ -37,12 +40,36 @@ public class AzureContextAutoConfigurationTest {
});
}
@Test
public void testAzurePropertiesTelemetryMissing() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.credentialFilePath=credential")
.withPropertyValues("spring.cloud.azure.resourceGroup=group1")
.run(context -> assertThat(context.getBean(TelemetryTracker.class)).isNotNull());
}
@Test
public void testAzurePropertiesTelemetryConfigured() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.credentialFilePath=credential")
.withPropertyValues("spring.cloud.azure.resourceGroup=group1")
.withPropertyValues("spring.cloud.azure.telemetryAllowed=true")
.run(context -> assertThat(context.getBean(TelemetryTracker.class)).isNotNull());
}
@Test
public void testAzurePropertiesTelemetryConfiguredException() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.credentialFilePath=credential")
.withPropertyValues("spring.cloud.azure.resourceGroup=group1")
.withPropertyValues("spring.cloud.azure.telemetryAllowed=false")
.run(context -> assertThat(context).doesNotHaveBean(TelemetryTracker.class));
}
@Test
public void testWithoutAzureProperties() {
this.contextRunner
.run(context -> {
assertThat(context).doesNotHaveBean(AzureProperties.class);
});
.run(context -> assertThat(context).doesNotHaveBean(AzureProperties.class));
}
@Configuration
@ -55,7 +82,13 @@ public class AzureContextAutoConfigurationTest {
@Bean
Azure azure() {
return mock(Azure.class);
final Azure azure = mock(Azure.class);
final Subscription subscription = mock(Subscription.class);
when(azure.getCurrentSubscription()).thenReturn(subscription);
when(subscription.subscriptionId()).thenReturn("Fake-Id");
return azure;
}
@Bean