Skip to content

Commit 532c7fe

Browse files
kryalamatrask
andauthored
Quick Pulse cleanup and add sample telemetry feature (#1852)
* initial commit - testing sample telemetry * working code and some functional tests * rename playback session records * debug session-records in build * working code with integration tests * add comments gradle file * fix integration postRequest test * debug integrationtests * debug with logger * fix postRequest regex * undo debug statements * add sample telemetry to quickpulse working code * address comments * remove debug statements * more cleanup * Small refactorings * address comments and more cleanup Co-authored-by: Trask Stalnaker <[email protected]>
1 parent 3e02339 commit 532c7fe

20 files changed

+1995
-204
lines changed

agent/agent-tooling/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ plugins {
44
id("com.github.johnrengelman.shadow")
55
}
66

7+
// Adding this step to copy playback test results from session-records to build/classes/java/test. Azure core testing framework follows this directory structure.
8+
sourceSets {
9+
test {
10+
output.setResourcesDir("build/classes/java/test")
11+
}
12+
}
13+
714
dependencies {
815
implementation(project(":agent:agent-profiler:agent-service-profiler"))
916
implementation(project(":agent:agent-profiler:agent-alerting-api"))
@@ -61,6 +68,7 @@ dependencies {
6168
testImplementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-annotation-support")
6269

6370
testImplementation("org.junit.jupiter:junit-jupiter")
71+
testImplementation("com.azure:azure-core-test:1.7.0")
6472
testImplementation("org.assertj:assertj-core")
6573
testImplementation("org.awaitility:awaitility")
6674
testImplementation("org.mockito:mockito-core")
@@ -72,3 +80,5 @@ dependencies {
7280
testImplementation("com.microsoft.jfr:jfr-streaming")
7381
testImplementation("com.azure:azure-storage-blob")
7482
}
83+
84+

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/MainEntryPoint.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class MainEntryPoint {
5252

5353
private static RpConfiguration rpConfiguration;
5454
private static Configuration configuration;
55+
private static String agentVersion = "(unknown)";
5556

5657
private MainEntryPoint() {}
5758

@@ -63,12 +64,15 @@ public static Configuration getConfiguration() {
6364
return configuration;
6465
}
6566

67+
public static String getAgentVersion() {
68+
return agentVersion;
69+
}
70+
6671
// TODO turn this into an interceptor
6772
@SuppressWarnings("SystemOut")
6873
public static void start(Instrumentation instrumentation, File javaagentFile) {
6974
boolean success = false;
7075
Logger startupLogger = null;
71-
String version = "(unknown)";
7276
try {
7377
if (DEBUG_SIGNED_JAR_ACCESS) {
7478
JarVerifierClassFileTransformer transformer = new JarVerifierClassFileTransformer();
@@ -78,7 +82,7 @@ public static void start(Instrumentation instrumentation, File javaagentFile) {
7882
}
7983
Path agentPath = javaagentFile.toPath();
8084
// need to initialize version before initializing DiagnosticsHelper
81-
version = SdkVersionFinder.initVersion(agentPath);
85+
agentVersion = SdkVersionFinder.initVersion(agentPath);
8286
DiagnosticsHelper.setAgentJarFile(agentPath);
8387
// configuration is only read this early in order to extract logging configuration
8488
rpConfiguration = RpConfigurationBuilder.create(agentPath);
@@ -92,17 +96,17 @@ public static void start(Instrumentation instrumentation, File javaagentFile) {
9296
instrumentation, ConfigOverride.getConfig(configuration), false);
9397
startupLogger.info(
9498
"ApplicationInsights Java Agent {} started successfully (PID {})",
95-
version,
99+
agentVersion,
96100
new PidFinder().getValue());
97101
success = true;
98102
LoggerFactory.getLogger(DiagnosticsHelper.DIAGNOSTICS_LOGGER_NAME)
99-
.info("Application Insights Codeless Agent {} Attach Successful", version);
103+
.info("Application Insights Codeless Agent {} Attach Successful", agentVersion);
100104
} catch (ThreadDeath td) {
101105
throw td;
102106
} catch (Throwable t) {
103107

104108
FriendlyException friendlyException = getFriendlyException(t);
105-
String banner = "ApplicationInsights Java Agent " + version + " failed to start";
109+
String banner = "ApplicationInsights Java Agent " + agentVersion + " failed to start";
106110
if (friendlyException != null) {
107111
logErrorMessage(
108112
startupLogger, friendlyException.getMessageWithBanner(banner), true, t, javaagentFile);

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/quickpulse/QuickPulseDataCollector.java

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,22 @@
2424
import com.microsoft.applicationinsights.agent.internal.exporter.models.MonitorDomain;
2525
import com.microsoft.applicationinsights.agent.internal.exporter.models.RemoteDependencyData;
2626
import com.microsoft.applicationinsights.agent.internal.exporter.models.RequestData;
27+
import com.microsoft.applicationinsights.agent.internal.exporter.models.StackFrame;
2728
import com.microsoft.applicationinsights.agent.internal.exporter.models.TelemetryExceptionData;
29+
import com.microsoft.applicationinsights.agent.internal.exporter.models.TelemetryExceptionDetails;
2830
import com.microsoft.applicationinsights.agent.internal.exporter.models.TelemetryItem;
2931
import com.microsoft.applicationinsights.agent.internal.perfcounter.CpuPerformanceCounterCalculator;
32+
import com.microsoft.applicationinsights.agent.internal.quickpulse.model.QuickPulseDependencyDocument;
33+
import com.microsoft.applicationinsights.agent.internal.quickpulse.model.QuickPulseDocument;
34+
import com.microsoft.applicationinsights.agent.internal.quickpulse.model.QuickPulseExceptionDocument;
35+
import com.microsoft.applicationinsights.agent.internal.quickpulse.model.QuickPulseRequestDocument;
3036
import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient;
3137
import java.lang.management.ManagementFactory;
3238
import java.lang.management.MemoryMXBean;
39+
import java.util.ArrayList;
40+
import java.util.HashMap;
41+
import java.util.List;
42+
import java.util.Map;
3343
import java.util.concurrent.atomic.AtomicInteger;
3444
import java.util.concurrent.atomic.AtomicLong;
3545
import java.util.concurrent.atomic.AtomicReference;
@@ -50,6 +60,7 @@ static class FinalCounters {
5060
public final int unsuccessfulRdds;
5161
public final long memoryCommitted;
5262
public final double cpuUsage;
63+
public final List<QuickPulseDocument> documentList = new ArrayList<>();
5364

5465
public FinalCounters(
5566
Counters currentCounters,
@@ -82,6 +93,9 @@ public FinalCounters(
8293
this.rdds = countAndDuration.count;
8394
this.rddsDuration = countAndDuration.duration;
8495
this.unsuccessfulRdds = currentCounters.unsuccessfulRdds.get();
96+
synchronized (currentCounters.documentList) {
97+
this.documentList.addAll(currentCounters.documentList);
98+
}
8599
}
86100
}
87101

@@ -106,6 +120,7 @@ static class Counters {
106120

107121
final AtomicLong rddsAndDuations = new AtomicLong(0);
108122
final AtomicInteger unsuccessfulRdds = new AtomicInteger(0);
123+
final List<QuickPulseDocument> documentList = new ArrayList<>();
109124

110125
static long encodeCountAndDuration(long count, long duration) {
111126
if (count > MAX_COUNT || duration > MAX_DURATION) {
@@ -166,7 +181,7 @@ public synchronized FinalCounters getAndRestart() {
166181
return null;
167182
}
168183

169-
/*@VisibleForTesting*/
184+
// only used by tests
170185
synchronized FinalCounters peek() {
171186
Counters currentCounters = this.counters.get(); // this should be the only differece
172187
if (currentCounters != null) {
@@ -199,7 +214,7 @@ public void add(TelemetryItem telemetryItem) {
199214
} else if (data instanceof RemoteDependencyData) {
200215
addDependency((RemoteDependencyData) data, itemCount);
201216
} else if (data instanceof TelemetryExceptionData) {
202-
addException(itemCount);
217+
addException((TelemetryExceptionData) data, itemCount);
203218
}
204219
}
205220

@@ -218,15 +233,59 @@ private void addDependency(RemoteDependencyData telemetry, int itemCount) {
218233
if (success != null && !success) { // success should not be null
219234
counters.unsuccessfulRdds.incrementAndGet();
220235
}
236+
QuickPulseDependencyDocument quickPulseDependencyDocument = new QuickPulseDependencyDocument();
237+
quickPulseDependencyDocument.setDocumentType("RemoteDependency");
238+
quickPulseDependencyDocument.setType("DependencyTelemetryDocument");
239+
quickPulseDependencyDocument.setOperationId(telemetry.getId());
240+
quickPulseDependencyDocument.setVersion("1.0");
241+
quickPulseDependencyDocument.setName(telemetry.getName());
242+
quickPulseDependencyDocument.setCommandName(telemetry.getData());
243+
quickPulseDependencyDocument.setTarget(telemetry.getTarget());
244+
quickPulseDependencyDocument.setSuccess(telemetry.isSuccess());
245+
quickPulseDependencyDocument.setDuration(telemetry.getDuration());
246+
quickPulseDependencyDocument.setResultCode(telemetry.getResultCode());
247+
quickPulseDependencyDocument.setOperationName(telemetry.getId());
248+
quickPulseDependencyDocument.setDependencyTypeName(telemetry.getType());
249+
quickPulseDependencyDocument.setProperties(
250+
aggregateProperties(telemetry.getProperties(), telemetry.getMeasurements()));
251+
synchronized (counters.documentList) {
252+
counters.documentList.add(quickPulseDependencyDocument);
253+
}
221254
}
222255

223-
private void addException(int itemCount) {
256+
private void addException(TelemetryExceptionData exceptionData, int itemCount) {
224257
Counters counters = this.counters.get();
225258
if (counters == null) {
226259
return;
227260
}
228261

229262
counters.exceptions.addAndGet(itemCount);
263+
QuickPulseExceptionDocument quickPulseExceptionDocument = new QuickPulseExceptionDocument();
264+
quickPulseExceptionDocument.setDocumentType("Exception");
265+
quickPulseExceptionDocument.setType("ExceptionTelemetryDocument");
266+
quickPulseExceptionDocument.setOperationId(exceptionData.getProblemId());
267+
quickPulseExceptionDocument.setVersion("1.0");
268+
List<TelemetryExceptionDetails> exceptionList = exceptionData.getExceptions();
269+
StringBuilder exceptions = new StringBuilder();
270+
if (exceptionList != null && exceptionList.size() > 0) {
271+
List<StackFrame> parsedStack = exceptionList.get(0).getParsedStack();
272+
String stack = exceptionList.get(0).getStack();
273+
if (parsedStack != null && parsedStack.size() > 0) {
274+
for (StackFrame stackFrame : parsedStack) {
275+
if (stackFrame != null && stackFrame.getAssembly() != null) {
276+
exceptions.append(stackFrame.getAssembly()).append("\n");
277+
}
278+
}
279+
} else if (stack != null && stack.length() > 0) {
280+
exceptions.append(stack);
281+
}
282+
quickPulseExceptionDocument.setException(exceptions.toString());
283+
quickPulseExceptionDocument.setExceptionMessage(exceptionList.get(0).getMessage());
284+
quickPulseExceptionDocument.setExceptionType(exceptionList.get(0).getTypeName());
285+
}
286+
synchronized (counters.documentList) {
287+
counters.documentList.add(quickPulseExceptionDocument);
288+
}
230289
}
231290

232291
private void addRequest(RequestData requestTelemetry, int itemCount) {
@@ -241,6 +300,32 @@ private void addRequest(RequestData requestTelemetry, int itemCount) {
241300
if (!requestTelemetry.isSuccess()) {
242301
counters.unsuccessfulRequests.incrementAndGet();
243302
}
303+
QuickPulseRequestDocument quickPulseRequestDocument = new QuickPulseRequestDocument();
304+
quickPulseRequestDocument.setDocumentType("Request");
305+
quickPulseRequestDocument.setType("RequestTelemetryDocument");
306+
quickPulseRequestDocument.setOperationId(requestTelemetry.getId());
307+
quickPulseRequestDocument.setVersion("1.0");
308+
quickPulseRequestDocument.setSuccess(requestTelemetry.isSuccess());
309+
quickPulseRequestDocument.setDuration(requestTelemetry.getDuration());
310+
quickPulseRequestDocument.setResponseCode(requestTelemetry.getResponseCode());
311+
quickPulseRequestDocument.setOperationName(requestTelemetry.getName());
312+
quickPulseRequestDocument.setProperties(
313+
aggregateProperties(requestTelemetry.getProperties(), requestTelemetry.getMeasurements()));
314+
synchronized (counters.documentList) {
315+
counters.documentList.add(quickPulseRequestDocument);
316+
}
317+
}
318+
319+
private static Map<String, String> aggregateProperties(
320+
Map<String, String> properties, Map<String, Double> measurements) {
321+
Map<String, String> aggregatedProperties = new HashMap<>();
322+
if (measurements != null) {
323+
measurements.forEach((k, v) -> aggregatedProperties.put(k, String.valueOf(v)));
324+
}
325+
if (properties != null) {
326+
aggregatedProperties.putAll(properties);
327+
}
328+
return aggregatedProperties;
244329
}
245330

246331
// TODO (trask) optimization: move live metrics request capture to OpenTelemetry layer so don't

0 commit comments

Comments
 (0)