-
Notifications
You must be signed in to change notification settings - Fork 9
Adds support for Microsoft Azure Application Insights(AppInsights) as a datastore for Zipkin #27
Changes from all commits
de546ef
e4401f2
3b4bc0a
5184e7c
b894c0b
f9912ea
c563faf
78a8ebd
219c4f1
71d4cec
735e056
249284b
607f59c
ab7fc99
795b03a
98cfa3d
ae56314
534f785
2d16b45
a63bf61
40950a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
|
||
Copyright 2017 The OpenZipkin Authors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
in compliance with the License. You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software distributed under the License | ||
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
or implied. See the License for the specific language governing permissions and limitations under | ||
the License. | ||
|
||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<groupId>io.zipkin.azure</groupId> | ||
<version>0.1.7-SNAPSHOT</version> | ||
<artifactId>zipkin-autoconfigure-parent</artifactId> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>zipkin-autoconfigure-storage-applicationinsights</artifactId> | ||
<name>Zipkin Auto Configuration: Azure Application Insights Storage</name> | ||
|
||
<properties> | ||
<main.basedir>${project.basedir}/../..</main.basedir> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.zipkin.azure</groupId> | ||
<artifactId>zipkin-storage-applicationinsights</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<!--<version>3.8.1</version>--> | ||
<version>4.12</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
<version>19.0</version> | ||
</dependency> | ||
<!--<dependency>--> | ||
<!--<groupId>io.zipkin.brave</groupId>--> | ||
<!--<artifactId>brave-core</artifactId>--> | ||
<!--<version>${brave.version}</version>--> | ||
<!--<optional>true</optional>--> | ||
<!--</dependency>--> | ||
</dependencies> | ||
<!--to do: got to check build contents - got it from autoconfigure-collector-eventhub--> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-maven-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>repackage</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
<configuration> | ||
<layout>MODULE</layout> | ||
<classifier>module</classifier> | ||
<!-- https://github.com/spring-projects/spring-boot/issues/3426 transitive exclude doesn't work --> | ||
<excludeGroupIds> | ||
io.zipkin.java,org.springframework.boot,org.springframework,commons-codec,com.fasterxml.jackson.core,com.fasterxml.jackson.dataformat,org.apache.httpcomponents,commons-logging,joda-time,software.amazon.ion | ||
</excludeGroupIds> | ||
<!-- already packaged in zipkin-server --> | ||
<excludeArtifactIds>jmespath-java</excludeArtifactIds> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Copyright 2017 The OpenZipkin Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License | ||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
* or implied. See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package zipkin.autoconfigure.storage.applicationinsights; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
import zipkin.storage.StorageComponent; | ||
import zipkin.storage.applicationinsights.ApplicationInsightsStorage; | ||
import java.util.concurrent.Executor; | ||
|
||
/** | ||
* This storage accepts ApplicationInsights logs in a specified category. Each log entry is expected | ||
* to contain a single span, which is TBinaryProtocol big-endian, then base64 encoded. Decoded spans | ||
* are stored asynchronously. | ||
*/ | ||
@Configuration | ||
@EnableConfigurationProperties(ZipkinApplicationInsightsStorageProperties.class) | ||
@ConditionalOnProperty(name = "zipkin.storage.type", havingValue = "applicationinsights") | ||
@ConditionalOnMissingBean(StorageComponent.class) | ||
public class ZipkinApplicationInsightsStorageAutoConfiguration { | ||
|
||
@Bean @ConditionalOnMissingBean(Executor.class) Executor executor() { | ||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||
executor.setThreadNamePrefix("ZipkinApplicationInsightsStorage-"); | ||
executor.initialize(); | ||
return executor; | ||
} | ||
|
||
@Bean StorageComponent storage(Executor executor, | ||
ZipkinApplicationInsightsStorageProperties properties, | ||
@Value("${zipkin.storage.strict-trace-id:true}") boolean strictTraceId) { | ||
return ApplicationInsightsStorage.builder() | ||
.strictTraceId(strictTraceId) | ||
.instrumentationKey(properties.getInstrumentationKey()) | ||
.applicationId(properties.getApplicationId()) | ||
.apikey(properties.getApiKey()) | ||
.executor(executor) | ||
.build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Copyright 2017 The OpenZipkin Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License | ||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
* or implied. See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package zipkin.autoconfigure.storage.applicationinsights; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import zipkin.storage.applicationinsights.ApplicationInsightsStorage; | ||
|
||
@ConfigurationProperties("zipkin.storage.applicationinsights") | ||
public class ZipkinApplicationInsightsStorageProperties { | ||
|
||
private String instrumentationKey; | ||
private String applicationId; | ||
private String apiKey; | ||
|
||
public String getInstrumentationKey() { | ||
return instrumentationKey; | ||
} | ||
|
||
public void setInstrumentationKey(String key) { | ||
this.instrumentationKey = key; | ||
} | ||
|
||
public String getApplicationId() { | ||
return applicationId; | ||
} | ||
|
||
public void setApplicationId(String key) { | ||
this.applicationId = key; | ||
} | ||
|
||
public String getApiKey() { | ||
return apiKey; | ||
} | ||
|
||
public void setApiKey(String key) { | ||
this.apiKey = key; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ | ||
zipkin.autoconfigure.storage.applicationinsights.ZipkinApplicationInsightsStorageAutoConfiguration |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# When enabled, this allows shorter env properties (ex -Dspring.profiles.active=applicationinsights) | ||
zipkin: | ||
storage: | ||
applicationinsights: | ||
instrumentationKey: ${AI_INSTRUMENTATION_KEY:} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if it's a section There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is readable here in config file.. but during actual configuration user jus sets AI_INSTRU... and it would be much clearer to have prefix. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. environment variable for instrumentation key that we typically use is It is not ideal as it uses a wrong name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will change it to APPINSIGHTS.. If thats norm.... i just thought AI_IN... will make the key shorter..and in power shell I often type so less work :) |
||
applicationId: ${AI_APPLICATION_ID:} | ||
apiKey: ${AI_API_KEY:} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how fast are you running to the query limit? Using Azure Active Directory authentication may eliminate this problem, but may be hard to implement. Just a thought in case you have an idea how to fix it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ran few thousands and didn't face much issues. For higher loads .. I am thinking of rotating API_Keys as a solution ..but would like to know about AAD. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/** | ||
* Copyright 2017 The OpenZipkin Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License | ||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
* or implied. See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package zipkin.storage.applicationinsights; | ||
|
||
import org.junit.After; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.ExpectedException; | ||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; | ||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||
import zipkin.autoconfigure.storage.applicationinsights.ZipkinApplicationInsightsStorageAutoConfiguration; | ||
import zipkin.autoconfigure.storage.applicationinsights.ZipkinApplicationInsightsStorageProperties; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment; | ||
|
||
public class ZipkinApplicationInsightsStorageAutoConfigurationTest { | ||
@Rule | ||
public ExpectedException thrown = ExpectedException.none(); | ||
|
||
AnnotationConfigApplicationContext context; | ||
|
||
@After | ||
public void close() { | ||
if (context != null) { | ||
context.close(); | ||
} | ||
} | ||
|
||
@Test | ||
public void doesntProvidesStorageComponent_whenStorageTypeNotApplicationInsights() { | ||
context = new AnnotationConfigApplicationContext(); | ||
addEnvironment(context, "zipkin.storage.type:elasticsearch"); | ||
context.register(PropertyPlaceholderAutoConfiguration.class, | ||
ZipkinApplicationInsightsStorageAutoConfiguration.class); | ||
context.refresh(); | ||
|
||
thrown.expect(NoSuchBeanDefinitionException.class); | ||
context.getBean(ApplicationInsightsStorage.class); | ||
} | ||
|
||
@Test | ||
public void providesStorageComponent_whenStorageTypeApplicationInsights() { | ||
context = new AnnotationConfigApplicationContext(); | ||
addEnvironment(context, "zipkin.storage.type:applicationinsights"); | ||
context.register(PropertyPlaceholderAutoConfiguration.class, | ||
ZipkinApplicationInsightsStorageAutoConfiguration.class); | ||
context.refresh(); | ||
|
||
assertThat(context.getBean(ApplicationInsightsStorage.class)).isNotNull(); | ||
} | ||
|
||
@Test | ||
public void canOverridesProperty_InstrumentationKey() { | ||
context = new AnnotationConfigApplicationContext(); | ||
addEnvironment(context, | ||
"zipkin.storage.type:applicationinsights", | ||
"zipkin.storage.applicationinsights.instrumentationKey:xyz", | ||
"zipkin.storage.applicationinsights.applicationId:abc", | ||
"zipkin.storage.applicationinsights.apiKey:mnm" | ||
); | ||
context.register(PropertyPlaceholderAutoConfiguration.class, | ||
ZipkinApplicationInsightsStorageAutoConfiguration.class); | ||
context.refresh(); | ||
|
||
assertThat( | ||
context.getBean(ZipkinApplicationInsightsStorageProperties.class).getInstrumentationKey()) | ||
.isEqualTo("xyz"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the difference between collector and storage? Should we have Application Insights collector AND storage. So collection part can be used separately from the storage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Collector is the transport protocol(default Http) you listen on ... for receiving spans. Right now we are using Http - so, I guess we might not have a separate AI collector unless you have a better business case where AI collector helps.
You can directly hit your storage with Spans if that is your question. It is fine as long as Zipkin REST API gets the right data while reading.
Collectors like Eventhub could have many clients other than storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can collector be used in-process? So we do not need a sidecar container hosting it? Also it looks to me this is a regular setup. Like here: