Skip to content

Commit 6711a93

Browse files
authored
Add ability to configure JFR profile settings (#1644)
1 parent b890a57 commit 6711a93

File tree

20 files changed

+1624
-114
lines changed

20 files changed

+1624
-114
lines changed

agent/agent-profiler/agent-profiler-api/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ dependencies {
66
implementation project(":agent:agent-profiler:agent-alerting-api")
77
implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: versions.apacheHttpClient
88
implementation group: 'com.squareup.moshi', name: 'moshi', version: versions.moshi
9+
implementation group: 'org.slf4j', name: 'slf4j-api', version: versions.slf4j
910
}

agent/agent-profiler/agent-profiler-api/gradle/dependency-locks/compileClasspath.lockfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ commons-codec:commons-codec:1.11
77
commons-logging:commons-logging:1.2
88
org.apache.httpcomponents:httpclient:4.5.13
99
org.apache.httpcomponents:httpcore:4.4.13
10+
org.slf4j:slf4j-api:1.7.30

agent/agent-profiler/agent-profiler-api/gradle/dependency-locks/runtimeClasspath.lockfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ commons-codec:commons-codec:1.11
77
commons-logging:commons-logging:1.2
88
org.apache.httpcomponents:httpclient:4.5.13
99
org.apache.httpcomponents:httpcore:4.4.13
10+
org.slf4j:slf4j-api:1.7.30

agent/agent-profiler/agent-profiler-api/src/main/java/com/microsoft/applicationinsights/profiler/config/ServiceProfilerServiceConfig.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@
2121
package com.microsoft.applicationinsights.profiler.config;
2222

2323

24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
26+
2427
/**
2528
* Configuration of the service profiler subsystem
2629
*/
2730
public class ServiceProfilerServiceConfig {
31+
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceProfilerServiceConfig.class);
32+
2833
public static final int DEFAULT_CONFIG_POLL_PERIOD_IN_MS = 60000;
2934
public static final int DEFAULT_PERIODIC_RECORDING_DURATION_IN_S = 120;
3035
public static final int DEFAULT_PERIODIC_RECORDING_INTERVAL_IN_S = 60 * 60;
@@ -43,12 +48,28 @@ public class ServiceProfilerServiceConfig {
4348
// Enable entire service profiler subsystem
4449
private final boolean enabled;
4550

46-
public ServiceProfilerServiceConfig(int configPollPeriod, int periodicRecordingDuration, int periodicRecordingInterval, String serviceProfilerFrontEndPoint, boolean enabled) {
51+
// Either an inbuilt profile as defined in ProfileTypes, or a path to a custom JFC file to use for memory profiling
52+
private String memoryTriggeredSettings;
53+
54+
// Either an inbuilt profile as defined in ProfileTypes, or a path to a custom JFC file to use for cpu profiling
55+
private String cpuTriggeredSettings;
56+
57+
public ServiceProfilerServiceConfig(
58+
int configPollPeriod,
59+
int periodicRecordingDuration,
60+
int periodicRecordingInterval,
61+
String serviceProfilerFrontEndPoint,
62+
boolean enabled,
63+
String memoryTriggeredSettings,
64+
String cpuTriggeredSettings
65+
) {
4766
this.configPollPeriod = configPollPeriod;
4867
this.periodicRecordingDuration = periodicRecordingDuration;
4968
this.periodicRecordingInterval = periodicRecordingInterval;
5069
this.serviceProfilerFrontEndPoint = serviceProfilerFrontEndPoint;
5170
this.enabled = enabled;
71+
this.memoryTriggeredSettings = memoryTriggeredSettings;
72+
this.cpuTriggeredSettings = cpuTriggeredSettings;
5273
}
5374

5475
public int getConfigPollPeriod() {
@@ -70,4 +91,12 @@ public String getServiceProfilerFrontEndPoint() {
7091
public boolean enabled() {
7192
return enabled;
7293
}
94+
95+
public String memoryTriggeredSettings() {
96+
return memoryTriggeredSettings;
97+
}
98+
99+
public String cpuTriggeredSettings() {
100+
return cpuTriggeredSettings;
101+
}
73102
}

agent/agent-profiler/agent-service-profiler/gradle/dependency-locks/compileClasspath.lockfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.2
1414
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.12.2
1515
com.fasterxml.jackson:jackson-bom:2.12.2
1616
com.fasterxml.woodstox:woodstox-core:6.2.4
17-
com.microsoft.jfr:jfr-streaming:1.0.0
17+
com.microsoft.jfr:jfr-streaming:1.1.0
1818
com.microsoft.rest.v2:client-runtime:2.1.1
1919
com.squareup.moshi:moshi-adapters:1.9.3
2020
com.squareup.moshi:moshi:1.9.3

agent/agent-profiler/agent-service-profiler/gradle/dependency-locks/runtimeClasspath.lockfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.2
1414
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.12.2
1515
com.fasterxml.jackson:jackson-bom:2.12.2
1616
com.fasterxml.woodstox:woodstox-core:6.2.4
17-
com.microsoft.jfr:jfr-streaming:1.0.0
17+
com.microsoft.jfr:jfr-streaming:1.1.0
1818
com.microsoft.rest.v2:client-runtime:2.1.1
1919
com.squareup.moshi:moshi-adapters:1.9.3
2020
com.squareup.moshi:moshi:1.9.3

agent/agent-profiler/agent-service-profiler/spotbugs.exclude.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@
1212
</And>
1313
</Or>
1414
</Match>
15+
<Match>
16+
<Bug pattern="PATH_TRAVERSAL_IN" />
17+
<Or>
18+
<And>
19+
<Class name="com.microsoft.applicationinsights.serviceprofilerapi.profiler.JfrProfiler" />
20+
<Method name="getRecordingConfiguration" />
21+
</And>
22+
</Or>
23+
</Match>
1524
<Match>
1625
<Bug pattern="RV_RETURN_VALUE_IGNORED" />
1726
<Or>

agent/agent-profiler/agent-service-profiler/src/main/java/com/microsoft/applicationinsights/serviceprofilerapi/profiler/JfrProfiler.java

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,6 @@
2020
*/
2121
package com.microsoft.applicationinsights.serviceprofilerapi.profiler;
2222

23-
import java.io.File;
24-
import java.io.IOException;
25-
import java.lang.management.ManagementFactory;
26-
import java.time.Duration;
27-
import java.time.Instant;
28-
import java.util.concurrent.CompletableFuture;
29-
import java.util.concurrent.ScheduledExecutorService;
30-
import java.util.concurrent.TimeUnit;
31-
import java.util.function.Consumer;
32-
import javax.management.InstanceNotFoundException;
33-
import javax.management.MBeanServerConnection;
34-
3523
import com.microsoft.applicationinsights.alerting.alert.AlertBreach;
3624
import com.microsoft.applicationinsights.alerting.alert.AlertMetricType;
3725
import com.microsoft.applicationinsights.alerting.config.AlertingConfiguration.AlertConfiguration;
@@ -48,13 +36,29 @@
4836
import org.slf4j.Logger;
4937
import org.slf4j.LoggerFactory;
5038

39+
import javax.management.InstanceNotFoundException;
40+
import javax.management.MBeanServerConnection;
41+
import java.io.File;
42+
import java.io.FileInputStream;
43+
import java.io.FileNotFoundException;
44+
import java.io.IOException;
45+
import java.lang.management.ManagementFactory;
46+
import java.time.Duration;
47+
import java.time.Instant;
48+
import java.util.concurrent.CompletableFuture;
49+
import java.util.concurrent.ScheduledExecutorService;
50+
import java.util.concurrent.TimeUnit;
51+
import java.util.function.Consumer;
52+
5153
/**
5254
* Manages connecting JFR interaction:
5355
* - Instantiates FlightRecorder subsystem
5456
* - Creates profiles on demand
5557
*/
5658
public class JfrProfiler implements ProfilerConfigurationHandler, Profiler {
5759
private static final Logger LOGGER = LoggerFactory.getLogger(JfrProfiler.class);
60+
public static final String REDUCED_MEMORY_PROFILE = "reduced-memory-profile.jfc";
61+
public static final String REDUCED_CPU_PROFILE = "reduced-cpu-profile.jfc";
5862

5963
// service execution context
6064
private ScheduledExecutorService scheduledExecutorService;
@@ -64,13 +68,15 @@ public class JfrProfiler implements ProfilerConfigurationHandler, Profiler {
6468

6569
private FlightRecorderConnection flightRecorderConnection;
6670
private RecordingOptions recordingOptions;
67-
private RecordingConfiguration recordingConfiguration;
6871

6972
private AlertConfiguration periodicConfig;
7073

7174
private final Object activeRecordingLock = new Object();
7275
private Recording activeRecording = null;
7376

77+
private final RecordingConfiguration memoryRecordingConfiguration;
78+
private final RecordingConfiguration cpuRecordingConfiguration;
79+
7480
public JfrProfiler(ServiceProfilerServiceConfig configuration) {
7581
periodicConfig = new AlertConfiguration(
7682
AlertMetricType.PERIODIC,
@@ -79,6 +85,42 @@ public JfrProfiler(ServiceProfilerServiceConfig configuration) {
7985
configuration.getPeriodicRecordingDuration(),
8086
configuration.getPeriodicRecordingInterval()
8187
);
88+
89+
memoryRecordingConfiguration = getMemoryProfileConfig(configuration);
90+
cpuRecordingConfiguration = getCpuProfileConfig(configuration);
91+
}
92+
93+
private RecordingConfiguration getMemoryProfileConfig(ServiceProfilerServiceConfig configuration) {
94+
return getRecordingConfiguration(configuration.memoryTriggeredSettings(), REDUCED_MEMORY_PROFILE);
95+
}
96+
97+
private RecordingConfiguration getCpuProfileConfig(ServiceProfilerServiceConfig configuration) {
98+
return getRecordingConfiguration(configuration.cpuTriggeredSettings(), REDUCED_CPU_PROFILE);
99+
}
100+
101+
private RecordingConfiguration getRecordingConfiguration(String triggeredSettings, String reducedProfile) {
102+
if (triggeredSettings != null) {
103+
try {
104+
ProfileTypes profile = ProfileTypes.valueOf(triggeredSettings);
105+
106+
if (profile == ProfileTypes.profile) {
107+
return RecordingConfiguration.PROFILE_CONFIGURATION;
108+
} else if (profile == ProfileTypes.profile_without_env_data) {
109+
return new RecordingConfiguration.JfcFileConfiguration(JfrProfiler.class.getResourceAsStream(reducedProfile));
110+
}
111+
} catch (IllegalArgumentException e) {
112+
//NOP, to be expected if a file is provided
113+
}
114+
115+
try {
116+
FileInputStream fis = new FileInputStream(triggeredSettings);
117+
return new RecordingConfiguration.JfcFileConfiguration(fis);
118+
} catch (FileNotFoundException e) {
119+
LOGGER.error("Failed to find custom JFC file " + triggeredSettings + " using default profile");
120+
}
121+
}
122+
123+
return RecordingConfiguration.PROFILE_CONFIGURATION;
82124
}
83125

84126
/**
@@ -93,7 +135,6 @@ public boolean initialize(ProfileHandler profileHandler, ScheduledExecutorServic
93135

94136
// TODO - allow user configuration of profile options
95137
recordingOptions = new RecordingOptions.Builder().build();
96-
recordingConfiguration = RecordingConfiguration.PROFILE_CONFIGURATION;
97138

98139
try {
99140
// connect to mbeans
@@ -119,16 +160,25 @@ public void updateConfiguration(ProfilerConfiguration newConfig) {
119160

120161
protected void profileAndUpload(AlertBreach alertBreach, Duration duration) {
121162
Instant recordingStart = Instant.now();
122-
executeProfile(duration, uploadNewRecording(alertBreach, recordingStart));
163+
executeProfile(alertBreach.getType(), duration, uploadNewRecording(alertBreach, recordingStart));
123164
}
124165

125-
private Recording startRecording() {
166+
private Recording startRecording(AlertMetricType alertType) {
126167
synchronized (activeRecordingLock) {
127168
if (activeRecording != null) {
128169
LOGGER.warn("Alert received, however a profile is already in progress, ignoring request.");
129170
return null;
130171
}
131172

173+
RecordingConfiguration recordingConfiguration;
174+
if (alertType == AlertMetricType.CPU) {
175+
recordingConfiguration = cpuRecordingConfiguration;
176+
} else if (alertType == AlertMetricType.MEMORY) {
177+
recordingConfiguration = memoryRecordingConfiguration;
178+
} else {
179+
recordingConfiguration = RecordingConfiguration.PROFILE_CONFIGURATION;
180+
}
181+
132182
activeRecording = flightRecorderConnection.newRecording(recordingOptions, recordingConfiguration);
133183
return activeRecording;
134184
}
@@ -137,7 +187,7 @@ private Recording startRecording() {
137187
/**
138188
* Perform a profile and notify the handler
139189
*/
140-
protected void executeProfile(Duration duration, Consumer<Recording> handler) {
190+
protected void executeProfile(AlertMetricType alertType, Duration duration, Consumer<Recording> handler) {
141191

142192
LOGGER.info("Starting profile");
143193

@@ -146,7 +196,7 @@ protected void executeProfile(Duration duration, Consumer<Recording> handler) {
146196
return;
147197
}
148198

149-
Recording newRecording = startRecording();
199+
Recording newRecording = startRecording(alertType);
150200

151201
if (newRecording == null) {
152202
return;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.microsoft.applicationinsights.serviceprofilerapi.profiler;
2+
3+
public enum ProfileTypes {
4+
profile,
5+
profile_without_env_data;
6+
}

0 commit comments

Comments
 (0)