Skip to content

Commit

Permalink
Merge pull request #631 from Microsoft/HeartBeat
Browse files Browse the repository at this point in the history
HeartBeat Feature Implementation
  • Loading branch information
dhaval24 authored Apr 20, 2018
2 parents f39dc55 + 7531583 commit 7e37691
Show file tree
Hide file tree
Showing 15 changed files with 1,597 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

# Version 2.1.0
- Introduced Heartbeat feature which sends periodic heartbeats with basic information about application and runtime to Application Insights.

## Version 2.0.2
- Fix incorrect success flag set when capturing HTTP Dependency.
- Fix [#577](https://github.com/Microsoft/ApplicationInsights-Java/issues/577), removed HttpFactory class as it was not being used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,11 @@ public void setInstrumentationKey(String key) {

instrumentationKey = key;
}

/**
* Method for tear down in tests
*/
private static void setActiveAsNull() {
active = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

package com.microsoft.applicationinsights.internal.config;

import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule;
import java.io.InputStream;
import java.util.Map;
import java.util.List;
Expand Down Expand Up @@ -119,7 +120,9 @@ public final void initialize(TelemetryConfiguration configuration) {
private void setMinimumConfiguration(ApplicationInsightsXmlConfiguration userConfiguration, TelemetryConfiguration configuration) {
setInstrumentationKey(userConfiguration, configuration);
configuration.setChannel(new InProcessTelemetryChannel());
addHeartBeatModule(configuration);
setContextInitializers(null, configuration);
initializeComponents(configuration);
}

private void setInternalLogger(SDKLoggerXmlElement sdkLogger, TelemetryConfiguration configuration) {
Expand Down Expand Up @@ -173,7 +176,13 @@ private void setTelemetryModules(ApplicationInsightsXmlConfiguration appConfigur
ReflectionUtils.loadComponents(TelemetryModule.class, modules, configurationModules.getAdds());
}

//if heartbeat module is not loaded, load heartbeat module
if (!isHeartBeatModuleAdded(modules)) {
addHeartBeatModule(configuration);
}

List<TelemetryModule> pcModules = getPerformanceModules(appConfiguration.getPerformance());

modules.addAll(pcModules);
}

Expand Down Expand Up @@ -502,6 +511,27 @@ private void initializeComponents(TelemetryConfiguration configuration) {
}
}

/**
* Adds heartbeat module with default configuration
* @param configuration TelemetryConfiguration Instance
*/
private void addHeartBeatModule(TelemetryConfiguration configuration) {
HeartBeatModule module = new HeartBeatModule(new HashMap<String, String>());
configuration.getTelemetryModules().add(module);
}

/**
* Checks if heartbeat module is present
* @param module List of modules in current TelemetryConfiguration Instance
* @return true if heartbeat module is present
*/
private boolean isHeartBeatModuleAdded(List<TelemetryModule> module) {
for (TelemetryModule mod : module) {
if (mod instanceof HeartBeatModule) return true;
}
return false;
}

void setPerformanceCountersSection(String performanceCountersSection) {
this.performanceCountersSection = performanceCountersSection;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.microsoft.applicationinsights.internal.heartbeat;

import com.microsoft.applicationinsights.internal.logger.InternalLogger;
import com.microsoft.applicationinsights.internal.util.PropertyHelper;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.apache.commons.lang3.exception.ExceptionUtils;

/**
* <h1>Base Heartbeat Property Provider</h1>
*
* <p>
* This class is a concrete implementation of {@link HeartBeatPayloadProviderInterface}
* It enables setting SDK Metadata to heartbeat payload.
* </p>
*
* @author Dhaval Doshi
*/
public class DefaultHeartBeatPropertyProvider implements HeartBeatPayloadProviderInterface {

/**
* Collection holding default properties for this default provider.
*/
private final Set<String> defaultFields;

/**
* Random GUID that would help in analysis when app has stopped and restarted. Each restart will
* have a new GUID. If the application is unstable and goes through frequent restarts this will help
* us identify instability in the analytics backend.
*/
private static UUID uniqueProcessId;

/**
* Name of this provider.
*/
private final String name = "Default";

private final String JRE_VERSION = "jreVersion";

private final String SDK_VERSION = "sdkVersion";

private final String OS_VERSION = "osVersion";

private final String PROCESS_SESSION_ID = "processSessionId";

public DefaultHeartBeatPropertyProvider() {
defaultFields = new HashSet<>();
initializeDefaultFields(defaultFields);
}

@Override
public String getName() {
return this.name;
}

@Override
public boolean isKeyword(String keyword) {
return defaultFields.contains(keyword);
}

@Override
public Callable<Boolean> setDefaultPayload(final List<String> disableFields,
final HeartBeatProviderInterface provider) {
return new Callable<Boolean>() {

Set<String> enabledProperties = MiscUtils.except(disableFields, defaultFields);
@Override
public Boolean call() {
boolean hasSetValues = false;
for (String fieldName : enabledProperties) {
try {
switch (fieldName) {
case JRE_VERSION:
provider.addHeartBeatProperty(fieldName, getJreVersion(), true);
hasSetValues = true;
break;
case SDK_VERSION:
provider.addHeartBeatProperty(fieldName, getSdkVersion(), true);
hasSetValues = true;
break;
case OS_VERSION:
provider.addHeartBeatProperty(fieldName, getOsVersion(), true);
hasSetValues = true;
break;
case PROCESS_SESSION_ID:
provider.addHeartBeatProperty(fieldName, getProcessSessionId(), true);
hasSetValues = true;
break;
default:
//We won't accept unknown properties in default providers.
InternalLogger.INSTANCE.trace("Encountered unknown default property");
break;
}
}
catch (Exception e) {
InternalLogger.INSTANCE.warn("Failed to obtain heartbeat property, stack trace"
+ "is: %s", ExceptionUtils.getStackTrace(e));
}
}
return hasSetValues;
}
};
}

/**
* This method initializes the collection with Default Properties of this provider.
* @param defaultFields collection to hold default properties.
*/
private void initializeDefaultFields(Set<String> defaultFields) {

if (defaultFields == null) {
defaultFields = new HashSet<>();
}
defaultFields.add(JRE_VERSION);
defaultFields.add(SDK_VERSION);
defaultFields.add(OS_VERSION);
defaultFields.add(PROCESS_SESSION_ID);
}

/**
* Gets the JDK version being used by the application
* @return String representing JDK Version
*/
private String getJreVersion() {
return System.getProperty("java.version");
}

/**
* Returns the Application Insights SDK version user is using to instrument his application
* @return returns string prefixed with "java" representing the Application Insights Java
* SDK version.
*/
private String getSdkVersion() {

String sdkVersion = "java";

Properties sdkVersionProps = PropertyHelper.getSdkVersionProperties();
if (sdkVersionProps != null) {
String version = sdkVersionProps.getProperty("version");
sdkVersion = String.format("java:%s", version);
return sdkVersion;
}
return sdkVersion + ":unknown-version";
}

/**
* Gets the OS version on which application is running.
* @return String representing OS version
*/
private String getOsVersion() {
return System.getProperty("os.name");
}

/**
* Returns the Unique GUID for the application's current session.
* @return String representing GUID for each running session
*/
private String getProcessSessionId() {
if (uniqueProcessId == null) {
uniqueProcessId = UUID.randomUUID();
}
return uniqueProcessId.toString();
}
}
Loading

0 comments on commit 7e37691

Please sign in to comment.