async def execute(self, query: str, *args: Any, query_name: Optional[str] = None) -> Optional[int]: with wrap2span( name=OraSpan.NAME_EXECUTE, kind=OraSpan.KIND_CLIENT, cls=OraSpan, app=self._conn._db.app, ) as span: span.set_name4adapter( self._conn._db.app.logger.ADAPTER_PROMETHEUS, OraSpan.P8S_NAME_EXECUTE, ) if query_name is not None: span.tag(OraSpan.TAG_QUERY_NAME, query_name) async with self._lock: if self._conn._db.cfg.log_query: span.annotate(OraSpan.ANN_QUERY, query) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_QUERY, json_encode({'query': str(query)}), ) span.annotate(OraSpan.ANN_PARAMS, str(args)) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_PARAMS, json_encode({'query_params': str(args)}), ) await self._loop.run_in_executor(None, self._ora_cur.execute, query, args) return self._ora_cur.rowcount
def test_encode_bytes() -> None: data = os.urandom(100) enc_data = json_encode(data) assert enc_data == f'"{BASE64_MARKER}{base64.b64encode(data).decode()}"' enc_data_ = json.loads(enc_data)[len(BASE64_MARKER):] bytes_from_enc_data = base64.b64decode(enc_data_.encode()) assert data == bytes_from_enc_data
def _span_ann_format4zipkin( self, span: Span, kind: str, content: str, ts: float ) -> None: span.annotate4adapter( self.app.logger.ADAPTER_ZIPKIN, kind, misc.json_encode({kind: content}), ts=ts, )
async def callfunc(self, name: str, return_type: Type, args: list) -> Any: with wrap2span( name=OraSpan.NAME_CALLFUNC, kind=OraSpan.KIND_CLIENT, cls=OraSpan, app=self._conn._db.app, ) as span: span.set_name4adapter( self._conn._db.app.logger.ADAPTER_PROMETHEUS, OraSpan.P8S_NAME_CALLFUNC, ) span.tag(OraSpan.TAG_FUNC_NAME, name) async with self._lock: if self._conn._db.cfg.log_query: span.annotate(OraSpan.ANN_QUERY, '%s:%r' % (name, return_type)) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_QUERY, json_encode({'proc': '%s:%r' % (name, return_type)}), ) span.annotate(OraSpan.ANN_PARAMS, str(args)) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_PARAMS, json_encode({'params': str(args)}), ) # todo timeout res = await self._conn._db.loop.run_in_executor( None, self._ora_cur.callfunc, name, return_type, args) if self._conn._db.cfg.log_result: span.annotate(OraSpan.ANN_RESULT, str(res)) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_RESULT, json_encode({ 'result': str(res), 'args': str(args) }), ) return res
async def fetchone( self, *, model_cls: Optional[Type[BaseModel]] = None, query_name: Optional[str] = None, ) -> Optional[Union[dict, BaseModel]]: with wrap2span( name=OraSpan.NAME_FETCH, kind=OraSpan.KIND_CLIENT, cls=OraSpan, app=self._conn._db.app, ) as span: span.set_name4adapter( self._conn._db.app.logger.ADAPTER_PROMETHEUS, OraSpan.P8S_NAME_FETCH, ) if query_name is not None: span.tag(OraSpan.TAG_QUERY_NAME, query_name) async with self._lock: row = await self._loop.run_in_executor( None, self._ora_cur.fetchone ) res: Optional[Union[dict, BaseModel]] = None if row is not None: column_names = [ d[0].lower() for d in self._ora_cur.description ] res = dict(zip(column_names, row)) if self._conn._db.cfg.log_result: span.annotate(OraSpan.ANN_RESULT, json_encode(res)) span.annotate4adapter( self._conn._db.app.logger.ADAPTER_ZIPKIN, OraSpan.ANN_RESULT, json_encode({'result': str(res)}), ) if model_cls is not None and res is not None: return model_cls(**res) # type: ignore else: return res
def handle(self, span: Span) -> None: # noqa if self.logger is None: # pragma: no cover raise UserWarning if self._stopping: # pragma: no cover self.logger.app.log_warn('WTF??? RAHSWS') if self._queue is None: # pragma: no cover raise UserWarning kwargs: Dict[str, Any] = dict( trace_id=span.trace_id, stamp_begin=round(span.start_stamp or 0, 6), stamp_end=round(span.finish_stamp or 0, 6), service=self.cfg.name, ) tags = span.get_tags4adapter(self.name).copy() if isinstance(span, ht.HttpSpan): kwargs['type'] = 'http' kwargs['is_out'] = span.kind != ht.HttpSpan.KIND_SERVER if kwargs['is_out']: kwargs['type'] += '_out' else: kwargs['type'] += '_in' if ht.HttpSpan.TAG_HTTP_URL in tags: kwargs['url'] = tags.pop(ht.HttpSpan.TAG_HTTP_URL) if 'rpc.method' in tags: kwargs['method'] = tags.pop('rpc.method') kwargs['type'] = 'rpc_' + kwargs['type'] elif ht.HttpSpan.TAG_HTTP_METHOD in tags: kwargs['method'] = tags.pop(ht.HttpSpan.TAG_HTTP_METHOD) if 'rpc.code' in tags: kwargs['status_code'] = tags.pop('rpc.code') elif ht.HttpSpan.TAG_HTTP_STATUS_CODE in tags: kwargs['status_code'] = tags.pop( ht.HttpSpan.TAG_HTTP_STATUS_CODE) elif amqp is not None and isinstance( span, (amqp.AmqpInSpan, amqp.AmqpOutSpan)): kwargs['type'] = 'amqp' kwargs['is_out'] = span.kind != amqp.AmqpSpan.KIND_SERVER if kwargs['is_out']: kwargs['type'] += '_out' else: kwargs['type'] += '_in' if 'rpc.code' in tags: kwargs['status_code'] = tags.pop('rpc.code') if 'rpc.method' in tags: kwargs['method'] = tags.pop('rpc.method') kwargs['type'] = 'rpc_' + kwargs['type'] else: exchange: Optional[str] = None routing_key: Optional[str] = None if amqp.AmqpSpan.TAG_EXCHANGE in tags: exchange = tags.pop(amqp.AmqpSpan.TAG_EXCHANGE) if amqp.AmqpSpan.TAG_ROUTING_KEY in tags: routing_key = tags.pop(amqp.AmqpSpan.TAG_ROUTING_KEY) if exchange: kwargs['method'] = 'ex:%s rk:%s' % ( exchange or '', routing_key or '', ) else: kwargs['method'] = 'rk:%s' % (routing_key or '') if isinstance(span, amqp.AmqpInSpan): kwargs['method'] = 'receive: %s' % kwargs['method'] else: kwargs['method'] = 'publish: %s' % kwargs['method'] if amqp.AmqpSpan.TAG_URL in tags: kwargs['url'] = tags.pop(amqp.AmqpSpan.TAG_URL) else: return if Span.TAG_ERROR_MESSAGE in tags: kwargs['error'] = tags.pop(Span.TAG_ERROR_MESSAGE) anns = span.get_annotations4adapter(self.name).copy() for key, ann_name, max_len in self._anns_mapping: if ann_name in anns: val = "\n\n".join([a for a, _ in anns.pop(ann_name)]) if len(val) > max_len: val = val[:max_len] kwargs[key] = val elif key not in kwargs: kwargs[key] = None # удаляем лишние теги ht.HttpSpan.TAG_ERROR in tags and tags.pop(ht.HttpSpan.TAG_ERROR) ht.HttpSpan.TAG_ERROR_CLASS in tags and tags.pop( ht.HttpSpan.TAG_ERROR_CLASS) ht.HttpSpan.TAG_HTTP_HOST in tags and tags.pop( ht.HttpSpan.TAG_HTTP_HOST) ht.HttpSpan.TAG_HTTP_PATH in tags and tags.pop( ht.HttpSpan.TAG_HTTP_PATH) ht.HttpSpan.TAG_HTTP_ROUTE in tags and tags.pop( ht.HttpSpan.TAG_HTTP_ROUTE) ht.HttpSpan.TAG_HTTP_REQUEST_SIZE in tags and tags.pop( ht.HttpSpan.TAG_HTTP_REQUEST_SIZE) ht.HttpSpan.TAG_HTTP_RESPONSE_SIZE in tags and tags.pop( ht.HttpSpan.TAG_HTTP_RESPONSE_SIZE) if amqp is not None: amqp.AmqpSpan.TAG_CHANNEL_NUMBER in tags and tags.pop( amqp.AmqpSpan.TAG_CHANNEL_NUMBER) if len(tags) > 0: kwargs['tags'] = misc.json_encode(tags) self._queue.append(Request(**kwargs)) if self.cfg.send_max_count <= len(self._queue): if self._sleep_fut is not None and not self._sleep_fut.done(): self._sleep_fut.cancel()
def test_encode_subclass() -> None: data = {"uuid": CustomUUID("53fa72dd-16d5-418c-8faa-b6a201202930")} json_encode(data)
async def test_success( loop, ): async with ZipkinServer() as zs: cfg = ZipkinConfig(name='123', addr=zs.addr) adapter = ZipkinAdapter(cfg) app = BaseApplication(BaseConfig()) app.logger.add(adapter) lgr = app.logger await lgr.start() with lgr.span_new(name='t1', kind=Span.KIND_SERVER) as sp: sp.tag('tag', 'abc') sp.annotate('k1', 'val1', ts=123456) with pytest.raises(Exception): with sp.new_child('t2', Span.KIND_CLIENT): raise Exception() with lgr.span_new(kind=Span.KIND_SERVER) as sp3: sp3.set_name4adapter(lgr.ADAPTER_ZIPKIN, '111') sp3.annotate4adapter( lgr.ADAPTER_ZIPKIN, PgSpan.ANN_RESULT, json_encode({'result': '123'}), ts=122211000000, ) sp3.set_tag4adapter( lgr.ADAPTER_ZIPKIN, PgSpan.TAG_QUERY_NAME, 'get_paym', ) await lgr.stop() assert len(zs.spans) == 3 span: SpanModel = zs.spans[1] span2: SpanModel = zs.spans[0] span3: SpanModel = zs.spans[2] assert span.name == 't1' assert span.tags == {'tag': 'abc'} assert span.annotations == [ Annotation(value='val1', timestamp=123456000000) ] assert span.duration > 0 assert span.timestamp > 0 assert not span.debug assert span.shared assert span2.name == 't2' assert span2.tags == { 'error': 'true', 'error.class': 'Exception', 'error.message': '', } assert 'raise Exception()' in span2.annotations[0].value assert span3.name == '111' assert span3.tags == {PgSpan.TAG_QUERY_NAME: 'get_paym'} assert span3.annotations == [ Annotation(value='{"result": "123"}', timestamp=122211000000000000) ]