diff --git a/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java b/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java index 42cdf4f0d76..4cd4220b80c 100644 --- a/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java +++ b/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java @@ -22,8 +22,10 @@ import java.net.URI; import java.net.URL; +import java.util.Collections; import java.util.Date; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import io.opentelemetry.instrumentation.api.aisdk.MicrometerUtil; import io.opentelemetry.instrumentation.api.aisdk.MicrometerUtil.MicrometerUtilDelegate; @@ -44,56 +46,63 @@ public static void setDelegate(final BytecodeUtilDelegate delegate) { MicrometerUtil.setDelegate(new MicrometerUtilDelegate() { @Override public void trackMetric(String name, double value, Integer count, Double min, Double max, Map properties) { - delegate.trackMetric(name, value, count, min, max, null, properties); + delegate.trackMetric(name, value, count, min, max, null, properties, Collections.emptyMap()); } }); } } - public static void trackEvent(String name, Map properties, Map metrics) { + public static void trackEvent(String name, Map properties, Map tags, Map metrics) { if (delegate != null) { - delegate.trackEvent(name, properties, metrics); + delegate.trackEvent(name, properties, tags, metrics); } } public static void trackMetric(String name, double value, Integer count, Double min, Double max, Double stdDev, - Map properties) { + Map properties, Map tags) { if (delegate != null) { - delegate.trackMetric(name, value, count, min, max, stdDev, properties); + delegate.trackMetric(name, value, count, min, max, stdDev, properties, tags); } } public static void trackDependency(String name, String id, String resultCode, Long totalMillis, boolean success, String commandName, String type, String target, Map properties, - Map metrics) { + Map tags, Map metrics) { if (delegate != null) { delegate.trackDependency(name, id, resultCode, totalMillis, success, commandName, type, target, properties, - metrics); + tags, metrics); } } - public static void trackPageView(String name, URI uri, long totalMillis, Map properties, + public static void trackPageView(String name, URI uri, long totalMillis, Map properties, Map tags, Map metrics) { if (delegate != null) { - delegate.trackPageView(name, uri, totalMillis, properties, metrics); + delegate.trackPageView(name, uri, totalMillis, properties, tags, metrics); } } - public static void trackTrace(String message, int severityLevel, Map properties) { + public static void trackTrace(String message, int severityLevel, Map properties, Map tags) { if (delegate != null) { - delegate.trackTrace(message, severityLevel, properties); + delegate.trackTrace(message, severityLevel, properties, tags); } } - public static void trackRequest(String id, String name, URL url, Date timestamp, long duration, String responseCode, boolean success) { + public static void trackRequest(String id, String name, URL url, Date timestamp, Long duration, String responseCode, boolean success, + Map properties, Map tags) { if (delegate != null) { - delegate.trackRequest(id, name, url, timestamp, duration, responseCode, success); + delegate.trackRequest(id, name, url, timestamp, duration, responseCode, success, properties, tags); } } - public static void trackException(Exception exception, Map properties, Map metrics) { + public static void trackException(Exception exception, Map properties, Map tags, Map metrics) { if (delegate != null) { - delegate.trackException(exception, properties, metrics); + delegate.trackException(exception, properties, tags, metrics); + } + } + + public static void flush() { + if (delegate != null) { + delegate.flush(); } } @@ -111,25 +120,54 @@ public static long getTotalMilliseconds(long days, int hours, int minutes, int s + milliseconds; } + // basically the same as SDK MapUtil.copy() + public static void copy(Map source, Map target) { + if (target == null) { + throw new IllegalArgumentException("target must not be null"); + } + + if (source == null || source.isEmpty()) { + return; + } + + for (Map.Entry entry : source.entrySet()) { + String key = entry.getKey(); + if (key == null || key.isEmpty()) { + continue; + } + + if (!target.containsKey(key)) { + if (target instanceof ConcurrentHashMap && entry.getValue() == null) { + continue; + } else { + target.put(key, entry.getValue()); + } + } + } + } + public interface BytecodeUtilDelegate { - void trackEvent(String name, Map properties, Map metrics); + void trackEvent(String name, Map properties, Map tags, Map metrics); void trackMetric(String name, double value, Integer count, Double min, Double max, - Double stdDev, Map properties); + Double stdDev, Map properties, Map tags); void trackDependency(String name, String id, String resultCode, Long totalMillis, boolean success, String commandName, String type, String target, - Map properties, Map metrics); + Map properties, Map tags, Map metrics); - void trackPageView(String name, URI uri, long totalMillis, Map properties, + void trackPageView(String name, URI uri, long totalMillis, Map properties, Map tags, Map metrics); - void trackTrace(String message, int severityLevel, Map properties); + void trackTrace(String message, int severityLevel, Map properties, Map tags); + + void trackRequest(String id, String name, URL url, Date timestamp, Long duration, String responseCode, boolean success, + Map properties, Map tags); - void trackRequest(String id, String name, URL url, Date timestamp, long duration, String responseCode, boolean success); + void trackException(Exception exception, Map properties, Map tags, Map metrics); - void trackException(Exception exception, Map properties, Map metrics); + void flush(); void logErrorOnce(Throwable t); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/BytecodeUtilImpl.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/BytecodeUtilImpl.java index ce02255e3e1..a595d332d24 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/BytecodeUtilImpl.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/BytecodeUtilImpl.java @@ -27,8 +27,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import com.google.common.base.Strings; -import com.microsoft.applicationinsights.agent.internal.Global; import com.microsoft.applicationinsights.agent.bootstrap.BytecodeUtil.BytecodeUtilDelegate; +import com.microsoft.applicationinsights.agent.internal.Global; import com.microsoft.applicationinsights.agent.internal.sampling.SamplingScoreGeneratorV2; import com.microsoft.applicationinsights.internal.util.MapUtil; import com.microsoft.applicationinsights.telemetry.Duration; @@ -55,21 +55,20 @@ // supporting all properties of event, metric, remove dependency and page view telemetry public class BytecodeUtilImpl implements BytecodeUtilDelegate { - private static final Tracer tracer = OpenTelemetry.getGlobalTracer(""); - private static final Logger logger = LoggerFactory.getLogger(BytecodeUtilImpl.class); private static final AtomicBoolean alreadyLoggedError = new AtomicBoolean(); @Override - public void trackEvent(String name, Map properties, Map metrics) { + public void trackEvent(String name, Map properties, Map tags, Map metrics) { if (Strings.isNullOrEmpty(name)) { return; } EventTelemetry telemetry = new EventTelemetry(name); - MapUtil.copy(properties, telemetry.getContext().getProperties()); - MapUtil.copy(metrics, telemetry.getMetrics()); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); + telemetry.getMetrics().putAll(metrics); track(telemetry); } @@ -77,7 +76,7 @@ public void trackEvent(String name, Map properties, Map properties) { + Double stdDev, Map properties, Map tags) { if (Strings.isNullOrEmpty(name)) { return; @@ -89,7 +88,8 @@ public void trackMetric(String name, double value, Integer count, Double min, Do telemetry.setMin(min); telemetry.setMax(max); telemetry.setStandardDeviation(stdDev); - MapUtil.copy(properties, telemetry.getProperties()); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); track(telemetry); } @@ -97,7 +97,7 @@ public void trackMetric(String name, double value, Integer count, Double min, Do @Override public void trackDependency(String name, String id, String resultCode, @Nullable Long totalMillis, boolean success, String commandName, String type, String target, - Map properties, Map metrics) { + Map properties, Map tags, Map metrics) { if (Strings.isNullOrEmpty(name)) { return; @@ -113,15 +113,16 @@ public void trackDependency(String name, String id, String resultCode, @Nullable telemetry.setCommandName(commandName); telemetry.setType(type); telemetry.setTarget(target); - MapUtil.copy(properties, telemetry.getProperties()); - MapUtil.copy(metrics, telemetry.getMetrics()); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); + telemetry.getMetrics().putAll(metrics); track(telemetry); } @Override public void trackPageView(String name, URI uri, long totalMillis, Map properties, - Map metrics) { + Map tags, Map metrics) { if (Strings.isNullOrEmpty(name)) { return; @@ -130,14 +131,15 @@ public void trackPageView(String name, URI uri, long totalMillis, Map properties) { + public void trackTrace(String message, int severityLevel, Map properties, Map tags) { if (Strings.isNullOrEmpty(message)) { return; } @@ -147,13 +149,15 @@ public void trackTrace(String message, int severityLevel, Map pr if (severityLevel != -1) { telemetry.setSeverityLevel(getSeverityLevel(severityLevel)); } - MapUtil.copy(properties, telemetry.getProperties()); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); track(telemetry); } @Override - public void trackRequest(String id, String name, URL url, Date timestamp, long duration, String responseCode, boolean success) { + public void trackRequest(String id, String name, URL url, Date timestamp, @Nullable Long duration, String responseCode, boolean success, + Map properties, Map tags) { if (Strings.isNullOrEmpty(name)) { return; } @@ -165,15 +169,20 @@ public void trackRequest(String id, String name, URL url, Date timestamp, long d telemetry.setUrl(url); } telemetry.setTimestamp(timestamp); - telemetry.setDuration(new Duration(duration)); + if (duration != null) { + telemetry.setDuration(new Duration(duration)); + } telemetry.setResponseCode(responseCode); telemetry.setSuccess(success); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); track(telemetry); } @Override - public void trackException(Exception exception, Map properties, Map metrics) { + public void trackException(Exception exception, Map properties, Map tags, + Map metrics) { if (exception == null) { return; } @@ -181,8 +190,9 @@ public void trackException(Exception exception, Map properties, ExceptionTelemetry telemetry = new ExceptionTelemetry(); telemetry.setException(exception); telemetry.setSeverityLevel(SeverityLevel.Error); - MapUtil.copy(properties, telemetry.getProperties()); - MapUtil.copy(metrics, telemetry.getMetrics()); + telemetry.getProperties().putAll(properties); + telemetry.getContext().getTags().putAll(tags); + telemetry.getMetrics().putAll(metrics); track(telemetry); } @@ -196,6 +206,12 @@ private SeverityLevel getSeverityLevel(int value) { return null; } + @Override + public void flush() { + // this is not null because sdk instrumentation is not added until Global.setTelemetryClient() is called + checkNotNull(Global.getTelemetryClient()).flush(); + } + @Override public void logErrorOnce(Throwable t) { if (!alreadyLoggedError.getAndSet(true)) { diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/TelemetryClientClassFileTransformer.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/TelemetryClientClassFileTransformer.java index c926ca228ff..3231fd06b31 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/TelemetryClientClassFileTransformer.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/instrumentation/sdk/TelemetryClientClassFileTransformer.java @@ -25,6 +25,7 @@ import java.lang.instrument.ClassFileTransformer; import java.net.MalformedURLException; import java.security.ProtectionDomain; +import java.util.Date; import com.google.common.base.Charsets; import com.microsoft.applicationinsights.TelemetryConfiguration; @@ -39,8 +40,8 @@ import com.microsoft.applicationinsights.telemetry.RequestTelemetry; import com.microsoft.applicationinsights.telemetry.SeverityLevel; import com.microsoft.applicationinsights.telemetry.Telemetry; +import com.microsoft.applicationinsights.telemetry.TelemetryContext; import com.microsoft.applicationinsights.telemetry.TraceTelemetry; -import org.checkerframework.checker.nullness.qual.Nullable; import net.bytebuddy.jar.asm.ClassReader; import net.bytebuddy.jar.asm.ClassVisitor; import net.bytebuddy.jar.asm.ClassWriter; @@ -48,12 +49,12 @@ import net.bytebuddy.jar.asm.Label; import net.bytebuddy.jar.asm.MethodVisitor; import net.bytebuddy.jar.asm.Opcodes; +import org.checkerframework.checker.nullness.qual.Nullable; import org.objectweb.asm.util.ASMifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; -import static net.bytebuddy.jar.asm.Opcodes.ACC_PUBLIC; import static net.bytebuddy.jar.asm.Opcodes.ACONST_NULL; import static net.bytebuddy.jar.asm.Opcodes.ALOAD; import static net.bytebuddy.jar.asm.Opcodes.ARETURN; @@ -63,21 +64,20 @@ import static net.bytebuddy.jar.asm.Opcodes.DLOAD; import static net.bytebuddy.jar.asm.Opcodes.DUP; import static net.bytebuddy.jar.asm.Opcodes.GETFIELD; -import static net.bytebuddy.jar.asm.Opcodes.GETSTATIC; import static net.bytebuddy.jar.asm.Opcodes.GOTO; +import static net.bytebuddy.jar.asm.Opcodes.ICONST_1; import static net.bytebuddy.jar.asm.Opcodes.ICONST_M1; import static net.bytebuddy.jar.asm.Opcodes.IFEQ; import static net.bytebuddy.jar.asm.Opcodes.IFNONNULL; import static net.bytebuddy.jar.asm.Opcodes.IFNULL; import static net.bytebuddy.jar.asm.Opcodes.ILOAD; import static net.bytebuddy.jar.asm.Opcodes.INSTANCEOF; +import static net.bytebuddy.jar.asm.Opcodes.INVOKEINTERFACE; import static net.bytebuddy.jar.asm.Opcodes.INVOKESPECIAL; import static net.bytebuddy.jar.asm.Opcodes.INVOKESTATIC; import static net.bytebuddy.jar.asm.Opcodes.INVOKEVIRTUAL; import static net.bytebuddy.jar.asm.Opcodes.IRETURN; import static net.bytebuddy.jar.asm.Opcodes.ISTORE; -import static net.bytebuddy.jar.asm.Opcodes.LLOAD; -import static net.bytebuddy.jar.asm.Opcodes.LSTORE; import static net.bytebuddy.jar.asm.Opcodes.NEW; import static net.bytebuddy.jar.asm.Opcodes.RETURN; @@ -157,6 +157,9 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, @Nu foundIsDisabledMethod = true; overwriteIsDisabledMethod(mv); return null; + } else if (name.equals("flush") && descriptor.equals("()V")) { + overwriteFlushMethod(mv); + return null; } else { return mv; } @@ -176,104 +179,157 @@ public void visitEnd() { private void overwriteTrackMethod(MethodVisitor mv) { mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); + Label label0 = new Label(); + Label label1 = new Label(); + Label label2 = new Label(); + mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable"); + Label label3 = new Label(); + mv.visitLabel(label3); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/TelemetryClient", "isDisabled", "()Z", false); - mv.visitJumpInsn(IFEQ, l0); + Label label4 = new Label(); + mv.visitJumpInsn(IFEQ, label4); + Label label5 = new Label(); + mv.visitLabel(label5); mv.visitInsn(RETURN); - mv.visitLabel(l0); + mv.visitLabel(label4); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, unshadedPrefix + "/telemetry/Telemetry", "getTimestamp", "()Ljava/util/Date;", true); + Label label6 = new Label(); + mv.visitJumpInsn(IFNONNULL, label6); + Label label7 = new Label(); + mv.visitLabel(label7); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(NEW, "java/util/Date"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "", "()V", false); + mv.visitMethodInsn(INVOKEINTERFACE, unshadedPrefix + "/telemetry/Telemetry", "setTimestamp", "(Ljava/util/Date;)V", true); + mv.visitLabel(label6); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/TelemetryClient", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, unshadedPrefix + "/telemetry/Telemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", true); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "copy", "(Ljava/util/Map;Ljava/util/Map;)V", false); + Label label8 = new Label(); + mv.visitLabel(label8); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/TelemetryClient", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getProperties", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, unshadedPrefix + "/telemetry/Telemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", true); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getProperties", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "copy", "(Ljava/util/Map;Ljava/util/Map;)V", false); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/EventTelemetry"); - Label l3 = new Label(); - mv.visitJumpInsn(IFEQ, l3); + Label label9 = new Label(); + mv.visitJumpInsn(IFEQ, label9); + Label label10 = new Label(); + mv.visitLabel(label10); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/EventTelemetry"); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackEventTelemetry", "(L" + unshadedPrefix + "/telemetry/EventTelemetry;)V", false); - mv.visitLabel(l3); + mv.visitLabel(label9); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/MetricTelemetry"); - Label l4 = new Label(); - mv.visitJumpInsn(IFEQ, l4); + Label label11 = new Label(); + mv.visitJumpInsn(IFEQ, label11); + Label label12 = new Label(); + mv.visitLabel(label12); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/MetricTelemetry"); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackMetricTelemetry", "(L" + unshadedPrefix + "/telemetry/MetricTelemetry;)V", false); - mv.visitLabel(l4); + mv.visitLabel(label11); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry"); - Label l5 = new Label(); - mv.visitJumpInsn(IFEQ, l5); + Label label13 = new Label(); + mv.visitJumpInsn(IFEQ, label13); + Label label14 = new Label(); + mv.visitLabel(label14); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry"); - mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", - "agent$trackRemoteDependencyTelemetry", + mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackRemoteDependencyTelemetry", "(L" + unshadedPrefix + "/telemetry/RemoteDependencyTelemetry;)V", false); - mv.visitLabel(l5); + mv.visitLabel(label13); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/PageViewTelemetry"); - Label l6 = new Label(); - mv.visitJumpInsn(IFEQ, l6); + Label label15 = new Label(); + mv.visitJumpInsn(IFEQ, label15); + Label label16 = new Label(); + mv.visitLabel(label16); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/PageViewTelemetry"); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackPageViewTelemetry", "(L" + unshadedPrefix + "/telemetry/PageViewTelemetry;)V", false); - mv.visitLabel(l6); + mv.visitLabel(label15); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/TraceTelemetry"); - Label l7 = new Label(); - mv.visitJumpInsn(IFEQ, l7); + Label label17 = new Label(); + mv.visitJumpInsn(IFEQ, label17); + Label label18 = new Label(); + mv.visitLabel(label18); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/TraceTelemetry"); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackTraceTelemetry", "(L" + unshadedPrefix + "/telemetry/TraceTelemetry;)V", false); - mv.visitLabel(l7); + mv.visitLabel(label17); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/RequestTelemetry"); - Label l8 = new Label(); - mv.visitJumpInsn(IFEQ, l8); + Label label19 = new Label(); + mv.visitJumpInsn(IFEQ, label19); + Label label20 = new Label(); + mv.visitLabel(label20); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/RequestTelemetry"); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackRequestTelemetry", "(L" + unshadedPrefix + "/telemetry/RequestTelemetry;)V", false); - mv.visitLabel(l8); + mv.visitLabel(label19); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, unshadedPrefix + "/telemetry/ExceptionTelemetry"); - Label l9 = new Label(); - mv.visitJumpInsn(IFEQ, l9); + mv.visitJumpInsn(IFEQ, label1); + Label label21 = new Label(); + mv.visitLabel(label21); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, unshadedPrefix + "/telemetry/ExceptionTelemetry"); - mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/TelemetryClient", "agent$trackExceptionTelemetry", + mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$trackExceptionTelemetry", "(L" + unshadedPrefix + "/telemetry/ExceptionTelemetry;)V", false); - mv.visitLabel(l1); - mv.visitJumpInsn(GOTO, l9); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"}); + mv.visitLabel(label1); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + Label label22 = new Label(); + mv.visitJumpInsn(GOTO, label22); + mv.visitLabel(label2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); mv.visitVarInsn(ASTORE, 2); + Label label23 = new Label(); + mv.visitLabel(label23); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "logErrorOnce", "(Ljava/lang/Throwable;)V", false); - mv.visitLabel(l9); + mv.visitLabel(label22); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitInsn(RETURN); - mv.visitMaxs(2, 3); + Label label24 = new Label(); + mv.visitLabel(label24); + mv.visitMaxs(3, 3); mv.visitEnd(); } @@ -305,10 +361,20 @@ private void overwriteIsDisabledMethod(MethodVisitor mv) { mv.visitEnd(); } + private void overwriteFlushMethod(MethodVisitor mv) { + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "flush", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + private void writeAgentTrackEventTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackEventTelemetry", "(L" + unshadedPrefix + "/telemetry/EventTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/EventTelemetry", "getName", "()Ljava/lang/String;", false); @@ -316,12 +382,19 @@ private void writeAgentTrackEventTelemetryMethod() { mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/EventTelemetry", "getProperties", "()Ljava/util/Map;", false); mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/EventTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/EventTelemetry", "getMetrics", "()Ljava/util/concurrent/ConcurrentMap;", false); mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackEvent", - "(Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V", false); + "(Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V", false); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitInsn(RETURN); - mv.visitMaxs(3, 2); + Label label2 = new Label(); + mv.visitLabel(label2); + mv.visitMaxs(4, 2); mv.visitEnd(); } @@ -329,6 +402,8 @@ private void writeAgentTrackMetricTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackMetricTelemetry", "(L" + unshadedPrefix + "/telemetry/MetricTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/MetricTelemetry", "getName", "()Ljava/lang/String;", false); @@ -344,17 +419,26 @@ private void writeAgentTrackMetricTelemetryMethod() { mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/MetricTelemetry", "getMax", "()Ljava/lang/Double;", false); mv.visitVarInsn(ALOAD, 1); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/MetricTelemetry", "getStandardDeviation", "()Ljava/lang/Double;", false); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/MetricTelemetry", "getProperties", "()Ljava/util/Map;", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/MetricTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + Label label2 = new Label(); + mv.visitLabel(label2); mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackMetric", - "(Ljava/lang/String;DLjava/lang/Integer;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Double;" + - "Ljava/util/Map;)V", - false); + "(Ljava/lang/String;DLjava/lang/Integer;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Double;Ljava/util/Map;Ljava/util/Map;)V", false); + Label label3 = new Label(); + mv.visitLabel(label3); mv.visitInsn(RETURN); - mv.visitMaxs(8, 2); + Label label4 = new Label(); + mv.visitLabel(label4); + mv.visitMaxs(9, 2); mv.visitEnd(); } @@ -362,6 +446,8 @@ private void writeAgentTrackRemoteDependencyTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackRemoteDependencyTelemetry", "(L" + unshadedPrefix + "/telemetry/RemoteDependencyTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", "getName", "()Ljava/lang/String;", false); @@ -378,6 +464,8 @@ private void writeAgentTrackRemoteDependencyTelemetryMethod() { mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$toMillis", "(L" + unshadedPrefix + "/telemetry/Duration;)Ljava/lang/Long;", false); mv.visitVarInsn(ALOAD, 1); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", "getSuccess", "()Z", false); mv.visitVarInsn(ALOAD, 1); @@ -393,14 +481,20 @@ private void writeAgentTrackRemoteDependencyTelemetryMethod() { mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", "getProperties", "()Ljava/util/Map;", false); mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", "getMetrics", "()Ljava/util/Map;", false); - mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackDependency", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;" + - "Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V", - false); + Label label2 = new Label(); + mv.visitLabel(label2); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackDependency", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V", false); + Label label3 = new Label(); + mv.visitLabel(label3); mv.visitInsn(RETURN); - mv.visitMaxs(10, 2); + Label label4 = new Label(); + mv.visitLabel(label4); + mv.visitMaxs(11, 2); mv.visitEnd(); } @@ -408,6 +502,8 @@ private void writeAgentTrackPageViewTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackPageViewTelemetry", "(L" + unshadedPrefix + "/telemetry/PageViewTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/PageViewTelemetry", "getName", "()Ljava/lang/String;", false); @@ -421,21 +517,31 @@ private void writeAgentTrackPageViewTelemetryMethod() { mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/PageViewTelemetry", "getProperties", "()Ljava/util/Map;", false); mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/PageViewTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/PageViewTelemetry", "getMetrics", "()Ljava/util/concurrent/ConcurrentMap;", false); - mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackPageView", - "(Ljava/lang/String;Ljava/net/URI;JLjava/util/Map;Ljava/util/Map;)V", false); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackPageView", "(Ljava/lang/String;Ljava/net/URI;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;)V", false); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitInsn(RETURN); - mv.visitMaxs(6, 2); + Label label2 = new Label(); + mv.visitLabel(label2); + mv.visitMaxs(7, 2); mv.visitEnd(); } private void writeAgentTrackTraceTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackTraceTelemetry", "(L" + unshadedPrefix + "/telemetry/TraceTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TraceTelemetry", "getSeverityLevel", "()L" + unshadedPrefix + "/telemetry/SeverityLevel;", false); mv.visitVarInsn(ASTORE, 2); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitVarInsn(ALOAD, 2); Label label2 = new Label(); mv.visitJumpInsn(IFNULL, label2); @@ -449,14 +555,23 @@ private void writeAgentTrackTraceTelemetryMethod() { mv.visitLabel(label3); mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {Opcodes.INTEGER}); mv.visitVarInsn(ISTORE, 3); + Label label4 = new Label(); + mv.visitLabel(label4); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TraceTelemetry", "getMessage", "()Ljava/lang/String;", false); mv.visitVarInsn(ILOAD, 3); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TraceTelemetry", "getProperties", "()Ljava/util/Map;", false); - mv.visitMethodInsn(INVOKESTATIC, "com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil", "trackTrace", "(Ljava/lang/String;ILjava/util/Map;)V", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TraceTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackTrace", "(Ljava/lang/String;ILjava/util/Map;Ljava/util/Map;)V", false); + Label label5 = new Label(); + mv.visitLabel(label5); mv.visitInsn(RETURN); - mv.visitMaxs(5, 4); + Label label6 = new Label(); + mv.visitLabel(label6); + mv.visitMaxs(4, 4); mv.visitEnd(); } @@ -480,39 +595,60 @@ private void writeAgentTrackRequestTelemetryMethod() { mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RequestTelemetry", "getDuration", "()L" + unshadedPrefix + "/telemetry/Duration;", false); mv.visitMethodInsn(INVOKESPECIAL, unshadedPrefix + "/TelemetryClient", "agent$toMillis", "(L" + unshadedPrefix + "/telemetry/Duration;)Ljava/lang/Long;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); mv.visitVarInsn(ALOAD, 1); + Label label3 = new Label(); + mv.visitLabel(label3); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RequestTelemetry", "getResponseCode", "()Ljava/lang/String;", false); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RequestTelemetry", "isSuccess", "()Z", false); - mv.visitMethodInsn(INVOKESTATIC, "com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil", "trackRequest", "(Ljava/lang/String;Ljava/lang/String;Ljava/net/URL;Ljava/util/Date;JLjava/lang/String;Z)V", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RequestTelemetry", "getProperties", "()Ljava/util/Map;", false); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/RequestTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + Label label4 = new Label(); + mv.visitLabel(label4); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackRequest", "(Ljava/lang/String;Ljava/lang/String;Ljava/net/URL;Ljava/util/Date;Ljava/lang/Long;Ljava/lang/String;ZLjava/util/Map;Ljava/util/Map;)V", false); mv.visitLabel(label1); - Label label3 = new Label(); - mv.visitJumpInsn(GOTO, label3); + Label label5 = new Label(); + mv.visitJumpInsn(GOTO, label5); mv.visitLabel(label2); mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/net/MalformedURLException"}); mv.visitVarInsn(ASTORE, 2); + Label label6 = new Label(); + mv.visitLabel(label6); mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESTATIC, "com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil", "logErrorOnce", "(Ljava/lang/Throwable;)V", false); - mv.visitLabel(label3); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "logErrorOnce", "(Ljava/lang/Throwable;)V", false); + mv.visitLabel(label5); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitInsn(RETURN); - mv.visitMaxs(8, 3); + Label label7 = new Label(); + mv.visitLabel(label7); + mv.visitMaxs(9, 3); mv.visitEnd(); } private void writeAgentTrackExceptionTelemetryMethod() { MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "agent$trackExceptionTelemetry", "(L" + unshadedPrefix + "/telemetry/ExceptionTelemetry;)V", null, null); mv.visitCode(); + Label label0 = new Label(); + mv.visitLabel(label0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/ExceptionTelemetry", "getException", "()Ljava/lang/Exception;", false); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/ExceptionTelemetry", "getProperties", "()Ljava/util/Map;", false); mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/ExceptionTelemetry", "getContext", "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", "getTags", "()Ljava/util/concurrent/ConcurrentMap;", false); + mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, unshadedPrefix + "/telemetry/ExceptionTelemetry", "getMetrics", "()Ljava/util/concurrent/ConcurrentMap;", false); - mv.visitMethodInsn(INVOKESTATIC, "com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil", "trackException", "(Ljava/lang/Exception;Ljava/util/Map;Ljava/util/Map;)V", false); + mv.visitMethodInsn(INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackException", "(Ljava/lang/Exception;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V", false); + Label label1 = new Label(); + mv.visitLabel(label1); mv.visitInsn(RETURN); - mv.visitMaxs(3, 2); + Label label2 = new Label(); + mv.visitLabel(label2); + mv.visitMaxs(4, 2); mv.visitEnd(); } @@ -558,6 +694,12 @@ public static void main(String[] args) throws Exception { content = content.replace("com/microsoft/applicationinsights/telemetry", "\" + unshadedPrefix + \"/telemetry"); content = content.replace("\"com/microsoft/applicationinsights/agent/internal/instrumentation/sdk" + "/TelemetryClientClassFileTransformer$TC", "unshadedPrefix + \"/TelemetryClient"); + content = content.replace("\"com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil\"", "BYTECODE_UTIL_INTERNAL_NAME"); + content = content.replace("methodVisitor = classWriter.", "MethodVisitor mv = cw."); + content = content.replace("methodVisitor.", "mv."); + content = content.replace("\r\n", "\n"); + content = content.replaceAll("(?m)^[^\n]*visitLineNumber[^\n]*\n", ""); + content = content.replaceAll("(?m)^[^\n]*visitLocalVariable[^\n]*\n", ""); System.out.println(content); } @@ -567,6 +709,14 @@ public static class TC { private TelemetryConfiguration configuration; + public TelemetryContext getContext() { + return null; + } + + public void flush() { + BytecodeUtil.flush(); + } + public boolean isDisabled() { return configuration.isTrackingDisabled(); } @@ -582,6 +732,25 @@ public void track(Telemetry telemetry) { if (isDisabled()) { return; } + + if (telemetry.getTimestamp() == null) { + telemetry.setTimestamp(new Date()); + } + + // intentionally not getting instrumentation key from TelemetryClient + // while still allowing it to be overridden at Telemetry level + + // intentionally not getting cloud role name or cloud role instance from TelemetryClient + // while still allowing them to be overridden at Telemetry level + + // rationale: if setting something programmatically, then can un-set it programmatically + + BytecodeUtil.copy(getContext().getTags(), telemetry.getContext().getTags()); + BytecodeUtil.copy(getContext().getProperties(), telemetry.getContext().getProperties()); + + // don't run telemetry initializers or telemetry processors + // (otherwise confusing message to have different rules for 2.x SDK interop telemetry) + try { if (telemetry instanceof EventTelemetry) { agent$trackEventTelemetry((EventTelemetry) telemetry); @@ -610,39 +779,40 @@ public void track(Telemetry telemetry) { } private void agent$trackEventTelemetry(EventTelemetry t) { - BytecodeUtil.trackEvent(t.getName(), t.getProperties(), t.getMetrics()); + BytecodeUtil.trackEvent(t.getName(), t.getProperties(), t.getContext().getTags(), t.getMetrics()); } private void agent$trackMetricTelemetry(MetricTelemetry t) { BytecodeUtil.trackMetric(t.getName(), t.getValue(), t.getCount(), t.getMin(), t.getMax(), - t.getStandardDeviation(), t.getProperties()); + t.getStandardDeviation(), t.getProperties(), t.getContext().getTags()); } private void agent$trackRemoteDependencyTelemetry(RemoteDependencyTelemetry t) { BytecodeUtil.trackDependency(t.getName(), t.getId(), t.getResultCode(), agent$toMillis(t.getDuration()), - t.getSuccess(), t.getCommandName(), t.getType(), t.getTarget(), t.getProperties(), t.getMetrics()); + t.getSuccess(), t.getCommandName(), t.getType(), t.getTarget(), t.getProperties(), t.getContext().getTags(), t.getMetrics()); } private void agent$trackPageViewTelemetry(PageViewTelemetry t) { - BytecodeUtil.trackPageView(t.getName(), t.getUri(), t.getDuration(), t.getProperties(), t.getMetrics()); + BytecodeUtil.trackPageView(t.getName(), t.getUri(), t.getDuration(), t.getProperties(), t.getContext().getTags(), t.getMetrics()); } private void agent$trackTraceTelemetry(TraceTelemetry t) { SeverityLevel level = t.getSeverityLevel(); - int severityLevel = level != null ? level.getValue(): -1; - BytecodeUtil.trackTrace(t.getMessage(), severityLevel, t.getProperties()); + int severityLevel = level != null ? level.getValue() : -1; + BytecodeUtil.trackTrace(t.getMessage(), severityLevel, t.getProperties(), t.getContext().getTags()); } private void agent$trackRequestTelemetry(RequestTelemetry t) { try { - BytecodeUtil.trackRequest(t.getId(), t.getName(), t.getUrl(), t.getTimestamp(), agent$toMillis(t.getDuration()), t.getResponseCode(), t.isSuccess()); + BytecodeUtil.trackRequest(t.getId(), t.getName(), t.getUrl(), t.getTimestamp(), agent$toMillis(t.getDuration()), + t.getResponseCode(), t.isSuccess(), t.getProperties(), t.getContext().getTags()); } catch (MalformedURLException e) { BytecodeUtil.logErrorOnce(e); } } - public void agent$trackExceptionTelemetry(ExceptionTelemetry telemetry) { - BytecodeUtil.trackException(telemetry.getException(), telemetry.getProperties(), telemetry.getMetrics()); + private void agent$trackExceptionTelemetry(ExceptionTelemetry t) { + BytecodeUtil.trackException(t.getException(), t.getProperties(), t.getContext().getTags(), t.getMetrics()); } @Nullable diff --git a/agent/instrumentation/build.gradle b/agent/instrumentation/build.gradle index 4ef76a2f0d0..8de99384b54 100644 --- a/agent/instrumentation/build.gradle +++ b/agent/instrumentation/build.gradle @@ -15,7 +15,7 @@ dependencies { compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-apache-httpasyncclient-4.0', version: instrumentationVersion compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-apache-httpclient-2.0', version: instrumentationVersion compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-apache-httpclient-4.0', version: instrumentationVersion - compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-applicationinsights-web-2.1', version: instrumentationVersion + compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-applicationinsights-web-2.3', version: instrumentationVersion compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-azure-functions', version: instrumentationVersion compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-cassandra-3.0', version: instrumentationVersion compile group: 'io.opentelemetry.javaagent.instrumentation', name: 'opentelemetry-javaagent-cassandra-4.0', version: instrumentationVersion diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryClient.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryClient.java index 7773812bb71..37d260a1473 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryClient.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryClient.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.Map; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; @@ -33,18 +34,8 @@ import com.microsoft.applicationinsights.extensibility.context.InternalContext; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulseDataCollector; import com.microsoft.applicationinsights.internal.util.MapUtil; -import com.microsoft.applicationinsights.telemetry.Duration; -import com.microsoft.applicationinsights.telemetry.EventTelemetry; -import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry; -import com.microsoft.applicationinsights.telemetry.MetricTelemetry; -import com.microsoft.applicationinsights.telemetry.PageViewTelemetry; -import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry; -import com.microsoft.applicationinsights.telemetry.RequestTelemetry; -import com.microsoft.applicationinsights.telemetry.SessionState; -import com.microsoft.applicationinsights.telemetry.SeverityLevel; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TelemetryContext; -import com.microsoft.applicationinsights.telemetry.TraceTelemetry; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; @@ -112,277 +103,6 @@ public boolean isDisabled() { || configuration.isTrackingDisabled(); } - /** - * Sends the specified state of a user session to Application Insights using {@link #trackEvent(String name)} as this method will be deprecated. - * @param sessionState {@link com.microsoft.applicationinsights.telemetry.SessionState} - * value indicating the state of a user session. - * @deprecated This method will be deprecated in version 2.0.0 of the Java SDK. - */ - @Deprecated - public void trackSessionState(SessionState sessionState) { - this.trackEvent("Track Session State: " + sessionState.toString()); - } - - /** - * Sends a custom event record to Application Insights. Appears in custom events in Analytics, Search and Metrics Explorer. - * @param name A name for the event. Max length 150. - * @param properties Named string values you can use to search and filter events. - * @param metrics Numeric measurements associated with this event. Appear under Custom Metrics in Metrics Explorer. - */ - public void trackEvent(String name, Map properties, Map metrics) { - if (isDisabled()) { - return; - } - - if (Strings.isNullOrEmpty(name)) { - name = ""; - } - - EventTelemetry et = new EventTelemetry(name); - - MapUtil.copy(properties, et.getContext().getProperties()); - MapUtil.copy(metrics, et.getMetrics()); - - this.track(et); - } - - /** - * Sends a custom event record to Application Insights. Appears in "custom events" in Analytics, Search and Metrics Explorer. - * @param name A name for the event. Max length 150. - */ - public void trackEvent(String name) { - trackEvent(name, null, null); - } - - /** - * Sends a custom event record to Application Insights. Appears in "custom events" in Analytics, Search and Metrics Explorer. - * @param telemetry An event telemetry item. - */ - public void trackEvent(EventTelemetry telemetry) { - track(telemetry); - } - - /** - * Sends a TraceTelemetry record to Application Insights. Appears in "traces" in Analytics and Search. - * @param message A log message. Max length 10000. - * @param severityLevel The severity level. - * @param properties Named string values you can use to search and classify trace messages. - */ - public void trackTrace(String message, SeverityLevel severityLevel, Map properties) { - if (isDisabled()) { - return; - } - - if (Strings.isNullOrEmpty(message)) { - message = ""; - } - - TraceTelemetry et = new TraceTelemetry(message, severityLevel); - - MapUtil.copy(properties, et.getContext().getProperties()); - - this.track(et); - } - - /** - * Sends a TraceTelemetry record to Application Insights. Appears in "traces" in Analytics and Search. - * @param message A log message. Max length 10000. - */ - public void trackTrace(String message) { - trackTrace(message, null, null); - } - - /** - * Sends a TraceTelemetry record. Appears in "traces" in Analytics and Search. - * @param message A log message. Max length 10000. - * @param severityLevel The severity level. - */ - public void trackTrace(String message, SeverityLevel severityLevel) { - trackTrace(message, severityLevel, null); - } - - /** - * Sends a TraceTelemetry record for display in Diagnostic Search. - * @param telemetry The {@link com.microsoft.applicationinsights.telemetry.Telemetry} instance. - */ - public void trackTrace(TraceTelemetry telemetry) { - this.track(telemetry); - } - - /** - * Sends a numeric metric to Application Insights. Appears in customMetrics in Analytics, and under Custom Metrics in Metric Explorer. - * @param name The name of the metric. Max length 150. - * @param value The value of the metric. Sum if based on more than one sample count. - * @param sampleCount The sample count. - * @param min The minimum value of the sample. - * @param max The maximum value of the sample. - * @param properties Named string values you can use to search and classify trace messages. - * @throws IllegalArgumentException if name is null or empty. - * @deprecated Use {@link #trackMetric(String, double, Integer, Double, Double, Double, Map)} - */ - @Deprecated - public void trackMetric(String name, double value, int sampleCount, double min, double max, Map properties) { - this.trackMetric(name, value, sampleCount, min, max, null, properties); - } - - /** - * Sends a numeric metric to Application Insights. Appears in customMetrics in Analytics, and under Custom Metrics in Metric Explorer. - * - * @param name The name of the metric. Max length 150. - * @param value The value of the metric. Sum if it represents an aggregation. - * @param sampleCount The sample count. - * @param min The minimum value of the sample. - * @param max The maximum value of the sample. - * @param stdDev The standard deviation of the sample. - * @param properties Named string values you can use to search and classify trace messages. - * @throws IllegalArgumentException if name is null or empty - */ - public void trackMetric(String name, double value, Integer sampleCount, Double min, Double max, Double stdDev, Map properties) { - if (isDisabled()) { - return; - } - - MetricTelemetry mt = new MetricTelemetry(name, value); - mt.setCount(sampleCount); - mt.setMin(min); - mt.setMax(max); - mt.setStandardDeviation(stdDev); - MapUtil.copy(properties, mt.getProperties()); - this.track(mt); - } - - /** - * Sends a numeric metric to Application Insights. Appears in customMetrics in Analytics, and under Custom Metrics in Metric Explorer. - * @param name The name of the metric. Max length 150. - * @param value The value of the metric. - * @throws IllegalArgumentException if name is null or empty. - */ - public void trackMetric(String name, double value) { - trackMetric(name, value, null, null, null, null, null); - } - - /** - * Sends a numeric metric to Application Insights. Appears in customMetrics in Analytics, and under Custom Metrics in Metric Explorer. - * @param telemetry The {@link com.microsoft.applicationinsights.telemetry.Telemetry} instance. - */ - public void trackMetric(MetricTelemetry telemetry) { - track(telemetry); - } - - /** - * Sends an exception record to Application Insights. Appears in "exceptions" in Analytics and Search. - * @param exception The exception to log information about. - * @param properties Named string values you can use to search and classify trace messages. - * @param metrics Measurements associated with this exception event. Appear in "custom metrics" in Metrics Explorer. - */ - public void trackException(Exception exception, Map properties, Map metrics) { - if (isDisabled()) { - return; - } - - ExceptionTelemetry et = new ExceptionTelemetry(exception); - - MapUtil.copy(properties, et.getContext().getProperties()); - MapUtil.copy(metrics, et.getMetrics()); - - this.track(et); - } - - /** - * Sends an exception record to Application Insights. Appears in "exceptions" in Analytics and Search. - * @param exception The exception to log information about. - */ - public void trackException(Exception exception) { - trackException(exception, null, null); - } - - /** - * Sends an ExceptionTelemetry record for display in Diagnostic Search. - * @param telemetry An already constructed exception telemetry record. - */ - public void trackException(ExceptionTelemetry telemetry) { - track(telemetry); - } - - /** - * Sends a request record to Application Insights. Appears in "requests" in Search and Analytics, - * and contributes to metric charts such as Server Requests, Server Response Time, Failed Requests. - * @param name A user-friendly name for the request or operation. - * @param timestamp The time of the request. - * @param duration The duration, in milliseconds, of the request processing. - * @param responseCode The HTTP response code. - * @param success true to record the operation as a successful request, false as a failed request. - */ - public void trackHttpRequest(String name, Date timestamp, long duration, String responseCode, boolean success) { - if (isDisabled()) { - return; - } - - track(new RequestTelemetry(name, timestamp, duration, responseCode, success)); - } - - - /** - * Sends a request record to Application Insights. Appears in "requests" in Search and Analytics, - * and contributes to metric charts such as Server Requests, Server Response Time, Failed Requests. - * - * @param request request - */ - public void trackRequest(RequestTelemetry request) { - track(request); - } - - public void trackDependency(String dependencyName, String commandName, Duration duration, boolean success) { - RemoteDependencyTelemetry remoteDependencyTelemetry = new RemoteDependencyTelemetry(dependencyName, commandName, duration, success); - - trackDependency(remoteDependencyTelemetry); - } - - /** - * Sends a dependency record to Application Insights. Appears in "dependencies" in Search and Analytics. - * Set device type == "PC" to have the record contribute to metric charts such as - * Server Dependency Calls, Dependency Response Time, and Dependency Failures. - * @param telemetry telemetry - */ - public void trackDependency(RemoteDependencyTelemetry telemetry) { - if (isDisabled()) { - return; - } - - if (telemetry == null) { - telemetry = new RemoteDependencyTelemetry(""); - } - - track(telemetry); - } - - /** - * Sends a page view record to Application Insights. Appears in "page views" in Search and Analytics, - * and contributes to metric charts such as Page View Load Time. - @param name The name of the page. - */ - public void trackPageView(String name) { - // Avoid creation of data if not needed - if (isDisabled()) { - return; - } - - if (name == null) { - name = ""; - } - - Telemetry telemetry = new PageViewTelemetry(name); - track(telemetry); - } - - /** - * Send information about the page viewed in the application. - * @param telemetry The telemetry to send - */ - public void trackPageView(PageViewTelemetry telemetry) { - track(telemetry); - } - /** * This method is part of the Application Insights infrastructure. Do not call it directly. * @param telemetry The {@link com.microsoft.applicationinsights.telemetry.Telemetry} instance. @@ -405,28 +125,28 @@ public void track(Telemetry telemetry) { telemetry.setTimestamp(new Date()); } - TelemetryContext ctx = this.getContext(); - - if (Strings.isNullOrEmpty(ctx.getInstrumentationKey())) { - ctx.setInstrumentationKey(configuration.getInstrumentationKey()); + // TODO does this work with auto-updating Azure Spring Cloud connection string, since existing is not null? + if (Strings.isNullOrEmpty(getContext().getInstrumentationKey())) { + getContext().setInstrumentationKey(configuration.getInstrumentationKey()); } - try { - telemetry.getContext().initialize(ctx); - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t) { - try { - logger.error("Exception while telemetry context's initialization: '{}'", t.toString()); } catch (ThreadDeath td) { - throw td; - } catch (Throwable t2) { - // chomp - } - } + TelemetryContext context = telemetry.getContext(); + // always use agent instrumentationKey, since that is (at least currently) always global in OpenTelemetry world + // (otherwise confusing message to have different rules for 2.x SDK interop telemetry) + context.setInstrumentationKey(getContext().getInstrumentationKey(), getContext().getNormalizedInstrumentationKey()); - if (Strings.isNullOrEmpty(telemetry.getContext().getInstrumentationKey())) { - throw new IllegalArgumentException("Instrumentation key cannot be undefined."); - } + // the TelemetryClient's base context contains tags: + // * cloud role name + // * cloud role instance + // * sdk version + // * component version + // always use agent "resource attributes", since those are (at least currently) always global in OpenTelemetry world + // (otherwise confusing message to have different rules for 2.x SDK interop telemetry) + context.getTags().putAll(getContext().getTags()); + + // the TelemetryClient's base context contains properties: + // * "customDimensions" provided by json configuration + context.getProperties().putAll(getContext().getProperties()); try { QuickPulseDataCollector.INSTANCE.add(telemetry); diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java index d3b6b419daa..334da6add3f 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java @@ -237,7 +237,7 @@ private void send() { MetricTelemetry telemetry = gatherData(); telemetry.getContext().getOperation().setSyntheticSource(HEARTBEAT_SYNTHETIC_METRIC_NAME); - telemetryClient.trackMetric(telemetry); + telemetryClient.track(telemetry); logger.trace("No of heartbeats sent, {}", ++heartbeatsSent); } diff --git a/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java b/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java index 14f5ec65381..2c3601fc98e 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java +++ b/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java @@ -207,14 +207,6 @@ public ConcurrentMap getTags() { return tags; } - public void initialize(TelemetryContext source) { - if (Strings.isNullOrEmpty(this.instrumentationKey) && !Strings.isNullOrEmpty(source.getInstrumentationKey())) - setInstrumentationKey(source.getInstrumentationKey(), source.getNormalizedInstrumentationKey()); - - MapUtil.copy(source.tags, this.tags); - MapUtil.copy(source.properties, this.properties); - } - public InternalContext getInternal() { if (internal == null) { internal = new InternalContext(tags); diff --git a/core/src/test/java/com/microsoft/applicationinsights/TelemetryClientTests.java b/core/src/test/java/com/microsoft/applicationinsights/TelemetryClientTests.java index 774d602b918..7b63a9420fd 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/TelemetryClientTests.java +++ b/core/src/test/java/com/microsoft/applicationinsights/TelemetryClientTests.java @@ -21,13 +21,10 @@ package com.microsoft.applicationinsights; -import java.net.URL; import java.util.List; import java.util.Map; -import java.util.HashMap; import java.util.Date; import java.util.LinkedList; -import java.util.concurrent.TimeUnit; import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.extensibility.ContextInitializer; @@ -44,7 +41,6 @@ import org.mockito.stubbing.Answer; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.any; @@ -103,58 +99,6 @@ public void testNodeNameExists() Assert.assertFalse(nodeName == null || nodeName.length()==0); } - @Test - public void testNodeNameSent() { - client.trackEvent("Event"); - - EventTelemetry telemetry = (EventTelemetry) verifyAndGetLastEventSent(); - String nodeName = telemetry.getContext().getInternal().getNodeName(); - Assert.assertFalse(nodeName == null || nodeName.length()==0); - } - - @Test - public void testOverideNodeName(){ - String overrideNode = "NewNodeName"; - client.getContext().getInternal().setNodeName(overrideNode); - client.trackEvent("Event"); - EventTelemetry telemetry = (EventTelemetry) verifyAndGetLastEventSent(); - String nodeName = telemetry.getContext().getInternal().getNodeName(); - Assert.assertTrue("NodeName was not overriden", nodeName.equals(overrideNode)); - } - - @Test - public void testChannelSendException() { - TelemetryChannel mockChannel = new TelemetryChannel() { - @Override - public boolean isDeveloperMode() { - return false; - } - - @Override - public void setDeveloperMode(boolean value) { - - } - - @Override - public void send(Telemetry item) { - throw new RuntimeException(); - } - - @Override - public void shutdown(long timeout, TimeUnit timeUnit) { - - } - - @Override - public void flush() { - - } - }; - - configuration.setChannel(mockChannel); - client.trackEvent("Mock"); - } - @Test(expected = IllegalArgumentException.class) public void testNullTrackTelemetry() { client.track(null); @@ -211,228 +155,10 @@ public void testTelemetryContextsAreCalled() { Mockito.verify(mockContextInitializer, Mockito.times(1)).initialize(any(TelemetryContext.class)); } - @Test - public void testTrackEventWithPropertiesAndMetrics() { - Map properties = new HashMap() {{ put("key", "value"); }}; - Map metrics = new HashMap() {{ put("key", 1d); }}; - - client.trackEvent("Event", properties, metrics); - - EventTelemetry telemetry = (EventTelemetry) verifyAndGetLastEventSent(); - Assert.assertTrue("Expected telemetry property not found", telemetry.getProperties().get("key").equalsIgnoreCase("value")); - Assert.assertTrue("Expected telemetry property not found", 1d == telemetry.getMetrics().get("key")); - } - - @Test - public void testTrackEventWithName() { - client.trackEvent("Event"); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackEventWithEventTelemetry() { - EventTelemetry eventTelemetry = new EventTelemetry("Event"); - client.trackEvent(eventTelemetry); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackSessionState() { - client.trackSessionState(SessionState.End); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackTraceAll() { - Map properties = new HashMap() {{ put("key", "value"); }}; - client.trackTrace("Trace", SeverityLevel.Error, properties); - - Telemetry telemetry = verifyAndGetLastEventSent(); - verifyTraceTelemetry(telemetry, SeverityLevel.Error, properties); - } - - @Test - public void testTrackTraceWithProperties() { - Map properties = new HashMap() {{ put("key", "value"); }}; - client.trackTrace("Trace", null, properties); - - Telemetry telemetry = verifyAndGetLastEventSent(); - verifyTraceTelemetry(telemetry, null, properties); - } - - @Test - public void testTrackTraceWithSeverityLevel() { - client.trackTrace("Trace", SeverityLevel.Critical); - - Telemetry telemetry = verifyAndGetLastEventSent(); - verifyTraceTelemetry(telemetry, SeverityLevel.Critical, null); - } - - @Test - public void testTrackTraceWithName() { - client.trackTrace("Trace"); - - verifyAndGetLastEventSent();} - - @Test - public void testTrackTraceWithTraceTelemetry() { - TraceTelemetry telemetry = new TraceTelemetry("Trace"); - client.trackTrace(telemetry); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackMetricWithExpandedValues() { - Map properties = new HashMap() {{ put("key", "value"); }}; - client.trackMetric("Metric", 1, 1, 1, 1, properties); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackMetricWithNameAndValue() { - final String name = "Metric"; - final double value = 1.11; - client.trackMetric(name, value); - - MetricTelemetry mt = (MetricTelemetry) verifyAndGetLastEventSent(); - assertEquals("getName", name, mt.getName()); - assertEquals("getValue", value, mt.getValue(), Math.ulp(value)); - - assertNull("getCount should be null", mt.getCount()); - assertNull("getMin should be null", mt.getMin()); - assertNull("getMax should be null", mt.getMax()); - assertNull("getStandardDeviation should be null", mt.getStandardDeviation()); - assertTrue("properties should be empty", mt.getProperties().isEmpty()); - } - - @Test - public void testTrackMetricWithAllValues() { - Map props = new HashMap() {{ - put("key1", "value1"); - put("key2", "value2"); - }}; - - final String name = "MyMetric"; - final double value = 1.01; - final Integer sampleCount = 2; - final Double min = 0.01; - final Double max = 1.0; - final Double stdDev = 0.636396; - - client.trackMetric(name, value, sampleCount, min, max, stdDev, props); - MetricTelemetry mt = (MetricTelemetry) verifyAndGetLastEventSent(); - - assertEquals("getName", name, mt.getName()); - assertEquals("getValue", value, mt.getValue(), Math.ulp(value)); - assertEquals("getMin", min, mt.getMin()); - assertEquals("getMax", max, mt.getMax()); - assertEquals("getStandardDeviation", stdDev, mt.getStandardDeviation()); - assertNotNull("getProperties should be non-null", mt.getProperties()); - for (String key : props.keySet()) { - assertTrue("metric properties contains key", mt.getProperties().containsKey(key)); - assertEquals("metric properties key/value pair did not match", props.get(key), mt.getProperties().get(key)); - } - } - - @Test - public void testTrackMetricAggregateWithSomeNulls() { - Map propsIsNull = null; - - final String name = "MyMetricHasNulls"; - final double value = 1.02; - final Integer sampleCount = 3; - final Double minIsNull = null; - final Double max = 0.99; - final Double stdDevIsNull = null; - - client.trackMetric(name, value, sampleCount, minIsNull, max, stdDevIsNull, propsIsNull); - MetricTelemetry mt = (MetricTelemetry) verifyAndGetLastEventSent(); - - assertEquals("getName", name, mt.getName()); - assertEquals("getValue", value, mt.getValue(), Math.ulp(value)); - assertNull("getMin should be null", mt.getMin()); - assertEquals("getMax", max, mt.getMax()); - assertNull("getStandardDeviation should be null", mt.getStandardDeviation()); - assertNotNull("getProperties should be null", mt.getProperties()); - assertEquals("properties size", 0, mt.getProperties().size()); - } - - @Test - public void testTrackMetricWithMetricTelemetry() { - MetricTelemetry telemetry = new MetricTelemetry("Metric", 1); - client.trackMetric(telemetry); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackExceptionWithPropertiesAndMetrics() { - Exception exception = new Exception("Exception"); - Map properties = new HashMap() {{ put("key", "value"); }}; - Map metrics = new HashMap() {{ put("key", 1d); }}; - - client.trackException(exception, properties, metrics); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackExceptionWithExceptionTelemetry() { - ExceptionTelemetry telemetry = new ExceptionTelemetry(new Exception("Exception")); - - client.trackException(telemetry); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackException() { - Exception exception = new Exception("Exception"); - - client.trackException(exception); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackHttpRequest() { - client.trackHttpRequest("Name", new Date(), 1, "200", true); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackHttpRequestWithHttpRequestTelemetry() { - RequestTelemetry telemetry = new RequestTelemetry("Name", new Date(), 1, "200", true); - client.trackRequest(telemetry); - - verifyAndGetLastEventSent(); - } - @Test @Ignore("Not supported yet.") //FIXME yes, it is public void testTrackRemoteDependency(){ } - @Test - public void testTrackPageViewWithName() { - client.trackPageView("PageName"); - - verifyAndGetLastEventSent(); - } - - @Test - public void testTrackPageViewWithPageViewTelemetry() { - PageViewTelemetry telemetry = new PageViewTelemetry("PageName"); - client.trackPageView(telemetry); - - verifyAndGetLastEventSent(); - } - @Test public void testTrackWithCustomTelemetryTimestamp() { Date timestamp = new Date(10000); diff --git a/core/src/test/java/com/microsoft/applicationinsights/telemetry/TelemetryContextTest.java b/core/src/test/java/com/microsoft/applicationinsights/telemetry/TelemetryContextTest.java index d88b15d3bb1..2e91cc4e5f6 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/telemetry/TelemetryContextTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/telemetry/TelemetryContextTest.java @@ -21,7 +21,6 @@ package com.microsoft.applicationinsights.telemetry; -import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.assertNull; @@ -29,7 +28,6 @@ import static org.junit.Assert.assertEquals; public final class TelemetryContextTest { - private final static String TEST_IKEY = "00000000-0000-0000-0000-000000000000"; @Test public void testCtor() { @@ -47,29 +45,4 @@ public void testSetInstrumentationKey() { assertEquals("key", context.getInstrumentationKey()); } - - @Test - public void testEmptyInstrumentationKeyOverridenWhenContextInitialized() { - TelemetryContext contextToInitialize = new TelemetryContext(); - - TelemetryContext context = new TelemetryContext(); - context.setInstrumentationKey(TEST_IKEY); - - contextToInitialize.initialize(context); - - Assert.assertEquals(TEST_IKEY, contextToInitialize.getInstrumentationKey()); - } - - @Test - public void testInstrumentationKeyNotOverridenWhenContextInitialized() { - TelemetryContext contextToInitialize = new TelemetryContext(); - contextToInitialize.setInstrumentationKey(TEST_IKEY); - - TelemetryContext context = new TelemetryContext(); - context.setInstrumentationKey(TEST_IKEY.replaceFirst("0", "1")); - - contextToInitialize.initialize(context); - - Assert.assertEquals(TEST_IKEY, contextToInitialize.getInstrumentationKey()); - } } diff --git a/otel b/otel index 07d69e7c31d..adf5d039383 160000 --- a/otel +++ b/otel @@ -1 +1 @@ -Subproject commit 07d69e7c31d77632fc989778e1418477c00be735 +Subproject commit adf5d039383a1d9399a46a0e7d0b96d76ca81c4f diff --git a/test/smoke/appServers/global-resources/default_applicationinsights.json b/test/smoke/appServers/global-resources/default_applicationinsights.json index 89a87209b8d..32c21914d09 100644 --- a/test/smoke/appServers/global-resources/default_applicationinsights.json +++ b/test/smoke/appServers/global-resources/default_applicationinsights.json @@ -1,3 +1,7 @@ { - "connectionString": "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://fakeingestion:60606/" + "connectionString": "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://fakeingestion:60606/", + "role": { + "name": "testrolename", + "instance": "testroleinstance" + } } diff --git a/test/smoke/testApps/CoreAndFilter/src/main/java/com/microsoft/ajl/simplecalc/SimpleTrackPageViewServlet.java b/test/smoke/testApps/CoreAndFilter/src/main/java/com/microsoft/ajl/simplecalc/SimpleTrackPageViewServlet.java index 916d483b6c5..c7851d8d3e5 100644 --- a/test/smoke/testApps/CoreAndFilter/src/main/java/com/microsoft/ajl/simplecalc/SimpleTrackPageViewServlet.java +++ b/test/smoke/testApps/CoreAndFilter/src/main/java/com/microsoft/ajl/simplecalc/SimpleTrackPageViewServlet.java @@ -1,7 +1,6 @@ package com.microsoft.ajl.simplecalc; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; @@ -14,7 +13,7 @@ /** * Servlet implementation class SimpleTrackTraceServlet */ -@WebServlet(description = "calls trackPageView twice; once vanilla, once with properties", urlPatterns = { "/trackPageView" }) +@WebServlet(description = "calls trackPageView twice; once vanilla, once with properties", urlPatterns = {"/trackPageView"}) public class SimpleTrackPageViewServlet extends HttpServlet { private static final long serialVersionUID = -633683109556605395L; private TelemetryClient client = new TelemetryClient(); @@ -25,10 +24,42 @@ public class SimpleTrackPageViewServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { client.trackPageView("test-page"); - PageViewTelemetry pvt = new PageViewTelemetry("test-page-2"); - pvt.getProperties().put("key", "value"); - pvt.setDuration(123456); - client.trackPageView(pvt); + // just making sure flush() doesn't throw exception + client.flush(); + + PageViewTelemetry pvt2 = new PageViewTelemetry("test-page-2"); + pvt2.getContext().setInstrumentationKey("12341234-1234-1234-1234-123412341234"); + pvt2.getContext().getUser().setId("user-id-goes-here"); + pvt2.getContext().getUser().setAccountId("account-id-goes-here"); + pvt2.getContext().getUser().setUserAgent("user-agent-goes-here"); + // don't set device id, because then tests fail with "Telemetry from previous container" + // because they use device id to verify telemetry is from the current container + pvt2.getContext().getDevice().setOperatingSystem("os-goes-here"); + pvt2.getContext().getSession().setId("session-id-goes-here"); + pvt2.getContext().getLocation().setIp("1.2.3.4"); + pvt2.getContext().getProperties().put("a-prop", "a-value"); + pvt2.getContext().getProperties().put("another-prop", "another-value"); + pvt2.getProperties().put("key", "value"); + pvt2.setDuration(123456); + client.trackPageView(pvt2); + + TelemetryClient otherClient = new TelemetryClient(); + // this instrumentation set directly on the TelemetryClient should is intentionally ignored by interop + otherClient.getContext().setInstrumentationKey("12341234-1234-1234-1234-123412341234"); + otherClient.getContext().getUser().setId("user-id-goes-here"); + otherClient.getContext().getUser().setAccountId("account-id-goes-here"); + otherClient.getContext().getUser().setUserAgent("user-agent-goes-here"); + // don't set device id, because then tests fail with "Telemetry from previous container" + // because they use device id to verify telemetry is from the current container + otherClient.getContext().getDevice().setOperatingSystem("os-goes-here"); + otherClient.getContext().getSession().setId("session-id-goes-here"); + otherClient.getContext().getLocation().setIp("1.2.3.4"); + otherClient.getContext().getProperties().put("a-prop", "a-value"); + otherClient.getContext().getProperties().put("another-prop", "another-value"); + PageViewTelemetry pvt3 = new PageViewTelemetry("test-page-3"); + pvt3.getProperties().put("key", "value"); + pvt3.setDuration(123456); + otherClient.trackPageView(pvt3); ServletFuncs.geRrenderHtml(request, response); } diff --git a/test/smoke/testApps/CoreAndFilter/src/main/resources/ApplicationInsights.xml b/test/smoke/testApps/CoreAndFilter/src/main/resources/ApplicationInsights.xml index b99edf3b42b..bf57db8effa 100644 --- a/test/smoke/testApps/CoreAndFilter/src/main/resources/ApplicationInsights.xml +++ b/test/smoke/testApps/CoreAndFilter/src/main/resources/ApplicationInsights.xml @@ -4,7 +4,9 @@ - InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://non-existent-host + + BAD1BAD1-BAD1-BAD1-BAD1-BAD1BAD1BAD1 true @@ -33,9 +35,11 @@ + http://non-existent-host/v2/track true 1 + False diff --git a/test/smoke/testApps/CoreAndFilter/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilterTests.java b/test/smoke/testApps/CoreAndFilter/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilterTests.java index 80b03d2306b..59371c6c83b 100644 --- a/test/smoke/testApps/CoreAndFilter/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilterTests.java +++ b/test/smoke/testApps/CoreAndFilter/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilterTests.java @@ -18,7 +18,6 @@ import com.microsoft.applicationinsights.internal.schemav2.RequestData; import com.microsoft.applicationinsights.internal.schemav2.SeverityLevel; import com.microsoft.applicationinsights.smoketest.matchers.ExceptionDataMatchers; -import com.microsoft.applicationinsights.smoketest.matchers.PageViewDataMatchers; import com.microsoft.applicationinsights.smoketest.matchers.TraceDataMatchers; import com.microsoft.applicationinsights.telemetry.Duration; import org.junit.Test; @@ -37,10 +36,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.lessThan; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; @UseAgent public class CoreAndFilterTests extends AiSmokeTest { @@ -254,27 +250,77 @@ public void testTrackPageView() throws Exception { Envelope rdEnvelope = rdList.get(0); String operationId = rdEnvelope.getTags().get("ai.operation.id"); - List pvdList = mockedIngestion.waitForItemsInOperation("PageViewData", 2, operationId); - - Envelope pvdEnvelope1 = pvdList.get(0); - Envelope pvdEnvelope2 = pvdList.get(1); + List pvdList = mockedIngestion.waitForItemsInOperation("PageViewData", 3, operationId); RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); - final List pageViews = mockedIngestion.getTelemetryDataByTypeInRequest("PageViewData"); - assertThat(pageViews, hasItem(allOf( - PageViewDataMatchers.hasName("test-page"), - PageViewDataMatchers.hasDuration(new Duration(0)) - ))); - - assertThat(pageViews, hasItem(allOf( - PageViewDataMatchers.hasName("test-page-2"), - PageViewDataMatchers.hasDuration(new Duration(123456)), - PageViewDataMatchers.hasProperty("key", "value") - ))); + Envelope pvdEnvelope1 = null; + Envelope pvdEnvelope2 = null; + Envelope pvdEnvelope3 = null; + + for (Envelope pvdEnvelope : pvdList) { + PageViewData pv = (PageViewData) ((Data) pvdEnvelope.getData()).getBaseData(); + if (pv.getName().equals("test-page")) { + pvdEnvelope1 = pvdEnvelope; + } else if (pv.getName().equals("test-page-2")) { + pvdEnvelope2 = pvdEnvelope; + } else if (pv.getName().equals("test-page-3")) { + pvdEnvelope3 = pvdEnvelope; + } else { + throw new AssertionError("Unexpected page view: " + pv.getName()); + } + } + + PageViewData pv1 = (PageViewData) ((Data) pvdEnvelope1.getData()).getBaseData(); + PageViewData pv2 = (PageViewData) ((Data) pvdEnvelope2.getData()).getBaseData(); + PageViewData pv3 = (PageViewData) ((Data) pvdEnvelope3.getData()).getBaseData(); + + assertNotNull(pv1); + assertEquals(new Duration(0), pv1.getDuration()); + // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are from the agent + assertEquals("00000000-0000-0000-0000-0FEEDDADBEEF", pvdEnvelope1.getIKey()); + assertEquals("testrolename", pvdEnvelope1.getTags().get("ai.cloud.role")); + assertEquals("testroleinstance", pvdEnvelope1.getTags().get("ai.cloud.roleInstance")); + assertTrue(pvdEnvelope1.getTags().get("ai.internal.sdkVersion").startsWith("java:3.")); + + assertNotNull(pv2); + assertEquals(new Duration(123456), pv2.getDuration()); + assertEquals("value", pv2.getProperties().get("key")); + assertEquals("a-value", pv2.getProperties().get("a-prop")); + assertEquals("another-value", pv2.getProperties().get("another-prop")); + assertEquals("user-id-goes-here", pvdEnvelope2.getTags().get("ai.user.id")); + assertEquals("account-id-goes-here", pvdEnvelope2.getTags().get("ai.user.accountId")); + assertEquals("user-agent-goes-here", pvdEnvelope2.getTags().get("ai.user.userAgent")); + assertEquals("os-goes-here", pvdEnvelope2.getTags().get("ai.device.os")); + assertEquals("session-id-goes-here", pvdEnvelope2.getTags().get("ai.session.id")); + assertEquals("1.2.3.4", pvdEnvelope2.getTags().get("ai.location.ip")); + // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are from the agent + assertEquals("00000000-0000-0000-0000-0FEEDDADBEEF", pvdEnvelope2.getIKey()); + assertEquals("testrolename", pvdEnvelope2.getTags().get("ai.cloud.role")); + assertEquals("testroleinstance", pvdEnvelope2.getTags().get("ai.cloud.roleInstance")); + assertTrue(pvdEnvelope2.getTags().get("ai.internal.sdkVersion").startsWith("java:3.")); + + + assertNotNull(pv3); + assertEquals(new Duration(123456), pv3.getDuration()); + assertEquals("value", pv3.getProperties().get("key")); + assertEquals("a-value", pv3.getProperties().get("a-prop")); + assertEquals("another-value", pv3.getProperties().get("another-prop")); + assertEquals("user-id-goes-here", pvdEnvelope3.getTags().get("ai.user.id")); + assertEquals("account-id-goes-here", pvdEnvelope3.getTags().get("ai.user.accountId")); + assertEquals("user-agent-goes-here", pvdEnvelope3.getTags().get("ai.user.userAgent")); + assertEquals("os-goes-here", pvdEnvelope3.getTags().get("ai.device.os")); + assertEquals("session-id-goes-here", pvdEnvelope3.getTags().get("ai.session.id")); + assertEquals("1.2.3.4", pvdEnvelope3.getTags().get("ai.location.ip")); + // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are from the agent + assertEquals("00000000-0000-0000-0000-0FEEDDADBEEF", pvdEnvelope3.getIKey()); + assertEquals("testrolename", pvdEnvelope3.getTags().get("ai.cloud.role")); + assertEquals("testroleinstance", pvdEnvelope3.getTags().get("ai.cloud.roleInstance")); + assertTrue(pvdEnvelope3.getTags().get("ai.internal.sdkVersion").startsWith("java:3.")); assertParentChild(rd, rdEnvelope, pvdEnvelope1); assertParentChild(rd, rdEnvelope, pvdEnvelope2); + assertParentChild(rd, rdEnvelope, pvdEnvelope3); } @Test