Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    dmy-gh
    @dmy-gh

    Hey there :)
    Playing around with Elixir I can't figure out how to set the parent span for a new span declared in an anonymous function in a Task.async.
    I tried something like this:

        OpenTelemetry.Tracer.with_span "span_1" do
          span_ctx = OpenTelemetry.Tracer.current_span_ctx()
    
          task =
            Task.async(fn ->
              OpenTelemetry.Tracer.with_span "span_2", %{parent: span_ctx} do
                nil
              end
            end)
    
          ... 
        end

    But the parent option does not seem to do anything.
    Can you please help me on what I am probably doing wrong here?

    dmy-gh
    @dmy-gh
    Digging into the code I couldn't find the parent key involved in the span creation.
    Tristan Sloughter
    @tsloughter
    actually working on an example for this for the docs page right now :)
    parent as an optoin is gone
    what is suggested for a spawned process is to create a new span before spawning and setting it to active in the spawned function
    in erlang this would look like
    SpanCtx = ?start_span(<<"child">>),
    Ctx = otel_ctx:get_current(),
    
    proc_lib:start_link(fun() ->
                            otel_ctx:attach(Ctx),
                            ?set_current_span(SpanCtx)
                            %% do work here
                        end),
    spawn not start...
    I don't do much Elixir so haven't got the Task version done yet
    linking is also an option when spawning a new process, since it doesn't necessarily have a parent/child relationship:
    SpanCtx = ?current_span_ctx,
    proc_lib:spawn_link(fun() ->
                            Link = opentelemetry:link(SpanCtx),
                            ?with_span(<<"other-process">>, #{links => [Link]},
                                       fun() -> ok end)
                        end),
    Tristan Sloughter
    @tsloughter
    ok, made a test that shows how to do this. should really have a way to automatically end a Task's span.. for now I'm just ending it manually
    there are a couple ways of doing the context part which may make it confusing
    dmy-gh
    @dmy-gh

    parent as an optoin is gone

    Ok, I switched from the hex package to the master of the git repository for the libs.

    Thank you for the examples!
    I can't make the link one work on my side as I can't get anything else than :undefined when doing parent_link = OpenTelemetry.link(parent).
    dmy-gh
    @dmy-gh
    parent = Tracer.start_span("parent") returns:
    {:span_ctx, 125339188436856308036143319152412608740, 14087508596670444880, 1,
     :undefined, true, :undefined, true,
     {:otel_span_ets, #Function<1.123713657/1 in :otel_tracer_server.on_end/1>}}
    dmy-gh
    @dmy-gh
    In your "child span" I replaced ctx = Tracer.set_current_span(ctx, SpanCtx) by ctx = Tracer.set_current_span(ctx, parent) and also tried to end the parent span:
    defmodule Test do
      alias OpenTelemetry.{Ctx, Span, Tracer}
      require OpenTelemetry.Tracer
    
      def child do
        parent_ctx = Ctx.new()
    
        # create the parent span
        parent = Tracer.start_span("parent")
        # make a new context with it as the active span
        ctx = Tracer.set_current_span(parent_ctx, parent)
        # attach this context (put it in the process dictionary)
        Ctx.attach(ctx)
    
        # start the child and set it to current in an unattached context
        child = Tracer.start_span("child")
        ctx = Tracer.set_current_span(ctx, child)
    
        task =
          Task.async(fn ->
            # attach the context with the child span active to this process
            Ctx.attach(ctx)
    
            Process.sleep(2_000)
            return = :ok
    
            Span.end_span(child)
    
            return
          end)
    
        return = Task.await(task)
    
        Process.sleep(1_000)
        Span.end_span(parent)
    
        return
      end
    end
    And here is the collector ouput:
     InstrumentationLibrarySpans #0
     InstrumentationLibrary  
     Span #0
         Trace ID       : afcfd96292df82aecfec73112021a913
         Parent ID      : 
         ID             : 47baabdfc4371036
         Name           : parent
         Kind           : SPAN_KIND_INTERNAL
         Start time     : 2021-02-01 10:42:38.169498618 +0000 UTC
         End time       : 2021-02-01 10:42:41.182688894 +0000 UTC
         Status code    : STATUS_CODE_UNSET
         Status message : 
     Span #1
         Trace ID       : afcfd96292df82aecfec73112021a913
         Parent ID      : 47baabdfc4371036
         ID             : 09e6b2017ab2872e
         Name           : child
         Kind           : SPAN_KIND_INTERNAL
         Start time     : 2021-02-01 10:42:38.174677904 +0000 UTC
         End time       : 2021-02-01 10:42:40.18240293 +0000 UTC
         Status code    : STATUS_CODE_UNSET
         Status message :
    So far so good, but...
    Calling Test.child() another time:
     InstrumentationLibrarySpans #0
     InstrumentationLibrary  
     Span #0
         Trace ID       : afcfd96292df82aecfec73112021a913
         Parent ID      : 47baabdfc4371036
         ID             : d12a03d31ace38e6
         Name           : parent
         Kind           : SPAN_KIND_INTERNAL
         Start time     : 2021-02-01 10:43:47.91497472 +0000 UTC
         End time       : 2021-02-01 10:43:50.916789458 +0000 UTC
         Status code    : STATUS_CODE_UNSET
         Status message : 
     Span #1
         Trace ID       : afcfd96292df82aecfec73112021a913
         Parent ID      : d12a03d31ace38e6
         ID             : a441a473c3d2071b
         Name           : child
         Kind           : SPAN_KIND_INTERNAL
         Start time     : 2021-02-01 10:43:47.915018609 +0000 UTC
         End time       : 2021-02-01 10:43:49.915748238 +0000 UTC
         Status code    : STATUS_CODE_UNSET
         Status message :
    The same IDs are generated for the trace and/or the span/ctx is not ended correctly so it leads to a cumulative trace with two spans the first time, four spans the second one and so on.
    dmy-gh
    @dmy-gh
    Isn't Span.end_span(parent) how I am supposed to end the span?
    dmy-gh
    @dmy-gh
    Got no more luck with Tracer.end_span()
    dmy-gh
    @dmy-gh
    Starting the span outside of the task and ending it inside is already tricky here but can be even more unclear for a GenServer.call/3.
    I like the "linked span" and would love to make it work.
    Tristan Sloughter
    @tsloughter
    @dmy-gh about links, sorry, I forgot to mention that I found a bug when wirting that test and haven't pushed it yet :(. I will this morning
    it wasn't able to handle an undefined TraceState when creating the link
    Tristan Sloughter
    @tsloughter
    I'm working on docs and tests that I hope bring out all these remaining bugs and can then release 1.0 very soon
    Tristan Sloughter
    @tsloughter
    should have this merged this morning
    dmy-gh
    @dmy-gh
    Nice, I will try the linked span with the PR
    What am I doing wrong when trying to close the parent span for the child span example, which leads me to a never ending parent span?
    Tristan Sloughter
    @tsloughter
    hm, that I'm not sure about yet. it looks right.
    updating my test to end it, forgot to have that in there
    dmy-gh
    @dmy-gh
    Ok, thank you again for the help :slight_smile:
    Tristan Sloughter
    @tsloughter
    test works fine, so may be some issue in the exporter pipeline that doesn't show up when using the otel_exporter_pid exporter like the tests do
    dmy-gh
    @dmy-gh
    Your test only creates parent and child span once
    I'm having issue on the second function call
    Tristan Sloughter
    @tsloughter
    oh
    dmy-gh
    @dmy-gh
    The "parent" span of the second function call has the "parent" span ID of the first call as a parent
    Tristan Sloughter
    @tsloughter
    so an issue in that case, if you are calling from the same process is you have to manually remove the parent span from the context
    ending it only ends it it doesn't make it in-active in the context (pdict)
    so using with_span is better for regular code
    Tristan Sloughter
    @tsloughter
    this is all stuff with_span does for you
    dmy-gh
    @dmy-gh
    Ok, I'll read the doc once again on this part as it seems I don't quite understand how contexts work
    dmy-gh
    @dmy-gh
      def child do
        OpenTelemetry.Tracer.with_span "parent" do
          # start the child and set it to current in an unattached context
          child = Tracer.start_span("child")
          Tracer.set_current_span(child)
    
          task =
            Task.async(fn ->
              # attach the context with the child span active to this process
              Ctx.attach(Ctx.get_current())
    
              Process.sleep(2_000)
              return = :ok
    
              Span.end_span(child)
    
              return
            end)
    
          return = Task.await(task)
    
          Process.sleep(1_000)
    
          return
        end
      end
    Works better this way, thank you :slight_smile:
    Tristan Sloughter
    @tsloughter
    that looks like your child span is being sent current only outside of the Task. if you want to create a context with it attached but that context not be the current processes pdict then you need to pass a context variable to set_current_span
    hopefully the docs I'm working on will explain this well..