3232 */
3333public final class Config {
3434 private static final String PYROSCOPE_AGENT_ENABLED_CONFIG = "PYROSCOPE_AGENT_ENABLED" ;
35+ private static final String PYROSCOPE_PROFILING_MODE = "PYROSCOPE_PROFILING_MODE" ;
36+ private static final String PYROSCOPE_PULL_BIND_ADDRESS = "PYROSCOPE_PULL_BIND_ADDRESS" ;
37+ private static final String PYROSCOPE_PULL_PORT = "PYROSCOPE_PULL_PORT" ;
3538 private static final String PYROSCOPE_APPLICATION_NAME_CONFIG = "PYROSCOPE_APPLICATION_NAME" ;
3639 private static final String PYROSCOPE_PROFILING_INTERVAL_CONFIG = "PYROSCOPE_PROFILING_INTERVAL" ;
3740 private static final String PYROSCOPE_PROFILER_TYPE_CONFIG = "PYROSCOPE_PROFILER_TYPE" ;
@@ -82,6 +85,8 @@ public final class Config {
8285 private static final String PYROSCOPE_JFR_PROFILER_SETTINGS = "PYROSCOPE_JFR_PROFILER_SETTINGS" ;
8386
8487 private static final boolean DEFAULT_AGENT_ENABLED = true ;
88+ private static final String DEFAULT_PULL_BIND_ADDRESS = "127.0.0.1" ;
89+ private static final int DEFAULT_PULL_PORT = 4041 ;
8590 public static final String DEFAULT_SPY_NAME = "javaspy" ;
8691 private static final Duration DEFAULT_PROFILING_INTERVAL = Duration .ofMillis (10 );
8792 private static final EventType DEFAULT_PROFILER_EVENT = EventType .ITIMER ;
@@ -104,6 +109,9 @@ public final class Config {
104109 private static final Duration DEFAULT_PROFILE_EXPORT_TIMEOUT = Duration .ofSeconds (10 );
105110
106111 public final boolean agentEnabled ;
112+ public final ProfilingMode profilingMode ;
113+ public final String pullBindAddress ;
114+ public final int pullPort ;
107115 public final String applicationName ;
108116 public final ProfilerType profilerType ;
109117 public final Duration profilingInterval ;
@@ -171,8 +179,37 @@ public final class Config {
171179 String basicAuthUser ,
172180 String basicAuthPassword ,
173181 Duration profileExportTimeout ,
174- @ Nullable Path tmpDir ) {
182+ @ Nullable Path tmpDir ,
183+ ProfilingMode profilingMode ,
184+ String pullBindAddress ,
185+ int pullPort ) {
175186 this .agentEnabled = agentEnabled ;
187+ this .profilingMode = checkNotNull (profilingMode , "profilingMode" );
188+ this .pullBindAddress = checkNotNull (pullBindAddress , "pullBindAddress" ).trim ();
189+ this .pullPort = pullPort ;
190+ if (profilingMode == ProfilingMode .PULL ) {
191+ if (this .pullBindAddress .isEmpty () || pullPort < 0 || pullPort > 65535 ) {
192+ throw new IllegalArgumentException ("Invalid pull listener address or port" );
193+ }
194+ if (format != Format .PPROF || profilerType != ProfilerType .ASYNC ) {
195+ throw new IllegalArgumentException ("Pull mode requires PPROF format and the ASYNC profiler" );
196+ }
197+ if ((profilingEvent != EventType .CPU && profilingEvent != EventType .ITIMER ) ||
198+ (profilingAlloc != null && !profilingAlloc .isEmpty ()) ||
199+ (profilingLock != null && !profilingLock .isEmpty ()) || allocLive ||
200+ samplingDuration != null || samplingEventOrder != null ) {
201+ throw new IllegalArgumentException ("Pull mode supports only CPU or ITIMER profiling without sampling or additional events" );
202+ }
203+ if (APExtraArguments != null && !APExtraArguments .isEmpty ()) {
204+ throw new IllegalArgumentException ("Pull mode does not support AP extra arguments" );
205+ }
206+ if (profilingInterval .isZero () || profilingInterval .isNegative ()) {
207+ throw new IllegalArgumentException ("Pull mode requires a positive profiling interval" );
208+ }
209+ profilingInterval .toNanos ();
210+ } else if (format == Format .PPROF ) {
211+ throw new IllegalArgumentException ("PPROF format requires pull mode" );
212+ }
176213 this .applicationName = applicationName ;
177214 this .profilerType = profilerType ;
178215 this .profilingInterval = profilingInterval ;
@@ -240,6 +277,9 @@ public long profilingIntervalInHertz() {
240277 public String toString () {
241278 return "Config{" +
242279 "agentEnabled=" + agentEnabled +
280+ ", profilingMode=" + profilingMode +
281+ ", pullBindAddress='" + pullBindAddress + '\'' +
282+ ", pullPort=" + pullPort +
243283 ", applicationName='" + applicationName + '\'' +
244284 ", profilerType=" + profilerType +
245285 ", profilingInterval=" + profilingInterval +
@@ -322,7 +362,10 @@ private static long durationToHertz(Duration duration) {
322362 cp .get (PYROSCOPE_AP_EXTRA_ARGUMENTS_CONFIG ),
323363 cp .get (PYROSCOPE_BASIC_AUTH_USER_CONFIG ), cp .get (PYROSCOPE_BASIC_AUTH_PASSWORD_CONFIG ),
324364 profileExportTimeout (cp ),
325- tmpDir (cp ));
365+ tmpDir (cp ),
366+ profilingMode (cp ),
367+ pullBindAddress (cp ),
368+ pullPort (cp ));
326369 }
327370
328371 /**
@@ -567,12 +610,30 @@ private static Format format(ConfigurationProvider configurationProvider) {
567610 return Format .JFR ;
568611 case "otlp" :
569612 return Format .OTLP ;
613+ case "pprof" :
614+ return Format .PPROF ;
570615 default :
571616 DefaultLogger .PRECONFIG_LOGGER .log (Logger .Level .WARN , "Unknown format %s, using %s" , format , DEFAULT_FORMAT );
572617 return DEFAULT_FORMAT ;
573618 }
574619 }
575620
621+ private static ProfilingMode profilingMode (ConfigurationProvider cp ) {
622+ String value = cp .get (PYROSCOPE_PROFILING_MODE );
623+ return value == null || value .isEmpty () ? ProfilingMode .PUSH :
624+ ProfilingMode .valueOf (value .trim ().toUpperCase (Locale .ROOT ));
625+ }
626+
627+ private static String pullBindAddress (ConfigurationProvider cp ) {
628+ String value = cp .get (PYROSCOPE_PULL_BIND_ADDRESS );
629+ return value == null ? DEFAULT_PULL_BIND_ADDRESS : value ;
630+ }
631+
632+ private static int pullPort (ConfigurationProvider cp ) {
633+ String value = cp .get (PYROSCOPE_PULL_PORT );
634+ return value == null || value .isEmpty () ? DEFAULT_PULL_PORT : Integer .parseInt (value );
635+ }
636+
576637 private static int pushQueueCapacity (ConfigurationProvider configurationProvider ) {
577638 final String strPushQueueCapacity = configurationProvider .get (PYROSCOPE_PUSH_QUEUE_CAPACITY_CONFIG );
578639 if (strPushQueueCapacity == null || strPushQueueCapacity .isEmpty ()) {
@@ -732,6 +793,9 @@ private static Duration samplingDuration(ConfigurationProvider configurationProv
732793
733794 public static class Builder {
734795 private boolean agentEnabled = DEFAULT_AGENT_ENABLED ;
796+ private ProfilingMode profilingMode = ProfilingMode .PUSH ;
797+ private String pullBindAddress = DEFAULT_PULL_BIND_ADDRESS ;
798+ private int pullPort = DEFAULT_PULL_PORT ;
735799 private String applicationName = null ;
736800 private ProfilerType profilerType = ProfilerType .ASYNC ;
737801 private Duration profilingInterval = DEFAULT_PROFILING_INTERVAL ;
@@ -770,6 +834,9 @@ public Builder() {
770834 public Builder (@ NotNull Config buildUpon ) {
771835 checkNotNull (buildUpon , "config" );
772836 agentEnabled = buildUpon .agentEnabled ;
837+ profilingMode = buildUpon .profilingMode ;
838+ pullBindAddress = buildUpon .pullBindAddress ;
839+ pullPort = buildUpon .pullPort ;
773840 applicationName = buildUpon .applicationName ;
774841 profilerType = buildUpon .profilerType ;
775842 profilingInterval = buildUpon .profilingInterval ;
@@ -807,6 +874,21 @@ public Builder setAgentEnabled(boolean agentEnabled) {
807874 return this ;
808875 }
809876
877+ public Builder setProfilingMode (ProfilingMode profilingMode ) {
878+ this .profilingMode = profilingMode ;
879+ return this ;
880+ }
881+
882+ public Builder setPullBindAddress (String pullBindAddress ) {
883+ this .pullBindAddress = pullBindAddress ;
884+ return this ;
885+ }
886+
887+ public Builder setPullPort (int pullPort ) {
888+ this .pullPort = pullPort ;
889+ return this ;
890+ }
891+
810892 public Builder setApplicationName (String applicationName ) {
811893 this .applicationName = applicationName ;
812894 return this ;
@@ -1013,7 +1095,10 @@ public Builder setTmpDir(@Nullable String tmpDir) {
10131095 APExtraArguments ,
10141096 basicAuthUser , basicAuthPassword ,
10151097 profileExportTimeout ,
1016- tmpDir );
1098+ tmpDir ,
1099+ profilingMode ,
1100+ pullBindAddress ,
1101+ pullPort );
10171102 }
10181103 }
10191104}
0 commit comments