Skip to content

Commit

Permalink
Add max_attr_value_length support to Jaeger exporter
Browse files Browse the repository at this point in the history
This commit adds ability to specifiy maximum length for string
attributes to the Jaeger exporter. This is similar to how Zipkin
exporter supports `max_tag_value_length`.
  • Loading branch information
owais committed Feb 24, 2021
1 parent 99128b3 commit 27619b5
Show file tree
Hide file tree
Showing 7 changed files with 630 additions and 403 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
# insecure=True, # optional
# credentials=xxx # optional channel creds
# transport_format='protobuf' # optional
# max_attr_value_length=None # optional
)
# Create a BatchExportSpanProcessor and add the exporter to it
Expand Down Expand Up @@ -120,6 +121,7 @@ class JaegerSpanExporter(SpanExporter):
insecure: True if collector has no encryption or authentication
credentials: Credentials for server authentication.
transport_format: Transport format for exporting spans to collector.
max_attr_value_length: Max length string attribute values can have. Set to None to disable.
"""

def __init__(
Expand All @@ -133,8 +135,10 @@ def __init__(
insecure: Optional[bool] = None,
credentials: Optional[ChannelCredentials] = None,
transport_format: Optional[str] = None,
max_attr_value_length: Optional[int] = None,
):
self.service_name = service_name
self._max_attr_value_length = max_attr_value_length
self.agent_host_name = _parameter_setter(
param=agent_host_name,
env_variable=environ.get(OTEL_EXPORTER_JAEGER_AGENT_HOST),
Expand Down Expand Up @@ -220,13 +224,15 @@ def _collector_http_client(self) -> Optional[Collector]:
def export(self, spans) -> SpanExportResult:
translator = Translate(spans)
if self.transport_format == TRANSPORT_FORMAT_PROTOBUF:
pb_translator = ProtobufTranslator(self.service_name)
pb_translator = ProtobufTranslator(
self.service_name, self._max_attr_value_length
)
jaeger_spans = translator._translate(pb_translator)
batch = model_pb2.Batch(spans=jaeger_spans)
request = PostSpansRequest(batch=batch)
self._collector_grpc_client.PostSpans(request)
else:
thrift_translator = ThriftTranslator()
thrift_translator = ThriftTranslator(self._max_attr_value_length)
jaeger_spans = translator._translate(thrift_translator)
batch = jaeger_thrift.Batch(
spans=jaeger_spans,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import abc
from typing import Optional

from opentelemetry.trace import SpanKind

Expand Down Expand Up @@ -41,6 +42,9 @@ def _convert_int_to_i64(val):


class Translator(abc.ABC):
def __init__(self, max_attr_value_length: Optional[int] = None):
self._max_attr_value_length = max_attr_value_length

@abc.abstractmethod
def _translate_span(self, span):
"""Translates span to jaeger format.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,24 +76,31 @@ def _get_binary_key_value(key: str, value: bytes) -> model_pb2.KeyValue:


def _translate_attribute(
key: str, value: types.AttributeValue
key: str, value: types.AttributeValue, max_length: Optional[int]
) -> Optional[model_pb2.KeyValue]:
"""Convert the attributes to jaeger keyvalues."""
translated = None
if isinstance(value, bool):
translated = _get_bool_key_value(key, value)
elif isinstance(value, str):
if max_length is not None:
value = value[:max_length]
translated = _get_string_key_value(key, value)
elif isinstance(value, int):
translated = _get_long_key_value(key, value)
elif isinstance(value, float):
translated = _get_double_key_value(key, value)
elif isinstance(value, tuple):
translated = _get_string_key_value(key, str(value))
value = str(value)
if max_length is not None:
value = value[:max_length]
translated = _get_string_key_value(key, value)
return translated


