def injected_span_pass_to_instance() -> ExternalClass: """Inject a span then pass onto an instance.""" assert wtt.get_current_span().is_recording() wtt.get_current_span().set_attribute("Random Int", random.randint(0, 9)) instance = ExternalClass(wtt.get_current_span()) instance.disjoint_spanned_method() return instance
def process_with_exception(self) -> None: """Do some things and reuse a span.""" time.sleep(1) assert self.span == wtt.get_current_span() assert wtt.get_current_span().is_recording() # this won't end the span so traces won't be sent, # unless the exception is excepted by the caller raise Exception("An exception!")
def process(self) -> None: """Do some things and reuse a span.""" time.sleep(2) assert self.span == wtt.get_current_span() assert wtt.get_current_span().is_recording() # this won't end the span try: raise KeyError() except: # noqa: E722 # pylint: disable=bare-except pass
def thread_work(worker: int, carrier: Dict[str, Any]) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert wtt.get_current_span().is_recording() # as expected assert outter_span != wtt.get_current_span() # good assert wtt.get_current_span( )._parent # type: ignore[attr-defined] # GREAT! # # # # print(carrier) time.sleep(1) return worker
def thread_work(worker: int, carrier: Dict[str, Any]) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert not wtt.get_current_span().is_recording() # BAD! assert outter_span != wtt.get_current_span() # good # assert wtt.get_current_span()._parent # (n/a b/c not recording) # # # # print(carrier) time.sleep(1) # shared memory allows this -- but not a great idea logically... outter_span.add_event("I'm", {"A": "Thread"}) return worker
def thread_work(worker: int) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert wtt.get_current_span().is_recording() # as expected assert outter_span != wtt.get_current_span() # good # NOT GOOD! assert not wtt.get_current_span()._parent # type: ignore[attr-defined] # # # # time.sleep(1) return worker
def thread_work(worker: int, span: wtt.Span) -> int: """Do thread's work.""" assert span == outter_span == wtt.get_current_span() assert outter_span.is_recording() # sure assert wtt.get_current_span().is_recording() # as expected assert outter_span == wtt.get_current_span() # as expected assert not wtt.get_current_span()._parent # type: ignore[attr-defined] # # # # # print(carrier) time.sleep(1) # shared memory allows this -- but not a great idea logically... outter_span.add_event("I'm", {"A": "Thread"}) return worker
def example_01_threads_incorrect(n_threads: int) -> None: """Run multiple independent threads, INCORRECTLY. A non-spanned in-thread function won't be spanned by its *intended* parent. Don't do this! """ outter_span = wtt.get_current_span() def thread_work(worker: int, carrier: Dict[str, Any]) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert not wtt.get_current_span().is_recording() # BAD! assert outter_span != wtt.get_current_span() # good # assert wtt.get_current_span()._parent # (n/a b/c not recording) # # # # print(carrier) time.sleep(1) # shared memory allows this -- but not a great idea logically... outter_span.add_event("I'm", {"A": "Thread"}) return worker futures: List[Future] = [] # type: ignore[type-arg] with ThreadPoolExecutor() as pool: for i in range(n_threads): carrier = wtt.inject_span_carrier() print(carrier) futures.append(pool.submit(thread_work, i, carrier)) for worker in as_completed(futures): ret = worker.result() wtt.add_event("Worker Join", {"worker-id": ret, "type": "thread"}) print(f"Returned Worker #{ret}")
def example_10_threads(n_threads: int) -> None: """Run multiple independent threads, with a common carrier.""" outter_span = wtt.get_current_span() @wtt.spanned(all_args=True, carrier="carrier") def thread_work(worker: int, carrier: Dict[str, Any]) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert wtt.get_current_span().is_recording() # as expected assert outter_span != wtt.get_current_span() # good assert wtt.get_current_span( )._parent # type: ignore[attr-defined] # GREAT! # # # # print(carrier) time.sleep(1) return worker futures: List[Future] = [] # type: ignore[type-arg] with ThreadPoolExecutor() as pool: for i in range(n_threads): carrier = wtt.inject_span_carrier() print(carrier) futures.append(pool.submit(thread_work, i, carrier)) for worker in as_completed(futures): ret = worker.result() wtt.add_event("Worker Join", {"worker-id": ret, "type": "thread"}) print(f"Returned Worker #{ret}")
def prepare(self) -> None: """Do some things and start an independent span.""" self.span = wtt.get_current_span() assert self.span.is_recording() self.span.add_event("(method) started span from instance method") time.sleep(3) @wtt.respanned(None, wtt.SpanBehavior.END_ON_EXIT, all_args=True) def illegal(num: int) -> None: # this would end the span before the caller does pass @wtt.respanned(None, wtt.SpanBehavior.ONLY_END_ON_EXCEPTION, all_args=True) def legal_and_rare(num: int) -> None: # this could end the span, which may or may not be wanted pass @wtt.respanned(None, wtt.SpanBehavior.DONT_END, all_args=True) def legal_and_fine(num: int) -> None: # this is okay, and a quick way to add to the span pass legal_and_rare(11) legal_and_fine(22) try: illegal(33) except wtt.spans.InvalidSpanBehavior: assert 1 else: assert 0
async def get(self) -> None: """Write existing fruits.""" assert tracing_tools.get_current_span().parent.span_id # type: ignore[attr-defined] logging.info("fruits: %r", self.fruit) self.write({"fruits": self.fruit})
def example_00_threads_incorrect(n_threads: int) -> None: """Run multiple independent threads, INCORRECTLY. Spanning an in-thread function will not inherit ANYTHING. The resulting span is completely not related in any way to the *intended* parent. Don't do this! """ outter_span = wtt.get_current_span() @wtt.spanned(all_args=True) def thread_work(worker: int) -> int: """Do thread's work.""" assert outter_span.is_recording( ) # surprising? this is b/c of shared memory assert wtt.get_current_span().is_recording() # as expected assert outter_span != wtt.get_current_span() # good # NOT GOOD! assert not wtt.get_current_span()._parent # type: ignore[attr-defined] # # # # time.sleep(1) return worker futures: List[Future] = [] # type: ignore[type-arg] with ThreadPoolExecutor() as pool: for i in range(n_threads): futures.append(pool.submit(thread_work, i)) for worker in as_completed(futures): ret = worker.result() print(f"Returned Worker #{ret}")
async def post(self) -> None: """Handle a new fruit.""" assert tracing_tools.get_current_span().parent.span_id # type: ignore[attr-defined] body = json_decode(self.request.body) logging.info("body: %r", body) self.fruit[body["name"]] = body self.write({})
def send(friend: str, myself: str) -> None: """Send a message.""" connection = pika.BlockingConnection( pika.ConnectionParameters(host=ADDRESS)) channel = connection.channel() channel.queue_declare(queue=friend) go_publish(wtt.get_current_span(), friend, myself, channel) connection.close()
def disjoint_spanned_method(self) -> None: """Do some things with a new disjoint span.""" print("disjoint_spanned_method") assert wtt.get_current_span().is_recording() assert self.span.is_recording() assert self.span != wtt.get_current_span() @wtt.evented(all_args=True) def inner_event_1(name: str, height: int) -> None: print(name) print(height) @wtt.evented(span="span", all_args=True) def inner_event_2(name: str, height: int, span: wtt.Span) -> None: assert span.is_recording() print(name) print(height) inner_event_1("Bar", 185) inner_event_2("Foo", 177, self.span)
def get_current_user(self): """Get the current user, and set auth-related attributes.""" try: type, token = self.request.headers['Authorization'].split(' ', 1) if type.lower() != 'bearer': raise Exception('bad header type') logger.debug('token: %r', token) data = self.auth.validate(token) self.auth_data = data self.auth_key = token if "role" in self.auth_data: wtt.get_current_span().set_attribute('self.auth_data.role', self.auth_data['role']) return data['sub'] # Auth Failed except Exception: if self.debug and 'Authorization' in self.request.headers: logger.info('Authorization: %r', self.request.headers['Authorization']) logger.info('failed auth', exc_info=True) return None
def _prepare( self, method: str, path: str, args: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None, ) -> Tuple[str, Dict[str, Any]]: """Internal method for preparing requests.""" if not args: args = {} # auto-inject the current span's info into the HTTP headers if wtt.get_current_span().is_recording(): wtt.propagations.inject_span_carrier( self.session.headers) # type: ignore[arg-type] if path.startswith('/'): path = path[1:] url = os.path.join(self.address, path) kwargs: Dict[str, Any] = {'timeout': self.timeout} if method in ('GET', 'HEAD'): # args should be urlencoded kwargs['params'] = args else: kwargs['json'] = args if self.token_func: self._get_token() if not headers: headers = {} if self.access_token: headers['Authorization'] = 'Bearer ' + _to_str(self.access_token) if headers: kwargs['headers'] = headers return (url, kwargs)
def example_02_threads_incorrect(n_threads: int) -> None: """Run multiple independent threads, INCORRECTLY. A re-spanned in-thread function may work, but is NOT SAFE. There's a race condition: a parent process/thread may end the span before the child thread uses it, or visa-versa. It's not a good idea. Don't do this! """ outter_span = wtt.get_current_span() # even with `wtt.SpanBehavior.DONT_END`, this isn't a good idea @wtt.respanned("span", wtt.SpanBehavior.END_ON_EXIT) def thread_work(worker: int, span: wtt.Span) -> int: """Do thread's work.""" assert span == outter_span == wtt.get_current_span() assert outter_span.is_recording() # sure assert wtt.get_current_span().is_recording() # as expected assert outter_span == wtt.get_current_span() # as expected assert not wtt.get_current_span()._parent # type: ignore[attr-defined] # # # # # print(carrier) time.sleep(1) # shared memory allows this -- but not a great idea logically... outter_span.add_event("I'm", {"A": "Thread"}) return worker futures: List[Future] = [] # type: ignore[type-arg] with ThreadPoolExecutor() as pool: for i in range(n_threads): # carrier = wtt.inject_span_carrier() # print(carrier) futures.append(pool.submit(thread_work, i, outter_span)) for worker in as_completed(futures): ret = worker.result() wtt.add_event("Worker Join", {"worker-id": ret, "type": "thread"}) print(f"Returned Worker #{ret}")
def the_one_that_returns_a_span() -> wtt.Span: """Use wtt.Span-injection to set the span.""" logging.info("the_one_that_returns_a_span()") return wtt.get_current_span()
def finish(self) -> None: """Do some things, reuse a span, then close that span.""" time.sleep(1) assert self.span == wtt.get_current_span() assert wtt.get_current_span().is_recording()