2020 */
2121package 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-
3523import com .microsoft .applicationinsights .alerting .alert .AlertBreach ;
3624import com .microsoft .applicationinsights .alerting .alert .AlertMetricType ;
3725import com .microsoft .applicationinsights .alerting .config .AlertingConfiguration .AlertConfiguration ;
4836import org .slf4j .Logger ;
4937import 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 */
5658public 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 ;
0 commit comments