Skip to content

Commit cbafd8d

Browse files
authored
Add cgroupv2 support and fix profile upload response body reading (#4592)
1 parent 73a56b8 commit cbafd8d

File tree

28 files changed

+1215
-103
lines changed

28 files changed

+1215
-103
lines changed

agent/agent-profiler/agent-diagnostics-api/src/main/java/com/microsoft/applicationinsights/diagnostics/DiagnosticEngineFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
package com.microsoft.applicationinsights.diagnostics;
55

66
import java.util.concurrent.ScheduledExecutorService;
7+
import javax.annotation.Nullable;
78

89
/**
910
* Factory to be invoked to create a DiagnosticEngine. This factory will be service loaded by the
1011
* agent and invoked. It is up to the provider of a DiagnosticEngine to provide a service loader for
1112
* this interface.
1213
*/
1314
public interface DiagnosticEngineFactory {
14-
DiagnosticEngine create(ScheduledExecutorService executorService);
15+
DiagnosticEngine create(
16+
ScheduledExecutorService executorService, @Nullable String cgroupBasePath);
1517
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerApplicationInsightFactoryJfr.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,58 @@
66
import com.google.auto.service.AutoService;
77
import com.microsoft.applicationinsights.diagnostics.DiagnosticEngine;
88
import com.microsoft.applicationinsights.diagnostics.DiagnosticEngineFactory;
9+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
913
import java.util.concurrent.ScheduledExecutorService;
14+
import javax.annotation.Nullable;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
1017

1118
/** Factory for Code Optimizer diagnostics to be service loaded */
1219
@AutoService(DiagnosticEngineFactory.class)
1320
public class CodeOptimizerApplicationInsightFactoryJfr implements DiagnosticEngineFactory {
21+
22+
private static final Path FILE_SYSTEM_ROOT =
23+
Paths.get(System.getProperty("applicationinsights.profiler.filesystemRoot", "/"));
24+
private static final Path CGROUP_DIR = Paths.get("./sys/fs/cgroup");
25+
26+
private static final Logger logger =
27+
LoggerFactory.getLogger(CodeOptimizerApplicationInsightFactoryJfr.class);
28+
1429
@Override
15-
public DiagnosticEngine create(ScheduledExecutorService executorService) {
16-
return new CodeOptimizerDiagnosticEngineJfr(executorService);
30+
public DiagnosticEngine create(
31+
ScheduledExecutorService executorService, @Nullable String cgroupBasePath) {
32+
Path cgroupPath = getCgroupPath(cgroupBasePath);
33+
return new CodeOptimizerDiagnosticEngineJfr(executorService, cgroupPath);
34+
}
35+
36+
@SuppressFBWarnings(
37+
value = "SECPTI", // Potential Path Traversal
38+
justification =
39+
"The constructed file path cannot be controlled by an end user of the instrumented application")
40+
@Nullable
41+
private static Path getCgroupPath(@Nullable String cgroupBasePath) {
42+
Path cgroupPath = null;
43+
if (cgroupBasePath != null) {
44+
cgroupPath = Paths.get(cgroupBasePath);
45+
46+
if (!Files.exists(cgroupPath)) {
47+
logger.warn("Configured Cgroup path {} does not exist, setting to default", cgroupBasePath);
48+
cgroupPath = null;
49+
}
50+
}
51+
52+
if (cgroupPath == null) {
53+
cgroupPath = FILE_SYSTEM_ROOT.resolve(CGROUP_DIR);
54+
55+
if (!Files.exists(cgroupPath)) {
56+
logger.warn("Expected default Cgroup path {} does not exist", cgroupBasePath);
57+
cgroupPath = null;
58+
}
59+
}
60+
61+
return cgroupPath;
1762
}
1863
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerDiagnosticEngineJfr.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.microsoft.applicationinsights.diagnostics.jfr.SystemStatsProvider;
1515
import java.io.IOException;
1616
import java.io.StringWriter;
17+
import java.nio.file.Path;
1718
import java.util.concurrent.CompletableFuture;
1819
import java.util.concurrent.Future;
1920
import java.util.concurrent.ScheduledExecutorService;
@@ -33,10 +34,13 @@ public class CodeOptimizerDiagnosticEngineJfr implements DiagnosticEngine {
3334
public static final long TIME_BEFORE_END_OF_PROFILE_TO_EMIT_EVENT = 10L;
3435
private final ScheduledExecutorService executorService;
3536
private final Semaphore semaphore = new Semaphore(1, false);
37+
private final Path cgroupBasePath;
3638
private int thisPid;
3739

38-
public CodeOptimizerDiagnosticEngineJfr(ScheduledExecutorService executorService) {
40+
public CodeOptimizerDiagnosticEngineJfr(
41+
ScheduledExecutorService executorService, Path cgroupBasePath) {
3942
this.executorService = executorService;
43+
this.cgroupBasePath = cgroupBasePath;
4044
}
4145

4246
@Override
@@ -49,14 +53,14 @@ public void init(int thisPid) {
4953
this.thisPid = thisPid;
5054

5155
logger.debug("Initialising Code Optimizer Diagnostic Engine");
52-
CodeOptimizerDiagnosticsJfrInit.initFeature(thisPid);
56+
CodeOptimizerDiagnosticsJfrInit.initFeature(thisPid, cgroupBasePath);
5357
logger.debug("Code Optimizer Diagnostic Engine Initialised");
5458
}
5559

56-
private static void startDiagnosticCycle(int thisPid) {
60+
private static void startDiagnosticCycle(int thisPid, Path cgroupBasePath) {
5761
logger.debug("Starting Code Optimizer Diagnostic Cycle");
58-
CodeOptimizerDiagnosticsJfrInit.initFeature(thisPid);
59-
CodeOptimizerDiagnosticsJfrInit.start(thisPid);
62+
CodeOptimizerDiagnosticsJfrInit.initFeature(thisPid, cgroupBasePath);
63+
CodeOptimizerDiagnosticsJfrInit.start(thisPid, cgroupBasePath);
6064
}
6165

6266
private static void endDiagnosticCycle() {
@@ -70,13 +74,13 @@ public Future<DiagnosisResult<?>> performDiagnosis(AlertBreach alert) {
7074
new CompletableFuture<>();
7175
try {
7276
if (semaphore.tryAcquire(SEMAPHORE_TIMEOUT_IN_SEC, TimeUnit.SECONDS)) {
73-
emitInfo(alert);
77+
emitInfo(alert, cgroupBasePath);
7478

7579
long profileDurationInSec = alert.getAlertConfiguration().getProfileDurationSeconds();
7680

7781
long end = profileDurationInSec - TIME_BEFORE_END_OF_PROFILE_TO_EMIT_EVENT;
7882

79-
startDiagnosticCycle(thisPid);
83+
startDiagnosticCycle(thisPid, cgroupBasePath);
8084

8185
scheduleEmittingAlertBreachEvent(alert, end);
8286

@@ -101,7 +105,7 @@ private void scheduleShutdown(
101105
executorService.schedule(
102106
() -> {
103107
try {
104-
emitInfo(alert);
108+
emitInfo(alert, cgroupBasePath);
105109

106110
// We do not return a result atm
107111
diagnosisResultCompletableFuture.complete(null);
@@ -123,7 +127,7 @@ private void scheduleEmittingAlertBreachEvent(AlertBreach alert, long end) {
123127
executorService.schedule(
124128
() -> {
125129
try {
126-
emitInfo(alert);
130+
emitInfo(alert, cgroupBasePath);
127131
} catch (RuntimeException e) {
128132
logger.error("Failed to emit breach", e);
129133
}
@@ -132,10 +136,10 @@ private void scheduleEmittingAlertBreachEvent(AlertBreach alert, long end) {
132136
TimeUnit.SECONDS);
133137
}
134138

135-
private static void emitInfo(AlertBreach alert) {
139+
private static void emitInfo(AlertBreach alert, Path cgroupBasePath) {
136140
logger.debug("Emitting Code Optimizer Diagnostic Event");
137141
emitAlertBreachJfrEvent(alert);
138-
CodeOptimizerDiagnosticsJfrInit.emitCGroupData();
142+
CodeOptimizerDiagnosticsJfrInit.emitCGroupData(cgroupBasePath);
139143
emitMachineStats();
140144
}
141145

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/kernel/CGroupDataReader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ public interface CGroupDataReader {
1919
long getCpuLimit() throws OperatingSystemInteractionException;
2020

2121
long getCpuPeriod() throws OperatingSystemInteractionException;
22+
23+
boolean isAvailable();
2224
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/kernel/CGroupUsageDataReader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313
public interface CGroupUsageDataReader extends TwoStepUpdatable, Closeable {
1414
@Nullable
1515
List<Double> getTelemetry();
16+
17+
boolean isAvailable();
1618
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/cgroups/CGroupCpuSystemReader.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
package com.microsoft.applicationinsights.diagnostics.collection.libos.os.linux.cgroups;
55

6-
@SuppressWarnings(
7-
"checkstyle:AbbreviationAsWordInName") // CGroup is the standard abbreviation for Control Group
6+
import java.nio.file.Path;
7+
8+
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
89
public class CGroupCpuSystemReader extends CGroupValueReader {
910
// total system CPU time (in nanoseconds) consumed by all tasks in this cgroup
10-
public CGroupCpuSystemReader() {
11-
super("/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage_sys");
11+
public CGroupCpuSystemReader(Path cgroupPath) {
12+
super(cgroupPath.resolve("./cpuacct.usage_sys"));
1213
}
1314
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/cgroups/CGroupCpuUsageReader.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
package com.microsoft.applicationinsights.diagnostics.collection.libos.os.linux.cgroups;
55

6-
@SuppressWarnings(
7-
"checkstyle:AbbreviationAsWordInName") // CGroup is the standard abbreviation for Control Group
6+
import java.nio.file.Path;
7+
8+
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
89
public class CGroupCpuUsageReader extends CGroupValueReader {
910
// total CPU usage (in nanoseconds) consumed by all tasks in this cgroup
10-
public CGroupCpuUsageReader() {
11-
super("/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage");
11+
public CGroupCpuUsageReader(Path cgroupPath) {
12+
super(cgroupPath.resolve("./cpuacct.usage"));
1213
}
1314
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/cgroups/CGroupCpuUserReader.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
package com.microsoft.applicationinsights.diagnostics.collection.libos.os.linux.cgroups;
55

6-
@SuppressWarnings(
7-
"checkstyle:AbbreviationAsWordInName") // CGroup is the standard abbreviation for Control Group
6+
import java.nio.file.Path;
7+
8+
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
89
public class CGroupCpuUserReader extends CGroupValueReader {
910
// total user CPU time (in nanoseconds) consumed by all tasks in this cgroup
10-
public CGroupCpuUserReader() {
11-
super("/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage_user");
11+
public CGroupCpuUserReader(Path cgroupPath) {
12+
super(cgroupPath.resolve("./cpuacct.usage_user"));
1213
}
1314
}

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/cgroups/CGroupStatReader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55

66
import com.microsoft.applicationinsights.diagnostics.collection.libos.BigIncrementalCounter;
77
import com.microsoft.applicationinsights.diagnostics.collection.libos.os.linux.TwoStepProcReader;
8-
import java.io.File;
8+
import java.nio.file.Path;
99

10-
@SuppressWarnings(
11-
"checkstyle:AbbreviationAsWordInName") // CGroup is the standard abbreviation for Control Group
10+
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
1211
public class CGroupStatReader extends TwoStepProcReader {
1312
private final BigIncrementalCounter user = new BigIncrementalCounter();
1413
private final BigIncrementalCounter system = new BigIncrementalCounter();
1514

16-
public CGroupStatReader() {
17-
super(new File("/sys/fs/cgroup/cpu,cpuacct/cpuacct.stat"), true);
15+
public CGroupStatReader(Path cgroupPath) {
16+
super(cgroupPath.resolve("./cpuacct.stat").toFile(), true);
1817
}
1918

2019
@Override

agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/cgroups/CGroupValueReader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55

66
import com.microsoft.applicationinsights.diagnostics.collection.libos.BigIncrementalCounter;
77
import com.microsoft.applicationinsights.diagnostics.collection.libos.os.linux.TwoStepProcReader;
8-
import java.io.File;
8+
import java.nio.file.Path;
99

10-
@SuppressWarnings(
11-
"checkstyle:AbbreviationAsWordInName") // CGroup is the standard abbreviation for Control Group
10+
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
1211
public abstract class CGroupValueReader extends TwoStepProcReader {
1312
private final BigIncrementalCounter usage = new BigIncrementalCounter();
1413

15-
public CGroupValueReader(String fileName) {
16-
super(new File(fileName), true);
14+
public CGroupValueReader(Path file) {
15+
super(file.toFile(), true);
1716
}
1817

1918
@Override

0 commit comments

Comments
 (0)