GoogleCloudPlatform / cloud-trace-java

Apache License 2.0
48 stars 42 forks source link

Creating (sub) spans in another thread #83

Closed sebastian-garn closed 7 years ago

sebastian-garn commented 7 years ago

Hi everyone,

I am currently trying to figure out how I can send traces to the StackDriver backend that contain "trees of spans". My goal is to measure the execution time of an operation and its sub operations (= different spans). By reading the documentation (https://cloud.google.com/trace/docs/reference/v1/rest/v1/projects.traces#TraceSpan) it should be possible to reference spans within a trace.

The only way I could accomplish that task so far was, by nesting the "tracer.startSpan()"-calls like shown below:

TraceContext traceContext = tracer.startSpan("/api/v1/abc");

// time consuming code

TraceContext traceContextChild = tracer.startSpan("getUsers");

// time consuming code

tracer.endSpan(traceContextChild);
tracer.endSpan(traceContext);

But as far as I could see this will only work for single threaded environments since the SpanContextHandlerTracer is accessing some thread local variables underneath in order to hook up the spans to each other.

Either I am doing something wrong or the feature is currently not available within the current version. Can you please give me some hints?

Btw. you should consider updating the part of the readme where you show the project exemplary dependencies: using the latest version of google dependencies (0.3.2) in combination with grpc-netty version 1.0.1 gives issues regarding conflicting dependencies.

Best regards Sebastian

sebastian-garn commented 7 years ago

OK...I finally found a way on how to make it work. I had to pass the parents SpanContext to the thread and reattached it to the SpanContextHandler. Is it supposed to work like that or am I misusing the sdk? ;) See example below:

Tracer tracer = Trace.getTracer();

TraceContext traceContext = tracer.startSpan("/api/v1/abc");
SpanContext parentContext = traceContext.getHandle().getCurrentSpanContext();

// ...

Runnable subRoutine = () -> {
    Trace.getSpanContextHandler().attach(parentContext);
    TraceContext traceContextChild = tracer.startSpan("childspan");

    // ...

    tracer.endSpan(traceContextChild);
};

new Thread(subRoutine).start();

tracer.endSpan(traceContext);
erikmcc commented 7 years ago

This is the way it's intended to work.

The idea is to use the SpanContextHandler to install the appropriate root context on any thread where it's required. The long-term goal is to provide implementations or wrappers for components that spawn threads, such as executors, that also install the desired context on any spawned threads.

sebastian-garn commented 7 years ago

Got it. Thanks ;)