From cae90388f1f6a2bbf888dd2942c942f7f2f14f5f Mon Sep 17 00:00:00 2001 From: Kate Anderson <90657569+kanderson250@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:26:45 -0700 Subject: [PATCH 1/4] Update class excludes list for Sonarqube9.9 --- newrelic-agent/src/main/resources/META-INF/excludes | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/newrelic-agent/src/main/resources/META-INF/excludes b/newrelic-agent/src/main/resources/META-INF/excludes index ba6c1b2df3..5ff4474e5e 100644 --- a/newrelic-agent/src/main/resources/META-INF/excludes +++ b/newrelic-agent/src/main/resources/META-INF/excludes @@ -88,4 +88,9 @@ # exclusions for Open Liberty 21+ so transactions start properly ^com/ibm/ws/security/jaspi/JaspiServletFilter # Websphere specific servlet wrapper class -^com/ibm/ws/webcontainer/servlet/ServletWrapperImpl \ No newline at end of file +^com/ibm/ws/webcontainer/servlet/ServletWrapperImpl +# Sonarqube9.9 ClassCircularityErrors +^java/util/AbstractList\$RandomAccessSpliterator +^java/util/stream/MatchOps\$MatchOp +^java/util/stream/MatchOps\$BooleanTerminalSink +^javax/security/auth/Subject\$SecureSet\$1 From 60fa9b2fda7f12b8bbed017f84dde1abdfb8e110 Mon Sep 17 00:00:00 2001 From: Saxon D'Aubin Date: Mon, 18 Sep 2023 15:07:04 -0700 Subject: [PATCH 2/4] Include stack traces in client spans --- .../com/newrelic/agent/model/SpanEvent.java | 17 +++++++++---- .../service/analytics/SpanEventFactory.java | 24 +++++++++++++++++-- .../service/analytics/TracerToSpanEvent.java | 1 + .../analytics/SpanEventFactoryTest.java | 21 ++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/agent-model/src/main/java/com/newrelic/agent/model/SpanEvent.java b/agent-model/src/main/java/com/newrelic/agent/model/SpanEvent.java index b7d40eaa48..03b2fd9a86 100644 --- a/agent-model/src/main/java/com/newrelic/agent/model/SpanEvent.java +++ b/agent-model/src/main/java/com/newrelic/agent/model/SpanEvent.java @@ -13,16 +13,14 @@ import java.io.IOException; import java.io.Writer; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Set; public class SpanEvent extends AnalyticsEvent implements JSONStreamAware { public static final String SPAN = "Span"; - static final String SPAN_KIND = "client"; + static final String CLIENT_SPAN_KIND = "client"; private final String appName; private final Map intrinsics; @@ -120,6 +118,7 @@ public static class Builder { private float priority; private boolean decider; private long timestamp; + private Object spanKind; public Builder appName(String appName) { this.appName = appName; @@ -177,9 +176,19 @@ public Builder putAgentAttribute(String key, Object value) { return this; } + public Builder spanKind(Object spanKind) { + putIntrinsic("span.kind", spanKind); + this.spanKind = spanKind; + return this; + } + + public boolean isClientSpan() { + return CLIENT_SPAN_KIND.equals(spanKind); + } + public Object getSpanKindFromUserAttributes() { Object result = userAttributes.get("span.kind"); - return result == null ? SPAN_KIND : result; + return result == null ? CLIENT_SPAN_KIND : result; } public Builder decider(boolean decider) { diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java index 42423a2942..32d3845fa7 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java @@ -17,7 +17,9 @@ import com.newrelic.agent.model.SpanError; import com.newrelic.agent.model.SpanEvent; import com.newrelic.agent.service.ServiceFactory; +import com.newrelic.agent.tracers.DefaultTracer; import com.newrelic.agent.util.ExternalsUtil; +import com.newrelic.agent.util.StackTraces; import com.newrelic.api.agent.DatastoreParameters; import com.newrelic.api.agent.ExternalParameters; import com.newrelic.api.agent.HttpParameters; @@ -25,6 +27,7 @@ import java.net.URI; import java.text.MessageFormat; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -40,6 +43,7 @@ public class SpanEventFactory { private static final Joiner TRACE_STATE_VENDOR_JOINER = Joiner.on(","); // Truncate `db.statement` at 2000 characters private static final int DB_STATEMENT_TRUNCATE_LENGTH = 2000; + private static final int MAX_EVENT_ATTRIBUTE_STRING_LENGTH = 4095; public static final Supplier DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER = System::currentTimeMillis; @@ -115,6 +119,23 @@ public SpanEventFactory putAllAgentAttributes(Map agentAttributes) { return this; } + /** + * This should be called after the span kind is set. + */ + public SpanEventFactory setStackTraceAttributes(Map agentAttributes) { + if (builder.isClientSpan()) { + final List stackTraceList = (List) agentAttributes.get(DefaultTracer.BACKTRACE_PARAMETER_NAME); + if (stackTraceList != null) { + final List preStackTraces = StackTraces.scrubAndTruncate(stackTraceList); + final List postParentRemovalTrace = StackTraces.toStringList(preStackTraces); + + putAgentAttribute("code.stacktrace", truncateWithEllipsis( + Joiner.on(',').join(postParentRemovalTrace), MAX_EVENT_ATTRIBUTE_STRING_LENGTH)); + } + } + return this; + } + public SpanEventFactory setClmAttributes(Map agentAttributes) { if (agentAttributes == null || agentAttributes.isEmpty()) { return this; @@ -166,8 +187,7 @@ public SpanEventFactory setCategory(SpanCategory category) { } public SpanEventFactory setKindFromUserAttributes() { - Object spanKind = builder.getSpanKindFromUserAttributes(); - builder.putIntrinsic("span.kind", spanKind); + builder.spanKind(builder.getSpanKindFromUserAttributes()); return this; } diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/TracerToSpanEvent.java b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/TracerToSpanEvent.java index b2337f817f..e40c7d243b 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/TracerToSpanEvent.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/TracerToSpanEvent.java @@ -94,6 +94,7 @@ public SpanEvent createSpanEvent(Tracer tracer, TransactionData transactionData, .setTimestamp(tracer.getStartTimeInMillis()) .setPriority(transactionData.getPriority()) .setExternalParameterAttributes(tracer.getExternalParameters()) + .setStackTraceAttributes(tracer.getAgentAttributes()) .setIsRootSpanEvent(isRoot) .setDecider(inboundPayload == null || inboundPayload.priority == null); diff --git a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java index fcdff75b3d..a695dc7eab 100644 --- a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java +++ b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java @@ -7,21 +7,29 @@ package com.newrelic.agent.service.analytics; +import com.google.common.collect.ImmutableMap; +import com.newrelic.agent.MockConfigService; +import com.newrelic.agent.MockServiceManager; +import com.newrelic.agent.config.AgentConfig; import com.newrelic.agent.model.AttributeFilter; import com.newrelic.agent.model.SpanCategory; import com.newrelic.agent.model.SpanError; import com.newrelic.agent.model.SpanEvent; +import com.newrelic.agent.service.ServiceFactory; +import com.newrelic.agent.tracers.DefaultTracer; import com.newrelic.api.agent.DatastoreParameters; import com.newrelic.api.agent.HttpParameters; import org.junit.Test; import java.net.URI; +import java.util.Arrays; import java.util.Collections; import java.util.Map; import static com.newrelic.agent.service.analytics.SpanEventFactory.DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -176,6 +184,19 @@ public void shouldSetDataStoreParameters() { assertEquals("database name", target.getIntrinsics().get("db.instance")); } + @Test + public void shouldStoreStackTrace() { + SpanEventFactory spanEventFactory = new SpanEventFactory("MyApp", new AttributeFilter.PassEverythingAttributeFilter(), DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER); + spanEventFactory.setKindFromUserAttributes(); + MockServiceManager serviceManager = new MockServiceManager(); + serviceManager.setConfigService(new MockConfigService(mock(AgentConfig.class))); + ServiceFactory.setServiceManager(serviceManager); + spanEventFactory.setStackTraceAttributes(ImmutableMap.of(DefaultTracer.BACKTRACE_PARAMETER_NAME, Arrays.asList(Thread.currentThread().getStackTrace()))); + + final Object stackTrace = spanEventFactory.build().getAgentAttributes().get("code.stacktrace"); + assertNotNull(stackTrace); + } + @Test public void shouldFilterUserAttributes() { SpanEventFactory target = new SpanEventFactory("blerb", new AttributeFilter.PassEverythingAttributeFilter() { From 046588cbdd95b1564c7565df3b717a4cdf916297 Mon Sep 17 00:00:00 2001 From: jasonjkeller Date: Mon, 25 Sep 2023 15:23:21 -0700 Subject: [PATCH 3/4] Refactor to use AttributeNames --- .../com/newrelic/agent/attributes/AttributeNames.java | 1 + .../agent/service/analytics/SpanEventFactory.java | 3 +-- .../agent/service/analytics/SpanEventFactoryTest.java | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/attributes/AttributeNames.java b/newrelic-agent/src/main/java/com/newrelic/agent/attributes/AttributeNames.java index 6aae781be2..2c4160b8fa 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/attributes/AttributeNames.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/attributes/AttributeNames.java @@ -28,6 +28,7 @@ public final class AttributeNames { public static final String TIMEOUT_CAUSE = "nr.timeoutCause"; public static final String ERROR_EXPECTED = "error.expected"; + public static final String CODE_STACKTRACE = "code.stacktrace"; public static final String COMPONENT = "component"; public static final String HTTP_METHOD = "http.method"; public static final String HTTP_STATUS_CODE = "http.statusCode"; diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java index dff981c778..721b6ad687 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java @@ -129,7 +129,7 @@ public SpanEventFactory setStackTraceAttributes(Map agentAttribu final List preStackTraces = StackTraces.scrubAndTruncate(stackTraceList); final List postParentRemovalTrace = StackTraces.toStringList(preStackTraces); - putAgentAttribute("code.stacktrace", truncateWithEllipsis( + putAgentAttribute(AttributeNames.CODE_STACKTRACE, truncateWithEllipsis( Joiner.on(',').join(postParentRemovalTrace), MAX_EVENT_ATTRIBUTE_STRING_LENGTH)); } } @@ -162,7 +162,6 @@ public SpanEventFactory putAllUserAttributesIfAbsent(Map userAttribut return this; } - public SpanEventFactory putAgentAttribute(String key, Object value) { builder.putAgentAttribute(key, value); return this; diff --git a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java index 997a8f2698..a405f93b60 100644 --- a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java +++ b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java @@ -10,8 +10,8 @@ import com.google.common.collect.ImmutableMap; import com.newrelic.agent.MockConfigService; import com.newrelic.agent.MockServiceManager; -import com.newrelic.agent.config.AgentConfig; import com.newrelic.agent.attributes.AttributeNames; +import com.newrelic.agent.config.AgentConfig; import com.newrelic.agent.model.AttributeFilter; import com.newrelic.agent.model.SpanCategory; import com.newrelic.agent.model.SpanError; @@ -187,14 +187,16 @@ public void shouldSetDataStoreParameters() { @Test public void shouldStoreStackTrace() { - SpanEventFactory spanEventFactory = new SpanEventFactory("MyApp", new AttributeFilter.PassEverythingAttributeFilter(), DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER); + SpanEventFactory spanEventFactory = new SpanEventFactory("MyApp", new AttributeFilter.PassEverythingAttributeFilter(), + DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER); spanEventFactory.setKindFromUserAttributes(); MockServiceManager serviceManager = new MockServiceManager(); serviceManager.setConfigService(new MockConfigService(mock(AgentConfig.class))); ServiceFactory.setServiceManager(serviceManager); - spanEventFactory.setStackTraceAttributes(ImmutableMap.of(DefaultTracer.BACKTRACE_PARAMETER_NAME, Arrays.asList(Thread.currentThread().getStackTrace()))); + spanEventFactory.setStackTraceAttributes( + ImmutableMap.of(DefaultTracer.BACKTRACE_PARAMETER_NAME, Arrays.asList(Thread.currentThread().getStackTrace()))); - final Object stackTrace = spanEventFactory.build().getAgentAttributes().get("code.stacktrace"); + final Object stackTrace = spanEventFactory.build().getAgentAttributes().get(AttributeNames.CODE_STACKTRACE); assertNotNull(stackTrace); } From dbbbeb2990b9d3ad461302dc037c617da24a0e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Onuki?= Date: Thu, 28 Sep 2023 11:46:04 -0400 Subject: [PATCH 4/4] Setting thread.id as an intrinsic (#1521) --- .../com/newrelic/agent/service/analytics/SpanEventFactory.java | 2 +- .../newrelic/agent/service/analytics/SpanEventFactoryTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java index b8c44cd962..c1abd31816 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/service/analytics/SpanEventFactory.java @@ -121,7 +121,7 @@ public SpanEventFactory setClmAttributes(Map agentAttributes) { } final Object threadId = agentAttributes.get(AttributeNames.THREAD_ID); if (threadId != null) { - builder.putAgentAttribute(AttributeNames.THREAD_ID, threadId); + builder.putIntrinsic(AttributeNames.THREAD_ID, threadId); } if (agentAttributes.containsKey(AttributeNames.CLM_NAMESPACE) && agentAttributes.containsKey(AttributeNames.CLM_FUNCTION)) { builder.putAgentAttribute(AttributeNames.CLM_NAMESPACE, agentAttributes.get(AttributeNames.CLM_NAMESPACE)); diff --git a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java index 72c6ab8399..c530ef1534 100644 --- a/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java +++ b/newrelic-agent/src/test/java/com/newrelic/agent/service/analytics/SpanEventFactoryTest.java @@ -191,7 +191,7 @@ public void shouldSetCLMParameters() { assertEquals("nr", target.getAgentAttributes().get(AttributeNames.CLM_NAMESPACE)); assertEquals("process", target.getAgentAttributes().get(AttributeNames.CLM_FUNCTION)); - assertEquals(666, target.getAgentAttributes().get(AttributeNames.THREAD_ID)); + assertEquals(666, target.getIntrinsics().get(AttributeNames.THREAD_ID)); } @Test