Skip to content
This repository has been archived by the owner on Oct 3, 2023. It is now read-only.

examples: provide an example for how to retrieve spans from thread local storage #580

Open
odeke-em opened this issue Jun 13, 2019 · 2 comments
Labels

Comments

@odeke-em
Copy link
Member

I understand that we use 'cls' for context storage/thread local storage. However, it is a little painful for me right now to try to get spans from thread local storage, that is because there are many moving parts: I need to initialize the tracer or get the global tracer (will creating a new tracer work?) and then check the current context but then check if the contextManager has a rootSpan. Also given that I don't code much in Node.js anymore, I am unfamiliar with the new tools and navigating the Typescript code -- I don't see direct code documentation to help me achieve my goal.

My use case is making instrumentation/an integration that doesn't have access to global or new tracers and just has to check if the code being executed has an OpenCensus span in it.

A guide for this would be helpful. @mayurkale22 helped me out about 6 days ago and corrected my code samples as per https://gist.github.com/odeke-em/533dd91cb4a1b955f17fdc7d05b5f1b2#gistcomment-2938019 but in this case I won't have a tracer that I am starting myself as I am making an integration.

@odeke-em odeke-em added the bug label Jun 13, 2019
@mayurkale22 mayurkale22 added document and removed bug labels Jun 13, 2019
@mayurkale22
Copy link
Member

Let me know if this works for you.

'use strict';

const tracing = require('@opencensus/nodejs');
const tracer = tracing.start().tracer;
let nested = 1;
// tracer.currentRootSpan -> will give you span from cls.
console.log('At start current span: ' + tracer.currentRootSpan);

tracer.startRootSpan({ name: 'main' }, rootSpan => {
    console.log('Start Scope 1, current span: ' + tracer.currentRootSpan.name);
    doWork();

    tracer.startRootSpan({ name: 'main1' }, rootSpan1 => {
        console.log('    Start Scope 2, current span: ' + tracer.currentRootSpan.name);
        doWork();
        rootSpan1.end();
    });

    console.log('    End Scope 2, ' + tracer.currentRootSpan.name);
    // Be sure to call rootSpan.end().
    rootSpan.end();
});
console.log('End Scope 1, current span: ' + tracer.currentRootSpan);

function doWork () {
  console.log(' '.repeat(nested*2) + 'doing busy work, current span: ' + tracer.currentRootSpan.name);
  const span = tracer.startChildSpan({ name: 'doWork' });
  for (let i = 0; i <= 40000000; i++) {} // short delay
  span.addAnnotation('invoking doWork');
  span.end();
  nested = nested * 4;
}

Output:

At start current span: null
Start Scope 1, current span: main
  doing busy work, current span: main
    Start Scope 2, current span: main1
        doing busy work, current span: main1
    End Scope 2, main
End Scope 1, current span: null

@odeke-em
Copy link
Member Author

odeke-em commented Jun 14, 2019

Hello @mayurkale22, thank you for the response!

The example you provided works for that example because we provide a tracer and start it in process. However, it doesn't work for my use case, which is for a third party instrumentation that doesn't even know which tracer was used so tracing.start().tracer won't be possible or might use the wrong tracer and we also want the current span not necessarily the root span, since the calls might be nested.

It just needs to get the current span e.g.

const tracing = require('@opencensus/nodejs');
const tracer = tracing.tracer;

function extract(arg) {
      // Check if we've got a span available or not
      const activeSpan = tracer.contextManager.active;
      console.log('\n\nIn third party instrumentation', activeSpan);
}

Illustration

In Express.js app {
  rootspan: RootSpan {
    startedLocal: true,
    endedLocal: false,
    truncated: false,
    logger: ConsoleLogger { level: 'error', logger: [LogDriver] },
    attributes: {},
    annotations: [],
    messageEvents: [],
    links: [],
    remoteParent: false,
    name: '/polls/10',
    kind: 1,
    status: { code: 0 },
    activeTraceParams: {
      numberOfAnnontationEventsPerSpan: 32,
      numberOfAttributesPerSpan: 32,
      numberOfMessageEventsPerSpan: 128,
      numberOfLinksPerSpan: 32
    },
    droppedAttributesCount: 0,
    droppedLinksCount: 0,
    droppedAnnotationsCount: 0,
    droppedMessageEventsCount: 0,
    tracer: CoreTracer {
      eventListenersLocal: [Array],
      IS_SAMPLED: 1,
      logger: [ConsoleLogger],
      activeLocal: true,
      activeTraceParams: [Object],
      contextManager: AsyncHooksNamespace {},
      config: [Object],
      sampler: [AlwaysSampler]
    },
    className: 'RootSpan',
    id: 'a01ab9a3f680d70b',
    spansLocal: [],
    root: [Circular],
    traceIdLocal: '1762372b2095478a8af1e78fd8097c78',
    parentSpanIdLocal: '',
    clock: Clock {
      endedLocal: false,
      diff: [Array],
      startTimeLocal: 2019-06-14T21:35:15.845Z,
      hrtimeLocal: [Array]
    }
  }
}


In third party instrumentation { rootspan: null }

which shows that using a different tracer creates different contexts/scopes but really I'd just like to grab the reigning context perhaps using cls and check directly if there is an activeSpan and if so grab its information.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants