Skip to content

Support long running spans#3452

Closed
amarziali wants to merge 7 commits into
masterfrom
andrea.marziali/longrunning
Closed

Support long running spans#3452
amarziali wants to merge 7 commits into
masterfrom
andrea.marziali/longrunning

Conversation

@amarziali

Copy link
Copy Markdown
Contributor

What Does This Do

Add support for long running spans. Allows incomplete spans to be reported to datadog and partial results to be displayed into the live view.
As well, this PR enables collecting complete traces for spans lasting more than 15 minutes.

The feature is released behind a configuration flag and it's disabled by default.

How does it work

Pending traces are scanned on a scheduled basis and if a long lasting span is found:

  • A copy of this span (same span_id, parent_it, trace_id) is added to the buffer. The span is tagged as partial (metrics[_dd.partial_version] with an incrementing number)
  • All finished spans also buffered on the same pending traces are flushed (similar to partial flush scenario)

Motivation

Today, due to internal datadog architecture, spans lasting more than 15 minutes may result in incomplete tracing. Additionally to this, spans are sent only when all pending ones are closed. Hence, live view won't display those ones.

Additional Notes

@amarziali
amarziali requested a review from a team as a code owner March 18, 2022 16:24
@amarziali
amarziali force-pushed the andrea.marziali/longrunning branch from 59850da to a75ab92 Compare March 18, 2022 16:39

@devinsba devinsba left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to address the pendingTraces map

public static final long MAX_SPAN_AGE_NANOS = TimeUnit.HOURS.toNanos(12);

private final Object dummy = new Object();
private final ConcurrentMap<PendingTrace, Object> pendingTraces = new ConcurrentHashMap<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't have this be an unbounded size. If there is a bug (in the tracer or manual tracing code) that causes traces to not get finished we would rather have those get garbage collected and lost then to effectively cause a memory leak

Comment thread dd-trace-api/src/main/java/datadog/trace/api/config/TracerConfig.java Outdated
Comment thread internal-api/src/main/java/datadog/trace/api/Config.java Outdated
Comment thread dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java Outdated
Comment on lines +218 to +241
span.setPartialVersion(partialVersion);
span.setMetric(DDTags.DD_PARTIAL_VERSION, partialVersion);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of storing this twice we should convert the field to a metric when writing the span out

@dougqh dougqh Mar 18, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 - I don't think should even be a tag / metric on the span. Logically, partialness is just transport concept. It doesn't really exist in the current data model.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe putting in the metadata like measured or top_level could be a better option so?

Comment thread dd-trace-core/src/main/java/datadog/trace/core/PendingTrace.java Outdated

int samplingPriority();

Long getPartialVersion();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I want partially pushed onto the span itself. It isn't really a data model concept. It is a transport concept.

private final HttpCodec.Extractor extractor;

private final InstrumentationGateway instrumentationGateway;
private final TraceKeepAlive traceKeepAlive;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need another object for this. I was thinking it would be handled inside of PendingTrace.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you prefer having PendingTrace handling a scheduled job?

* A monitor thread scheduled on a regular basis. It triggers keep-alive spans to be sent for
* long-running traces.
*/
public class TraceKeepAlive implements AgentTaskScheduler.Task<Boolean> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted elsewhere, I don't think we need a separate class for this. I think this would better be handled inside of PendingTrace.

return null == mapped ? serviceName : mapped;
}

boolean isDisableSamplingMechanismValidation() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being added?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return durationNano != 0;
}

public Long getPartialVersion() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These shouldn't be part of the public span API. I don't think should be on span at all.


public void processTagsAndBaggage(final MetadataConsumer consumer) {
synchronized (unsafeTags) {
final boolean incomplete = unsafeTags.containsKey(DDTags.DD_PARTIAL_VERSION);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be using a tag for partialness. It isn't really a tag in the data model -- that's just a trick to fit into the existing protocol.

return null != span ? span.context() : this;
}

String getParentServiceName() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we adding these? I don't think this is the right place for them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this information is needed to construct a new SpanContext here: https://github.com/DataDog/dd-trace-java/blob/7b5d30060e0d3bc2218bc230809440a831fd8522/dd-trace-core/src/main/java/datadog/trace/core/PendingTrace.java#L201

I gave only package visibility. Maybe something can be simplified. Please advice

this.strictTraceWrites = strictTraceWrites;

if (tracer.getTraceKeepAlive() != null) {
tracer.getTraceKeepAlive().onPendingTraceBegins(this);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly confirming that should just be part of PendingTrace.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far I can see, on PendingTrace I would have the possibility to emit keepalives when write is called (e.g. a span of the same trace is finished). But what in case nothing happens and I've just to keep alive an unfinished span? I don't see any other solution than using a scheduled thread. The advantage of externalizing is just use one thread for all the pending traces and separate roles

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done as part of the existing writer loop in datadog.trace.core.PendingTraceBuffer.DelayingPendingTraceBuffer.Worker so we wouldn't need a new thread.

@dougqh dougqh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've commented on this PR, but I'd really suggest that the PR just be abandoned.

I think we need to back and talk about the protocol and how to make the changes more before jumping into code.

@amarziali
amarziali force-pushed the andrea.marziali/longrunning branch 2 times, most recently from 7b5d300 to 9e6265f Compare March 23, 2022 08:24
@amarziali
amarziali force-pushed the andrea.marziali/longrunning branch from 0c360bf to 9d5d72d Compare March 31, 2022 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants