From da6ea6dd47f8d7c653157253e7271d6c448b6de0 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 13 Aug 2018 17:52:47 -0700 Subject: [PATCH 1/8] Initial OpenCensusD exporter implementation --- .coveragerc | 8 +- .../exporters/gen/opencensusd/__init__.py | 13 + .../gen/opencensusd/agent/__init__.py | 13 + .../gen/opencensusd/agent/common/__init__.py | 13 + .../opencensusd/agent/common/v1/__init__.py | 13 + .../opencensusd/agent/common/v1/common_pb2.py | 342 +++++ .../gen/opencensusd/agent/trace/__init__.py | 13 + .../opencensusd/agent/trace/v1/__init__.py | 13 + .../agent/trace/v1/trace_service_pb2.py | 236 ++++ .../agent/trace/v1/trace_service_pb2_grpc.py | 67 + .../gen/opencensusd/trace/__init__.py | 15 + .../gen/opencensusd/trace/v1/__init__.py | 15 + .../opencensusd/trace/v1/trace_config_pb2.py | 217 ++++ .../gen/opencensusd/trace/v1/trace_pb2.py | 1135 +++++++++++++++++ .../trace/exporters/opencensusd_exporter.py | 400 ++++++ .../exporters/test_opensensusd_exporter.py | 1008 +++++++++++++++ 16 files changed, 3519 insertions(+), 2 deletions(-) create mode 100644 opencensus/trace/exporters/gen/opencensusd/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/trace/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py create mode 100644 opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py create mode 100644 opencensus/trace/exporters/opencensusd_exporter.py create mode 100644 tests/unit/trace/exporters/test_opensensusd_exporter.py diff --git a/.coveragerc b/.coveragerc index ea6f23d52..9560a35e6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,8 @@ [run] branch = True -omit = *gen/jaeger* +omit = + *gen/jaeger* + *gen/opencensusd* [report] fail_under = 100 @@ -10,4 +12,6 @@ exclude_lines = pragma: NO COVER # Ignore debug-only repr def __repr__ -omit = *gen/jaeger* +omit = + *gen/jaeger* + *gen/opencensusd* diff --git a/opencensus/trace/exporters/gen/opencensusd/__init__.py b/opencensus/trace/exporters/gen/opencensusd/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/__init__.py b/opencensus/trace/exporters/gen/opencensusd/agent/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py b/opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py b/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py b/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py new file mode 100644 index 000000000..cb79adc04 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py @@ -0,0 +1,342 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/agent/common/v1/common.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='opencensus/proto/agent/common/v1/common.proto', + package='opencensus.proto.agent.common.v1', + syntax='proto3', + serialized_pb=_b('\n-opencensus/proto/agent/common/v1/common.proto\x12 opencensus.proto.agent.common.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd8\x02\n\x04Node\x12G\n\nidentifier\x18\x01 \x01(\x0b\x32\x33.opencensus.proto.agent.common.v1.ProcessIdentifier\x12\x43\n\x0clibrary_info\x18\x02 \x01(\x0b\x32-.opencensus.proto.agent.common.v1.LibraryInfo\x12\x43\n\x0cservice_info\x18\x03 \x01(\x0b\x32-.opencensus.proto.agent.common.v1.ServiceInfo\x12J\n\nattributes\x18\x04 \x03(\x0b\x32\x36.opencensus.proto.agent.common.v1.Node.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"h\n\x11ProcessIdentifier\x12\x11\n\thost_name\x18\x01 \x01(\t\x12\x0b\n\x03pid\x18\x02 \x01(\r\x12\x33\n\x0fstart_timestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xf4\x01\n\x0bLibraryInfo\x12H\n\x08language\x18\x01 \x01(\x0e\x32\x36.opencensus.proto.agent.common.v1.LibraryInfo.Language\x12\x0f\n\x07version\x18\x02 \x01(\t\"\x89\x01\n\x08Language\x12\x18\n\x14LANGUAGE_UNSPECIFIED\x10\x00\x12\x07\n\x03\x43PP\x10\x01\x12\x0b\n\x07\x43_SHARP\x10\x02\x12\n\n\x06\x45RLANG\x10\x03\x12\x0b\n\x07GO_LANG\x10\x04\x12\x08\n\x04JAVA\x10\x05\x12\x0b\n\x07NODE_JS\x10\x06\x12\x07\n\x03PHP\x10\x07\x12\n\n\x06PYTHON\x10\x08\x12\x08\n\x04RUBY\x10\t\"\x1b\n\x0bServiceInfo\x12\x0c\n\x04name\x18\x01 \x01(\tB\x7f\n#io.opencensus.proto.agent.common.v1B\x0b\x43ommonProtoP\x01ZIgithub.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1b\x06proto3') + , + dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + + + +_LIBRARYINFO_LANGUAGE = _descriptor.EnumDescriptor( + name='Language', + full_name='opencensus.proto.agent.common.v1.LibraryInfo.Language', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LANGUAGE_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CPP', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='C_SHARP', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERLANG', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='GO_LANG', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='JAVA', index=5, number=5, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='NODE_JS', index=6, number=6, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='PHP', index=7, number=7, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='PYTHON', index=8, number=8, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RUBY', index=9, number=9, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=677, + serialized_end=814, +) +_sym_db.RegisterEnumDescriptor(_LIBRARYINFO_LANGUAGE) + + +_NODE_ATTRIBUTESENTRY = _descriptor.Descriptor( + name='AttributesEntry', + full_name='opencensus.proto.agent.common.v1.Node.AttributesEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='opencensus.proto.agent.common.v1.Node.AttributesEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='opencensus.proto.agent.common.v1.Node.AttributesEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=412, + serialized_end=461, +) + +_NODE = _descriptor.Descriptor( + name='Node', + full_name='opencensus.proto.agent.common.v1.Node', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='identifier', full_name='opencensus.proto.agent.common.v1.Node.identifier', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='library_info', full_name='opencensus.proto.agent.common.v1.Node.library_info', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='service_info', full_name='opencensus.proto.agent.common.v1.Node.service_info', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='attributes', full_name='opencensus.proto.agent.common.v1.Node.attributes', index=3, + number=4, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_NODE_ATTRIBUTESENTRY, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=117, + serialized_end=461, +) + + +_PROCESSIDENTIFIER = _descriptor.Descriptor( + name='ProcessIdentifier', + full_name='opencensus.proto.agent.common.v1.ProcessIdentifier', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='host_name', full_name='opencensus.proto.agent.common.v1.ProcessIdentifier.host_name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='pid', full_name='opencensus.proto.agent.common.v1.ProcessIdentifier.pid', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='start_timestamp', full_name='opencensus.proto.agent.common.v1.ProcessIdentifier.start_timestamp', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=463, + serialized_end=567, +) + + +_LIBRARYINFO = _descriptor.Descriptor( + name='LibraryInfo', + full_name='opencensus.proto.agent.common.v1.LibraryInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='language', full_name='opencensus.proto.agent.common.v1.LibraryInfo.language', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='version', full_name='opencensus.proto.agent.common.v1.LibraryInfo.version', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LIBRARYINFO_LANGUAGE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=570, + serialized_end=814, +) + + +_SERVICEINFO = _descriptor.Descriptor( + name='ServiceInfo', + full_name='opencensus.proto.agent.common.v1.ServiceInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='opencensus.proto.agent.common.v1.ServiceInfo.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=816, + serialized_end=843, +) + +_NODE_ATTRIBUTESENTRY.containing_type = _NODE +_NODE.fields_by_name['identifier'].message_type = _PROCESSIDENTIFIER +_NODE.fields_by_name['library_info'].message_type = _LIBRARYINFO +_NODE.fields_by_name['service_info'].message_type = _SERVICEINFO +_NODE.fields_by_name['attributes'].message_type = _NODE_ATTRIBUTESENTRY +_PROCESSIDENTIFIER.fields_by_name['start_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_LIBRARYINFO.fields_by_name['language'].enum_type = _LIBRARYINFO_LANGUAGE +_LIBRARYINFO_LANGUAGE.containing_type = _LIBRARYINFO +DESCRIPTOR.message_types_by_name['Node'] = _NODE +DESCRIPTOR.message_types_by_name['ProcessIdentifier'] = _PROCESSIDENTIFIER +DESCRIPTOR.message_types_by_name['LibraryInfo'] = _LIBRARYINFO +DESCRIPTOR.message_types_by_name['ServiceInfo'] = _SERVICEINFO +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Node = _reflection.GeneratedProtocolMessageType('Node', (_message.Message,), dict( + + AttributesEntry = _reflection.GeneratedProtocolMessageType('AttributesEntry', (_message.Message,), dict( + DESCRIPTOR = _NODE_ATTRIBUTESENTRY, + __module__ = 'opencensus.proto.agent.common.v1.common_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.common.v1.Node.AttributesEntry) + )) + , + DESCRIPTOR = _NODE, + __module__ = 'opencensus.proto.agent.common.v1.common_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.common.v1.Node) + )) +_sym_db.RegisterMessage(Node) +_sym_db.RegisterMessage(Node.AttributesEntry) + +ProcessIdentifier = _reflection.GeneratedProtocolMessageType('ProcessIdentifier', (_message.Message,), dict( + DESCRIPTOR = _PROCESSIDENTIFIER, + __module__ = 'opencensus.proto.agent.common.v1.common_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.common.v1.ProcessIdentifier) + )) +_sym_db.RegisterMessage(ProcessIdentifier) + +LibraryInfo = _reflection.GeneratedProtocolMessageType('LibraryInfo', (_message.Message,), dict( + DESCRIPTOR = _LIBRARYINFO, + __module__ = 'opencensus.proto.agent.common.v1.common_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.common.v1.LibraryInfo) + )) +_sym_db.RegisterMessage(LibraryInfo) + +ServiceInfo = _reflection.GeneratedProtocolMessageType('ServiceInfo', (_message.Message,), dict( + DESCRIPTOR = _SERVICEINFO, + __module__ = 'opencensus.proto.agent.common.v1.common_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.common.v1.ServiceInfo) + )) +_sym_db.RegisterMessage(ServiceInfo) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n#io.opencensus.proto.agent.common.v1B\013CommonProtoP\001ZIgithub.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1')) +_NODE_ATTRIBUTESENTRY.has_options = True +_NODE_ATTRIBUTESENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +# @@protoc_insertion_point(module_scope) diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py b/opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py new file mode 100644 index 000000000..c2791ba2a --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py @@ -0,0 +1,236 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/agent/trace/v1/trace_service.proto + +import sys +_b = sys.version_info[0] < 3 and ( + lambda x: x) or (lambda x: x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import common_pb2 as opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2 +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2 +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='opencensus/proto/agent/trace/v1/trace_service.proto', + package='opencensus.proto.agent.trace.v1', + syntax='proto3', + serialized_pb=_b('\n3opencensus/proto/agent/trace/v1/trace_service.proto\x12\x1fopencensus.proto.agent.trace.v1\x1a-opencensus/proto/agent/common/v1/common.proto\x1a%opencensus/proto/trace/v1/trace.proto\x1a,opencensus/proto/trace/v1/trace_config.proto\"\x89\x01\n\x19\x43onfigTraceServiceRequest\x12\x34\n\x04node\x18\x01 \x01(\x0b\x32&.opencensus.proto.agent.common.v1.Node\x12\x36\n\x06\x63onfig\x18\x02 \x01(\x0b\x32&.opencensus.proto.trace.v1.TraceConfig\"T\n\x1a\x43onfigTraceServiceResponse\x12\x36\n\x06\x63onfig\x18\x02 \x01(\x0b\x32&.opencensus.proto.trace.v1.TraceConfig\"\x81\x01\n\x19\x45xportTraceServiceRequest\x12\x34\n\x04node\x18\x01 \x01(\x0b\x32&.opencensus.proto.agent.common.v1.Node\x12.\n\x05spans\x18\x02 \x03(\x0b\x32\x1f.opencensus.proto.trace.v1.Span\"\x1c\n\x1a\x45xportTraceServiceResponse2\xa2\x02\n\x0cTraceService\x12\x87\x01\n\x06\x43onfig\x12:.opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest\x1a;.opencensus.proto.agent.trace.v1.ConfigTraceServiceResponse\"\x00(\x01\x30\x01\x12\x87\x01\n\x06\x45xport\x12:.opencensus.proto.agent.trace.v1.ExportTraceServiceRequest\x1a;.opencensus.proto.agent.trace.v1.ExportTraceServiceResponse\"\x00(\x01\x30\x01\x42\x83\x01\n\"io.opencensus.proto.agent.trace.v1B\x11TraceServiceProtoP\x01ZHgithub.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1b\x06proto3'), + dependencies=[opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2.DESCRIPTOR, opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2.DESCRIPTOR, opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2.DESCRIPTOR, ]) + + +_CONFIGTRACESERVICEREQUEST = _descriptor.Descriptor( + name='ConfigTraceServiceRequest', + full_name='opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='node', full_name='opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest.node', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='config', full_name='opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest.config', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=221, + serialized_end=358, +) + + +_CONFIGTRACESERVICERESPONSE = _descriptor.Descriptor( + name='ConfigTraceServiceResponse', + full_name='opencensus.proto.agent.trace.v1.ConfigTraceServiceResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='config', full_name='opencensus.proto.agent.trace.v1.ConfigTraceServiceResponse.config', index=0, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=360, + serialized_end=444, +) + + +_EXPORTTRACESERVICEREQUEST = _descriptor.Descriptor( + name='ExportTraceServiceRequest', + full_name='opencensus.proto.agent.trace.v1.ExportTraceServiceRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='node', full_name='opencensus.proto.agent.trace.v1.ExportTraceServiceRequest.node', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='spans', full_name='opencensus.proto.agent.trace.v1.ExportTraceServiceRequest.spans', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=447, + serialized_end=576, +) + + +_EXPORTTRACESERVICERESPONSE = _descriptor.Descriptor( + name='ExportTraceServiceResponse', + full_name='opencensus.proto.agent.trace.v1.ExportTraceServiceResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=578, + serialized_end=606, +) + +_CONFIGTRACESERVICEREQUEST.fields_by_name['node'].message_type = opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2._NODE +_CONFIGTRACESERVICEREQUEST.fields_by_name['config'].message_type = opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2._TRACECONFIG +_CONFIGTRACESERVICERESPONSE.fields_by_name['config'].message_type = opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2._TRACECONFIG +_EXPORTTRACESERVICEREQUEST.fields_by_name['node'].message_type = opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2._NODE +_EXPORTTRACESERVICEREQUEST.fields_by_name['spans'].message_type = opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2._SPAN +DESCRIPTOR.message_types_by_name['ConfigTraceServiceRequest'] = _CONFIGTRACESERVICEREQUEST +DESCRIPTOR.message_types_by_name['ConfigTraceServiceResponse'] = _CONFIGTRACESERVICERESPONSE +DESCRIPTOR.message_types_by_name['ExportTraceServiceRequest'] = _EXPORTTRACESERVICEREQUEST +DESCRIPTOR.message_types_by_name['ExportTraceServiceResponse'] = _EXPORTTRACESERVICERESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ConfigTraceServiceRequest = _reflection.GeneratedProtocolMessageType('ConfigTraceServiceRequest', (_message.Message,), dict( + DESCRIPTOR=_CONFIGTRACESERVICEREQUEST, + __module__='opencensus.proto.agent.trace.v1.trace_service_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest) +)) +_sym_db.RegisterMessage(ConfigTraceServiceRequest) + +ConfigTraceServiceResponse = _reflection.GeneratedProtocolMessageType('ConfigTraceServiceResponse', (_message.Message,), dict( + DESCRIPTOR=_CONFIGTRACESERVICERESPONSE, + __module__='opencensus.proto.agent.trace.v1.trace_service_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.trace.v1.ConfigTraceServiceResponse) +)) +_sym_db.RegisterMessage(ConfigTraceServiceResponse) + +ExportTraceServiceRequest = _reflection.GeneratedProtocolMessageType('ExportTraceServiceRequest', (_message.Message,), dict( + DESCRIPTOR=_EXPORTTRACESERVICEREQUEST, + __module__='opencensus.proto.agent.trace.v1.trace_service_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.trace.v1.ExportTraceServiceRequest) +)) +_sym_db.RegisterMessage(ExportTraceServiceRequest) + +ExportTraceServiceResponse = _reflection.GeneratedProtocolMessageType('ExportTraceServiceResponse', (_message.Message,), dict( + DESCRIPTOR=_EXPORTTRACESERVICERESPONSE, + __module__='opencensus.proto.agent.trace.v1.trace_service_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.agent.trace.v1.ExportTraceServiceResponse) +)) +_sym_db.RegisterMessage(ExportTraceServiceResponse) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b( + '\n\"io.opencensus.proto.agent.trace.v1B\021TraceServiceProtoP\001ZHgithub.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1')) + +_TRACESERVICE = _descriptor.ServiceDescriptor( + name='TraceService', + full_name='opencensus.proto.agent.trace.v1.TraceService', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=609, + serialized_end=899, + methods=[ + _descriptor.MethodDescriptor( + name='Config', + full_name='opencensus.proto.agent.trace.v1.TraceService.Config', + index=0, + containing_service=None, + input_type=_CONFIGTRACESERVICEREQUEST, + output_type=_CONFIGTRACESERVICERESPONSE, + options=None, + ), + _descriptor.MethodDescriptor( + name='Export', + full_name='opencensus.proto.agent.trace.v1.TraceService.Export', + index=1, + containing_service=None, + input_type=_EXPORTTRACESERVICEREQUEST, + output_type=_EXPORTTRACESERVICERESPONSE, + options=None, + ), + ]) +_sym_db.RegisterServiceDescriptor(_TRACESERVICE) + +DESCRIPTOR.services_by_name['TraceService'] = _TRACESERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py new file mode 100644 index 000000000..63a3aadc4 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py @@ -0,0 +1,67 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 as opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2 + + +class TraceServiceStub(object): + # missing associated documentation comment in .proto file + pass + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Config = channel.stream_stream( + '/opencensus.proto.agent.trace.v1.TraceService/Config', + request_serializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ConfigTraceServiceRequest.SerializeToString, + response_deserializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ConfigTraceServiceResponse.FromString, + ) + self.Export = channel.stream_stream( + '/opencensus.proto.agent.trace.v1.TraceService/Export', + request_serializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ExportTraceServiceRequest.SerializeToString, + response_deserializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ExportTraceServiceResponse.FromString, + ) + + +class TraceServiceServicer(object): + # missing associated documentation comment in .proto file + pass + + def Config(self, request_iterator, context): + """After the initialization this RPC must be kept alive for the + entire life of the application. Agent pushes configs to the + application via a stream of responses. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Export(self, request_iterator, context): + """Allow to export Spans. + For performance reason, it is recommended to keep this RPC + alive for the entire life of the application. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_TraceServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Config': grpc.stream_stream_rpc_method_handler( + servicer.Config, + request_deserializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ConfigTraceServiceRequest.FromString, + response_serializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ConfigTraceServiceResponse.SerializeToString, + ), + 'Export': grpc.stream_stream_rpc_method_handler( + servicer.Export, + request_deserializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ExportTraceServiceRequest.FromString, + response_serializer=opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2.ExportTraceServiceResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'opencensus.proto.agent.trace.v1.TraceService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/__init__.py b/opencensus/trace/exporters/gen/opencensusd/trace/__init__.py new file mode 100644 index 000000000..797e9d33e --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/trace/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__all__ = ['trace_pb2'] diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py b/opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py new file mode 100644 index 000000000..797e9d33e --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__all__ = ['trace_pb2'] diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py new file mode 100644 index 000000000..7673eca1a --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py @@ -0,0 +1,217 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/trace/v1/trace_config.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='opencensus/proto/trace/v1/trace_config.proto', + package='opencensus.proto.trace.v1', + syntax='proto3', + serialized_pb=_b('\n,opencensus/proto/trace/v1/trace_config.proto\x12\x19opencensus.proto.trace.v1\"\xff\x01\n\x0bTraceConfig\x12L\n\x13probability_sampler\x18\x01 \x01(\x0b\x32-.opencensus.proto.trace.v1.ProbabilitySamplerH\x00\x12\x46\n\x10\x63onstant_sampler\x18\x02 \x01(\x0b\x32*.opencensus.proto.trace.v1.ConstantSamplerH\x00\x12O\n\x15rate_limiting_sampler\x18\x03 \x01(\x0b\x32..opencensus.proto.trace.v1.RateLimitingSamplerH\x00\x42\t\n\x07sampler\"1\n\x12ProbabilitySampler\x12\x1b\n\x13samplingProbability\x18\x01 \x01(\x01\"#\n\x0f\x43onstantSampler\x12\x10\n\x08\x64\x65\x63ision\x18\x01 \x01(\x08\"\"\n\x13RateLimitingSampler\x12\x0b\n\x03qps\x18\x01 \x01(\x03\x42v\n\x1cio.opencensus.proto.trace.v1B\x10TraceConfigProtoP\x01ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1b\x06proto3') +) + + + + +_TRACECONFIG = _descriptor.Descriptor( + name='TraceConfig', + full_name='opencensus.proto.trace.v1.TraceConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='probability_sampler', full_name='opencensus.proto.trace.v1.TraceConfig.probability_sampler', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='constant_sampler', full_name='opencensus.proto.trace.v1.TraceConfig.constant_sampler', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rate_limiting_sampler', full_name='opencensus.proto.trace.v1.TraceConfig.rate_limiting_sampler', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='sampler', full_name='opencensus.proto.trace.v1.TraceConfig.sampler', + index=0, containing_type=None, fields=[]), + ], + serialized_start=76, + serialized_end=331, +) + + +_PROBABILITYSAMPLER = _descriptor.Descriptor( + name='ProbabilitySampler', + full_name='opencensus.proto.trace.v1.ProbabilitySampler', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='samplingProbability', full_name='opencensus.proto.trace.v1.ProbabilitySampler.samplingProbability', index=0, + number=1, type=1, cpp_type=5, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=333, + serialized_end=382, +) + + +_CONSTANTSAMPLER = _descriptor.Descriptor( + name='ConstantSampler', + full_name='opencensus.proto.trace.v1.ConstantSampler', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='decision', full_name='opencensus.proto.trace.v1.ConstantSampler.decision', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=384, + serialized_end=419, +) + + +_RATELIMITINGSAMPLER = _descriptor.Descriptor( + name='RateLimitingSampler', + full_name='opencensus.proto.trace.v1.RateLimitingSampler', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='qps', full_name='opencensus.proto.trace.v1.RateLimitingSampler.qps', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=421, + serialized_end=455, +) + +_TRACECONFIG.fields_by_name['probability_sampler'].message_type = _PROBABILITYSAMPLER +_TRACECONFIG.fields_by_name['constant_sampler'].message_type = _CONSTANTSAMPLER +_TRACECONFIG.fields_by_name['rate_limiting_sampler'].message_type = _RATELIMITINGSAMPLER +_TRACECONFIG.oneofs_by_name['sampler'].fields.append( + _TRACECONFIG.fields_by_name['probability_sampler']) +_TRACECONFIG.fields_by_name['probability_sampler'].containing_oneof = _TRACECONFIG.oneofs_by_name['sampler'] +_TRACECONFIG.oneofs_by_name['sampler'].fields.append( + _TRACECONFIG.fields_by_name['constant_sampler']) +_TRACECONFIG.fields_by_name['constant_sampler'].containing_oneof = _TRACECONFIG.oneofs_by_name['sampler'] +_TRACECONFIG.oneofs_by_name['sampler'].fields.append( + _TRACECONFIG.fields_by_name['rate_limiting_sampler']) +_TRACECONFIG.fields_by_name['rate_limiting_sampler'].containing_oneof = _TRACECONFIG.oneofs_by_name['sampler'] +DESCRIPTOR.message_types_by_name['TraceConfig'] = _TRACECONFIG +DESCRIPTOR.message_types_by_name['ProbabilitySampler'] = _PROBABILITYSAMPLER +DESCRIPTOR.message_types_by_name['ConstantSampler'] = _CONSTANTSAMPLER +DESCRIPTOR.message_types_by_name['RateLimitingSampler'] = _RATELIMITINGSAMPLER +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +TraceConfig = _reflection.GeneratedProtocolMessageType('TraceConfig', (_message.Message,), dict( + DESCRIPTOR = _TRACECONFIG, + __module__ = 'opencensus.proto.trace.v1.trace_config_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.TraceConfig) + )) +_sym_db.RegisterMessage(TraceConfig) + +ProbabilitySampler = _reflection.GeneratedProtocolMessageType('ProbabilitySampler', (_message.Message,), dict( + DESCRIPTOR = _PROBABILITYSAMPLER, + __module__ = 'opencensus.proto.trace.v1.trace_config_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.ProbabilitySampler) + )) +_sym_db.RegisterMessage(ProbabilitySampler) + +ConstantSampler = _reflection.GeneratedProtocolMessageType('ConstantSampler', (_message.Message,), dict( + DESCRIPTOR = _CONSTANTSAMPLER, + __module__ = 'opencensus.proto.trace.v1.trace_config_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.ConstantSampler) + )) +_sym_db.RegisterMessage(ConstantSampler) + +RateLimitingSampler = _reflection.GeneratedProtocolMessageType('RateLimitingSampler', (_message.Message,), dict( + DESCRIPTOR = _RATELIMITINGSAMPLER, + __module__ = 'opencensus.proto.trace.v1.trace_config_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.RateLimitingSampler) + )) +_sym_db.RegisterMessage(RateLimitingSampler) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\034io.opencensus.proto.trace.v1B\020TraceConfigProtoP\001ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1')) +# @@protoc_insertion_point(module_scope) diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py new file mode 100644 index 000000000..8c156d4a6 --- /dev/null +++ b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py @@ -0,0 +1,1135 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/trace/v1/trace.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 +from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='opencensus/proto/trace/v1/trace.proto', + package='opencensus.proto.trace.v1', + syntax='proto3', + serialized_pb=_b('\n%opencensus/proto/trace/v1/trace.proto\x12\x19opencensus.proto.trace.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xf4\x10\n\x04Span\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12\x43\n\ntracestate\x18\x0f \x03(\x0b\x32/.opencensus.proto.trace.v1.Span.TracestateEntry\x12\x16\n\x0eparent_span_id\x18\x03 \x01(\x0c\x12:\n\x04name\x18\x04 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x36\n\x04kind\x18\x0e \x01(\x0e\x32(.opencensus.proto.trace.v1.Span.SpanKind\x12.\n\nstart_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12>\n\nattributes\x18\x07 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x12:\n\x0bstack_trace\x18\x08 \x01(\x0b\x32%.opencensus.proto.trace.v1.StackTrace\x12?\n\x0btime_events\x18\t \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.TimeEvents\x12\x34\n\x05links\x18\n \x01(\x0b\x32%.opencensus.proto.trace.v1.Span.Links\x12\x31\n\x06status\x18\x0b \x01(\x0b\x32!.opencensus.proto.trace.v1.Status\x12?\n\x1bsame_process_as_parent_span\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x36\n\x10\x63hild_span_count\x18\r \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x1a\x31\n\x0fTracestateEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xe3\x01\n\nAttributes\x12S\n\rattribute_map\x18\x01 \x03(\x0b\x32<.opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry\x12 \n\x18\x64ropped_attributes_count\x18\x02 \x01(\x05\x1a^\n\x11\x41ttributeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).opencensus.proto.trace.v1.AttributeValue:\x02\x38\x01\x1a\xbf\x04\n\tTimeEvent\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12J\n\nannotation\x18\x02 \x01(\x0b\x32\x34.opencensus.proto.trace.v1.Span.TimeEvent.AnnotationH\x00\x12O\n\rmessage_event\x18\x03 \x01(\x0b\x32\x36.opencensus.proto.trace.v1.Span.TimeEvent.MessageEventH\x00\x1a\x8f\x01\n\nAnnotation\x12\x41\n\x0b\x64\x65scription\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\nattributes\x18\x02 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x1a\xcf\x01\n\x0cMessageEvent\x12I\n\x04type\x18\x01 \x01(\x0e\x32;.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type\x12\n\n\x02id\x18\x02 \x01(\x04\x12\x19\n\x11uncompressed_size\x18\x03 \x01(\x04\x12\x17\n\x0f\x63ompressed_size\x18\x04 \x01(\x04\"4\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x08\n\x04SENT\x10\x01\x12\x0c\n\x08RECEIVED\x10\x02\x42\x07\n\x05value\x1a\x94\x01\n\nTimeEvents\x12=\n\ntime_event\x18\x01 \x03(\x0b\x32).opencensus.proto.trace.v1.Span.TimeEvent\x12!\n\x19\x64ropped_annotations_count\x18\x02 \x01(\x05\x12$\n\x1c\x64ropped_message_events_count\x18\x03 \x01(\x05\x1a\xef\x01\n\x04Link\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12\x37\n\x04type\x18\x03 \x01(\x0e\x32).opencensus.proto.trace.v1.Span.Link.Type\x12>\n\nattributes\x18\x04 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\"K\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11\x43HILD_LINKED_SPAN\x10\x01\x12\x16\n\x12PARENT_LINKED_SPAN\x10\x02\x1aX\n\x05Links\x12\x32\n\x04link\x18\x01 \x03(\x0b\x32$.opencensus.proto.trace.v1.Span.Link\x12\x1b\n\x13\x64ropped_links_count\x18\x02 \x01(\x05\"=\n\x08SpanKind\x12\x19\n\x15SPAN_KIND_UNSPECIFIED\x10\x00\x12\n\n\x06SERVER\x10\x01\x12\n\n\x06\x43LIENT\x10\x02\"\'\n\x06Status\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x8a\x01\n\x0e\x41ttributeValue\x12\x44\n\x0cstring_value\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableStringH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"\xed\x04\n\nStackTrace\x12G\n\x0cstack_frames\x18\x01 \x01(\x0b\x32\x31.opencensus.proto.trace.v1.StackTrace.StackFrames\x12\x1b\n\x13stack_trace_hash_id\x18\x02 \x01(\x04\x1a\x8a\x03\n\nStackFrame\x12\x43\n\rfunction_name\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12L\n\x16original_function_name\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12?\n\tfile_name\x18\x03 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x13\n\x0bline_number\x18\x04 \x01(\x03\x12\x15\n\rcolumn_number\x18\x05 \x01(\x03\x12\x36\n\x0bload_module\x18\x06 \x01(\x0b\x32!.opencensus.proto.trace.v1.Module\x12\x44\n\x0esource_version\x18\x07 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x1al\n\x0bStackFrames\x12?\n\x05\x66rame\x18\x01 \x03(\x0b\x32\x30.opencensus.proto.trace.v1.StackTrace.StackFrame\x12\x1c\n\x14\x64ropped_frames_count\x18\x02 \x01(\x05\"\x86\x01\n\x06Module\x12<\n\x06module\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\x08\x62uild_id\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\"@\n\x11TruncatableString\x12\r\n\x05value\x18\x01 \x01(\t\x12\x1c\n\x14truncated_byte_count\x18\x02 \x01(\x05\x42p\n\x1cio.opencensus.proto.trace.v1B\nTraceProtoP\x01ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1b\x06proto3') + , + dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,]) + + + +_SPAN_TIMEEVENT_MESSAGEEVENT_TYPE = _descriptor.EnumDescriptor( + name='Type', + full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TYPE_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SENT', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RECEIVED', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1691, + serialized_end=1743, +) +_sym_db.RegisterEnumDescriptor(_SPAN_TIMEEVENT_MESSAGEEVENT_TYPE) + +_SPAN_LINK_TYPE = _descriptor.EnumDescriptor( + name='Type', + full_name='opencensus.proto.trace.v1.Span.Link.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TYPE_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CHILD_LINKED_SPAN', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='PARENT_LINKED_SPAN', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2070, + serialized_end=2145, +) +_sym_db.RegisterEnumDescriptor(_SPAN_LINK_TYPE) + +_SPAN_SPANKIND = _descriptor.EnumDescriptor( + name='SpanKind', + full_name='opencensus.proto.trace.v1.Span.SpanKind', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SPAN_KIND_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVER', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CLIENT', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2237, + serialized_end=2298, +) +_sym_db.RegisterEnumDescriptor(_SPAN_SPANKIND) + + +_SPAN_TRACESTATEENTRY = _descriptor.Descriptor( + name='TracestateEntry', + full_name='opencensus.proto.trace.v1.Span.TracestateEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='opencensus.proto.trace.v1.Span.TracestateEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='opencensus.proto.trace.v1.Span.TracestateEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=895, + serialized_end=944, +) + +_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY = _descriptor.Descriptor( + name='AttributeMapEntry', + full_name='opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry.value', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1080, + serialized_end=1174, +) + +_SPAN_ATTRIBUTES = _descriptor.Descriptor( + name='Attributes', + full_name='opencensus.proto.trace.v1.Span.Attributes', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='attribute_map', full_name='opencensus.proto.trace.v1.Span.Attributes.attribute_map', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dropped_attributes_count', full_name='opencensus.proto.trace.v1.Span.Attributes.dropped_attributes_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=947, + serialized_end=1174, +) + +_SPAN_TIMEEVENT_ANNOTATION = _descriptor.Descriptor( + name='Annotation', + full_name='opencensus.proto.trace.v1.Span.TimeEvent.Annotation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='description', full_name='opencensus.proto.trace.v1.Span.TimeEvent.Annotation.description', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='attributes', full_name='opencensus.proto.trace.v1.Span.TimeEvent.Annotation.attributes', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1390, + serialized_end=1533, +) + +_SPAN_TIMEEVENT_MESSAGEEVENT = _descriptor.Descriptor( + name='MessageEvent', + full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='id', full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.id', index=1, + number=2, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='uncompressed_size', full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.uncompressed_size', index=2, + number=3, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='compressed_size', full_name='opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.compressed_size', index=3, + number=4, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SPAN_TIMEEVENT_MESSAGEEVENT_TYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1536, + serialized_end=1743, +) + +_SPAN_TIMEEVENT = _descriptor.Descriptor( + name='TimeEvent', + full_name='opencensus.proto.trace.v1.Span.TimeEvent', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='time', full_name='opencensus.proto.trace.v1.Span.TimeEvent.time', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='annotation', full_name='opencensus.proto.trace.v1.Span.TimeEvent.annotation', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message_event', full_name='opencensus.proto.trace.v1.Span.TimeEvent.message_event', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_SPAN_TIMEEVENT_ANNOTATION, _SPAN_TIMEEVENT_MESSAGEEVENT, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='value', full_name='opencensus.proto.trace.v1.Span.TimeEvent.value', + index=0, containing_type=None, fields=[]), + ], + serialized_start=1177, + serialized_end=1752, +) + +_SPAN_TIMEEVENTS = _descriptor.Descriptor( + name='TimeEvents', + full_name='opencensus.proto.trace.v1.Span.TimeEvents', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='time_event', full_name='opencensus.proto.trace.v1.Span.TimeEvents.time_event', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dropped_annotations_count', full_name='opencensus.proto.trace.v1.Span.TimeEvents.dropped_annotations_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dropped_message_events_count', full_name='opencensus.proto.trace.v1.Span.TimeEvents.dropped_message_events_count', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1755, + serialized_end=1903, +) + +_SPAN_LINK = _descriptor.Descriptor( + name='Link', + full_name='opencensus.proto.trace.v1.Span.Link', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='trace_id', full_name='opencensus.proto.trace.v1.Span.Link.trace_id', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='span_id', full_name='opencensus.proto.trace.v1.Span.Link.span_id', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='type', full_name='opencensus.proto.trace.v1.Span.Link.type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='attributes', full_name='opencensus.proto.trace.v1.Span.Link.attributes', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SPAN_LINK_TYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1906, + serialized_end=2145, +) + +_SPAN_LINKS = _descriptor.Descriptor( + name='Links', + full_name='opencensus.proto.trace.v1.Span.Links', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='link', full_name='opencensus.proto.trace.v1.Span.Links.link', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dropped_links_count', full_name='opencensus.proto.trace.v1.Span.Links.dropped_links_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2147, + serialized_end=2235, +) + +_SPAN = _descriptor.Descriptor( + name='Span', + full_name='opencensus.proto.trace.v1.Span', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='trace_id', full_name='opencensus.proto.trace.v1.Span.trace_id', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='span_id', full_name='opencensus.proto.trace.v1.Span.span_id', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='tracestate', full_name='opencensus.proto.trace.v1.Span.tracestate', index=2, + number=15, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='parent_span_id', full_name='opencensus.proto.trace.v1.Span.parent_span_id', index=3, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='name', full_name='opencensus.proto.trace.v1.Span.name', index=4, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='kind', full_name='opencensus.proto.trace.v1.Span.kind', index=5, + number=14, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='start_time', full_name='opencensus.proto.trace.v1.Span.start_time', index=6, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='end_time', full_name='opencensus.proto.trace.v1.Span.end_time', index=7, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='attributes', full_name='opencensus.proto.trace.v1.Span.attributes', index=8, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='stack_trace', full_name='opencensus.proto.trace.v1.Span.stack_trace', index=9, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='time_events', full_name='opencensus.proto.trace.v1.Span.time_events', index=10, + number=9, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='links', full_name='opencensus.proto.trace.v1.Span.links', index=11, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='status', full_name='opencensus.proto.trace.v1.Span.status', index=12, + number=11, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='same_process_as_parent_span', full_name='opencensus.proto.trace.v1.Span.same_process_as_parent_span', index=13, + number=12, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='child_span_count', full_name='opencensus.proto.trace.v1.Span.child_span_count', index=14, + number=13, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_SPAN_TRACESTATEENTRY, _SPAN_ATTRIBUTES, _SPAN_TIMEEVENT, _SPAN_TIMEEVENTS, _SPAN_LINK, _SPAN_LINKS, ], + enum_types=[ + _SPAN_SPANKIND, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=134, + serialized_end=2298, +) + + +_STATUS = _descriptor.Descriptor( + name='Status', + full_name='opencensus.proto.trace.v1.Status', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='code', full_name='opencensus.proto.trace.v1.Status.code', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='opencensus.proto.trace.v1.Status.message', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2300, + serialized_end=2339, +) + + +_ATTRIBUTEVALUE = _descriptor.Descriptor( + name='AttributeValue', + full_name='opencensus.proto.trace.v1.AttributeValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='string_value', full_name='opencensus.proto.trace.v1.AttributeValue.string_value', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='int_value', full_name='opencensus.proto.trace.v1.AttributeValue.int_value', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='bool_value', full_name='opencensus.proto.trace.v1.AttributeValue.bool_value', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='value', full_name='opencensus.proto.trace.v1.AttributeValue.value', + index=0, containing_type=None, fields=[]), + ], + serialized_start=2342, + serialized_end=2480, +) + + +_STACKTRACE_STACKFRAME = _descriptor.Descriptor( + name='StackFrame', + full_name='opencensus.proto.trace.v1.StackTrace.StackFrame', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='function_name', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.function_name', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='original_function_name', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.original_function_name', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='file_name', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.file_name', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='line_number', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.line_number', index=3, + number=4, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='column_number', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.column_number', index=4, + number=5, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='load_module', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.load_module', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='source_version', full_name='opencensus.proto.trace.v1.StackTrace.StackFrame.source_version', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2600, + serialized_end=2994, +) + +_STACKTRACE_STACKFRAMES = _descriptor.Descriptor( + name='StackFrames', + full_name='opencensus.proto.trace.v1.StackTrace.StackFrames', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='frame', full_name='opencensus.proto.trace.v1.StackTrace.StackFrames.frame', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dropped_frames_count', full_name='opencensus.proto.trace.v1.StackTrace.StackFrames.dropped_frames_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2996, + serialized_end=3104, +) + +_STACKTRACE = _descriptor.Descriptor( + name='StackTrace', + full_name='opencensus.proto.trace.v1.StackTrace', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='stack_frames', full_name='opencensus.proto.trace.v1.StackTrace.stack_frames', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='stack_trace_hash_id', full_name='opencensus.proto.trace.v1.StackTrace.stack_trace_hash_id', index=1, + number=2, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_STACKTRACE_STACKFRAME, _STACKTRACE_STACKFRAMES, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2483, + serialized_end=3104, +) + + +_MODULE = _descriptor.Descriptor( + name='Module', + full_name='opencensus.proto.trace.v1.Module', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='module', full_name='opencensus.proto.trace.v1.Module.module', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='build_id', full_name='opencensus.proto.trace.v1.Module.build_id', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3107, + serialized_end=3241, +) + + +_TRUNCATABLESTRING = _descriptor.Descriptor( + name='TruncatableString', + full_name='opencensus.proto.trace.v1.TruncatableString', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='opencensus.proto.trace.v1.TruncatableString.value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='truncated_byte_count', full_name='opencensus.proto.trace.v1.TruncatableString.truncated_byte_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3243, + serialized_end=3307, +) + +_SPAN_TRACESTATEENTRY.containing_type = _SPAN +_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.fields_by_name['value'].message_type = _ATTRIBUTEVALUE +_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.containing_type = _SPAN_ATTRIBUTES +_SPAN_ATTRIBUTES.fields_by_name['attribute_map'].message_type = _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY +_SPAN_ATTRIBUTES.containing_type = _SPAN +_SPAN_TIMEEVENT_ANNOTATION.fields_by_name['description'].message_type = _TRUNCATABLESTRING +_SPAN_TIMEEVENT_ANNOTATION.fields_by_name['attributes'].message_type = _SPAN_ATTRIBUTES +_SPAN_TIMEEVENT_ANNOTATION.containing_type = _SPAN_TIMEEVENT +_SPAN_TIMEEVENT_MESSAGEEVENT.fields_by_name['type'].enum_type = _SPAN_TIMEEVENT_MESSAGEEVENT_TYPE +_SPAN_TIMEEVENT_MESSAGEEVENT.containing_type = _SPAN_TIMEEVENT +_SPAN_TIMEEVENT_MESSAGEEVENT_TYPE.containing_type = _SPAN_TIMEEVENT_MESSAGEEVENT +_SPAN_TIMEEVENT.fields_by_name['time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_SPAN_TIMEEVENT.fields_by_name['annotation'].message_type = _SPAN_TIMEEVENT_ANNOTATION +_SPAN_TIMEEVENT.fields_by_name['message_event'].message_type = _SPAN_TIMEEVENT_MESSAGEEVENT +_SPAN_TIMEEVENT.containing_type = _SPAN +_SPAN_TIMEEVENT.oneofs_by_name['value'].fields.append( + _SPAN_TIMEEVENT.fields_by_name['annotation']) +_SPAN_TIMEEVENT.fields_by_name['annotation'].containing_oneof = _SPAN_TIMEEVENT.oneofs_by_name['value'] +_SPAN_TIMEEVENT.oneofs_by_name['value'].fields.append( + _SPAN_TIMEEVENT.fields_by_name['message_event']) +_SPAN_TIMEEVENT.fields_by_name['message_event'].containing_oneof = _SPAN_TIMEEVENT.oneofs_by_name['value'] +_SPAN_TIMEEVENTS.fields_by_name['time_event'].message_type = _SPAN_TIMEEVENT +_SPAN_TIMEEVENTS.containing_type = _SPAN +_SPAN_LINK.fields_by_name['type'].enum_type = _SPAN_LINK_TYPE +_SPAN_LINK.fields_by_name['attributes'].message_type = _SPAN_ATTRIBUTES +_SPAN_LINK.containing_type = _SPAN +_SPAN_LINK_TYPE.containing_type = _SPAN_LINK +_SPAN_LINKS.fields_by_name['link'].message_type = _SPAN_LINK +_SPAN_LINKS.containing_type = _SPAN +_SPAN.fields_by_name['tracestate'].message_type = _SPAN_TRACESTATEENTRY +_SPAN.fields_by_name['name'].message_type = _TRUNCATABLESTRING +_SPAN.fields_by_name['kind'].enum_type = _SPAN_SPANKIND +_SPAN.fields_by_name['start_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_SPAN.fields_by_name['end_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_SPAN.fields_by_name['attributes'].message_type = _SPAN_ATTRIBUTES +_SPAN.fields_by_name['stack_trace'].message_type = _STACKTRACE +_SPAN.fields_by_name['time_events'].message_type = _SPAN_TIMEEVENTS +_SPAN.fields_by_name['links'].message_type = _SPAN_LINKS +_SPAN.fields_by_name['status'].message_type = _STATUS +_SPAN.fields_by_name['same_process_as_parent_span'].message_type = google_dot_protobuf_dot_wrappers__pb2._BOOLVALUE +_SPAN.fields_by_name['child_span_count'].message_type = google_dot_protobuf_dot_wrappers__pb2._UINT32VALUE +_SPAN_SPANKIND.containing_type = _SPAN +_ATTRIBUTEVALUE.fields_by_name['string_value'].message_type = _TRUNCATABLESTRING +_ATTRIBUTEVALUE.oneofs_by_name['value'].fields.append( + _ATTRIBUTEVALUE.fields_by_name['string_value']) +_ATTRIBUTEVALUE.fields_by_name['string_value'].containing_oneof = _ATTRIBUTEVALUE.oneofs_by_name['value'] +_ATTRIBUTEVALUE.oneofs_by_name['value'].fields.append( + _ATTRIBUTEVALUE.fields_by_name['int_value']) +_ATTRIBUTEVALUE.fields_by_name['int_value'].containing_oneof = _ATTRIBUTEVALUE.oneofs_by_name['value'] +_ATTRIBUTEVALUE.oneofs_by_name['value'].fields.append( + _ATTRIBUTEVALUE.fields_by_name['bool_value']) +_ATTRIBUTEVALUE.fields_by_name['bool_value'].containing_oneof = _ATTRIBUTEVALUE.oneofs_by_name['value'] +_STACKTRACE_STACKFRAME.fields_by_name['function_name'].message_type = _TRUNCATABLESTRING +_STACKTRACE_STACKFRAME.fields_by_name['original_function_name'].message_type = _TRUNCATABLESTRING +_STACKTRACE_STACKFRAME.fields_by_name['file_name'].message_type = _TRUNCATABLESTRING +_STACKTRACE_STACKFRAME.fields_by_name['load_module'].message_type = _MODULE +_STACKTRACE_STACKFRAME.fields_by_name['source_version'].message_type = _TRUNCATABLESTRING +_STACKTRACE_STACKFRAME.containing_type = _STACKTRACE +_STACKTRACE_STACKFRAMES.fields_by_name['frame'].message_type = _STACKTRACE_STACKFRAME +_STACKTRACE_STACKFRAMES.containing_type = _STACKTRACE +_STACKTRACE.fields_by_name['stack_frames'].message_type = _STACKTRACE_STACKFRAMES +_MODULE.fields_by_name['module'].message_type = _TRUNCATABLESTRING +_MODULE.fields_by_name['build_id'].message_type = _TRUNCATABLESTRING +DESCRIPTOR.message_types_by_name['Span'] = _SPAN +DESCRIPTOR.message_types_by_name['Status'] = _STATUS +DESCRIPTOR.message_types_by_name['AttributeValue'] = _ATTRIBUTEVALUE +DESCRIPTOR.message_types_by_name['StackTrace'] = _STACKTRACE +DESCRIPTOR.message_types_by_name['Module'] = _MODULE +DESCRIPTOR.message_types_by_name['TruncatableString'] = _TRUNCATABLESTRING +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Span = _reflection.GeneratedProtocolMessageType('Span', (_message.Message,), dict( + + TracestateEntry = _reflection.GeneratedProtocolMessageType('TracestateEntry', (_message.Message,), dict( + DESCRIPTOR = _SPAN_TRACESTATEENTRY, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TracestateEntry) + )) + , + + Attributes = _reflection.GeneratedProtocolMessageType('Attributes', (_message.Message,), dict( + + AttributeMapEntry = _reflection.GeneratedProtocolMessageType('AttributeMapEntry', (_message.Message,), dict( + DESCRIPTOR = _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry) + )) + , + DESCRIPTOR = _SPAN_ATTRIBUTES, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Attributes) + )) + , + + TimeEvent = _reflection.GeneratedProtocolMessageType('TimeEvent', (_message.Message,), dict( + + Annotation = _reflection.GeneratedProtocolMessageType('Annotation', (_message.Message,), dict( + DESCRIPTOR = _SPAN_TIMEEVENT_ANNOTATION, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TimeEvent.Annotation) + )) + , + + MessageEvent = _reflection.GeneratedProtocolMessageType('MessageEvent', (_message.Message,), dict( + DESCRIPTOR = _SPAN_TIMEEVENT_MESSAGEEVENT, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent) + )) + , + DESCRIPTOR = _SPAN_TIMEEVENT, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TimeEvent) + )) + , + + TimeEvents = _reflection.GeneratedProtocolMessageType('TimeEvents', (_message.Message,), dict( + DESCRIPTOR = _SPAN_TIMEEVENTS, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TimeEvents) + )) + , + + Link = _reflection.GeneratedProtocolMessageType('Link', (_message.Message,), dict( + DESCRIPTOR = _SPAN_LINK, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Link) + )) + , + + Links = _reflection.GeneratedProtocolMessageType('Links', (_message.Message,), dict( + DESCRIPTOR = _SPAN_LINKS, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Links) + )) + , + DESCRIPTOR = _SPAN, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span) + )) +_sym_db.RegisterMessage(Span) +_sym_db.RegisterMessage(Span.TracestateEntry) +_sym_db.RegisterMessage(Span.Attributes) +_sym_db.RegisterMessage(Span.Attributes.AttributeMapEntry) +_sym_db.RegisterMessage(Span.TimeEvent) +_sym_db.RegisterMessage(Span.TimeEvent.Annotation) +_sym_db.RegisterMessage(Span.TimeEvent.MessageEvent) +_sym_db.RegisterMessage(Span.TimeEvents) +_sym_db.RegisterMessage(Span.Link) +_sym_db.RegisterMessage(Span.Links) + +Status = _reflection.GeneratedProtocolMessageType('Status', (_message.Message,), dict( + DESCRIPTOR = _STATUS, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Status) + )) +_sym_db.RegisterMessage(Status) + +AttributeValue = _reflection.GeneratedProtocolMessageType('AttributeValue', (_message.Message,), dict( + DESCRIPTOR = _ATTRIBUTEVALUE, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.AttributeValue) + )) +_sym_db.RegisterMessage(AttributeValue) + +StackTrace = _reflection.GeneratedProtocolMessageType('StackTrace', (_message.Message,), dict( + + StackFrame = _reflection.GeneratedProtocolMessageType('StackFrame', (_message.Message,), dict( + DESCRIPTOR = _STACKTRACE_STACKFRAME, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.StackTrace.StackFrame) + )) + , + + StackFrames = _reflection.GeneratedProtocolMessageType('StackFrames', (_message.Message,), dict( + DESCRIPTOR = _STACKTRACE_STACKFRAMES, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.StackTrace.StackFrames) + )) + , + DESCRIPTOR = _STACKTRACE, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.StackTrace) + )) +_sym_db.RegisterMessage(StackTrace) +_sym_db.RegisterMessage(StackTrace.StackFrame) +_sym_db.RegisterMessage(StackTrace.StackFrames) + +Module = _reflection.GeneratedProtocolMessageType('Module', (_message.Message,), dict( + DESCRIPTOR = _MODULE, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Module) + )) +_sym_db.RegisterMessage(Module) + +TruncatableString = _reflection.GeneratedProtocolMessageType('TruncatableString', (_message.Message,), dict( + DESCRIPTOR = _TRUNCATABLESTRING, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.TruncatableString) + )) +_sym_db.RegisterMessage(TruncatableString) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\034io.opencensus.proto.trace.v1B\nTraceProtoP\001ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1')) +_SPAN_TRACESTATEENTRY.has_options = True +_SPAN_TRACESTATEENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.has_options = True +_SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +# @@protoc_insertion_point(module_scope) diff --git a/opencensus/trace/exporters/opencensusd_exporter.py b/opencensus/trace/exporters/opencensusd_exporter.py new file mode 100644 index 000000000..82ebe9fd0 --- /dev/null +++ b/opencensus/trace/exporters/opencensusd_exporter.py @@ -0,0 +1,400 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Export the trace spans to OpenCensusD""" + +import datetime +import grpc +import os +import socket +from threading import Lock +from google.protobuf.internal.well_known_types import ParseError +from google.protobuf.timestamp_pb2 import Timestamp +from google.protobuf.wrappers_pb2 import BoolValue, UInt32Value + +from opencensus.trace.exporters import base +from opencensus.trace.exporters.transports import sync +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 +from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import ( + common_pb2 +) +from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import ( + trace_service_pb2, + trace_service_pb2_grpc +) + +# Default agent endpoint +DEFAULT_ENDPOINT = 'localhost:50051' + +# OpenCensus Version +VERSION = '0.1.6' + + +class OpenCensusDExporter(base.Exporter): + """Export the spans by sending them to opencensus agent. + + :type service_name: str + :param service_name: name of the service + + :type host_name: str + :param host_name: name of the host (machine or host name) + + :type endpoint: str + :param endpoint: opencensus agent endpoint. + + :type client: class:`~.trace_service_pb2_grpc.TraceServiceStub` + :param client: OpenCensusD client. + + :type transport: :class:`type` + :param transport: Class for creating new transport objects. It should + extend from the base :class:`.Transport` type and + implement :meth:`.Transport.export`. Defaults to + :class:`.SyncTransport`. The other option is + :class:`.BackgroundThreadTransport`. + """ + + def __init__( + self, + service_name, + host_name=None, + endpoint=None, + client=None, + transport=sync.SyncTransport): + self.transport = transport(self) + + self.endpoint = DEFAULT_ENDPOINT if endpoint is None else endpoint + + if client is None: + self.channel = grpc.insecure_channel(self.endpoint) + self.client = trace_service_pb2_grpc.TraceServiceStub( + channel=self.channel) + else: + self.client = client + + self.node = common_pb2.Node( + identifier=common_pb2.ProcessIdentifier( + host_name=socket.gethostname() if host_name is None + else host_name, + pid=os.getpid(), + start_timestamp=self.proto_ts_from_datetime( + datetime.datetime.now()) + ), + library_info=common_pb2.LibraryInfo( + language=common_pb2.LibraryInfo.Language.Value('PYTHON'), + version=VERSION + ), + service_info=common_pb2.ServiceInfo(name=service_name)) + + self.send_node_in_config = True + self.send_node_in_export = True + + def emit(self, span_datas): + """ + :type span_datas: list of :class: + `~opencensus.trace.span_data.SpanData` + :param list of opencensus.trace.span_data.SpanData span_datas: + SpanData tuples to emit + """ + + try: + responses = self.client.Export( + self.generate_span_requests(span_datas)) + + # read response + for _ in responses: + pass + + # Node was successfully sent, unless there is a connectivity + # issue between app and agent, Node should not be sent again + self.send_node_in_export = False + except grpc.RpcError: + self.send_node_in_export = True + self.send_node_in_config = True + pass + + def export(self, span_datas): + """Export the trace. + Send trace to transport, and transport will call exporter.emit() + to actually send the trace to the specified tracing + backend. + + :type span_datas: list of :class: + `~opencensus.trace.span_data.SpanData` + :param list of opencensus.trace.span_data.SpanData span_datas: + SpanData tuples to export + """ + self.transport.export(span_datas) + + def generate_span_requests(self, span_datas): + """Span request generator. + + :type span_datas: list of + :class:`~opencensus.trace.span_data.SpanData` + :param span_datas: SpanData tuples to convert to protocuf spans + and send to opensensusd agent + + :rtype: list of + `~gen.opencensusd.agent.trace.v1.trace_service_pb2.ExportTraceServiceRequest` + :returns: List of span export requests. + """ + + pb_spans = [self.translate_to_opencensusd( + span_data) for span_data in span_datas] + + yield trace_service_pb2.ExportTraceServiceRequest( + node=self.node if self.send_node_in_export else None, + spans=pb_spans) + + def update_config(self, config): + """Sends TraceConfig to the agent and gets agent's config in reply. + + :type config: `~opencensus.proto.trace.v1.TraceConfig` + :param config: Trace config with sampling and other settings + + :rtype: `~opencensus.proto.trace.v1.TraceConfig` + :returns: Trace config from agent. + """ + + # do not allow updating config simultaneously + lock = Lock() + with lock: + try: + config_responses = self.client.Config( + self.generate_config_request(config)) + + agent_config = next(config_responses) + self.send_node_in_config = False + return agent_config + except grpc.RpcError as e: + self.send_node_in_config = True + self.send_node_in_export = True + raise e + + def generate_config_request(self, config): + """ConfigTraceServiceRequest generator. + + :type config: `~opencensus.proto.trace.v1.TraceConfig` + :param config: Trace config with sampling and other settings + + :rtype: list of + `~opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest` + :returns: List of config requests. + """ + + request = trace_service_pb2.ConfigTraceServiceRequest( + node=self.node if self.send_node_in_config else None, + config=config) + + yield request + + def translate_to_opencensusd(self, span_data): + """Translates the opencensus spans to OpenCensusD spans. + + :type span_data: :class:`~opencensus.trace.span_data.SpanData` + :param span_data: SpanData tuples to convert to protobuf spans + + :rtype: :class:`~opencensus.proto.trace.Span` + :returns: Protobuf format span. + """ + + if not span_data: + return None + + pb_span = trace_pb2.Span( + name=trace_pb2.TruncatableString(value=span_data.name), + kind=span_data.span_kind, + trace_id=self.hex_str_to_bytes_str(span_data.context.trace_id), + span_id=self.hex_str_to_bytes_str(span_data.span_id), + parent_span_id=self.hex_str_to_bytes_str(span_data.parent_span_id) + if span_data.parent_span_id is not None else None, + start_time=self.proto_ts_from_datetime_str(span_data.start_time), + end_time=self.proto_ts_from_datetime_str(span_data.end_time), + status=trace_pb2.Status( + code=span_data.status.code, + message=span_data.status.message) + if span_data.status is not None else None, + same_process_as_parent_span=BoolValue( + value=span_data.same_process_as_parent_span) + if span_data.same_process_as_parent_span is not None + else None, + child_span_count=UInt32Value(value=span_data.child_span_count) + if span_data.child_span_count is not None else None) + + # attributes + if span_data.attributes is not None: + for attribute_key, attribute_value \ + in span_data.attributes.items(): + self.add_proto_attribute_value( + pb_span.attributes, + attribute_key, + attribute_value) + + # time events + if span_data.time_events is not None: + for span_data_event in span_data.time_events: + if span_data_event.message_event is not None: + pb_event = pb_span.time_events.time_event.add() + pb_event.time.FromJsonString(span_data_event.timestamp) + self.set_proto_message_event( + pb_event.message_event, + span_data_event.message_event) + elif span_data_event.annotation is not None: + pb_event = pb_span.time_events.time_event.add() + pb_event.time.FromJsonString(span_data_event.timestamp) + self.set_proto_annotation( + pb_event.annotation, + span_data_event.annotation) + + # links + if span_data.links is not None: + for link in span_data.links: + pb_link = pb_span.links.link.add( + trace_id=self.hex_str_to_bytes_str(link.trace_id), + span_id=self.hex_str_to_bytes_str(link.span_id), + type=link.type) + + if link.attributes is not None and \ + link.attributes.attributes is not None: + for attribute_key, attribute_value \ + in link.attributes.attributes.items(): + self.add_proto_attribute_value( + pb_link.attributes, + attribute_key, + attribute_value) + + # tracestate + if span_data.context.tracestate is not None: + for (key, value) in span_data.context.tracestate.items(): + pb_span.tracestate[key] = value + + return pb_span + + def set_proto_message_event( + self, + pb_message_event, + span_data_message_event): + """Sets properties on the protobuf message event. + + :type pb_message_event: + :class: `~opencensus.proto.trace.Span.TimeEvent.MessageEvent` + :param pb_message_event: protobuf message event + + :type span_data_message_event: + :class: `~opencensus.trace.time_event.MessageEvent` + :param span_data_message_event: opencensus message event + """ + + pb_message_event.type = span_data_message_event.type + pb_message_event.id = span_data_message_event.id + pb_message_event.uncompressed_size = \ + span_data_message_event.uncompressed_size_bytes + pb_message_event.compressed_size = \ + span_data_message_event.compressed_size_bytes + + def set_proto_annotation(self, pb_annotation, span_data_annotation): + """Sets properties on the protobuf Span annotation. + + :type pb_annotation: + :class: `~opencensus.proto.trace.Span.TimeEvent.Annotation` + :param pb_annotation: protobuf annotation + + :type span_data_annotation: + :class: `~opencensus.trace.time_event.Annotation` + :param span_data_annotation: opencensus annotation + + """ + + pb_annotation.description.value = span_data_annotation.description + if span_data_annotation.attributes is not None \ + and span_data_annotation.attributes.attributes is not None: + for attribute_key, attribute_value in \ + span_data_annotation.attributes.attributes.items(): + self.add_proto_attribute_value( + pb_annotation.attributes, + attribute_key, + attribute_value) + + def hex_str_to_bytes_str(self, hex_str): + """Converts the hex string to bytes string. + + :type hex_str: str + :param hex_str: The hex tring representing trace_id or span_id. + + :rtype: str + :returns: string representing byte array + """ + + return bytes(bytearray.fromhex(hex_str)) + + def proto_ts_from_datetime_str(self, dt): + """Converts string datetime in ISO format to protobuf timestamp. + + :type dt: str + :param dt: string with datetime in ISO format + + :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` + :returns: protobuf timestamp + """ + + ts = Timestamp() + if (dt is not None): + try: + ts.FromJsonString(dt) + except ParseError: + pass + return ts + + def proto_ts_from_datetime(self, dt): + """Converts datetime to protobuf timestamp. + + :type dt: datetime + :param dt: date and time + + :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` + :returns: protobuf timestamp + """ + + ts = Timestamp() + if (dt is not None): + ts.FromDatetime(dt) + return ts + + def add_proto_attribute_value( + self, + pb_attributes, + attribute_key, + attribute_value): + """Sets string, int or boolean value on protobuf + span, link or annotation attributes. + + :type pb_attributes: + :class: `~opencensus.proto.trace.Span.Attributes` + :param pb_attributes: protobuf Span's attributes property + + :type attribute_key: str + :param attribute_key: attribute key to set + + :type attribute_value: str or int or bool + :param attribute_value: attribute value + """ + + if isinstance(attribute_value, bool): + pb_attributes.attribute_map[attribute_key].\ + bool_value = attribute_value + elif isinstance(attribute_value, int): + pb_attributes.attribute_map[attribute_key].\ + int_value = attribute_value + elif isinstance(attribute_value, str): + pb_attributes.attribute_map[attribute_key].\ + string_value.value = attribute_value diff --git a/tests/unit/trace/exporters/test_opensensusd_exporter.py b/tests/unit/trace/exporters/test_opensensusd_exporter.py new file mode 100644 index 000000000..95558dc12 --- /dev/null +++ b/tests/unit/trace/exporters/test_opensensusd_exporter.py @@ -0,0 +1,1008 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import codecs +from datetime import datetime, timedelta +import grpc +import mock +import os +import socket +import unittest + +from google.protobuf.timestamp_pb2 import Timestamp +from google.protobuf.wrappers_pb2 import BoolValue, UInt32Value + +from opencensus.trace import attributes as attributes_module +from opencensus.trace import link as link_module +from opencensus.trace import span as span_module +from opencensus.trace import span_context as span_context_module +from opencensus.trace import span_data as span_data_module +from opencensus.trace import status as status_module +from opencensus.trace import time_event as time_event_module +from opencensus.trace import tracestate as tracestate_module +from opencensus.trace.exporters import opencensusd_exporter +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 +from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 + + +SERVICE_NAME = 'my-service' + + +class TestOpenCensusDExporter(unittest.TestCase): + + def test_constructor(self): + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME) + + self.assertEqual(exporter.endpoint, 'localhost:50051') + + def test_constructor_with_endpoint(self): + expected_endpoint = '0.0.0.0:50000' + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + endpoint=expected_endpoint) + + self.assertEqual(exporter.endpoint, expected_endpoint) + + def test_constructor_with_client(self): + client = mock.Mock() + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + self.assertEqual(exporter.client, client) + + def test_constructor_node(self): + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + host_name='my host') + + self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) + self.assertEqual(exporter.node.library_info.language, 8) + self.assertIsNotNone(exporter.node.library_info.version) + + self.assertEqual(exporter.node.identifier.host_name, 'my host') + self.assertEqual(exporter.node.identifier.pid, os.getpid()) + + self.assertIsNotNone(exporter.node.identifier.start_timestamp) + self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) + + def test_constructor_node(self): + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME) + + self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) + self.assertEqual(exporter.node.library_info.language, 8) + self.assertIsNotNone(exporter.node.library_info.version) + + self.assertEqual(exporter.node.identifier.host_name, + socket.gethostname()) + self.assertEqual(exporter.node.identifier.pid, os.getpid()) + + self.assertIsNotNone(exporter.node.identifier.start_timestamp) + self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) + + def test_export(self): + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + exporter.export({}) + + self.assertTrue(exporter.transport.export_called) + + def test_emit(self): + client = mock.Mock() + client.Export.return_value = [1] + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit({}) + + self.assertTrue(client.Export.called) + + def test_emit_throw(self): + client = mock.Mock() + client.Export.side_effect = grpc.RpcError() + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + # does not throw + exporter.emit({}) + + self.assertTrue(client.Export.called) + + def export_iterate(self, *args, **kwargs): + self.export_requests = list(args[0]) + return iter(self.export_requests) + + def test_basic_span_emit(self): + hex_encoder = codecs.getencoder('hex') + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included. + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + span_data = span_data_module.SpanData( + name="name", + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit([span_data]) + + self.assertTrue(client.Export.called) + + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + pb_span = actual_request.spans[0] + + self.assertEqual(pb_span.name.value, "name") + self.assertEqual(hex_encoder(pb_span.trace_id)[ + 0], b'6e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span.span_id)[0], b'6e0c63257de34c92') + + def test_second_span_emit_without_node(self): + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + span_data0 = span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + span_data1 = span_data_module.SpanData( + name="name1", + context=span_context_module.SpanContext( + trace_id='1e0c63257de34c92bf9efcd03927272e'), + span_id='1e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit([span_data0]) + + actual_request = self.export_requests[0] + self.assertIsNotNone(actual_request.node) + self.assertEqual(actual_request.node, exporter.node) + + exporter.emit([span_data1]) + + self.assertEqual(len(client.Export.mock_calls), 2) + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, + trace_service_pb2.ExportTraceServiceRequest().node) + + def test_second_span_emit_after_exception_with_node(self): + client = mock.Mock() + + span_data0 = span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Export.side_effect = grpc.RpcError() + exporter.emit([span_data0]) + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + exporter.emit([span_data0]) + + self.assertEqual(len(client.Export.mock_calls), 2) + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + def test_basic_span_export(self): + hex_encoder = codecs.getencoder('hex') + + span_data = span_data_module.SpanData( + name="name", + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + parent_span_id='6e0c63257de34c93', + attributes={'test_str_key': 'test_str_value', + 'test_int_key': 1, 'test_bool_key': False}, + start_time='2017-08-15T18:02:26.071158Z', + end_time='2017-08-15T18:02:36.071158Z', + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(span_data) + + self.assertEqual(pb_span.name.value, "name") + self.assertEqual(hex_encoder(pb_span.trace_id)[ + 0], b'6e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span.span_id)[0], b'6e0c63257de34c92') + self.assertEqual(hex_encoder(pb_span.parent_span_id) + [0], b'6e0c63257de34c93') + self.assertEqual(pb_span.kind, 0) + + self.assertEqual(len(pb_span.attributes.attribute_map), 3) + self.assertEqual(pb_span.attributes.attribute_map['test_str_key'], + trace_pb2.AttributeValue(string_value=trace_pb2.TruncatableString(value='test_str_value'))) + + self.assertEqual( + pb_span.attributes.attribute_map['test_int_key'], trace_pb2.AttributeValue(int_value=1)) + self.assertEqual( + pb_span.attributes.attribute_map['test_bool_key'], trace_pb2.AttributeValue(bool_value=False)) + + self.assertEqual(pb_span.start_time.ToJsonString(), + '2017-08-15T18:02:26.071158Z') + self.assertEqual(pb_span.end_time.ToJsonString(), + '2017-08-15T18:02:36.071158Z') + + self.assertEqual(pb_span.child_span_count.value, 0) + self.assertEqual(pb_span.same_process_as_parent_span.value, False) + self.assertEqual(len(pb_span.time_events.time_event), 0) + + self.assertEqual(pb_span.status.code, 0) + self.assertFalse(pb_span.status.message) + + self.assertEqual(len(pb_span.links.link), 0) + self.assertEqual(len(pb_span.tracestate), 0) + + def test_none_span_export(self): + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(None) + + self.assertIsNone(pb_span) + + def test_client_span_kind_export(self): + client_span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + start_time='2017-08-15T18:02:26.071158Z', + end_time='2017-08-15T18:02:36.071158Z', + span_kind=span_module.SpanKind.CLIENT, + same_process_as_parent_span=True, + name=None, + parent_span_id=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(client_span_data) + + self.assertEqual(pb_span.kind, 2) + self.assertEqual(pb_span.same_process_as_parent_span.value, True) + + def test_server_span_kind_export(self): + server_span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + span_kind=span_module.SpanKind.SERVER, + child_span_count=1, + start_time=None, + end_time=None, + name=None, + parent_span_id=None, + attributes=None, + same_process_as_parent_span=False, + stack_trace=None, + time_events=None, + links=None, + status=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(server_span_data) + + self.assertEqual(pb_span.kind, 1) + self.assertEqual(pb_span.child_span_count.value, 1) + + def test_status_export(self): + span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + status=status_module.Status( + code=2, message='ERR', details='details'), + span_kind=span_module.SpanKind.SERVER, + start_time=None, + end_time=None, + child_span_count=None, + name=None, + parent_span_id=None, + attributes=None, + same_process_as_parent_span=False, + stack_trace=None, + time_events=None, + links=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(span_data) + + self.assertEqual(pb_span.status.code, 2) + self.assertEqual(pb_span.status.message, 'ERR') + + def test_links_export(self): + hex_encoder = codecs.getencoder('hex') + + span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + links=[ + link_module.Link(trace_id='0e0c63257de34c92bf9efcd03927272e', + span_id='0e0c63257de34c92', + type=link_module.Type.TYPE_UNSPECIFIED, + attributes=attributes_module.Attributes( + attributes={'test_str_key': 'test_str_value', 'test_int_key': 1, 'test_bool_key': False})), + link_module.Link(trace_id='1e0c63257de34c92bf9efcd03927272e', + span_id='1e0c63257de34c92', + type=link_module.Type.CHILD_LINKED_SPAN), + link_module.Link(trace_id='2e0c63257de34c92bf9efcd03927272e', + span_id='2e0c63257de34c92', + type=link_module.Type.PARENT_LINKED_SPAN) + ], + span_kind=span_module.SpanKind.SERVER, + status=None, + start_time=None, + end_time=None, + child_span_count=None, + name=None, + parent_span_id=None, + attributes=None, + same_process_as_parent_span=False, + stack_trace=None, + time_events=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(span_data) + + self.assertEqual(len(pb_span.links.link), 3) + self.assertEqual(hex_encoder(pb_span.links.link[0].trace_id)[ + 0], b'0e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span.links.link[1].trace_id)[ + 0], b'1e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span.links.link[2].trace_id)[ + 0], b'2e0c63257de34c92bf9efcd03927272e') + + self.assertEqual(hex_encoder(pb_span.links.link[0].span_id)[ + 0], b'0e0c63257de34c92') + self.assertEqual(hex_encoder(pb_span.links.link[1].span_id)[ + 0], b'1e0c63257de34c92') + self.assertEqual(hex_encoder(pb_span.links.link[2].span_id)[ + 0], b'2e0c63257de34c92') + + self.assertEqual(pb_span.links.link[0].type, 0) + self.assertEqual(pb_span.links.link[1].type, 1) + self.assertEqual(pb_span.links.link[2].type, 2) + + self.assertEqual( + len(pb_span.links.link[0].attributes.attribute_map), 3) + self.assertEqual( + len(pb_span.links.link[1].attributes.attribute_map), 0) + self.assertEqual( + len(pb_span.links.link[2].attributes.attribute_map), 0) + + self.assertEqual(pb_span.links.link[0].attributes.attribute_map['test_str_key'], + trace_pb2.AttributeValue(string_value=trace_pb2.TruncatableString(value='test_str_value'))) + + self.assertEqual( + pb_span.links.link[0].attributes.attribute_map['test_int_key'], trace_pb2.AttributeValue(int_value=1)) + self.assertEqual( + pb_span.links.link[0].attributes.attribute_map['test_bool_key'], trace_pb2.AttributeValue(bool_value=False)) + + def test_time_events_export(self): + + annotation0_ts = datetime.utcnow() + timedelta(seconds=-10) + annotation1_ts = datetime.utcnow() + timedelta(seconds=-9) + message0_ts = datetime.utcnow() + timedelta(seconds=-8) + message1_ts = datetime.utcnow() + timedelta(seconds=-7) + message2_ts = datetime.utcnow() + timedelta(seconds=-6) + + span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + time_events=[ + time_event_module.TimeEvent( + timestamp=annotation0_ts, + annotation=time_event_module.Annotation( + description="hi there0", + attributes=attributes_module.Attributes( + attributes={'test_str_key': 'test_str_value', 'test_int_key': 1, 'test_bool_key': False}))), + time_event_module.TimeEvent( + timestamp=annotation1_ts, annotation=time_event_module.Annotation(description="hi there1")), + time_event_module.TimeEvent( + timestamp=message0_ts, + message_event=time_event_module.MessageEvent( + id=0, + type=time_event_module.Type.SENT, + uncompressed_size_bytes=10, + compressed_size_bytes=1)), + time_event_module.TimeEvent( + timestamp=message1_ts, + message_event=time_event_module.MessageEvent(id=1, + type=time_event_module.Type.RECEIVED, + uncompressed_size_bytes=20, + compressed_size_bytes=2)), + time_event_module.TimeEvent( + timestamp=message2_ts, + message_event=time_event_module.MessageEvent(id=2, + type=time_event_module.Type.TYPE_UNSPECIFIED, + uncompressed_size_bytes=30, + compressed_size_bytes=3)) + ], + span_kind=span_module.SpanKind.SERVER, + status=None, + start_time=None, + end_time=None, + child_span_count=None, + name=None, + parent_span_id=None, + attributes=None, + same_process_as_parent_span=False, + stack_trace=None, + links=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(span_data) + + self.assertEqual(len(pb_span.time_events.time_event), 5) + + event0 = pb_span.time_events.time_event[0] + event1 = pb_span.time_events.time_event[1] + event2 = pb_span.time_events.time_event[2] + event3 = pb_span.time_events.time_event[3] + event4 = pb_span.time_events.time_event[4] + self.assertEqual(event0.time.ToDatetime(), annotation0_ts) + self.assertEqual(event1.time.ToDatetime(), annotation1_ts) + self.assertEqual(event2.time.ToDatetime(), message0_ts) + self.assertEqual(event3.time.ToDatetime(), message1_ts) + self.assertEqual(event4.time.ToDatetime(), message2_ts) + + self.assertEqual(event0.annotation.description.value, "hi there0") + self.assertEqual(event1.annotation.description.value, "hi there1") + + self.assertEqual(len(event0.annotation.attributes.attribute_map), 3) + self.assertEqual(len(event1.annotation.attributes.attribute_map), 0) + + self.assertEqual(event0.annotation.attributes.attribute_map['test_str_key'], + trace_pb2.AttributeValue(string_value=trace_pb2.TruncatableString(value='test_str_value'))) + + self.assertEqual( + event0.annotation.attributes.attribute_map['test_int_key'], trace_pb2.AttributeValue(int_value=1)) + self.assertEqual( + event0.annotation.attributes.attribute_map['test_bool_key'], trace_pb2.AttributeValue(bool_value=False)) + + self.assertEqual(event2.message_event.id, 0) + self.assertEqual(event3.message_event.id, 1) + self.assertEqual(event4.message_event.id, 2) + + self.assertEqual(event2.message_event.uncompressed_size, 10) + self.assertEqual(event3.message_event.uncompressed_size, 20) + self.assertEqual(event4.message_event.uncompressed_size, 30) + + self.assertEqual(event2.message_event.compressed_size, 1) + self.assertEqual(event3.message_event.compressed_size, 2) + self.assertEqual(event4.message_event.compressed_size, 3) + + self.assertEqual(event2.message_event.type, 1) + self.assertEqual(event3.message_event.type, 2) + self.assertEqual(event4.message_event.type, 0) + + def test_time_events_export_invalid(self): + + ts = datetime.utcnow() + timedelta(seconds=-10) + + span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + time_events=[ + time_event_module.TimeEvent(timestamp=ts)], + span_kind=span_module.SpanKind.SERVER, + status=None, + start_time=None, + end_time=None, + child_span_count=None, + name=None, + parent_span_id=None, + attributes=None, + same_process_as_parent_span=False, + stack_trace=None, + links=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(span_data) + + self.assertEqual(len(pb_span.time_events.time_event), 0) + + def test_tracestate_export(self): + + tracestate = tracestate_module.Tracestate() + tracestate.append("k1", "v1") + tracestate.append("k2", "v2") + tracestate.append("k3", "v3") + + client_span_data = span_data_module.SpanData( + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e', tracestate=tracestate), + span_id='6e0c63257de34c92', + start_time='2017-08-15T18:02:26.071158Z', + end_time='2017-08-15T18:02:36.071158Z', + span_kind=span_module.SpanKind.CLIENT, + same_process_as_parent_span=True, + name=None, + parent_span_id=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + pb_span = exporter.translate_to_opencensusd(client_span_data) + + self.assertEqual(len(pb_span.tracestate), 3) + self.assertEqual(pb_span.tracestate["k1"], "v1") + self.assertEqual(pb_span.tracestate["k2"], "v2") + self.assertEqual(pb_span.tracestate["k3"], "v3") + + def test_span_generator(self): + + hex_encoder = codecs.getencoder('hex') + span_datas = [ + span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + attributes=None, + start_time=None, + end_time=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0), + span_data_module.SpanData( + name="name1", + context=span_context_module.SpanContext( + trace_id='1e0c63257de34c92bf9efcd03927272e'), + span_id='1e0c63257de34c92', + parent_span_id=None, + attributes=None, + start_time=None, + end_time=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + ] + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + export_requests = list(exporter.generate_span_requests(span_datas)) + + self.assertEqual(len(export_requests), 1) + self.assertEqual(export_requests[0].node, exporter.node) + self.assertEqual(len(export_requests[0].spans), 2) + + self.assertEqual(export_requests[0].spans[0].name.value, 'name0') + self.assertEqual(export_requests[0].spans[1].name.value, 'name1') + self.assertEqual(hex_encoder(export_requests[0].spans[0].trace_id)[ + 0], b'0e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(export_requests[0].spans[0].span_id)[ + 0], b'0e0c63257de34c92') + self.assertEqual(hex_encoder(export_requests[0].spans[1].trace_id)[ + 0], b'1e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(export_requests[0].spans[1].span_id)[ + 0], b'1e0c63257de34c92') + + def test_add_attribute_value(self): + pb_span = trace_pb2.Span() + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + exporter.add_proto_attribute_value(pb_span.attributes, 'int_key', 42) + exporter.add_proto_attribute_value( + pb_span.attributes, 'bool_key', True) + exporter.add_proto_attribute_value( + pb_span.attributes, 'string_key', 'value') + exporter.add_proto_attribute_value( + pb_span.attributes, 'dict_key', {"a": "b"}) + + self.assertEqual(len(pb_span.attributes.attribute_map), 3) + self.assertEqual( + pb_span.attributes.attribute_map['int_key'].int_value, 42) + self.assertEqual( + pb_span.attributes.attribute_map['bool_key'].bool_value, True) + self.assertEqual( + pb_span.attributes.attribute_map['string_key'].string_value.value, 'value') + + def test_set_proto_event(self): + pb_span = trace_pb2.Span() + pb_event = pb_span.time_events.time_event.add() + + message_event = time_event_module.MessageEvent( + id=0, + type=time_event_module.Type.SENT, + uncompressed_size_bytes=10, + compressed_size_bytes=1) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + exporter.set_proto_message_event(pb_event.message_event, message_event) + + self.assertEqual(pb_event.message_event.id, 0) + self.assertEqual(pb_event.message_event.type, 1) + self.assertEqual(pb_event.message_event.uncompressed_size, 10) + self.assertEqual(pb_event.message_event.compressed_size, 1) + + def test_set_annotation_with_attributes(self): + pb_span = trace_pb2.Span() + pb_event = pb_span.time_events.time_event.add() + + annotation = time_event_module.Annotation( + description="hi there", + attributes=attributes_module.Attributes( + attributes={'test_str_key': 'test_str_value', 'test_int_key': 1, 'test_bool_key': False})) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + exporter.set_proto_annotation(pb_event.annotation, annotation) + + self.assertEqual(pb_event.annotation.description.value, "hi there") + self.assertEqual(len(pb_event.annotation.attributes.attribute_map), 3) + self.assertEqual(pb_event.annotation.attributes.attribute_map['test_str_key'], + trace_pb2.AttributeValue(string_value=trace_pb2.TruncatableString(value='test_str_value'))) + self.assertEqual( + pb_event.annotation.attributes.attribute_map['test_int_key'], trace_pb2.AttributeValue(int_value=1)) + self.assertEqual( + pb_event.annotation.attributes.attribute_map['test_bool_key'], trace_pb2.AttributeValue(bool_value=False)) + + def test_set_annotation_without_attributes(self): + pb_span = trace_pb2.Span() + pb_event0 = pb_span.time_events.time_event.add() + pb_event1 = pb_span.time_events.time_event.add() + + annotation0 = time_event_module.Annotation(description="hi there0") + annotation1 = time_event_module.Annotation( + description="hi there1", attributes=attributes_module.Attributes()) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + exporter.set_proto_annotation(pb_event0.annotation, annotation0) + exporter.set_proto_annotation(pb_event1.annotation, annotation1) + + self.assertEqual(pb_event0.annotation.description.value, "hi there0") + self.assertEqual(pb_event1.annotation.description.value, "hi there1") + self.assertEqual(len(pb_event0.annotation.attributes.attribute_map), 0) + self.assertEqual(len(pb_event1.annotation.attributes.attribute_map), 0) + + def test_datetime_str_to_proto_ts_conversion(self): + now = datetime.utcnow() + delta = now - datetime(1970, 1, 1) + expected_seconds = int(delta.total_seconds()) + expected_nanos = delta.microseconds * 1000 + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime_str(now.isoformat() + 'Z') + self.assertEqual(proto_ts.seconds, int(expected_seconds)) + self.assertEqual(proto_ts.nanos, expected_nanos) + + def test_datetime_str_to_proto_ts_conversion_none(self): + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime_str(None) + self.assertEquals(proto_ts.seconds, 0) + self.assertEquals(proto_ts.nanos, 0) + + def test_datetime_str_to_proto_ts_conversion_empty(self): + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime_str('') + self.assertEquals(proto_ts.seconds, 0) + self.assertEquals(proto_ts.nanos, 0) + + def test_datetime_str_to_proto_ts_conversion_invalid(self): + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime_str('2018 08 22 T 11:53') + self.assertEquals(proto_ts.seconds, 0) + self.assertEquals(proto_ts.nanos, 0) + + def test_hex_str_to_proto_bytes_conversion(self): + + hex_encoder = codecs.getencoder('hex') + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_bytes = exporter.hex_str_to_bytes_str( + '00010203040506070a0b0c0d0eff') + self.assertEqual(hex_encoder(proto_bytes)[0], + b'00010203040506070a0b0c0d0eff') + + def test_datetime_to_proto_ts_conversion_none(self): + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime(None) + self.assertEquals(proto_ts.seconds, 0) + self.assertEquals(proto_ts.nanos, 0) + + def test_datetime_to_proto_ts_conversion(self): + now = datetime.utcnow() + delta = now - datetime(1970, 1, 1) + expected_seconds = int(delta.total_seconds()) + expected_nanos = delta.microseconds * 1000 + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime(now) + self.assertEqual(proto_ts.seconds, int(expected_seconds)) + self.assertEqual(proto_ts.nanos, expected_nanos) + + def test_datetime_to_proto_ts_conversion_zero(self): + zero = datetime(1970, 1, 1) + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + proto_ts = exporter.proto_ts_from_datetime(zero) + self.assertEqual(proto_ts.seconds, 0) + self.assertEqual(proto_ts.nanos, 0) + + def test_config_generator(self): + + config = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + config_requests = list(exporter.generate_config_request(config)) + + self.assertEqual(len(config_requests), 1) + self.assertEqual(config_requests[0].node, exporter.node) + self.assertEqual(config_requests[0].config, config) + + def config_iterate(self, *args, **kwargs): + self.config_requests = list(args[0]) + return iter(self.config_requests) + + def test_second_config_update_without_node(self): + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Config returns + # and it won't be possible to check if node is included. + # passed config request will be stored in self.config_requests + client.Config.side_effect = self.config_iterate + + config0 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + config1 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=False)) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.update_config(config0) + + actual_request = self.config_requests[0] + self.assertIsNotNone(actual_request.node) + self.assertEqual(actual_request.node, exporter.node) + + exporter.update_config(config1) + + self.assertEqual(len(client.Config.mock_calls), 2) + actual_request = self.config_requests[0] + self.assertEqual(actual_request.node, + trace_service_pb2.ConfigTraceServiceRequest().node) + + def test_second_config_update_after_exception_with_node(self): + client = mock.Mock() + + config0 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + config1 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=False)) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Config.side_effect = grpc.RpcError() + with self.assertRaises(grpc.RpcError): + exporter.update_config(config0) + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Config returns + # and it won't be possible to check if node is included. + # passed config request will be stored in self.config_requests + client.Config.side_effect = self.config_iterate + + exporter.update_config(config1) + + self.assertEqual(len(client.Config.mock_calls), 2) + actual_request = self.config_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + def test_update_config_return_value(self): + client = mock.Mock() + + client_config = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + agent_config = trace_config_pb2.TraceConfig( + probability_sampler=trace_config_pb2.ProbabilitySampler( + samplingProbability=0.1)) + + exporter = opencensusd_exporter.OpenCensusDExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Config.return_value = iter([agent_config]) + actual_response = exporter.update_config(client_config) + + self.assertEqual(actual_response, agent_config) + + +class MockTransport(object): + def __init__(self, exporter=None): + self.export_called = False + self.exporter = exporter + + def export(self, trace): + self.export_called = True From 74553244437f9dd09c8a1db043d73b20c75542ec Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 30 Aug 2018 12:22:05 -0700 Subject: [PATCH 2/8] Update protos (tracestate is a list) --- .../agent/trace/v1/trace_service_pb2.py | 1 - .../gen/opencensusd/trace/v1/trace_pb2.py | 152 +++++++++++------- .../trace/exporters/opencensusd_exporter.py | 2 +- .../exporters/test_opensensusd_exporter.py | 13 +- 4 files changed, 104 insertions(+), 64 deletions(-) diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py index c2791ba2a..7b489ec96 100644 --- a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py +++ b/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py @@ -18,7 +18,6 @@ from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2 from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2 - DESCRIPTOR = _descriptor.FileDescriptor( name='opencensus/proto/agent/trace/v1/trace_service.proto', package='opencensus.proto.agent.trace.v1', diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py index 8c156d4a6..a859a172d 100644 --- a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py +++ b/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py @@ -21,7 +21,7 @@ name='opencensus/proto/trace/v1/trace.proto', package='opencensus.proto.trace.v1', syntax='proto3', - serialized_pb=_b('\n%opencensus/proto/trace/v1/trace.proto\x12\x19opencensus.proto.trace.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xf4\x10\n\x04Span\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12\x43\n\ntracestate\x18\x0f \x03(\x0b\x32/.opencensus.proto.trace.v1.Span.TracestateEntry\x12\x16\n\x0eparent_span_id\x18\x03 \x01(\x0c\x12:\n\x04name\x18\x04 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x36\n\x04kind\x18\x0e \x01(\x0e\x32(.opencensus.proto.trace.v1.Span.SpanKind\x12.\n\nstart_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12>\n\nattributes\x18\x07 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x12:\n\x0bstack_trace\x18\x08 \x01(\x0b\x32%.opencensus.proto.trace.v1.StackTrace\x12?\n\x0btime_events\x18\t \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.TimeEvents\x12\x34\n\x05links\x18\n \x01(\x0b\x32%.opencensus.proto.trace.v1.Span.Links\x12\x31\n\x06status\x18\x0b \x01(\x0b\x32!.opencensus.proto.trace.v1.Status\x12?\n\x1bsame_process_as_parent_span\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x36\n\x10\x63hild_span_count\x18\r \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x1a\x31\n\x0fTracestateEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xe3\x01\n\nAttributes\x12S\n\rattribute_map\x18\x01 \x03(\x0b\x32<.opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry\x12 \n\x18\x64ropped_attributes_count\x18\x02 \x01(\x05\x1a^\n\x11\x41ttributeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).opencensus.proto.trace.v1.AttributeValue:\x02\x38\x01\x1a\xbf\x04\n\tTimeEvent\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12J\n\nannotation\x18\x02 \x01(\x0b\x32\x34.opencensus.proto.trace.v1.Span.TimeEvent.AnnotationH\x00\x12O\n\rmessage_event\x18\x03 \x01(\x0b\x32\x36.opencensus.proto.trace.v1.Span.TimeEvent.MessageEventH\x00\x1a\x8f\x01\n\nAnnotation\x12\x41\n\x0b\x64\x65scription\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\nattributes\x18\x02 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x1a\xcf\x01\n\x0cMessageEvent\x12I\n\x04type\x18\x01 \x01(\x0e\x32;.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type\x12\n\n\x02id\x18\x02 \x01(\x04\x12\x19\n\x11uncompressed_size\x18\x03 \x01(\x04\x12\x17\n\x0f\x63ompressed_size\x18\x04 \x01(\x04\"4\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x08\n\x04SENT\x10\x01\x12\x0c\n\x08RECEIVED\x10\x02\x42\x07\n\x05value\x1a\x94\x01\n\nTimeEvents\x12=\n\ntime_event\x18\x01 \x03(\x0b\x32).opencensus.proto.trace.v1.Span.TimeEvent\x12!\n\x19\x64ropped_annotations_count\x18\x02 \x01(\x05\x12$\n\x1c\x64ropped_message_events_count\x18\x03 \x01(\x05\x1a\xef\x01\n\x04Link\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12\x37\n\x04type\x18\x03 \x01(\x0e\x32).opencensus.proto.trace.v1.Span.Link.Type\x12>\n\nattributes\x18\x04 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\"K\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11\x43HILD_LINKED_SPAN\x10\x01\x12\x16\n\x12PARENT_LINKED_SPAN\x10\x02\x1aX\n\x05Links\x12\x32\n\x04link\x18\x01 \x03(\x0b\x32$.opencensus.proto.trace.v1.Span.Link\x12\x1b\n\x13\x64ropped_links_count\x18\x02 \x01(\x05\"=\n\x08SpanKind\x12\x19\n\x15SPAN_KIND_UNSPECIFIED\x10\x00\x12\n\n\x06SERVER\x10\x01\x12\n\n\x06\x43LIENT\x10\x02\"\'\n\x06Status\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x8a\x01\n\x0e\x41ttributeValue\x12\x44\n\x0cstring_value\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableStringH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"\xed\x04\n\nStackTrace\x12G\n\x0cstack_frames\x18\x01 \x01(\x0b\x32\x31.opencensus.proto.trace.v1.StackTrace.StackFrames\x12\x1b\n\x13stack_trace_hash_id\x18\x02 \x01(\x04\x1a\x8a\x03\n\nStackFrame\x12\x43\n\rfunction_name\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12L\n\x16original_function_name\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12?\n\tfile_name\x18\x03 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x13\n\x0bline_number\x18\x04 \x01(\x03\x12\x15\n\rcolumn_number\x18\x05 \x01(\x03\x12\x36\n\x0bload_module\x18\x06 \x01(\x0b\x32!.opencensus.proto.trace.v1.Module\x12\x44\n\x0esource_version\x18\x07 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x1al\n\x0bStackFrames\x12?\n\x05\x66rame\x18\x01 \x03(\x0b\x32\x30.opencensus.proto.trace.v1.StackTrace.StackFrame\x12\x1c\n\x14\x64ropped_frames_count\x18\x02 \x01(\x05\"\x86\x01\n\x06Module\x12<\n\x06module\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\x08\x62uild_id\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\"@\n\x11TruncatableString\x12\r\n\x05value\x18\x01 \x01(\t\x12\x1c\n\x14truncated_byte_count\x18\x02 \x01(\x05\x42p\n\x1cio.opencensus.proto.trace.v1B\nTraceProtoP\x01ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1b\x06proto3') + serialized_pb=_b('\n%opencensus/proto/trace/v1/trace.proto\x12\x19opencensus.proto.trace.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xb2\x11\n\x04Span\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12>\n\ntracestate\x18\x0f \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Tracestate\x12\x16\n\x0eparent_span_id\x18\x03 \x01(\x0c\x12:\n\x04name\x18\x04 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x36\n\x04kind\x18\x0e \x01(\x0e\x32(.opencensus.proto.trace.v1.Span.SpanKind\x12.\n\nstart_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12>\n\nattributes\x18\x07 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x12:\n\x0bstack_trace\x18\x08 \x01(\x0b\x32%.opencensus.proto.trace.v1.StackTrace\x12?\n\x0btime_events\x18\t \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.TimeEvents\x12\x34\n\x05links\x18\n \x01(\x0b\x32%.opencensus.proto.trace.v1.Span.Links\x12\x31\n\x06status\x18\x0b \x01(\x0b\x32!.opencensus.proto.trace.v1.Status\x12?\n\x1bsame_process_as_parent_span\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x36\n\x10\x63hild_span_count\x18\r \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x1at\n\nTracestate\x12\x41\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x30.opencensus.proto.trace.v1.Span.Tracestate.Entry\x1a#\n\x05\x45ntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x1a\xe3\x01\n\nAttributes\x12S\n\rattribute_map\x18\x01 \x03(\x0b\x32<.opencensus.proto.trace.v1.Span.Attributes.AttributeMapEntry\x12 \n\x18\x64ropped_attributes_count\x18\x02 \x01(\x05\x1a^\n\x11\x41ttributeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).opencensus.proto.trace.v1.AttributeValue:\x02\x38\x01\x1a\xbf\x04\n\tTimeEvent\x12(\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12J\n\nannotation\x18\x02 \x01(\x0b\x32\x34.opencensus.proto.trace.v1.Span.TimeEvent.AnnotationH\x00\x12O\n\rmessage_event\x18\x03 \x01(\x0b\x32\x36.opencensus.proto.trace.v1.Span.TimeEvent.MessageEventH\x00\x1a\x8f\x01\n\nAnnotation\x12\x41\n\x0b\x64\x65scription\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\nattributes\x18\x02 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\x1a\xcf\x01\n\x0cMessageEvent\x12I\n\x04type\x18\x01 \x01(\x0e\x32;.opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type\x12\n\n\x02id\x18\x02 \x01(\x04\x12\x19\n\x11uncompressed_size\x18\x03 \x01(\x04\x12\x17\n\x0f\x63ompressed_size\x18\x04 \x01(\x04\"4\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x08\n\x04SENT\x10\x01\x12\x0c\n\x08RECEIVED\x10\x02\x42\x07\n\x05value\x1a\x94\x01\n\nTimeEvents\x12=\n\ntime_event\x18\x01 \x03(\x0b\x32).opencensus.proto.trace.v1.Span.TimeEvent\x12!\n\x19\x64ropped_annotations_count\x18\x02 \x01(\x05\x12$\n\x1c\x64ropped_message_events_count\x18\x03 \x01(\x05\x1a\xef\x01\n\x04Link\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x12\x37\n\x04type\x18\x03 \x01(\x0e\x32).opencensus.proto.trace.v1.Span.Link.Type\x12>\n\nattributes\x18\x04 \x01(\x0b\x32*.opencensus.proto.trace.v1.Span.Attributes\"K\n\x04Type\x12\x14\n\x10TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11\x43HILD_LINKED_SPAN\x10\x01\x12\x16\n\x12PARENT_LINKED_SPAN\x10\x02\x1aX\n\x05Links\x12\x32\n\x04link\x18\x01 \x03(\x0b\x32$.opencensus.proto.trace.v1.Span.Link\x12\x1b\n\x13\x64ropped_links_count\x18\x02 \x01(\x05\"=\n\x08SpanKind\x12\x19\n\x15SPAN_KIND_UNSPECIFIED\x10\x00\x12\n\n\x06SERVER\x10\x01\x12\n\n\x06\x43LIENT\x10\x02\"\'\n\x06Status\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x8a\x01\n\x0e\x41ttributeValue\x12\x44\n\x0cstring_value\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableStringH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"\xed\x04\n\nStackTrace\x12G\n\x0cstack_frames\x18\x01 \x01(\x0b\x32\x31.opencensus.proto.trace.v1.StackTrace.StackFrames\x12\x1b\n\x13stack_trace_hash_id\x18\x02 \x01(\x04\x1a\x8a\x03\n\nStackFrame\x12\x43\n\rfunction_name\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12L\n\x16original_function_name\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12?\n\tfile_name\x18\x03 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12\x13\n\x0bline_number\x18\x04 \x01(\x03\x12\x15\n\rcolumn_number\x18\x05 \x01(\x03\x12\x36\n\x0bload_module\x18\x06 \x01(\x0b\x32!.opencensus.proto.trace.v1.Module\x12\x44\n\x0esource_version\x18\x07 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x1al\n\x0bStackFrames\x12?\n\x05\x66rame\x18\x01 \x03(\x0b\x32\x30.opencensus.proto.trace.v1.StackTrace.StackFrame\x12\x1c\n\x14\x64ropped_frames_count\x18\x02 \x01(\x05\"\x86\x01\n\x06Module\x12<\n\x06module\x18\x01 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\x12>\n\x08\x62uild_id\x18\x02 \x01(\x0b\x32,.opencensus.proto.trace.v1.TruncatableString\"@\n\x11TruncatableString\x12\r\n\x05value\x18\x01 \x01(\t\x12\x1c\n\x14truncated_byte_count\x18\x02 \x01(\x05\x42p\n\x1cio.opencensus.proto.trace.v1B\nTraceProtoP\x01ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1b\x06proto3') , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,]) @@ -48,8 +48,8 @@ ], containing_type=None, options=None, - serialized_start=1691, - serialized_end=1743, + serialized_start=1753, + serialized_end=1805, ) _sym_db.RegisterEnumDescriptor(_SPAN_TIMEEVENT_MESSAGEEVENT_TYPE) @@ -74,8 +74,8 @@ ], containing_type=None, options=None, - serialized_start=2070, - serialized_end=2145, + serialized_start=2132, + serialized_end=2207, ) _sym_db.RegisterEnumDescriptor(_SPAN_LINK_TYPE) @@ -100,28 +100,28 @@ ], containing_type=None, options=None, - serialized_start=2237, - serialized_end=2298, + serialized_start=2299, + serialized_end=2360, ) _sym_db.RegisterEnumDescriptor(_SPAN_SPANKIND) -_SPAN_TRACESTATEENTRY = _descriptor.Descriptor( - name='TracestateEntry', - full_name='opencensus.proto.trace.v1.Span.TracestateEntry', +_SPAN_TRACESTATE_ENTRY = _descriptor.Descriptor( + name='Entry', + full_name='opencensus.proto.trace.v1.Span.Tracestate.Entry', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='key', full_name='opencensus.proto.trace.v1.Span.TracestateEntry.key', index=0, + name='key', full_name='opencensus.proto.trace.v1.Span.Tracestate.Entry.key', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='value', full_name='opencensus.proto.trace.v1.Span.TracestateEntry.value', index=1, + name='value', full_name='opencensus.proto.trace.v1.Span.Tracestate.Entry.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, @@ -133,14 +133,44 @@ nested_types=[], enum_types=[ ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=895, - serialized_end=944, + serialized_start=971, + serialized_end=1006, +) + +_SPAN_TRACESTATE = _descriptor.Descriptor( + name='Tracestate', + full_name='opencensus.proto.trace.v1.Span.Tracestate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='entries', full_name='opencensus.proto.trace.v1.Span.Tracestate.entries', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_SPAN_TRACESTATE_ENTRY, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=890, + serialized_end=1006, ) _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY = _descriptor.Descriptor( @@ -176,8 +206,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1080, - serialized_end=1174, + serialized_start=1142, + serialized_end=1236, ) _SPAN_ATTRIBUTES = _descriptor.Descriptor( @@ -213,8 +243,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=947, - serialized_end=1174, + serialized_start=1009, + serialized_end=1236, ) _SPAN_TIMEEVENT_ANNOTATION = _descriptor.Descriptor( @@ -250,8 +280,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1390, - serialized_end=1533, + serialized_start=1452, + serialized_end=1595, ) _SPAN_TIMEEVENT_MESSAGEEVENT = _descriptor.Descriptor( @@ -302,8 +332,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1536, - serialized_end=1743, + serialized_start=1598, + serialized_end=1805, ) _SPAN_TIMEEVENT = _descriptor.Descriptor( @@ -349,8 +379,8 @@ name='value', full_name='opencensus.proto.trace.v1.Span.TimeEvent.value', index=0, containing_type=None, fields=[]), ], - serialized_start=1177, - serialized_end=1752, + serialized_start=1239, + serialized_end=1814, ) _SPAN_TIMEEVENTS = _descriptor.Descriptor( @@ -393,8 +423,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1755, - serialized_end=1903, + serialized_start=1817, + serialized_end=1965, ) _SPAN_LINK = _descriptor.Descriptor( @@ -445,8 +475,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1906, - serialized_end=2145, + serialized_start=1968, + serialized_end=2207, ) _SPAN_LINKS = _descriptor.Descriptor( @@ -482,8 +512,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2147, - serialized_end=2235, + serialized_start=2209, + serialized_end=2297, ) _SPAN = _descriptor.Descriptor( @@ -509,8 +539,8 @@ options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tracestate', full_name='opencensus.proto.trace.v1.Span.tracestate', index=2, - number=15, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], + number=15, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), @@ -601,7 +631,7 @@ ], extensions=[ ], - nested_types=[_SPAN_TRACESTATEENTRY, _SPAN_ATTRIBUTES, _SPAN_TIMEEVENT, _SPAN_TIMEEVENTS, _SPAN_LINK, _SPAN_LINKS, ], + nested_types=[_SPAN_TRACESTATE, _SPAN_ATTRIBUTES, _SPAN_TIMEEVENT, _SPAN_TIMEEVENTS, _SPAN_LINK, _SPAN_LINKS, ], enum_types=[ _SPAN_SPANKIND, ], @@ -612,7 +642,7 @@ oneofs=[ ], serialized_start=134, - serialized_end=2298, + serialized_end=2360, ) @@ -649,8 +679,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2300, - serialized_end=2339, + serialized_start=2362, + serialized_end=2401, ) @@ -697,8 +727,8 @@ name='value', full_name='opencensus.proto.trace.v1.AttributeValue.value', index=0, containing_type=None, fields=[]), ], - serialized_start=2342, - serialized_end=2480, + serialized_start=2404, + serialized_end=2542, ) @@ -770,8 +800,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2600, - serialized_end=2994, + serialized_start=2662, + serialized_end=3056, ) _STACKTRACE_STACKFRAMES = _descriptor.Descriptor( @@ -807,8 +837,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2996, - serialized_end=3104, + serialized_start=3058, + serialized_end=3166, ) _STACKTRACE = _descriptor.Descriptor( @@ -844,8 +874,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2483, - serialized_end=3104, + serialized_start=2545, + serialized_end=3166, ) @@ -882,8 +912,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3107, - serialized_end=3241, + serialized_start=3169, + serialized_end=3303, ) @@ -920,11 +950,13 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3243, - serialized_end=3307, + serialized_start=3305, + serialized_end=3369, ) -_SPAN_TRACESTATEENTRY.containing_type = _SPAN +_SPAN_TRACESTATE_ENTRY.containing_type = _SPAN_TRACESTATE +_SPAN_TRACESTATE.fields_by_name['entries'].message_type = _SPAN_TRACESTATE_ENTRY +_SPAN_TRACESTATE.containing_type = _SPAN _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.fields_by_name['value'].message_type = _ATTRIBUTEVALUE _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.containing_type = _SPAN_ATTRIBUTES _SPAN_ATTRIBUTES.fields_by_name['attribute_map'].message_type = _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY @@ -953,7 +985,7 @@ _SPAN_LINK_TYPE.containing_type = _SPAN_LINK _SPAN_LINKS.fields_by_name['link'].message_type = _SPAN_LINK _SPAN_LINKS.containing_type = _SPAN -_SPAN.fields_by_name['tracestate'].message_type = _SPAN_TRACESTATEENTRY +_SPAN.fields_by_name['tracestate'].message_type = _SPAN_TRACESTATE _SPAN.fields_by_name['name'].message_type = _TRUNCATABLESTRING _SPAN.fields_by_name['kind'].enum_type = _SPAN_SPANKIND _SPAN.fields_by_name['start_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP @@ -997,10 +1029,17 @@ Span = _reflection.GeneratedProtocolMessageType('Span', (_message.Message,), dict( - TracestateEntry = _reflection.GeneratedProtocolMessageType('TracestateEntry', (_message.Message,), dict( - DESCRIPTOR = _SPAN_TRACESTATEENTRY, + Tracestate = _reflection.GeneratedProtocolMessageType('Tracestate', (_message.Message,), dict( + + Entry = _reflection.GeneratedProtocolMessageType('Entry', (_message.Message,), dict( + DESCRIPTOR = _SPAN_TRACESTATE_ENTRY, + __module__ = 'opencensus.proto.trace.v1.trace_pb2' + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Tracestate.Entry) + )) + , + DESCRIPTOR = _SPAN_TRACESTATE, __module__ = 'opencensus.proto.trace.v1.trace_pb2' - # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.TracestateEntry) + # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span.Tracestate) )) , @@ -1064,7 +1103,8 @@ # @@protoc_insertion_point(class_scope:opencensus.proto.trace.v1.Span) )) _sym_db.RegisterMessage(Span) -_sym_db.RegisterMessage(Span.TracestateEntry) +_sym_db.RegisterMessage(Span.Tracestate) +_sym_db.RegisterMessage(Span.Tracestate.Entry) _sym_db.RegisterMessage(Span.Attributes) _sym_db.RegisterMessage(Span.Attributes.AttributeMapEntry) _sym_db.RegisterMessage(Span.TimeEvent) @@ -1128,8 +1168,6 @@ DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\034io.opencensus.proto.trace.v1B\nTraceProtoP\001ZBgithub.com/census-instrumentation/opencensus-proto/gen-go/trace/v1')) -_SPAN_TRACESTATEENTRY.has_options = True -_SPAN_TRACESTATEENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY.has_options = True _SPAN_ATTRIBUTES_ATTRIBUTEMAPENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) # @@protoc_insertion_point(module_scope) diff --git a/opencensus/trace/exporters/opencensusd_exporter.py b/opencensus/trace/exporters/opencensusd_exporter.py index 82ebe9fd0..1df8267a4 100644 --- a/opencensus/trace/exporters/opencensusd_exporter.py +++ b/opencensus/trace/exporters/opencensusd_exporter.py @@ -276,7 +276,7 @@ def translate_to_opencensusd(self, span_data): # tracestate if span_data.context.tracestate is not None: for (key, value) in span_data.context.tracestate.items(): - pb_span.tracestate[key] = value + pb_span.tracestate.entries.add(key=key, value=value) return pb_span diff --git a/tests/unit/trace/exporters/test_opensensusd_exporter.py b/tests/unit/trace/exporters/test_opensensusd_exporter.py index 95558dc12..a5c6716d6 100644 --- a/tests/unit/trace/exporters/test_opensensusd_exporter.py +++ b/tests/unit/trace/exporters/test_opensensusd_exporter.py @@ -335,7 +335,7 @@ def test_basic_span_export(self): self.assertFalse(pb_span.status.message) self.assertEqual(len(pb_span.links.link), 0) - self.assertEqual(len(pb_span.tracestate), 0) + self.assertEqual(len(pb_span.tracestate.entries), 0) def test_none_span_export(self): exporter = opencensusd_exporter.OpenCensusDExporter( @@ -654,10 +654,13 @@ def test_tracestate_export(self): transport=MockTransport) pb_span = exporter.translate_to_opencensusd(client_span_data) - self.assertEqual(len(pb_span.tracestate), 3) - self.assertEqual(pb_span.tracestate["k1"], "v1") - self.assertEqual(pb_span.tracestate["k2"], "v2") - self.assertEqual(pb_span.tracestate["k3"], "v3") + self.assertEqual(len(pb_span.tracestate.entries), 3) + self.assertEqual(pb_span.tracestate.entries[0].key, "k1") + self.assertEqual(pb_span.tracestate.entries[0].value, "v1") + self.assertEqual(pb_span.tracestate.entries[1].key, "k2") + self.assertEqual(pb_span.tracestate.entries[1].value, "v2") + self.assertEqual(pb_span.tracestate.entries[2].key, "k3") + self.assertEqual(pb_span.tracestate.entries[2].value, "v3") def test_span_generator(self): From 57eb7df5846a123f3898e8433de69483ff4c7a3b Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 30 Aug 2018 14:18:26 -0700 Subject: [PATCH 3/8] allow non-str attributes --- opencensus/trace/exporters/opencensusd_exporter.py | 3 +++ .../trace/exporters/test_opensensusd_exporter.py | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/opencensus/trace/exporters/opencensusd_exporter.py b/opencensus/trace/exporters/opencensusd_exporter.py index 1df8267a4..b225835c4 100644 --- a/opencensus/trace/exporters/opencensusd_exporter.py +++ b/opencensus/trace/exporters/opencensusd_exporter.py @@ -398,3 +398,6 @@ def add_proto_attribute_value( elif isinstance(attribute_value, str): pb_attributes.attribute_map[attribute_key].\ string_value.value = attribute_value + else: + pb_attributes.attribute_map[attribute_key].\ + string_value.value = str(attribute_value) diff --git a/tests/unit/trace/exporters/test_opensensusd_exporter.py b/tests/unit/trace/exporters/test_opensensusd_exporter.py index a5c6716d6..28e80639d 100644 --- a/tests/unit/trace/exporters/test_opensensusd_exporter.py +++ b/tests/unit/trace/exporters/test_opensensusd_exporter.py @@ -656,9 +656,9 @@ def test_tracestate_export(self): self.assertEqual(len(pb_span.tracestate.entries), 3) self.assertEqual(pb_span.tracestate.entries[0].key, "k1") - self.assertEqual(pb_span.tracestate.entries[0].value, "v1") + self.assertEqual(pb_span.tracestate.entries[0].value, "v1") self.assertEqual(pb_span.tracestate.entries[1].key, "k2") - self.assertEqual(pb_span.tracestate.entries[1].value, "v2") + self.assertEqual(pb_span.tracestate.entries[1].value, "v2") self.assertEqual(pb_span.tracestate.entries[2].key, "k3") self.assertEqual(pb_span.tracestate.entries[2].value, "v3") @@ -731,16 +731,22 @@ def test_add_attribute_value(self): pb_span.attributes, 'bool_key', True) exporter.add_proto_attribute_value( pb_span.attributes, 'string_key', 'value') + exporter.add_proto_attribute_value( + pb_span.attributes, 'unicode_key', u'uvalue') exporter.add_proto_attribute_value( pb_span.attributes, 'dict_key', {"a": "b"}) - self.assertEqual(len(pb_span.attributes.attribute_map), 3) + self.assertEqual(len(pb_span.attributes.attribute_map), 5) self.assertEqual( pb_span.attributes.attribute_map['int_key'].int_value, 42) self.assertEqual( pb_span.attributes.attribute_map['bool_key'].bool_value, True) self.assertEqual( pb_span.attributes.attribute_map['string_key'].string_value.value, 'value') + self.assertEqual( + pb_span.attributes.attribute_map['unicode_key'].string_value.value, 'uvalue') + self.assertEqual( + pb_span.attributes.attribute_map['dict_key'].string_value.value, "{'a': 'b'}") def test_set_proto_event(self): pb_span = trace_pb2.Span() From f11df53a0b59eff6b1701c4e24055ec5717a9598 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Fri, 31 Aug 2018 11:04:53 -0700 Subject: [PATCH 4/8] Rename to SpanProtoExporter --- ...usd_exporter.py => span_proto_exporter.py} | 2 +- ...xporter.py => test_span_proto_exporter.py} | 78 +++++++++---------- 2 files changed, 40 insertions(+), 40 deletions(-) rename opencensus/trace/exporters/{opencensusd_exporter.py => span_proto_exporter.py} (99%) rename tests/unit/trace/exporters/{test_opensensusd_exporter.py => test_span_proto_exporter.py} (94%) diff --git a/opencensus/trace/exporters/opencensusd_exporter.py b/opencensus/trace/exporters/span_proto_exporter.py similarity index 99% rename from opencensus/trace/exporters/opencensusd_exporter.py rename to opencensus/trace/exporters/span_proto_exporter.py index b225835c4..cd3e293c7 100644 --- a/opencensus/trace/exporters/opencensusd_exporter.py +++ b/opencensus/trace/exporters/span_proto_exporter.py @@ -41,7 +41,7 @@ VERSION = '0.1.6' -class OpenCensusDExporter(base.Exporter): +class SpanProtoExporter(base.Exporter): """Export the spans by sending them to opencensus agent. :type service_name: str diff --git a/tests/unit/trace/exporters/test_opensensusd_exporter.py b/tests/unit/trace/exporters/test_span_proto_exporter.py similarity index 94% rename from tests/unit/trace/exporters/test_opensensusd_exporter.py rename to tests/unit/trace/exporters/test_span_proto_exporter.py index 28e80639d..e4a7d8dfa 100644 --- a/tests/unit/trace/exporters/test_opensensusd_exporter.py +++ b/tests/unit/trace/exporters/test_span_proto_exporter.py @@ -31,7 +31,7 @@ from opencensus.trace import status as status_module from opencensus.trace import time_event as time_event_module from opencensus.trace import tracestate as tracestate_module -from opencensus.trace.exporters import opencensusd_exporter +from opencensus.trace.exporters import span_proto_exporter from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 @@ -40,17 +40,17 @@ SERVICE_NAME = 'my-service' -class TestOpenCensusDExporter(unittest.TestCase): +class TestSpanProtoExporter(unittest.TestCase): def test_constructor(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME) self.assertEqual(exporter.endpoint, 'localhost:50051') def test_constructor_with_endpoint(self): expected_endpoint = '0.0.0.0:50000' - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, endpoint=expected_endpoint) @@ -58,7 +58,7 @@ def test_constructor_with_endpoint(self): def test_constructor_with_client(self): client = mock.Mock() - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -66,7 +66,7 @@ def test_constructor_with_client(self): self.assertEqual(exporter.client, client) def test_constructor_node(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, host_name='my host') @@ -81,7 +81,7 @@ def test_constructor_node(self): self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) def test_constructor_node(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME) self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) @@ -96,7 +96,7 @@ def test_constructor_node(self): self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) def test_export(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) exporter.export({}) @@ -106,7 +106,7 @@ def test_export(self): def test_emit(self): client = mock.Mock() client.Export.return_value = [1] - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -118,7 +118,7 @@ def test_emit(self): def test_emit_throw(self): client = mock.Mock() client.Export.side_effect = grpc.RpcError() - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -159,7 +159,7 @@ def test_basic_span_emit(self): same_process_as_parent_span=None, span_kind=0) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -221,7 +221,7 @@ def test_second_span_emit_without_node(self): same_process_as_parent_span=None, span_kind=0) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -259,7 +259,7 @@ def test_second_span_emit_after_exception_with_node(self): same_process_as_parent_span=None, span_kind=0) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -300,7 +300,7 @@ def test_basic_span_export(self): same_process_as_parent_span=None, span_kind=0) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(span_data) @@ -338,7 +338,7 @@ def test_basic_span_export(self): self.assertEqual(len(pb_span.tracestate.entries), 0) def test_none_span_export(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(None) @@ -363,7 +363,7 @@ def test_client_span_kind_export(self): links=None, status=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(client_span_data) @@ -389,7 +389,7 @@ def test_server_span_kind_export(self): links=None, status=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(server_span_data) @@ -416,7 +416,7 @@ def test_status_export(self): time_events=None, links=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(span_data) @@ -456,7 +456,7 @@ def test_links_export(self): stack_trace=None, time_events=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(span_data) @@ -548,7 +548,7 @@ def test_time_events_export(self): stack_trace=None, links=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(span_data) @@ -618,7 +618,7 @@ def test_time_events_export_invalid(self): stack_trace=None, links=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(span_data) @@ -649,7 +649,7 @@ def test_tracestate_export(self): links=None, status=None) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) pb_span = exporter.translate_to_opencensusd(client_span_data) @@ -700,7 +700,7 @@ def test_span_generator(self): span_kind=0) ] - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) export_requests = list(exporter.generate_span_requests(span_datas)) @@ -723,7 +723,7 @@ def test_span_generator(self): def test_add_attribute_value(self): pb_span = trace_pb2.Span() - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) exporter.add_proto_attribute_value(pb_span.attributes, 'int_key', 42) @@ -758,7 +758,7 @@ def test_set_proto_event(self): uncompressed_size_bytes=10, compressed_size_bytes=1) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) exporter.set_proto_message_event(pb_event.message_event, message_event) @@ -777,7 +777,7 @@ def test_set_annotation_with_attributes(self): attributes=attributes_module.Attributes( attributes={'test_str_key': 'test_str_value', 'test_int_key': 1, 'test_bool_key': False})) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) exporter.set_proto_annotation(pb_event.annotation, annotation) @@ -800,7 +800,7 @@ def test_set_annotation_without_attributes(self): annotation1 = time_event_module.Annotation( description="hi there1", attributes=attributes_module.Attributes()) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -817,7 +817,7 @@ def test_datetime_str_to_proto_ts_conversion(self): delta = now - datetime(1970, 1, 1) expected_seconds = int(delta.total_seconds()) expected_nanos = delta.microseconds * 1000 - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -827,7 +827,7 @@ def test_datetime_str_to_proto_ts_conversion(self): def test_datetime_str_to_proto_ts_conversion_none(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -837,7 +837,7 @@ def test_datetime_str_to_proto_ts_conversion_none(self): def test_datetime_str_to_proto_ts_conversion_empty(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -847,7 +847,7 @@ def test_datetime_str_to_proto_ts_conversion_empty(self): def test_datetime_str_to_proto_ts_conversion_invalid(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -858,7 +858,7 @@ def test_datetime_str_to_proto_ts_conversion_invalid(self): def test_hex_str_to_proto_bytes_conversion(self): hex_encoder = codecs.getencoder('hex') - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -869,7 +869,7 @@ def test_hex_str_to_proto_bytes_conversion(self): def test_datetime_to_proto_ts_conversion_none(self): - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -882,7 +882,7 @@ def test_datetime_to_proto_ts_conversion(self): delta = now - datetime(1970, 1, 1) expected_seconds = int(delta.total_seconds()) expected_nanos = delta.microseconds * 1000 - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -892,7 +892,7 @@ def test_datetime_to_proto_ts_conversion(self): def test_datetime_to_proto_ts_conversion_zero(self): zero = datetime(1970, 1, 1) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -905,7 +905,7 @@ def test_config_generator(self): config = trace_config_pb2.TraceConfig( constant_sampler=trace_config_pb2.ConstantSampler( decision=True)) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, transport=MockTransport) @@ -936,7 +936,7 @@ def test_second_config_update_without_node(self): constant_sampler=trace_config_pb2.ConstantSampler( decision=False)) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -965,7 +965,7 @@ def test_second_config_update_after_exception_with_node(self): constant_sampler=trace_config_pb2.ConstantSampler( decision=False)) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -997,7 +997,7 @@ def test_update_config_return_value(self): probability_sampler=trace_config_pb2.ProbabilitySampler( samplingProbability=0.1)) - exporter = opencensusd_exporter.OpenCensusDExporter( + exporter = span_proto_exporter.SpanProtoExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) From b48c33c2e6158d1437c4a4b85371c53da43ad973 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Tue, 4 Sep 2018 13:36:20 -0700 Subject: [PATCH 5/8] move span conversion to utils --- .../trace/exporters/span_proto_exporter.py | 403 ------------- .../exporters/span_proto_exporter/__init__.py | 13 + .../span_proto_exporter.py | 196 ++++++ .../exporters/span_proto_exporter/utils.py | 229 +++++++ .../test_span_proto_exporter.py | 445 ++++++++++++++ .../test_span_proto_exporter_utils.py} | 568 ++---------------- 6 files changed, 920 insertions(+), 934 deletions(-) delete mode 100644 opencensus/trace/exporters/span_proto_exporter.py create mode 100644 opencensus/trace/exporters/span_proto_exporter/__init__.py create mode 100644 opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py create mode 100644 opencensus/trace/exporters/span_proto_exporter/utils.py create mode 100644 tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py rename tests/unit/trace/exporters/{test_span_proto_exporter.py => span_proto_exporter/test_span_proto_exporter_utils.py} (51%) diff --git a/opencensus/trace/exporters/span_proto_exporter.py b/opencensus/trace/exporters/span_proto_exporter.py deleted file mode 100644 index cd3e293c7..000000000 --- a/opencensus/trace/exporters/span_proto_exporter.py +++ /dev/null @@ -1,403 +0,0 @@ -# Copyright 2018, OpenCensus Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Export the trace spans to OpenCensusD""" - -import datetime -import grpc -import os -import socket -from threading import Lock -from google.protobuf.internal.well_known_types import ParseError -from google.protobuf.timestamp_pb2 import Timestamp -from google.protobuf.wrappers_pb2 import BoolValue, UInt32Value - -from opencensus.trace.exporters import base -from opencensus.trace.exporters.transports import sync -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 -from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import ( - common_pb2 -) -from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import ( - trace_service_pb2, - trace_service_pb2_grpc -) - -# Default agent endpoint -DEFAULT_ENDPOINT = 'localhost:50051' - -# OpenCensus Version -VERSION = '0.1.6' - - -class SpanProtoExporter(base.Exporter): - """Export the spans by sending them to opencensus agent. - - :type service_name: str - :param service_name: name of the service - - :type host_name: str - :param host_name: name of the host (machine or host name) - - :type endpoint: str - :param endpoint: opencensus agent endpoint. - - :type client: class:`~.trace_service_pb2_grpc.TraceServiceStub` - :param client: OpenCensusD client. - - :type transport: :class:`type` - :param transport: Class for creating new transport objects. It should - extend from the base :class:`.Transport` type and - implement :meth:`.Transport.export`. Defaults to - :class:`.SyncTransport`. The other option is - :class:`.BackgroundThreadTransport`. - """ - - def __init__( - self, - service_name, - host_name=None, - endpoint=None, - client=None, - transport=sync.SyncTransport): - self.transport = transport(self) - - self.endpoint = DEFAULT_ENDPOINT if endpoint is None else endpoint - - if client is None: - self.channel = grpc.insecure_channel(self.endpoint) - self.client = trace_service_pb2_grpc.TraceServiceStub( - channel=self.channel) - else: - self.client = client - - self.node = common_pb2.Node( - identifier=common_pb2.ProcessIdentifier( - host_name=socket.gethostname() if host_name is None - else host_name, - pid=os.getpid(), - start_timestamp=self.proto_ts_from_datetime( - datetime.datetime.now()) - ), - library_info=common_pb2.LibraryInfo( - language=common_pb2.LibraryInfo.Language.Value('PYTHON'), - version=VERSION - ), - service_info=common_pb2.ServiceInfo(name=service_name)) - - self.send_node_in_config = True - self.send_node_in_export = True - - def emit(self, span_datas): - """ - :type span_datas: list of :class: - `~opencensus.trace.span_data.SpanData` - :param list of opencensus.trace.span_data.SpanData span_datas: - SpanData tuples to emit - """ - - try: - responses = self.client.Export( - self.generate_span_requests(span_datas)) - - # read response - for _ in responses: - pass - - # Node was successfully sent, unless there is a connectivity - # issue between app and agent, Node should not be sent again - self.send_node_in_export = False - except grpc.RpcError: - self.send_node_in_export = True - self.send_node_in_config = True - pass - - def export(self, span_datas): - """Export the trace. - Send trace to transport, and transport will call exporter.emit() - to actually send the trace to the specified tracing - backend. - - :type span_datas: list of :class: - `~opencensus.trace.span_data.SpanData` - :param list of opencensus.trace.span_data.SpanData span_datas: - SpanData tuples to export - """ - self.transport.export(span_datas) - - def generate_span_requests(self, span_datas): - """Span request generator. - - :type span_datas: list of - :class:`~opencensus.trace.span_data.SpanData` - :param span_datas: SpanData tuples to convert to protocuf spans - and send to opensensusd agent - - :rtype: list of - `~gen.opencensusd.agent.trace.v1.trace_service_pb2.ExportTraceServiceRequest` - :returns: List of span export requests. - """ - - pb_spans = [self.translate_to_opencensusd( - span_data) for span_data in span_datas] - - yield trace_service_pb2.ExportTraceServiceRequest( - node=self.node if self.send_node_in_export else None, - spans=pb_spans) - - def update_config(self, config): - """Sends TraceConfig to the agent and gets agent's config in reply. - - :type config: `~opencensus.proto.trace.v1.TraceConfig` - :param config: Trace config with sampling and other settings - - :rtype: `~opencensus.proto.trace.v1.TraceConfig` - :returns: Trace config from agent. - """ - - # do not allow updating config simultaneously - lock = Lock() - with lock: - try: - config_responses = self.client.Config( - self.generate_config_request(config)) - - agent_config = next(config_responses) - self.send_node_in_config = False - return agent_config - except grpc.RpcError as e: - self.send_node_in_config = True - self.send_node_in_export = True - raise e - - def generate_config_request(self, config): - """ConfigTraceServiceRequest generator. - - :type config: `~opencensus.proto.trace.v1.TraceConfig` - :param config: Trace config with sampling and other settings - - :rtype: list of - `~opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest` - :returns: List of config requests. - """ - - request = trace_service_pb2.ConfigTraceServiceRequest( - node=self.node if self.send_node_in_config else None, - config=config) - - yield request - - def translate_to_opencensusd(self, span_data): - """Translates the opencensus spans to OpenCensusD spans. - - :type span_data: :class:`~opencensus.trace.span_data.SpanData` - :param span_data: SpanData tuples to convert to protobuf spans - - :rtype: :class:`~opencensus.proto.trace.Span` - :returns: Protobuf format span. - """ - - if not span_data: - return None - - pb_span = trace_pb2.Span( - name=trace_pb2.TruncatableString(value=span_data.name), - kind=span_data.span_kind, - trace_id=self.hex_str_to_bytes_str(span_data.context.trace_id), - span_id=self.hex_str_to_bytes_str(span_data.span_id), - parent_span_id=self.hex_str_to_bytes_str(span_data.parent_span_id) - if span_data.parent_span_id is not None else None, - start_time=self.proto_ts_from_datetime_str(span_data.start_time), - end_time=self.proto_ts_from_datetime_str(span_data.end_time), - status=trace_pb2.Status( - code=span_data.status.code, - message=span_data.status.message) - if span_data.status is not None else None, - same_process_as_parent_span=BoolValue( - value=span_data.same_process_as_parent_span) - if span_data.same_process_as_parent_span is not None - else None, - child_span_count=UInt32Value(value=span_data.child_span_count) - if span_data.child_span_count is not None else None) - - # attributes - if span_data.attributes is not None: - for attribute_key, attribute_value \ - in span_data.attributes.items(): - self.add_proto_attribute_value( - pb_span.attributes, - attribute_key, - attribute_value) - - # time events - if span_data.time_events is not None: - for span_data_event in span_data.time_events: - if span_data_event.message_event is not None: - pb_event = pb_span.time_events.time_event.add() - pb_event.time.FromJsonString(span_data_event.timestamp) - self.set_proto_message_event( - pb_event.message_event, - span_data_event.message_event) - elif span_data_event.annotation is not None: - pb_event = pb_span.time_events.time_event.add() - pb_event.time.FromJsonString(span_data_event.timestamp) - self.set_proto_annotation( - pb_event.annotation, - span_data_event.annotation) - - # links - if span_data.links is not None: - for link in span_data.links: - pb_link = pb_span.links.link.add( - trace_id=self.hex_str_to_bytes_str(link.trace_id), - span_id=self.hex_str_to_bytes_str(link.span_id), - type=link.type) - - if link.attributes is not None and \ - link.attributes.attributes is not None: - for attribute_key, attribute_value \ - in link.attributes.attributes.items(): - self.add_proto_attribute_value( - pb_link.attributes, - attribute_key, - attribute_value) - - # tracestate - if span_data.context.tracestate is not None: - for (key, value) in span_data.context.tracestate.items(): - pb_span.tracestate.entries.add(key=key, value=value) - - return pb_span - - def set_proto_message_event( - self, - pb_message_event, - span_data_message_event): - """Sets properties on the protobuf message event. - - :type pb_message_event: - :class: `~opencensus.proto.trace.Span.TimeEvent.MessageEvent` - :param pb_message_event: protobuf message event - - :type span_data_message_event: - :class: `~opencensus.trace.time_event.MessageEvent` - :param span_data_message_event: opencensus message event - """ - - pb_message_event.type = span_data_message_event.type - pb_message_event.id = span_data_message_event.id - pb_message_event.uncompressed_size = \ - span_data_message_event.uncompressed_size_bytes - pb_message_event.compressed_size = \ - span_data_message_event.compressed_size_bytes - - def set_proto_annotation(self, pb_annotation, span_data_annotation): - """Sets properties on the protobuf Span annotation. - - :type pb_annotation: - :class: `~opencensus.proto.trace.Span.TimeEvent.Annotation` - :param pb_annotation: protobuf annotation - - :type span_data_annotation: - :class: `~opencensus.trace.time_event.Annotation` - :param span_data_annotation: opencensus annotation - - """ - - pb_annotation.description.value = span_data_annotation.description - if span_data_annotation.attributes is not None \ - and span_data_annotation.attributes.attributes is not None: - for attribute_key, attribute_value in \ - span_data_annotation.attributes.attributes.items(): - self.add_proto_attribute_value( - pb_annotation.attributes, - attribute_key, - attribute_value) - - def hex_str_to_bytes_str(self, hex_str): - """Converts the hex string to bytes string. - - :type hex_str: str - :param hex_str: The hex tring representing trace_id or span_id. - - :rtype: str - :returns: string representing byte array - """ - - return bytes(bytearray.fromhex(hex_str)) - - def proto_ts_from_datetime_str(self, dt): - """Converts string datetime in ISO format to protobuf timestamp. - - :type dt: str - :param dt: string with datetime in ISO format - - :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` - :returns: protobuf timestamp - """ - - ts = Timestamp() - if (dt is not None): - try: - ts.FromJsonString(dt) - except ParseError: - pass - return ts - - def proto_ts_from_datetime(self, dt): - """Converts datetime to protobuf timestamp. - - :type dt: datetime - :param dt: date and time - - :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` - :returns: protobuf timestamp - """ - - ts = Timestamp() - if (dt is not None): - ts.FromDatetime(dt) - return ts - - def add_proto_attribute_value( - self, - pb_attributes, - attribute_key, - attribute_value): - """Sets string, int or boolean value on protobuf - span, link or annotation attributes. - - :type pb_attributes: - :class: `~opencensus.proto.trace.Span.Attributes` - :param pb_attributes: protobuf Span's attributes property - - :type attribute_key: str - :param attribute_key: attribute key to set - - :type attribute_value: str or int or bool - :param attribute_value: attribute value - """ - - if isinstance(attribute_value, bool): - pb_attributes.attribute_map[attribute_key].\ - bool_value = attribute_value - elif isinstance(attribute_value, int): - pb_attributes.attribute_map[attribute_key].\ - int_value = attribute_value - elif isinstance(attribute_value, str): - pb_attributes.attribute_map[attribute_key].\ - string_value.value = attribute_value - else: - pb_attributes.attribute_map[attribute_key].\ - string_value.value = str(attribute_value) diff --git a/opencensus/trace/exporters/span_proto_exporter/__init__.py b/opencensus/trace/exporters/span_proto_exporter/__init__.py new file mode 100644 index 000000000..ebe2afa10 --- /dev/null +++ b/opencensus/trace/exporters/span_proto_exporter/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py b/opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py new file mode 100644 index 000000000..6f32202d5 --- /dev/null +++ b/opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py @@ -0,0 +1,196 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Export opencensus spans to trace proto agent""" + +import datetime +import grpc +import os +import socket +from threading import Lock +from opencensus.trace.exporters import base +from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import ( + common_pb2 +) +from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import ( + trace_service_pb2, + trace_service_pb2_grpc +) +from opencensus.trace.exporters.transports import sync +from opencensus.trace.exporters.span_proto_exporter import utils + +# Default agent endpoint +DEFAULT_ENDPOINT = 'localhost:50051' + +# OpenCensus Version +VERSION = '0.1.6' + + +class SpanProtoExporter(base.Exporter): + """Export the spans by sending them to opencensus agent. + + :type service_name: str + :param service_name: name of the service + + :type host_name: str + :param host_name: name of the host (machine or host name) + + :type endpoint: str + :param endpoint: opencensus agent endpoint. + + :type client: class:`~.trace_service_pb2_grpc.TraceServiceStub` + :param client: OpenCensusD client. + + :type transport: :class:`type` + :param transport: Class for creating new transport objects. It should + extend from the base :class:`.Transport` type and + implement :meth:`.Transport.export`. Defaults to + :class:`.SyncTransport`. The other option is + :class:`.BackgroundThreadTransport`. + """ + + def __init__( + self, + service_name, + host_name=None, + endpoint=None, + client=None, + transport=sync.SyncTransport): + self.transport = transport(self) + + self.endpoint = DEFAULT_ENDPOINT if endpoint is None else endpoint + + if client is None: + self.channel = grpc.insecure_channel(self.endpoint) + self.client = trace_service_pb2_grpc.TraceServiceStub( + channel=self.channel) + else: + self.client = client + + self.node = common_pb2.Node( + identifier=common_pb2.ProcessIdentifier( + host_name=socket.gethostname() if host_name is None + else host_name, + pid=os.getpid(), + start_timestamp=utils.proto_ts_from_datetime( + datetime.datetime.now()) + ), + library_info=common_pb2.LibraryInfo( + language=common_pb2.LibraryInfo.Language.Value('PYTHON'), + version=VERSION + ), + service_info=common_pb2.ServiceInfo(name=service_name)) + + self.send_node_in_config = True + self.send_node_in_export = True + + def emit(self, span_datas): + """ + :type span_datas: list of :class: + `~opencensus.trace.span_data.SpanData` + :param list of opencensus.trace.span_data.SpanData span_datas: + SpanData tuples to emit + """ + + try: + responses = self.client.Export( + self.generate_span_requests(span_datas)) + + # read response + for _ in responses: + pass + + # Node was successfully sent, unless there is a connectivity + # issue between app and agent, Node should not be sent again + self.send_node_in_export = False + except grpc.RpcError: + self.send_node_in_export = True + self.send_node_in_config = True + pass + + def export(self, span_datas): + """Export the trace. + Send trace to transport, and transport will call exporter.emit() + to actually send the trace to the specified tracing + backend. + + :type span_datas: list of :class: + `~opencensus.trace.span_data.SpanData` + :param list of opencensus.trace.span_data.SpanData span_datas: + SpanData tuples to export + """ + self.transport.export(span_datas) + + def generate_span_requests(self, span_datas): + """Span request generator. + + :type span_datas: list of + :class:`~opencensus.trace.span_data.SpanData` + :param span_datas: SpanData tuples to convert to protocuf spans + and send to opensensusd agent + + :rtype: list of + `~gen.opencensusd.agent.trace.v1.trace_service_pb2.ExportTraceServiceRequest` + :returns: List of span export requests. + """ + + pb_spans = [utils.translate_to_opencensusd( + span_data) for span_data in span_datas] + + yield trace_service_pb2.ExportTraceServiceRequest( + node=self.node if self.send_node_in_export else None, + spans=pb_spans) + + # TODO: better support for receiving config updates + def update_config(self, config): + """Sends TraceConfig to the agent and gets agent's config in reply. + + :type config: `~opencensus.proto.trace.v1.TraceConfig` + :param config: Trace config with sampling and other settings + + :rtype: `~opencensus.proto.trace.v1.TraceConfig` + :returns: Trace config from agent. + """ + + # do not allow updating config simultaneously + lock = Lock() + with lock: + try: + config_responses = self.client.Config( + self.generate_config_request(config)) + + agent_config = next(config_responses) + self.send_node_in_config = False + return agent_config + except grpc.RpcError as e: + self.send_node_in_config = True + self.send_node_in_export = True + raise e + + def generate_config_request(self, config): + """ConfigTraceServiceRequest generator. + + :type config: `~opencensus.proto.trace.v1.TraceConfig` + :param config: Trace config with sampling and other settings + + :rtype: list of + `~opencensus.proto.agent.trace.v1.ConfigTraceServiceRequest` + :returns: List of config requests. + """ + + request = trace_service_pb2.ConfigTraceServiceRequest( + node=self.node if self.send_node_in_config else None, + config=config) + + yield request diff --git a/opencensus/trace/exporters/span_proto_exporter/utils.py b/opencensus/trace/exporters/span_proto_exporter/utils.py new file mode 100644 index 000000000..63064fc46 --- /dev/null +++ b/opencensus/trace/exporters/span_proto_exporter/utils.py @@ -0,0 +1,229 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Translates opencensus span data to trace proto""" + +from google.protobuf.internal.well_known_types import ParseError +from google.protobuf.timestamp_pb2 import Timestamp +from google.protobuf.wrappers_pb2 import BoolValue, UInt32Value +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 + + +def translate_to_opencensusd(span_data): + """Translates the opencensus spans to OpenCensusD spans. + + :type span_data: :class:`~opencensus.trace.span_data.SpanData` + :param span_data: SpanData tuples to convert to protobuf spans + + :rtype: :class:`~opencensus.proto.trace.Span` + :returns: Protobuf format span. + """ + + if not span_data: + return None + + pb_span = trace_pb2.Span( + name=trace_pb2.TruncatableString(value=span_data.name), + kind=span_data.span_kind, + trace_id=hex_str_to_bytes_str(span_data.context.trace_id), + span_id=hex_str_to_bytes_str(span_data.span_id), + parent_span_id=hex_str_to_bytes_str(span_data.parent_span_id) + if span_data.parent_span_id is not None else None, + start_time=proto_ts_from_datetime_str(span_data.start_time), + end_time=proto_ts_from_datetime_str(span_data.end_time), + status=trace_pb2.Status( + code=span_data.status.code, + message=span_data.status.message) + if span_data.status is not None else None, + same_process_as_parent_span=BoolValue( + value=span_data.same_process_as_parent_span) + if span_data.same_process_as_parent_span is not None + else None, + child_span_count=UInt32Value(value=span_data.child_span_count) + if span_data.child_span_count is not None else None) + + # attributes + if span_data.attributes is not None: + for attribute_key, attribute_value \ + in span_data.attributes.items(): + add_proto_attribute_value( + pb_span.attributes, + attribute_key, + attribute_value) + + # time events + if span_data.time_events is not None: + for span_data_event in span_data.time_events: + if span_data_event.message_event is not None: + pb_event = pb_span.time_events.time_event.add() + pb_event.time.FromJsonString(span_data_event.timestamp) + set_proto_message_event( + pb_event.message_event, + span_data_event.message_event) + elif span_data_event.annotation is not None: + pb_event = pb_span.time_events.time_event.add() + pb_event.time.FromJsonString(span_data_event.timestamp) + set_proto_annotation( + pb_event.annotation, + span_data_event.annotation) + + # links + if span_data.links is not None: + for link in span_data.links: + pb_link = pb_span.links.link.add( + trace_id=hex_str_to_bytes_str(link.trace_id), + span_id=hex_str_to_bytes_str(link.span_id), + type=link.type) + + if link.attributes is not None and \ + link.attributes.attributes is not None: + for attribute_key, attribute_value \ + in link.attributes.attributes.items(): + add_proto_attribute_value( + pb_link.attributes, + attribute_key, + attribute_value) + + # tracestate + if span_data.context.tracestate is not None: + for (key, value) in span_data.context.tracestate.items(): + pb_span.tracestate.entries.add(key=key, value=value) + + return pb_span + + +def set_proto_message_event( + pb_message_event, + span_data_message_event): + """Sets properties on the protobuf message event. + + :type pb_message_event: + :class: `~opencensus.proto.trace.Span.TimeEvent.MessageEvent` + :param pb_message_event: protobuf message event + + :type span_data_message_event: + :class: `~opencensus.trace.time_event.MessageEvent` + :param span_data_message_event: opencensus message event + """ + + pb_message_event.type = span_data_message_event.type + pb_message_event.id = span_data_message_event.id + pb_message_event.uncompressed_size = \ + span_data_message_event.uncompressed_size_bytes + pb_message_event.compressed_size = \ + span_data_message_event.compressed_size_bytes + + +def set_proto_annotation(pb_annotation, span_data_annotation): + """Sets properties on the protobuf Span annotation. + + :type pb_annotation: + :class: `~opencensus.proto.trace.Span.TimeEvent.Annotation` + :param pb_annotation: protobuf annotation + + :type span_data_annotation: + :class: `~opencensus.trace.time_event.Annotation` + :param span_data_annotation: opencensus annotation + + """ + + pb_annotation.description.value = span_data_annotation.description + if span_data_annotation.attributes is not None \ + and span_data_annotation.attributes.attributes is not None: + for attribute_key, attribute_value in \ + span_data_annotation.attributes.attributes.items(): + add_proto_attribute_value( + pb_annotation.attributes, + attribute_key, + attribute_value) + + +def hex_str_to_bytes_str(hex_str): + """Converts the hex string to bytes string. + + :type hex_str: str + :param hex_str: The hex tring representing trace_id or span_id. + + :rtype: str + :returns: string representing byte array + """ + + return bytes(bytearray.fromhex(hex_str)) + + +def proto_ts_from_datetime_str(dt): + """Converts string datetime in ISO format to protobuf timestamp. + + :type dt: str + :param dt: string with datetime in ISO format + + :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` + :returns: protobuf timestamp + """ + + ts = Timestamp() + if (dt is not None): + try: + ts.FromJsonString(dt) + except ParseError: + pass + return ts + + +def proto_ts_from_datetime(dt): + """Converts datetime to protobuf timestamp. + + :type dt: datetime + :param dt: date and time + + :rtype: :class:`~google.protobuf.timestamp_pb2.Timestamp` + :returns: protobuf timestamp + """ + + ts = Timestamp() + if (dt is not None): + ts.FromDatetime(dt) + return ts + + +def add_proto_attribute_value( + pb_attributes, + attribute_key, + attribute_value): + """Sets string, int or boolean value on protobuf + span, link or annotation attributes. + + :type pb_attributes: + :class: `~opencensus.proto.trace.Span.Attributes` + :param pb_attributes: protobuf Span's attributes property + + :type attribute_key: str + :param attribute_key: attribute key to set + + :type attribute_value: str or int or bool + :param attribute_value: attribute value + """ + + if isinstance(attribute_value, bool): + pb_attributes.attribute_map[attribute_key].\ + bool_value = attribute_value + elif isinstance(attribute_value, int): + pb_attributes.attribute_map[attribute_key].\ + int_value = attribute_value + elif isinstance(attribute_value, str): + pb_attributes.attribute_map[attribute_key].\ + string_value.value = attribute_value + else: + pb_attributes.attribute_map[attribute_key].\ + string_value.value = str(attribute_value) diff --git a/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py b/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py new file mode 100644 index 000000000..efee6a18f --- /dev/null +++ b/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py @@ -0,0 +1,445 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import codecs +import grpc +import mock +import os +import socket +import unittest + +from google.protobuf.timestamp_pb2 import Timestamp + +from opencensus.trace import span_context as span_context_module +from opencensus.trace import span_data as span_data_module +from opencensus.trace.exporters.span_proto_exporter import span_proto_exporter +from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 +from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 + + +SERVICE_NAME = 'my-service' + + +class TestSpanProtoExporter(unittest.TestCase): + + def test_constructor(self): + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME) + + self.assertEqual(exporter.endpoint, 'localhost:50051') + + def test_constructor_with_endpoint(self): + expected_endpoint = '0.0.0.0:50000' + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + endpoint=expected_endpoint) + + self.assertEqual(exporter.endpoint, expected_endpoint) + + def test_constructor_with_client(self): + client = mock.Mock() + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + self.assertEqual(exporter.client, client) + + def test_constructor_node_host(self): + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + host_name='my host') + + self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) + self.assertEqual(exporter.node.library_info.language, 8) + self.assertIsNotNone(exporter.node.library_info.version) + + self.assertEqual(exporter.node.identifier.host_name, 'my host') + self.assertEqual(exporter.node.identifier.pid, os.getpid()) + + self.assertIsNotNone(exporter.node.identifier.start_timestamp) + self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) + + def test_constructor_node(self): + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME) + + self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) + self.assertEqual(exporter.node.library_info.language, 8) + self.assertIsNotNone(exporter.node.library_info.version) + + self.assertEqual(exporter.node.identifier.host_name, + socket.gethostname()) + self.assertEqual(exporter.node.identifier.pid, os.getpid()) + + self.assertIsNotNone(exporter.node.identifier.start_timestamp) + self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) + + def test_export(self): + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + exporter.export({}) + + self.assertTrue(exporter.transport.export_called) + + def test_emit(self): + client = mock.Mock() + client.Export.return_value = [1] + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit({}) + + self.assertTrue(client.Export.called) + + def test_emit_throw(self): + client = mock.Mock() + client.Export.side_effect = grpc.RpcError() + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + # does not throw + exporter.emit({}) + + self.assertTrue(client.Export.called) + + def export_iterate(self, *args, **kwargs): + self.export_requests = list(args[0]) + return iter(self.export_requests) + + def test_span_generator(self): + + hex_encoder = codecs.getencoder('hex') + span_datas = [ + span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + attributes=None, + start_time=None, + end_time=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0), + span_data_module.SpanData( + name="name1", + context=span_context_module.SpanContext( + trace_id='1e0c63257de34c92bf9efcd03927272e'), + span_id='1e0c63257de34c92', + parent_span_id=None, + attributes=None, + start_time=None, + end_time=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + ] + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + export_requests = list(exporter.generate_span_requests(span_datas)) + + self.assertEqual(len(export_requests), 1) + self.assertEqual(export_requests[0].node, exporter.node) + self.assertEqual(len(export_requests[0].spans), 2) + + self.assertEqual(export_requests[0].spans[0].name.value, 'name0') + self.assertEqual(export_requests[0].spans[1].name.value, 'name1') + self.assertEqual(hex_encoder(export_requests[0].spans[0].trace_id)[ + 0], b'0e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(export_requests[0].spans[0].span_id)[ + 0], b'0e0c63257de34c92') + self.assertEqual(hex_encoder(export_requests[0].spans[1].trace_id)[ + 0], b'1e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(export_requests[0].spans[1].span_id)[ + 0], b'1e0c63257de34c92') + + def test_basic_span_emit(self): + hex_encoder = codecs.getencoder('hex') + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included. + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + span_data = span_data_module.SpanData( + name="name", + context=span_context_module.SpanContext( + trace_id='6e0c63257de34c92bf9efcd03927272e'), + span_id='6e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit([span_data]) + + self.assertTrue(client.Export.called) + + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + pb_span = actual_request.spans[0] + + self.assertEqual(pb_span.name.value, "name") + self.assertEqual(hex_encoder(pb_span.trace_id)[ + 0], b'6e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span.span_id)[0], b'6e0c63257de34c92') + + def test_second_span_emit_without_node(self): + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + span_data0 = span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + span_data1 = span_data_module.SpanData( + name="name1", + context=span_context_module.SpanContext( + trace_id='1e0c63257de34c92bf9efcd03927272e'), + span_id='1e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.emit([span_data0]) + + actual_request = self.export_requests[0] + self.assertIsNotNone(actual_request.node) + self.assertEqual(actual_request.node, exporter.node) + + exporter.emit([span_data1]) + + self.assertEqual(len(client.Export.mock_calls), 2) + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, + trace_service_pb2.ExportTraceServiceRequest().node) + + def test_second_span_emit_after_exception_with_node(self): + client = mock.Mock() + + span_data0 = span_data_module.SpanData( + name="name0", + context=span_context_module.SpanContext( + trace_id='0e0c63257de34c92bf9efcd03927272e'), + span_id='0e0c63257de34c92', + parent_span_id=None, + start_time=None, + end_time=None, + attributes=None, + child_span_count=None, + stack_trace=None, + time_events=None, + links=None, + status=None, + same_process_as_parent_span=None, + span_kind=0) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Export.side_effect = grpc.RpcError() + exporter.emit([span_data0]) + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Export returns + # and it won't be possible to check if node is included + # passed export request will be stored in self.export_requests + client.Export.side_effect = self.export_iterate + + exporter.emit([span_data0]) + + self.assertEqual(len(client.Export.mock_calls), 2) + actual_request = self.export_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + def test_config_generator(self): + + config = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + transport=MockTransport) + + config_requests = list(exporter.generate_config_request(config)) + + self.assertEqual(len(config_requests), 1) + self.assertEqual(config_requests[0].node, exporter.node) + self.assertEqual(config_requests[0].config, config) + + def config_iterate(self, *args, **kwargs): + self.config_requests = list(args[0]) + return iter(self.config_requests) + + def test_second_config_update_without_node(self): + client = mock.Mock() + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Config returns + # and it won't be possible to check if node is included. + # passed config request will be stored in self.config_requests + client.Config.side_effect = self.config_iterate + + config0 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + config1 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=False)) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + exporter.update_config(config0) + + actual_request = self.config_requests[0] + self.assertIsNotNone(actual_request.node) + self.assertEqual(actual_request.node, exporter.node) + + exporter.update_config(config1) + + self.assertEqual(len(client.Config.mock_calls), 2) + actual_request = self.config_requests[0] + self.assertEqual(actual_request.node, + trace_service_pb2.ConfigTraceServiceRequest().node) + + def test_second_config_update_after_exception_with_node(self): + client = mock.Mock() + + config0 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + config1 = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=False)) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Config.side_effect = grpc.RpcError() + with self.assertRaises(grpc.RpcError): + exporter.update_config(config0) + + # we need to make exporter iterate over passed generator, + # otherwise iteration will happen after Config returns + # and it won't be possible to check if node is included. + # passed config request will be stored in self.config_requests + client.Config.side_effect = self.config_iterate + + exporter.update_config(config1) + + self.assertEqual(len(client.Config.mock_calls), 2) + actual_request = self.config_requests[0] + self.assertEqual(actual_request.node, exporter.node) + + def test_update_config_return_value(self): + client = mock.Mock() + + client_config = trace_config_pb2.TraceConfig( + constant_sampler=trace_config_pb2.ConstantSampler( + decision=True)) + + agent_config = trace_config_pb2.TraceConfig( + probability_sampler=trace_config_pb2.ProbabilitySampler( + samplingProbability=0.1)) + + exporter = span_proto_exporter.SpanProtoExporter( + service_name=SERVICE_NAME, + client=client, + transport=MockTransport) + + client.Config.return_value = iter([agent_config]) + actual_response = exporter.update_config(client_config) + + self.assertEqual(actual_response, agent_config) + + +class MockTransport(object): + def __init__(self, exporter=None): + self.export_called = False + self.exporter = exporter + + def export(self, trace): + self.export_called = True diff --git a/tests/unit/trace/exporters/test_span_proto_exporter.py b/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py similarity index 51% rename from tests/unit/trace/exporters/test_span_proto_exporter.py rename to tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py index e4a7d8dfa..bb588e1a6 100644 --- a/tests/unit/trace/exporters/test_span_proto_exporter.py +++ b/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py @@ -14,10 +14,6 @@ import codecs from datetime import datetime, timedelta -import grpc -import mock -import os -import socket import unittest from google.protobuf.timestamp_pb2 import Timestamp @@ -31,255 +27,12 @@ from opencensus.trace import status as status_module from opencensus.trace import time_event as time_event_module from opencensus.trace import tracestate as tracestate_module -from opencensus.trace.exporters import span_proto_exporter +from opencensus.trace.exporters.span_proto_exporter import utils from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 -from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 -SERVICE_NAME = 'my-service' - - -class TestSpanProtoExporter(unittest.TestCase): - - def test_constructor(self): - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME) - - self.assertEqual(exporter.endpoint, 'localhost:50051') - - def test_constructor_with_endpoint(self): - expected_endpoint = '0.0.0.0:50000' - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - endpoint=expected_endpoint) - - self.assertEqual(exporter.endpoint, expected_endpoint) - - def test_constructor_with_client(self): - client = mock.Mock() - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - self.assertEqual(exporter.client, client) - - def test_constructor_node(self): - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - host_name='my host') - - self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) - self.assertEqual(exporter.node.library_info.language, 8) - self.assertIsNotNone(exporter.node.library_info.version) - - self.assertEqual(exporter.node.identifier.host_name, 'my host') - self.assertEqual(exporter.node.identifier.pid, os.getpid()) - - self.assertIsNotNone(exporter.node.identifier.start_timestamp) - self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) - - def test_constructor_node(self): - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME) - - self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) - self.assertEqual(exporter.node.library_info.language, 8) - self.assertIsNotNone(exporter.node.library_info.version) - - self.assertEqual(exporter.node.identifier.host_name, - socket.gethostname()) - self.assertEqual(exporter.node.identifier.pid, os.getpid()) - - self.assertIsNotNone(exporter.node.identifier.start_timestamp) - self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) - - def test_export(self): - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - exporter.export({}) - - self.assertTrue(exporter.transport.export_called) - - def test_emit(self): - client = mock.Mock() - client.Export.return_value = [1] - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.emit({}) - - self.assertTrue(client.Export.called) - - def test_emit_throw(self): - client = mock.Mock() - client.Export.side_effect = grpc.RpcError() - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - # does not throw - exporter.emit({}) - - self.assertTrue(client.Export.called) - - def export_iterate(self, *args, **kwargs): - self.export_requests = list(args[0]) - return iter(self.export_requests) - - def test_basic_span_emit(self): - hex_encoder = codecs.getencoder('hex') - client = mock.Mock() - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included. - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate - - span_data = span_data_module.SpanData( - name="name", - context=span_context_module.SpanContext( - trace_id='6e0c63257de34c92bf9efcd03927272e'), - span_id='6e0c63257de34c92', - parent_span_id=None, - start_time=None, - end_time=None, - attributes=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.emit([span_data]) - - self.assertTrue(client.Export.called) - - actual_request = self.export_requests[0] - self.assertEqual(actual_request.node, exporter.node) - - pb_span = actual_request.spans[0] - - self.assertEqual(pb_span.name.value, "name") - self.assertEqual(hex_encoder(pb_span.trace_id)[ - 0], b'6e0c63257de34c92bf9efcd03927272e') - self.assertEqual(hex_encoder(pb_span.span_id)[0], b'6e0c63257de34c92') - - def test_second_span_emit_without_node(self): - client = mock.Mock() - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate - - span_data0 = span_data_module.SpanData( - name="name0", - context=span_context_module.SpanContext( - trace_id='0e0c63257de34c92bf9efcd03927272e'), - span_id='0e0c63257de34c92', - parent_span_id=None, - start_time=None, - end_time=None, - attributes=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - - span_data1 = span_data_module.SpanData( - name="name1", - context=span_context_module.SpanContext( - trace_id='1e0c63257de34c92bf9efcd03927272e'), - span_id='1e0c63257de34c92', - parent_span_id=None, - start_time=None, - end_time=None, - attributes=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.emit([span_data0]) - - actual_request = self.export_requests[0] - self.assertIsNotNone(actual_request.node) - self.assertEqual(actual_request.node, exporter.node) - - exporter.emit([span_data1]) - - self.assertEqual(len(client.Export.mock_calls), 2) - actual_request = self.export_requests[0] - self.assertEqual(actual_request.node, - trace_service_pb2.ExportTraceServiceRequest().node) - - def test_second_span_emit_after_exception_with_node(self): - client = mock.Mock() - - span_data0 = span_data_module.SpanData( - name="name0", - context=span_context_module.SpanContext( - trace_id='0e0c63257de34c92bf9efcd03927272e'), - span_id='0e0c63257de34c92', - parent_span_id=None, - start_time=None, - end_time=None, - attributes=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - client.Export.side_effect = grpc.RpcError() - exporter.emit([span_data0]) - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate - - exporter.emit([span_data0]) - - self.assertEqual(len(client.Export.mock_calls), 2) - actual_request = self.export_requests[0] - self.assertEqual(actual_request.node, exporter.node) - - def test_basic_span_export(self): +class TestSpanProtoExporterUtils(unittest.TestCase): + def test_basic_span_translation(self): hex_encoder = codecs.getencoder('hex') span_data = span_data_module.SpanData( @@ -300,10 +53,7 @@ def test_basic_span_export(self): same_process_as_parent_span=None, span_kind=0) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_opencensusd(span_data) self.assertEqual(pb_span.name.value, "name") self.assertEqual(hex_encoder(pb_span.trace_id)[ @@ -337,15 +87,12 @@ def test_basic_span_export(self): self.assertEqual(len(pb_span.links.link), 0) self.assertEqual(len(pb_span.tracestate.entries), 0) - def test_none_span_export(self): - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(None) + def test_translate_none_span(self): + pb_span = utils.translate_to_opencensusd(None) self.assertIsNone(pb_span) - def test_client_span_kind_export(self): + def test_translate_client_span_kind(self): client_span_data = span_data_module.SpanData( context=span_context_module.SpanContext( trace_id='6e0c63257de34c92bf9efcd03927272e'), @@ -363,15 +110,12 @@ def test_client_span_kind_export(self): links=None, status=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(client_span_data) + pb_span = utils.translate_to_opencensusd(client_span_data) self.assertEqual(pb_span.kind, 2) self.assertEqual(pb_span.same_process_as_parent_span.value, True) - def test_server_span_kind_export(self): + def test_translate_server_span_kindt(self): server_span_data = span_data_module.SpanData( context=span_context_module.SpanContext( trace_id='6e0c63257de34c92bf9efcd03927272e'), @@ -389,15 +133,12 @@ def test_server_span_kind_export(self): links=None, status=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(server_span_data) + pb_span = utils.translate_to_opencensusd(server_span_data) self.assertEqual(pb_span.kind, 1) self.assertEqual(pb_span.child_span_count.value, 1) - def test_status_export(self): + def test_translate_status(self): span_data = span_data_module.SpanData( context=span_context_module.SpanContext( trace_id='6e0c63257de34c92bf9efcd03927272e'), @@ -416,15 +157,12 @@ def test_status_export(self): time_events=None, links=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_opencensusd(span_data) self.assertEqual(pb_span.status.code, 2) self.assertEqual(pb_span.status.message, 'ERR') - def test_links_export(self): + def test_translate_links(self): hex_encoder = codecs.getencoder('hex') span_data = span_data_module.SpanData( @@ -456,10 +194,7 @@ def test_links_export(self): stack_trace=None, time_events=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_opencensusd(span_data) self.assertEqual(len(pb_span.links.link), 3) self.assertEqual(hex_encoder(pb_span.links.link[0].trace_id)[ @@ -495,7 +230,7 @@ def test_links_export(self): self.assertEqual( pb_span.links.link[0].attributes.attribute_map['test_bool_key'], trace_pb2.AttributeValue(bool_value=False)) - def test_time_events_export(self): + def test_translate_time_events(self): annotation0_ts = datetime.utcnow() + timedelta(seconds=-10) annotation1_ts = datetime.utcnow() + timedelta(seconds=-9) @@ -548,10 +283,7 @@ def test_time_events_export(self): stack_trace=None, links=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_opencensusd(span_data) self.assertEqual(len(pb_span.time_events.time_event), 5) @@ -596,7 +328,7 @@ def test_time_events_export(self): self.assertEqual(event3.message_event.type, 2) self.assertEqual(event4.message_event.type, 0) - def test_time_events_export_invalid(self): + def test_translate_time_events_invalid(self): ts = datetime.utcnow() + timedelta(seconds=-10) @@ -618,14 +350,11 @@ def test_time_events_export_invalid(self): stack_trace=None, links=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_opencensusd(span_data) self.assertEqual(len(pb_span.time_events.time_event), 0) - def test_tracestate_export(self): + def test_translate_tracestate(self): tracestate = tracestate_module.Tracestate() tracestate.append("k1", "v1") @@ -649,10 +378,7 @@ def test_tracestate_export(self): links=None, status=None) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - pb_span = exporter.translate_to_opencensusd(client_span_data) + pb_span = utils.translate_to_opencensusd(client_span_data) self.assertEqual(len(pb_span.tracestate.entries), 3) self.assertEqual(pb_span.tracestate.entries[0].key, "k1") @@ -662,78 +388,17 @@ def test_tracestate_export(self): self.assertEqual(pb_span.tracestate.entries[2].key, "k3") self.assertEqual(pb_span.tracestate.entries[2].value, "v3") - def test_span_generator(self): - - hex_encoder = codecs.getencoder('hex') - span_datas = [ - span_data_module.SpanData( - name="name0", - context=span_context_module.SpanContext( - trace_id='0e0c63257de34c92bf9efcd03927272e'), - span_id='0e0c63257de34c92', - parent_span_id=None, - attributes=None, - start_time=None, - end_time=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0), - span_data_module.SpanData( - name="name1", - context=span_context_module.SpanContext( - trace_id='1e0c63257de34c92bf9efcd03927272e'), - span_id='1e0c63257de34c92', - parent_span_id=None, - attributes=None, - start_time=None, - end_time=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - ] - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - export_requests = list(exporter.generate_span_requests(span_datas)) - - self.assertEqual(len(export_requests), 1) - self.assertEqual(export_requests[0].node, exporter.node) - self.assertEqual(len(export_requests[0].spans), 2) - - self.assertEqual(export_requests[0].spans[0].name.value, 'name0') - self.assertEqual(export_requests[0].spans[1].name.value, 'name1') - self.assertEqual(hex_encoder(export_requests[0].spans[0].trace_id)[ - 0], b'0e0c63257de34c92bf9efcd03927272e') - self.assertEqual(hex_encoder(export_requests[0].spans[0].span_id)[ - 0], b'0e0c63257de34c92') - self.assertEqual(hex_encoder(export_requests[0].spans[1].trace_id)[ - 0], b'1e0c63257de34c92bf9efcd03927272e') - self.assertEqual(hex_encoder(export_requests[0].spans[1].span_id)[ - 0], b'1e0c63257de34c92') - def test_add_attribute_value(self): pb_span = trace_pb2.Span() - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - exporter.add_proto_attribute_value(pb_span.attributes, 'int_key', 42) - exporter.add_proto_attribute_value( + utils.add_proto_attribute_value(pb_span.attributes, 'int_key', 42) + utils.add_proto_attribute_value( pb_span.attributes, 'bool_key', True) - exporter.add_proto_attribute_value( + utils.add_proto_attribute_value( pb_span.attributes, 'string_key', 'value') - exporter.add_proto_attribute_value( + utils.add_proto_attribute_value( pb_span.attributes, 'unicode_key', u'uvalue') - exporter.add_proto_attribute_value( + utils.add_proto_attribute_value( pb_span.attributes, 'dict_key', {"a": "b"}) self.assertEqual(len(pb_span.attributes.attribute_map), 5) @@ -758,10 +423,7 @@ def test_set_proto_event(self): uncompressed_size_bytes=10, compressed_size_bytes=1) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - exporter.set_proto_message_event(pb_event.message_event, message_event) + utils.set_proto_message_event(pb_event.message_event, message_event) self.assertEqual(pb_event.message_event.id, 0) self.assertEqual(pb_event.message_event.type, 1) @@ -777,10 +439,7 @@ def test_set_annotation_with_attributes(self): attributes=attributes_module.Attributes( attributes={'test_str_key': 'test_str_value', 'test_int_key': 1, 'test_bool_key': False})) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - exporter.set_proto_annotation(pb_event.annotation, annotation) + utils.set_proto_annotation(pb_event.annotation, annotation) self.assertEqual(pb_event.annotation.description.value, "hi there") self.assertEqual(len(pb_event.annotation.attributes.attribute_map), 3) @@ -800,12 +459,8 @@ def test_set_annotation_without_attributes(self): annotation1 = time_event_module.Annotation( description="hi there1", attributes=attributes_module.Attributes()) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - exporter.set_proto_annotation(pb_event0.annotation, annotation0) - exporter.set_proto_annotation(pb_event1.annotation, annotation1) + utils.set_proto_annotation(pb_event0.annotation, annotation0) + utils.set_proto_annotation(pb_event1.annotation, annotation1) self.assertEqual(pb_event0.annotation.description.value, "hi there0") self.assertEqual(pb_event1.annotation.description.value, "hi there1") @@ -817,63 +472,36 @@ def test_datetime_str_to_proto_ts_conversion(self): delta = now - datetime(1970, 1, 1) expected_seconds = int(delta.total_seconds()) expected_nanos = delta.microseconds * 1000 - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - proto_ts = exporter.proto_ts_from_datetime_str(now.isoformat() + 'Z') + proto_ts = utils.proto_ts_from_datetime_str(now.isoformat() + 'Z') self.assertEqual(proto_ts.seconds, int(expected_seconds)) self.assertEqual(proto_ts.nanos, expected_nanos) def test_datetime_str_to_proto_ts_conversion_none(self): - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - proto_ts = exporter.proto_ts_from_datetime_str(None) + proto_ts = utils.proto_ts_from_datetime_str(None) self.assertEquals(proto_ts.seconds, 0) self.assertEquals(proto_ts.nanos, 0) def test_datetime_str_to_proto_ts_conversion_empty(self): - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - proto_ts = exporter.proto_ts_from_datetime_str('') + proto_ts = utils.proto_ts_from_datetime_str('') self.assertEquals(proto_ts.seconds, 0) self.assertEquals(proto_ts.nanos, 0) def test_datetime_str_to_proto_ts_conversion_invalid(self): - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - proto_ts = exporter.proto_ts_from_datetime_str('2018 08 22 T 11:53') + proto_ts = utils.proto_ts_from_datetime_str('2018 08 22 T 11:53') self.assertEquals(proto_ts.seconds, 0) self.assertEquals(proto_ts.nanos, 0) def test_hex_str_to_proto_bytes_conversion(self): - hex_encoder = codecs.getencoder('hex') - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - proto_bytes = exporter.hex_str_to_bytes_str( + proto_bytes = utils.hex_str_to_bytes_str( '00010203040506070a0b0c0d0eff') self.assertEqual(hex_encoder(proto_bytes)[0], b'00010203040506070a0b0c0d0eff') def test_datetime_to_proto_ts_conversion_none(self): - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - proto_ts = exporter.proto_ts_from_datetime(None) + proto_ts = utils.proto_ts_from_datetime(None) self.assertEquals(proto_ts.seconds, 0) self.assertEquals(proto_ts.nanos, 0) @@ -882,136 +510,14 @@ def test_datetime_to_proto_ts_conversion(self): delta = now - datetime(1970, 1, 1) expected_seconds = int(delta.total_seconds()) expected_nanos = delta.microseconds * 1000 - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - proto_ts = exporter.proto_ts_from_datetime(now) + proto_ts = utils.proto_ts_from_datetime(now) self.assertEqual(proto_ts.seconds, int(expected_seconds)) self.assertEqual(proto_ts.nanos, expected_nanos) def test_datetime_to_proto_ts_conversion_zero(self): zero = datetime(1970, 1, 1) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - proto_ts = exporter.proto_ts_from_datetime(zero) + proto_ts = utils.proto_ts_from_datetime(zero) self.assertEqual(proto_ts.seconds, 0) self.assertEqual(proto_ts.nanos, 0) - - def test_config_generator(self): - - config = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=True)) - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - transport=MockTransport) - - config_requests = list(exporter.generate_config_request(config)) - - self.assertEqual(len(config_requests), 1) - self.assertEqual(config_requests[0].node, exporter.node) - self.assertEqual(config_requests[0].config, config) - - def config_iterate(self, *args, **kwargs): - self.config_requests = list(args[0]) - return iter(self.config_requests) - - def test_second_config_update_without_node(self): - client = mock.Mock() - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Config returns - # and it won't be possible to check if node is included. - # passed config request will be stored in self.config_requests - client.Config.side_effect = self.config_iterate - - config0 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=True)) - - config1 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=False)) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.update_config(config0) - - actual_request = self.config_requests[0] - self.assertIsNotNone(actual_request.node) - self.assertEqual(actual_request.node, exporter.node) - - exporter.update_config(config1) - - self.assertEqual(len(client.Config.mock_calls), 2) - actual_request = self.config_requests[0] - self.assertEqual(actual_request.node, - trace_service_pb2.ConfigTraceServiceRequest().node) - - def test_second_config_update_after_exception_with_node(self): - client = mock.Mock() - - config0 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=True)) - - config1 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=False)) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - client.Config.side_effect = grpc.RpcError() - with self.assertRaises(grpc.RpcError): - exporter.update_config(config0) - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Config returns - # and it won't be possible to check if node is included. - # passed config request will be stored in self.config_requests - client.Config.side_effect = self.config_iterate - - exporter.update_config(config1) - - self.assertEqual(len(client.Config.mock_calls), 2) - actual_request = self.config_requests[0] - self.assertEqual(actual_request.node, exporter.node) - - def test_update_config_return_value(self): - client = mock.Mock() - - client_config = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=True)) - - agent_config = trace_config_pb2.TraceConfig( - probability_sampler=trace_config_pb2.ProbabilitySampler( - samplingProbability=0.1)) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - client.Config.return_value = iter([agent_config]) - actual_response = exporter.update_config(client_config) - - self.assertEqual(actual_response, agent_config) - - -class MockTransport(object): - def __init__(self, exporter=None): - self.export_called = False - self.exporter = exporter - - def export(self, trace): - self.export_called = True From ebd74d9b161e552e1b7ee1174554608b927189ef Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 5 Sep 2018 12:45:20 -0700 Subject: [PATCH 6/8] Review: send node on each request for now, renmae to ocagent/trace_exporter --- .coveragerc | 4 +- .../{opencensusd => opencensus}/__init__.py | 0 .../agent/__init__.py | 0 .../agent/common/__init__.py | 0 .../agent/common/v1/__init__.py | 0 .../agent/common/v1/common_pb2.py | 0 .../agent/trace/__init__.py | 0 .../agent/trace/v1/__init__.py | 0 .../agent/trace/v1/trace_service_pb2.py | 6 +- .../agent/trace/v1/trace_service_pb2_grpc.py | 2 +- .../trace/__init__.py | 0 .../trace/v1/__init__.py | 0 .../trace/v1/trace_config_pb2.py | 0 .../trace/v1/trace_pb2.py | 0 .../__init__.py | 0 .../trace_exporter.py} | 37 ++-- .../{span_proto_exporter => ocagent}/utils.py | 6 +- .../test_trace_exporter.py} | 193 +++++------------- .../test_trace_exporter_utils.py} | 24 +-- 19 files changed, 88 insertions(+), 184 deletions(-) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/common/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/common/v1/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/common/v1/common_pb2.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/trace/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/trace/v1/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/trace/v1/trace_service_pb2.py (96%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/agent/trace/v1/trace_service_pb2_grpc.py (95%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/trace/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/trace/v1/__init__.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/trace/v1/trace_config_pb2.py (100%) rename opencensus/trace/exporters/gen/{opencensusd => opencensus}/trace/v1/trace_pb2.py (100%) rename opencensus/trace/exporters/{span_proto_exporter => ocagent}/__init__.py (100%) rename opencensus/trace/exporters/{span_proto_exporter/span_proto_exporter.py => ocagent/trace_exporter.py} (82%) rename opencensus/trace/exporters/{span_proto_exporter => ocagent}/utils.py (97%) rename tests/unit/trace/exporters/{span_proto_exporter/test_span_proto_exporter.py => ocagent/test_trace_exporter.py} (62%) rename tests/unit/trace/exporters/{span_proto_exporter/test_span_proto_exporter_utils.py => ocagent/test_trace_exporter_utils.py} (96%) diff --git a/.coveragerc b/.coveragerc index 9560a35e6..56f144748 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,7 +2,7 @@ branch = True omit = *gen/jaeger* - *gen/opencensusd* + *gen/opencensus* [report] fail_under = 100 @@ -14,4 +14,4 @@ exclude_lines = def __repr__ omit = *gen/jaeger* - *gen/opencensusd* + *gen/opencensus* diff --git a/opencensus/trace/exporters/gen/opencensusd/__init__.py b/opencensus/trace/exporters/gen/opencensus/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/__init__.py rename to opencensus/trace/exporters/gen/opencensus/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/__init__.py b/opencensus/trace/exporters/gen/opencensus/agent/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/__init__.py rename to opencensus/trace/exporters/gen/opencensus/agent/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py b/opencensus/trace/exporters/gen/opencensus/agent/common/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/common/__init__.py rename to opencensus/trace/exporters/gen/opencensus/agent/common/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py b/opencensus/trace/exporters/gen/opencensus/agent/common/v1/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/common/v1/__init__.py rename to opencensus/trace/exporters/gen/opencensus/agent/common/v1/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py b/opencensus/trace/exporters/gen/opencensus/agent/common/v1/common_pb2.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/common/v1/common_pb2.py rename to opencensus/trace/exporters/gen/opencensus/agent/common/v1/common_pb2.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py b/opencensus/trace/exporters/gen/opencensus/agent/trace/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/trace/__init__.py rename to opencensus/trace/exporters/gen/opencensus/agent/trace/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py b/opencensus/trace/exporters/gen/opencensus/agent/trace/v1/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/__init__.py rename to opencensus/trace/exporters/gen/opencensus/agent/trace/v1/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py b/opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2.py similarity index 96% rename from opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py rename to opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2.py index 7b489ec96..4b40de544 100644 --- a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2.py +++ b/opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2.py @@ -14,9 +14,9 @@ _sym_db = _symbol_database.Default() -from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import common_pb2 as opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2 -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2 -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2 +from opencensus.trace.exporters.gen.opencensus.agent.common.v1 import common_pb2 as opencensus_dot_proto_dot_agent_dot_common_dot_v1_dot_common__pb2 +from opencensus.trace.exporters.gen.opencensus.trace.v1 import trace_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__pb2 +from opencensus.trace.exporters.gen.opencensus.trace.v1 import trace_config_pb2 as opencensus_dot_proto_dot_trace_dot_v1_dot_trace__config__pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='opencensus/proto/agent/trace/v1/trace_service.proto', diff --git a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py b/opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2_grpc.py similarity index 95% rename from opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py rename to opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2_grpc.py index 63a3aadc4..a7c2cd736 100644 --- a/opencensus/trace/exporters/gen/opencensusd/agent/trace/v1/trace_service_pb2_grpc.py +++ b/opencensus/trace/exporters/gen/opencensus/agent/trace/v1/trace_service_pb2_grpc.py @@ -1,7 +1,7 @@ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc -from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 as opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2 +from opencensus.trace.exporters.gen.opencensus.agent.trace.v1 import trace_service_pb2 as opencensus_dot_proto_dot_agent_dot_trace_dot_v1_dot_trace__service__pb2 class TraceServiceStub(object): diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/__init__.py b/opencensus/trace/exporters/gen/opencensus/trace/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/trace/__init__.py rename to opencensus/trace/exporters/gen/opencensus/trace/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py b/opencensus/trace/exporters/gen/opencensus/trace/v1/__init__.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/trace/v1/__init__.py rename to opencensus/trace/exporters/gen/opencensus/trace/v1/__init__.py diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py b/opencensus/trace/exporters/gen/opencensus/trace/v1/trace_config_pb2.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_config_pb2.py rename to opencensus/trace/exporters/gen/opencensus/trace/v1/trace_config_pb2.py diff --git a/opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py b/opencensus/trace/exporters/gen/opencensus/trace/v1/trace_pb2.py similarity index 100% rename from opencensus/trace/exporters/gen/opencensusd/trace/v1/trace_pb2.py rename to opencensus/trace/exporters/gen/opencensus/trace/v1/trace_pb2.py diff --git a/opencensus/trace/exporters/span_proto_exporter/__init__.py b/opencensus/trace/exporters/ocagent/__init__.py similarity index 100% rename from opencensus/trace/exporters/span_proto_exporter/__init__.py rename to opencensus/trace/exporters/ocagent/__init__.py diff --git a/opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py b/opencensus/trace/exporters/ocagent/trace_exporter.py similarity index 82% rename from opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py rename to opencensus/trace/exporters/ocagent/trace_exporter.py index 6f32202d5..ea4db9d49 100644 --- a/opencensus/trace/exporters/span_proto_exporter/span_proto_exporter.py +++ b/opencensus/trace/exporters/ocagent/trace_exporter.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Export opencensus spans to trace proto agent""" +"""Export opencensus spans to ocagent""" import datetime import grpc @@ -20,24 +20,26 @@ import socket from threading import Lock from opencensus.trace.exporters import base -from opencensus.trace.exporters.gen.opencensusd.agent.common.v1 import ( +from opencensus.trace.exporters.gen.opencensus.agent.common.v1 import ( common_pb2 ) -from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import ( +from opencensus.trace.exporters.gen.opencensus.agent.trace.v1 import ( trace_service_pb2, trace_service_pb2_grpc ) +from opencensus.trace.exporters.ocagent import utils from opencensus.trace.exporters.transports import sync -from opencensus.trace.exporters.span_proto_exporter import utils # Default agent endpoint +# TODO: subject to change: this is not a final default endpoint! DEFAULT_ENDPOINT = 'localhost:50051' # OpenCensus Version +# TODO: https://github.com/census-instrumentation/opencensus-python/issues/296 VERSION = '0.1.6' -class SpanProtoExporter(base.Exporter): +class TraceExporter(base.Exporter): """Export the spans by sending them to opencensus agent. :type service_name: str @@ -50,7 +52,7 @@ class SpanProtoExporter(base.Exporter): :param endpoint: opencensus agent endpoint. :type client: class:`~.trace_service_pb2_grpc.TraceServiceStub` - :param client: OpenCensusD client. + :param client: TraceService client stub. :type transport: :class:`type` :param transport: Class for creating new transport objects. It should @@ -92,9 +94,6 @@ def __init__( ), service_info=common_pb2.ServiceInfo(name=service_name)) - self.send_node_in_config = True - self.send_node_in_export = True - def emit(self, span_datas): """ :type span_datas: list of :class: @@ -111,12 +110,7 @@ def emit(self, span_datas): for _ in responses: pass - # Node was successfully sent, unless there is a connectivity - # issue between app and agent, Node should not be sent again - self.send_node_in_export = False except grpc.RpcError: - self.send_node_in_export = True - self.send_node_in_config = True pass def export(self, span_datas): @@ -137,19 +131,20 @@ def generate_span_requests(self, span_datas): :type span_datas: list of :class:`~opencensus.trace.span_data.SpanData` - :param span_datas: SpanData tuples to convert to protocuf spans + :param span_datas: SpanData tuples to convert to protobuf spans and send to opensensusd agent :rtype: list of - `~gen.opencensusd.agent.trace.v1.trace_service_pb2.ExportTraceServiceRequest` + `~gen.opencensus.agent.trace.v1.trace_service_pb2.ExportTraceServiceRequest` :returns: List of span export requests. """ - pb_spans = [utils.translate_to_opencensusd( + pb_spans = [utils.translate_to_trace_proto( span_data) for span_data in span_datas] + # TODO: send node once per channel yield trace_service_pb2.ExportTraceServiceRequest( - node=self.node if self.send_node_in_export else None, + node=self.node, spans=pb_spans) # TODO: better support for receiving config updates @@ -171,11 +166,8 @@ def update_config(self, config): self.generate_config_request(config)) agent_config = next(config_responses) - self.send_node_in_config = False return agent_config except grpc.RpcError as e: - self.send_node_in_config = True - self.send_node_in_export = True raise e def generate_config_request(self, config): @@ -189,8 +181,9 @@ def generate_config_request(self, config): :returns: List of config requests. """ + # TODO: send node once per channel request = trace_service_pb2.ConfigTraceServiceRequest( - node=self.node if self.send_node_in_config else None, + node=self.node, config=config) yield request diff --git a/opencensus/trace/exporters/span_proto_exporter/utils.py b/opencensus/trace/exporters/ocagent/utils.py similarity index 97% rename from opencensus/trace/exporters/span_proto_exporter/utils.py rename to opencensus/trace/exporters/ocagent/utils.py index 63064fc46..750f6f2ff 100644 --- a/opencensus/trace/exporters/span_proto_exporter/utils.py +++ b/opencensus/trace/exporters/ocagent/utils.py @@ -17,11 +17,11 @@ from google.protobuf.internal.well_known_types import ParseError from google.protobuf.timestamp_pb2 import Timestamp from google.protobuf.wrappers_pb2 import BoolValue, UInt32Value -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 +from opencensus.trace.exporters.gen.opencensus.trace.v1 import trace_pb2 -def translate_to_opencensusd(span_data): - """Translates the opencensus spans to OpenCensusD spans. +def translate_to_trace_proto(span_data): + """Translates the opencensus spans to ocagent proto spans. :type span_data: :class:`~opencensus.trace.span_data.SpanData` :param span_data: SpanData tuples to convert to protobuf spans diff --git a/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py b/tests/unit/trace/exporters/ocagent/test_trace_exporter.py similarity index 62% rename from tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py rename to tests/unit/trace/exporters/ocagent/test_trace_exporter.py index efee6a18f..f411e7dae 100644 --- a/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter.py +++ b/tests/unit/trace/exporters/ocagent/test_trace_exporter.py @@ -23,25 +23,25 @@ from opencensus.trace import span_context as span_context_module from opencensus.trace import span_data as span_data_module -from opencensus.trace.exporters.span_proto_exporter import span_proto_exporter -from opencensus.trace.exporters.gen.opencensusd.agent.trace.v1 import trace_service_pb2 -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_config_pb2 +from opencensus.trace.exporters.ocagent.trace_exporter import TraceExporter +from opencensus.trace.exporters.gen.opencensus.agent.trace.v1 import trace_service_pb2 +from opencensus.trace.exporters.gen.opencensus.trace.v1 import trace_config_pb2 SERVICE_NAME = 'my-service' -class TestSpanProtoExporter(unittest.TestCase): +class TestTraceExporter(unittest.TestCase): def test_constructor(self): - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME) self.assertEqual(exporter.endpoint, 'localhost:50051') def test_constructor_with_endpoint(self): expected_endpoint = '0.0.0.0:50000' - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, endpoint=expected_endpoint) @@ -49,7 +49,7 @@ def test_constructor_with_endpoint(self): def test_constructor_with_client(self): client = mock.Mock() - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -57,7 +57,7 @@ def test_constructor_with_client(self): self.assertEqual(exporter.client, client) def test_constructor_node_host(self): - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, host_name='my host') @@ -72,7 +72,7 @@ def test_constructor_node_host(self): self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) def test_constructor_node(self): - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME) self.assertEqual(exporter.node.service_info.name, SERVICE_NAME) @@ -87,7 +87,7 @@ def test_constructor_node(self): self.assertGreater(exporter.node.identifier.start_timestamp.seconds, 0) def test_export(self): - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, transport=MockTransport) exporter.export({}) @@ -96,8 +96,8 @@ def test_export(self): def test_emit(self): client = mock.Mock() - client.Export.return_value = [1] - exporter = span_proto_exporter.SpanProtoExporter( + client.Export.return_value = iter([1]) + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -109,7 +109,7 @@ def test_emit(self): def test_emit_throw(self): client = mock.Mock() client.Export.side_effect = grpc.RpcError() - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) @@ -161,7 +161,7 @@ def test_span_generator(self): span_kind=0) ] - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, transport=MockTransport) export_requests = list(exporter.generate_span_requests(span_datas)) @@ -181,60 +181,10 @@ def test_span_generator(self): self.assertEqual(hex_encoder(export_requests[0].spans[1].span_id)[ 0], b'1e0c63257de34c92') - def test_basic_span_emit(self): + def test_basic_spans_emit(self): hex_encoder = codecs.getencoder('hex') client = mock.Mock() - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included. - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate - - span_data = span_data_module.SpanData( - name="name", - context=span_context_module.SpanContext( - trace_id='6e0c63257de34c92bf9efcd03927272e'), - span_id='6e0c63257de34c92', - parent_span_id=None, - start_time=None, - end_time=None, - attributes=None, - child_span_count=None, - stack_trace=None, - time_events=None, - links=None, - status=None, - same_process_as_parent_span=None, - span_kind=0) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.emit([span_data]) - - self.assertTrue(client.Export.called) - - actual_request = self.export_requests[0] - self.assertEqual(actual_request.node, exporter.node) - - pb_span = actual_request.spans[0] - - self.assertEqual(pb_span.name.value, "name") - self.assertEqual(hex_encoder(pb_span.trace_id)[ - 0], b'6e0c63257de34c92bf9efcd03927272e') - self.assertEqual(hex_encoder(pb_span.span_id)[0], b'6e0c63257de34c92') - - def test_second_span_emit_without_node(self): - client = mock.Mock() - - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate + client.Export.return_value = iter([1]) span_data0 = span_data_module.SpanData( name="name0", @@ -270,28 +220,37 @@ def test_second_span_emit_without_node(self): same_process_as_parent_span=None, span_kind=0) - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) exporter.emit([span_data0]) - actual_request = self.export_requests[0] - self.assertIsNotNone(actual_request.node) - self.assertEqual(actual_request.node, exporter.node) + actual_request0 = list(client.Export.call_args[0][0])[0] + self.assertEqual(actual_request0.node, exporter.node) + + pb_span0 = actual_request0.spans[0] + self.assertEqual(pb_span0.name.value, "name0") + self.assertEqual(hex_encoder(pb_span0.trace_id)[ + 0], b'0e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span0.span_id)[0], b'0e0c63257de34c92') exporter.emit([span_data1]) self.assertEqual(len(client.Export.mock_calls), 2) - actual_request = self.export_requests[0] - self.assertEqual(actual_request.node, - trace_service_pb2.ExportTraceServiceRequest().node) + actual_request1 = list(client.Export.call_args[0][0])[0] + self.assertEqual(actual_request1.node, exporter.node) + pb_span1 = actual_request1.spans[0] + self.assertEqual(pb_span1.name.value, "name1") + self.assertEqual(hex_encoder(pb_span1.trace_id)[ + 0], b'1e0c63257de34c92bf9efcd03927272e') + self.assertEqual(hex_encoder(pb_span1.span_id)[0], b'1e0c63257de34c92') - def test_second_span_emit_after_exception_with_node(self): + def test_span_emit_exception(self): client = mock.Mock() - span_data0 = span_data_module.SpanData( + span_data = span_data_module.SpanData( name="name0", context=span_context_module.SpanContext( trace_id='0e0c63257de34c92bf9efcd03927272e'), @@ -308,24 +267,22 @@ def test_second_span_emit_after_exception_with_node(self): same_process_as_parent_span=None, span_kind=0) - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) client.Export.side_effect = grpc.RpcError() - exporter.emit([span_data0]) - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Export returns - # and it won't be possible to check if node is included - # passed export request will be stored in self.export_requests - client.Export.side_effect = self.export_iterate + # does not throw: + exporter.emit([span_data]) + + client.Export.return_value = iter([1]) - exporter.emit([span_data0]) + exporter.emit([span_data]) self.assertEqual(len(client.Export.mock_calls), 2) - actual_request = self.export_requests[0] + actual_request = list(client.Export.call_args[0][0])[0] self.assertEqual(actual_request.node, exporter.node) def test_config_generator(self): @@ -333,85 +290,39 @@ def test_config_generator(self): config = trace_config_pb2.TraceConfig( constant_sampler=trace_config_pb2.ConstantSampler( decision=True)) - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, transport=MockTransport) - config_requests = list(exporter.generate_config_request(config)) + config_requests = list(exporter.generate_config_request( + config)) self.assertEqual(len(config_requests), 1) self.assertEqual(config_requests[0].node, exporter.node) self.assertEqual(config_requests[0].config, config) - def config_iterate(self, *args, **kwargs): - self.config_requests = list(args[0]) - return iter(self.config_requests) - - def test_second_config_update_without_node(self): + def test_config_update_exception(self): client = mock.Mock() - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Config returns - # and it won't be possible to check if node is included. - # passed config request will be stored in self.config_requests - client.Config.side_effect = self.config_iterate - - config0 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=True)) - - config1 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=False)) - - exporter = span_proto_exporter.SpanProtoExporter( - service_name=SERVICE_NAME, - client=client, - transport=MockTransport) - - exporter.update_config(config0) - - actual_request = self.config_requests[0] - self.assertIsNotNone(actual_request.node) - self.assertEqual(actual_request.node, exporter.node) - - exporter.update_config(config1) - - self.assertEqual(len(client.Config.mock_calls), 2) - actual_request = self.config_requests[0] - self.assertEqual(actual_request.node, - trace_service_pb2.ConfigTraceServiceRequest().node) - - def test_second_config_update_after_exception_with_node(self): - client = mock.Mock() - - config0 = trace_config_pb2.TraceConfig( + config = trace_config_pb2.TraceConfig( constant_sampler=trace_config_pb2.ConstantSampler( decision=True)) - config1 = trace_config_pb2.TraceConfig( - constant_sampler=trace_config_pb2.ConstantSampler( - decision=False)) - - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) client.Config.side_effect = grpc.RpcError() with self.assertRaises(grpc.RpcError): - exporter.update_config(config0) + exporter.update_config(config) - # we need to make exporter iterate over passed generator, - # otherwise iteration will happen after Config returns - # and it won't be possible to check if node is included. - # passed config request will be stored in self.config_requests - client.Config.side_effect = self.config_iterate + client.Config.side_effect = lambda config: iter([config]) - exporter.update_config(config1) + exporter.update_config(config) self.assertEqual(len(client.Config.mock_calls), 2) - actual_request = self.config_requests[0] + actual_request = list(client.Config.call_args[0][0])[0] self.assertEqual(actual_request.node, exporter.node) def test_update_config_return_value(self): @@ -425,7 +336,7 @@ def test_update_config_return_value(self): probability_sampler=trace_config_pb2.ProbabilitySampler( samplingProbability=0.1)) - exporter = span_proto_exporter.SpanProtoExporter( + exporter = TraceExporter( service_name=SERVICE_NAME, client=client, transport=MockTransport) diff --git a/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py b/tests/unit/trace/exporters/ocagent/test_trace_exporter_utils.py similarity index 96% rename from tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py rename to tests/unit/trace/exporters/ocagent/test_trace_exporter_utils.py index bb588e1a6..91f1a2787 100644 --- a/tests/unit/trace/exporters/span_proto_exporter/test_span_proto_exporter_utils.py +++ b/tests/unit/trace/exporters/ocagent/test_trace_exporter_utils.py @@ -27,11 +27,11 @@ from opencensus.trace import status as status_module from opencensus.trace import time_event as time_event_module from opencensus.trace import tracestate as tracestate_module -from opencensus.trace.exporters.span_proto_exporter import utils -from opencensus.trace.exporters.gen.opencensusd.trace.v1 import trace_pb2 +from opencensus.trace.exporters.ocagent import utils +from opencensus.trace.exporters.gen.opencensus.trace.v1 import trace_pb2 -class TestSpanProtoExporterUtils(unittest.TestCase): +class TestTraceExporterUtils(unittest.TestCase): def test_basic_span_translation(self): hex_encoder = codecs.getencoder('hex') @@ -53,7 +53,7 @@ def test_basic_span_translation(self): same_process_as_parent_span=None, span_kind=0) - pb_span = utils.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_trace_proto(span_data) self.assertEqual(pb_span.name.value, "name") self.assertEqual(hex_encoder(pb_span.trace_id)[ @@ -88,7 +88,7 @@ def test_basic_span_translation(self): self.assertEqual(len(pb_span.tracestate.entries), 0) def test_translate_none_span(self): - pb_span = utils.translate_to_opencensusd(None) + pb_span = utils.translate_to_trace_proto(None) self.assertIsNone(pb_span) @@ -110,7 +110,7 @@ def test_translate_client_span_kind(self): links=None, status=None) - pb_span = utils.translate_to_opencensusd(client_span_data) + pb_span = utils.translate_to_trace_proto(client_span_data) self.assertEqual(pb_span.kind, 2) self.assertEqual(pb_span.same_process_as_parent_span.value, True) @@ -133,7 +133,7 @@ def test_translate_server_span_kindt(self): links=None, status=None) - pb_span = utils.translate_to_opencensusd(server_span_data) + pb_span = utils.translate_to_trace_proto(server_span_data) self.assertEqual(pb_span.kind, 1) self.assertEqual(pb_span.child_span_count.value, 1) @@ -157,7 +157,7 @@ def test_translate_status(self): time_events=None, links=None) - pb_span = utils.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_trace_proto(span_data) self.assertEqual(pb_span.status.code, 2) self.assertEqual(pb_span.status.message, 'ERR') @@ -194,7 +194,7 @@ def test_translate_links(self): stack_trace=None, time_events=None) - pb_span = utils.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_trace_proto(span_data) self.assertEqual(len(pb_span.links.link), 3) self.assertEqual(hex_encoder(pb_span.links.link[0].trace_id)[ @@ -283,7 +283,7 @@ def test_translate_time_events(self): stack_trace=None, links=None) - pb_span = utils.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_trace_proto(span_data) self.assertEqual(len(pb_span.time_events.time_event), 5) @@ -350,7 +350,7 @@ def test_translate_time_events_invalid(self): stack_trace=None, links=None) - pb_span = utils.translate_to_opencensusd(span_data) + pb_span = utils.translate_to_trace_proto(span_data) self.assertEqual(len(pb_span.time_events.time_event), 0) @@ -378,7 +378,7 @@ def test_translate_tracestate(self): links=None, status=None) - pb_span = utils.translate_to_opencensusd(client_span_data) + pb_span = utils.translate_to_trace_proto(client_span_data) self.assertEqual(len(pb_span.tracestate.entries), 3) self.assertEqual(pb_span.tracestate.entries[0].key, "k1") From e742aaa623ac18e039f716fe310e7fa92c0826ef Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 6 Sep 2018 09:38:35 -0700 Subject: [PATCH 7/8] add TODO to keep stream alive --- opencensus/trace/exporters/ocagent/trace_exporter.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/opencensus/trace/exporters/ocagent/trace_exporter.py b/opencensus/trace/exporters/ocagent/trace_exporter.py index ea4db9d49..3de6c0542 100644 --- a/opencensus/trace/exporters/ocagent/trace_exporter.py +++ b/opencensus/trace/exporters/ocagent/trace_exporter.py @@ -103,6 +103,11 @@ def emit(self, span_datas): """ try: + + # TODO: keep the stream alive. + # The stream is terminated after iteration completes. + # To keep it alive, we can enqueue proto spans here + # and asyncronously read them and send to the agent. responses = self.client.Export( self.generate_span_requests(span_datas)) @@ -162,6 +167,10 @@ def update_config(self, config): lock = Lock() with lock: try: + # TODO: keep the stream alive. + # The stream is terminated after iteration completes. + # To keep it alive, we can enqueue proto configs here + # and asyncronously read them and send to the agent. config_responses = self.client.Config( self.generate_config_request(config)) From 78845325969e45b94b60490879514fc2ad0292ee Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 6 Sep 2018 13:50:13 -0700 Subject: [PATCH 8/8] disable lint checks on proto-generated files --- nox.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nox.py b/nox.py index c1dd98b45..6a1618db9 100644 --- a/nox.py +++ b/nox.py @@ -83,7 +83,10 @@ def lint(session): session.interpreter = 'python3.6' session.install('flake8') session.install('.') - session.run('flake8', 'opencensus/') + session.run( + 'flake8', + '--exclude=opencensus/trace/exporters/gen/opencensus/', + 'opencensus/') @nox.session @@ -124,4 +127,3 @@ def docs(session): # Build the docs! session.run( 'bash', os.path.join('.', 'scripts', 'update_docs.sh')) -