diff --git a/spm-monitor-generic/pom.xml b/spm-monitor-generic/pom.xml
index ceac8e7c..aba2e0e1 100644
--- a/spm-monitor-generic/pom.xml
+++ b/spm-monitor-generic/pom.xml
@@ -78,7 +78,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.5.0
org.apache.maven.plugins
diff --git a/spm-monitor-parent/pom.xml b/spm-monitor-parent/pom.xml
index c15b6e0f..bccc1f1b 100644
--- a/spm-monitor-parent/pom.xml
+++ b/spm-monitor-parent/pom.xml
@@ -40,7 +40,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.5.0
package-shaded-implementation-jar
diff --git a/spm-monitor-redis/pom.xml b/spm-monitor-redis/pom.xml
index 1100598f..b467886a 100644
--- a/spm-monitor-redis/pom.xml
+++ b/spm-monitor-redis/pom.xml
@@ -68,7 +68,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.5.0
org.apache.maven.plugins
diff --git a/spm-monitor-storm/pom.xml b/spm-monitor-storm/pom.xml
index 4c544c97..046f072f 100644
--- a/spm-monitor-storm/pom.xml
+++ b/spm-monitor-storm/pom.xml
@@ -96,7 +96,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.5.0
package-shaded-implementation-jar
diff --git a/spm-monitor/pom.xml b/spm-monitor/pom.xml
index 96711797..2fda59c4 100644
--- a/spm-monitor/pom.xml
+++ b/spm-monitor/pom.xml
@@ -63,6 +63,13 @@
compile
+
+ io.pyroscope
+ agent
+ 0.13.0
+ compile
+
+
diff --git a/spm-monitor/src/main/java/com/sematext/spm/client/MonitorAgent.java b/spm-monitor/src/main/java/com/sematext/spm/client/MonitorAgent.java
index 29ed8732..4f4b8540 100644
--- a/spm-monitor/src/main/java/com/sematext/spm/client/MonitorAgent.java
+++ b/spm-monitor/src/main/java/com/sematext/spm/client/MonitorAgent.java
@@ -31,6 +31,7 @@
import com.sematext.spm.client.command.BasicCommandPollingSetup.CommandPollingRunner;
import com.sematext.spm.client.jmx.JmxServiceContext;
import com.sematext.spm.client.monitor.SourceConfigProperties;
+import com.sematext.spm.client.profiling.PyroscopeInitializer;
import com.sematext.spm.client.sender.SenderUtil;
import com.sematext.spm.client.tracing.agent.impl.AgentInitializer;
import com.sematext.spm.client.util.PropertiesReader;
@@ -226,6 +227,12 @@ public static void startMonitoring(String agentArgs, Instrumentation inst) throw
throw new ConfigurationFailedException("Can't initialize tracing agent for " + propsFile.getName(), e);
}
+ try {
+ PyroscopeInitializer.initialize(props);
+ } catch (Exception e) {
+ log.error("Failed to initialize Pyroscope profiling for " + propsFile.getName(), e);
+ }
+
final MonitorConfig metricsConfig = getMonitorConfig(null, monitorArgs, inst, DataFormat.PLAIN_TEXT, processOrdinal);
if (metricsConfig == null) {
return;
diff --git a/spm-monitor/src/main/java/com/sematext/spm/client/profiling/PyroscopeInitializer.java b/spm-monitor/src/main/java/com/sematext/spm/client/profiling/PyroscopeInitializer.java
new file mode 100644
index 00000000..96c3dc5c
--- /dev/null
+++ b/spm-monitor/src/main/java/com/sematext/spm/client/profiling/PyroscopeInitializer.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to Sematext Group, Inc
+ *
+ * See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Sematext Group, Inc licenses this file to you 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 com.sematext.spm.client.profiling;
+
+import com.google.common.base.Splitter;
+import com.sematext.spm.client.Log;
+import com.sematext.spm.client.LogFactory;
+import io.pyroscope.http.Format;
+import io.pyroscope.javaagent.PyroscopeAgent;
+import io.pyroscope.javaagent.config.Config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class PyroscopeInitializer {
+ private static final Log LOG = LogFactory.getLog(PyroscopeInitializer.class);
+
+ private static final String ENV_ENABLED = "PYROSCOPE_ENABLED";
+ private static final String ENV_SERVER_ADDRESS = "PYROSCOPE_SERVER_ADDRESS";
+ private static final String ENV_APPLICATION_NAME = "PYROSCOPE_APPLICATION_NAME";
+ private static final String ENV_LABELS = "PYROSCOPE_LABELS";
+ private static final String ENV_PROFILER_ALLOC = "PYROSCOPE_PROFILER_ALLOC";
+ private static final String ENV_PROFILER_LOCK = "PYROSCOPE_PROFILER_LOCK";
+
+ private static final String DEFAULT_SERVER_ADDRESS = "http://localhost:4040";
+ private static final String DEFAULT_APPLICATION_NAME = "sematext-agent";
+
+ private static boolean profilingEnabled = false;
+
+ private PyroscopeInitializer() {
+ }
+
+ public static void initialize(Map props) {
+ try {
+ String enabled = getConfigValue(props, ENV_ENABLED, "false");
+ if (!"true".equalsIgnoreCase(enabled)) {
+ LOG.info("Pyroscope profiling is disabled. Set " + ENV_ENABLED + "=true to enable");
+ return;
+ }
+
+ String serverAddress = getConfigValue(props, ENV_SERVER_ADDRESS, DEFAULT_SERVER_ADDRESS);
+ String applicationName = getConfigValue(props, ENV_APPLICATION_NAME, DEFAULT_APPLICATION_NAME);
+ String labelsString = getConfigValue(props, ENV_LABELS, null);
+ String allocThreshold = getConfigValue(props, ENV_PROFILER_ALLOC, null);
+ String lockThreshold = getConfigValue(props, ENV_PROFILER_LOCK, null);
+
+ LOG.info("Initializing Pyroscope profiling:");
+ LOG.info(" Server Address: " + serverAddress);
+ LOG.info(" Application Name: " + applicationName);
+
+ Map labels = parseLabels(labelsString);
+ if (!labels.isEmpty()) {
+ LOG.info(" Static Labels: " + labels);
+ }
+
+ Config.Builder configBuilder = new Config.Builder()
+ .setApplicationName(applicationName)
+ .setFormat(Format.JFR)
+ .setServerAddress(serverAddress);
+
+ if (!labels.isEmpty()) {
+ configBuilder.setLabels(labels);
+ }
+
+ if (allocThreshold != null && !allocThreshold.trim().isEmpty()) {
+ configBuilder.setProfilingAlloc(allocThreshold);
+ LOG.info(" Allocation profiling enabled with threshold: " + allocThreshold);
+ }
+
+ if (lockThreshold != null && !lockThreshold.trim().isEmpty()) {
+ configBuilder.setProfilingLock(lockThreshold);
+ LOG.info(" Lock profiling enabled with threshold: " + lockThreshold);
+ }
+
+ Config config = configBuilder.build();
+
+ PyroscopeAgent.start(config);
+ profilingEnabled = true;
+
+ LOG.info("Pyroscope profiling started successfully with JFR format (CPU, allocations, and lock profiling)");
+
+ } catch (Exception e) {
+ LOG.error("Failed to initialize Pyroscope profiling. Agent will continue without profiling.", e);
+ profilingEnabled = false;
+ }
+ }
+
+ private static Map parseLabels(String labelsString) {
+ if (labelsString == null || labelsString.trim().isEmpty()) {
+ return new HashMap();
+ }
+
+ try {
+ return Splitter.on(',')
+ .trimResults()
+ .omitEmptyStrings()
+ .withKeyValueSeparator("=")
+ .split(labelsString);
+ } catch (Exception e) {
+ LOG.warn("Failed to parse Pyroscope labels from: " + labelsString, e);
+ return new HashMap();
+ }
+ }
+
+ private static String getConfigValue(Map props, String key, String defaultValue) {
+ String value = System.getenv(key);
+
+ if (value == null) {
+ value = System.getProperty(key);
+ }
+
+ if (value == null && props != null) {
+ value = props.get(key);
+ }
+
+ return value != null ? value : defaultValue;
+ }
+
+ public static boolean isProfilingEnabled() {
+ return profilingEnabled;
+ }
+}
diff --git a/spm-sender/src/main/resources/agent.default.properties b/spm-sender/src/main/resources/agent.default.properties
index a98ae543..0ccdf2b4 100644
--- a/spm-sender/src/main/resources/agent.default.properties
+++ b/spm-sender/src/main/resources/agent.default.properties
@@ -9,3 +9,10 @@ server_base_url=https://spm-receiver.sematext.com
metrics_endpoint=/write?db=metrics
tag_aliases_endpoint=/write?db=tagAliases
metainfo_endpoint=/write?db=metainfo
+
+PYROSCOPE_ENABLED=false
+PYROSCOPE_SERVER_ADDRESS=http://localhost:4040
+PYROSCOPE_APPLICATION_NAME=sematext-agent
+PYROSCOPE_LABELS=
+PYROSCOPE_PROFILER_ALLOC=512k
+PYROSCOPE_PROFILER_LOCK=10ms