Skip to content

Commit

Permalink
Merge pull request #1520 from newrelic/pr-1507
Browse files Browse the repository at this point in the history
Pr 1507
  • Loading branch information
jasonjkeller authored Sep 28, 2023
2 parents dbbbeb2 + 046588c commit 1537c79
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 7 deletions.
17 changes: 13 additions & 4 deletions agent-model/src/main/java/com/newrelic/agent/model/SpanEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, Object> intrinsics;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
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;
import com.newrelic.api.agent.SlowQueryDatastoreParameters;

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;
Expand All @@ -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<Long> DEFAULT_SYSTEM_TIMESTAMP_SUPPLIER = System::currentTimeMillis;

Expand Down Expand Up @@ -115,6 +119,23 @@ public SpanEventFactory putAllAgentAttributes(Map<String, ?> agentAttributes) {
return this;
}

/**
* This should be called after the span kind is set.
*/
public SpanEventFactory setStackTraceAttributes(Map<String, Object> agentAttributes) {
if (builder.isClientSpan()) {
final List<StackTraceElement> stackTraceList = (List<StackTraceElement>) agentAttributes.get(DefaultTracer.BACKTRACE_PARAMETER_NAME);
if (stackTraceList != null) {
final List<StackTraceElement> preStackTraces = StackTraces.scrubAndTruncate(stackTraceList);
final List<String> postParentRemovalTrace = StackTraces.toStringList(preStackTraces);

putAgentAttribute(AttributeNames.CODE_STACKTRACE, truncateWithEllipsis(
Joiner.on(',').join(postParentRemovalTrace), MAX_EVENT_ATTRIBUTE_STRING_LENGTH));
}
}
return this;
}

public SpanEventFactory setClmAttributes(Map<String, Object> agentAttributes) {
if (agentAttributes == null || agentAttributes.isEmpty()) {
return this;
Expand All @@ -141,7 +162,6 @@ public SpanEventFactory putAllUserAttributesIfAbsent(Map<String, ?> userAttribut
return this;
}


public SpanEventFactory putAgentAttribute(String key, Object value) {
builder.putAgentAttribute(key, value);
return this;
Expand Down Expand Up @@ -170,8 +190,7 @@ public SpanEventFactory setCategory(SpanCategory category) {
}

public SpanEventFactory setKindFromUserAttributes() {
Object spanKind = builder.getSpanKindFromUserAttributes();
builder.putIntrinsic("span.kind", spanKind);
builder.spanKind(builder.getSpanKindFromUserAttributes());
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,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.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;
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;
Expand Down Expand Up @@ -179,6 +185,21 @@ 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(AttributeNames.CODE_STACKTRACE);
assertNotNull(stackTrace);
}

@Test
public void shouldSetCLMParameters() {
Map<String, Object> agentAttributes = ImmutableMap.of(
Expand Down

0 comments on commit 1537c79

Please sign in to comment.