def _extract_resource_tags(span: ReadableSpan) -> Sequence[model_pb2.KeyValue]:
def _extract_resource_tags(
span: ReadableSpan, max_attr_value_length: Optional[int]
) -> Sequence[model_pb2.KeyValue]:
"""Extracts resource attributes from span and returns
list of jaeger keyvalues.
Expand All @@ -102,7 +109,7 @@ def _extract_resource_tags(span: ReadableSpan) -> Sequence[model_pb2.KeyValue]:
"""
tags = []
for key, value in span.resource.attributes.items():
tag = _translate_attribute(key, value)
tag = _translate_attribute(key, value, max_attr_value_length)
if tag:
tags.append(tag)
return tags
Expand Down Expand Up @@ -140,7 +147,10 @@ def _proto_timestamp_from_epoch_nanos(nsec: int) -> Timestamp:


class ProtobufTranslator(Translator):
def __init__(self, svc_name):
def __init__(
self, svc_name: str, max_attr_value_length: Optional[int] = None
):
super().__init__(max_attr_value_length)
self.svc_name = svc_name

def _translate_span(self, span: ReadableSpan) -> model_pb2.Span:
Expand All @@ -161,7 +171,8 @@ def _translate_span(self, span: ReadableSpan) -> model_pb2.Span:
flags = int(ctx.trace_flags)

process = model_pb2.Process(
service_name=self.svc_name, tags=_extract_resource_tags(span)
service_name=self.svc_name,
tags=_extract_resource_tags(span, self.max_attr_value_length),
)
jaeger_span = model_pb2.Span(
trace_id=trace_id,
Expand All @@ -183,12 +194,16 @@ def _extract_tags(
translated = []
if span.attributes:
for key, value in span.attributes.items():
key_value = _translate_attribute(key, value)
key_value = _translate_attribute(
key, value, self._max_attr_value_length
)
if key_value is not None:
translated.append(key_value)
if span.resource.attributes:
for key, value in span.resource.attributes.items():
key_value = _translate_attribute(key, value)
key_value = _translate_attribute(
key, value, self._max_attr_value_length
)
if key_value:
translated.append(key_value)

Expand Down Expand Up @@ -256,7 +271,9 @@ def _extract_logs(
for event in span.events:
fields = []
for key, value in event.attributes.items():
tag = _translate_attribute(key, value)
tag = _translate_attribute(
key, value, self._max_attr_value_length
)
if tag:
fields.append(tag)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,24 @@ def _get_trace_id_high(trace_id):


def _translate_attribute(
key: str, value: types.AttributeValue
key: str, value: types.AttributeValue, max_length: Optional[int]
) -> Optional[TCollector.Tag]:
"""Convert the attributes to jaeger tags."""
if isinstance(value, bool):
return _get_bool_tag(key, value)
if isinstance(value, str):
if max_length is not None:
value = value[:max_length]
return _get_string_tag(key, value)
if isinstance(value, int):
return _get_long_tag(key, value)
if isinstance(value, float):
return _get_double_tag(key, value)
if isinstance(value, tuple):
return _get_string_tag(key, str(value))
value = str(value)
if max_length is not None:
value = value[:max_length]
return _get_string_tag(key, value)
return None


Expand Down Expand Up @@ -111,12 +116,16 @@ def _extract_tags(self, span: ReadableSpan) -> Sequence[TCollector.Tag]:
translated = []
if span.attributes:
for key, value in span.attributes.items():
tag = _translate_attribute(key, value)
tag = _translate_attribute(
key, value, self._max_attr_value_length
)
if tag:
translated.append(tag)
if span.resource.attributes:
for key, value in span.resource.attributes.items():
tag = _translate_attribute(key, value)
tag = _translate_attribute(
key, value, self._max_attr_value_length
)
if tag:
translated.append(tag)

Expand Down Expand Up @@ -185,7 +194,9 @@ def _extract_logs(
for event in span.events:
fields = []
for key, value in event.attributes.items():
tag = _translate_attribute(key, value)
tag = _translate_attribute(
key, value, self._max_attr_value_length
)
if tag:
fields.append(tag)

Expand Down
Loading

0 comments on commit 27619b5

Please sign in to comment.