Skip to content

Commit 22715dd

Browse files
authored
[EXPORTER] Add bytes support for OTLP recordables (#3495)
1 parent 7059f73 commit 22715dd

File tree

8 files changed

+194
-43
lines changed

8 files changed

+194
-43
lines changed

api/include/opentelemetry/common/attribute_value.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ namespace common
2424
/// - Homogenous arrays of primitive type values.
2525
///
2626
/// \warning The OpenTelemetry C++ API does not support the following attribute:
27-
/// uint64_t, nostd::span<const uint64_t>, and nostd::span<uint8_t> types.
27+
/// uint64_t, nostd::span<const uint64_t>, and nostd::span<const uint8_t> types.
2828
/// \parblock The OpenTelemetry C++ API currently supports several attribute
2929
/// value types that are not covered by the OpenTelemetry specification:
3030
/// - \c uint64_t
3131
/// - \c nostd::span<const uint64_t>
32-
/// - \c nostd::span<uint8_t>
32+
/// - \c nostd::span<const uint8_t>
3333
///
3434
/// Those types are reserved for future use and currently should not be
3535
/// used. There are no guarantees around how those values are handled by
@@ -55,8 +55,6 @@ using AttributeValue =
5555
// Not currently supported by the specification, but reserved for future use.
5656
// Added to provide support for all primitive C++ types.
5757
nostd::span<const uint64_t>,
58-
// Not currently supported by the specification, but reserved for future use.
59-
// See https://github.com/open-telemetry/opentelemetry-specification/issues/780
6058
nostd::span<const uint8_t>>;
6159

6260
enum AttributeType

exporters/otlp/include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,22 @@ class OtlpPopulateAttributeUtils
5656
&instrumentation_scope) noexcept;
5757

5858
static void PopulateAnyValue(opentelemetry::proto::common::v1::AnyValue *proto_value,
59-
const opentelemetry::common::AttributeValue &value) noexcept;
59+
const opentelemetry::common::AttributeValue &value,
60+
bool allow_bytes) noexcept;
6061

61-
static void PopulateAnyValue(
62-
opentelemetry::proto::common::v1::AnyValue *proto_value,
63-
const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept;
62+
static void PopulateAnyValue(opentelemetry::proto::common::v1::AnyValue *proto_value,
63+
const opentelemetry::sdk::common::OwnedAttributeValue &value,
64+
bool allow_bytes) noexcept;
6465

6566
static void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute,
6667
nostd::string_view key,
67-
const opentelemetry::common::AttributeValue &value) noexcept;
68+
const opentelemetry::common::AttributeValue &value,
69+
bool allow_bytes) noexcept;
6870

69-
static void PopulateAttribute(
70-
opentelemetry::proto::common::v1::KeyValue *attribute,
71-
nostd::string_view key,
72-
const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept;
71+
static void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute,
72+
nostd::string_view key,
73+
const opentelemetry::sdk::common::OwnedAttributeValue &value,
74+
bool allow_bytes) noexcept;
7375
};
7476

7577
} // namespace otlp

exporters/otlp/src/otlp_log_recordable.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ void OtlpLogRecordable::SetSeverity(opentelemetry::logs::Severity severity) noex
194194

195195
void OtlpLogRecordable::SetBody(const opentelemetry::common::AttributeValue &message) noexcept
196196
{
197-
OtlpPopulateAttributeUtils::PopulateAnyValue(proto_record_.mutable_body(), message);
197+
OtlpPopulateAttributeUtils::PopulateAnyValue(proto_record_.mutable_body(), message, true);
198198
}
199199

200200
void OtlpLogRecordable::SetEventId(int64_t /* id */, nostd::string_view event_name) noexcept
@@ -236,7 +236,7 @@ void OtlpLogRecordable::SetTraceFlags(const opentelemetry::trace::TraceFlags &tr
236236
void OtlpLogRecordable::SetAttribute(opentelemetry::nostd::string_view key,
237237
const opentelemetry::common::AttributeValue &value) noexcept
238238
{
239-
OtlpPopulateAttributeUtils::PopulateAttribute(proto_record_.add_attributes(), key, value);
239+
OtlpPopulateAttributeUtils::PopulateAttribute(proto_record_.add_attributes(), key, value, true);
240240
}
241241

242242
void OtlpLogRecordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept

exporters/otlp/src/otlp_metric_utils.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ void OtlpMetricUtils::ConvertSumMetric(const metric_sdk::MetricData &metric_data
108108
for (auto &kv_attr : point_data_with_attributes.attributes)
109109
{
110110
OtlpPopulateAttributeUtils::PopulateAttribute(proto_sum_point_data->add_attributes(),
111-
kv_attr.first, kv_attr.second);
111+
kv_attr.first, kv_attr.second, false);
112112
}
113113
}
114114
}
@@ -180,7 +180,7 @@ void OtlpMetricUtils::ConvertHistogramMetric(
180180
for (auto &kv_attr : point_data_with_attributes.attributes)
181181
{
182182
OtlpPopulateAttributeUtils::PopulateAttribute(proto_histogram_point_data->add_attributes(),
183-
kv_attr.first, kv_attr.second);
183+
kv_attr.first, kv_attr.second, false);
184184
}
185185
}
186186
}
@@ -244,7 +244,7 @@ void OtlpMetricUtils::ConvertExponentialHistogramMetric(
244244
for (auto &kv_attr : point_data_with_attributes.attributes)
245245
{
246246
OtlpPopulateAttributeUtils::PopulateAttribute(proto_histogram_point_data->add_attributes(),
247-
kv_attr.first, kv_attr.second);
247+
kv_attr.first, kv_attr.second, false);
248248
}
249249
}
250250
}
@@ -274,7 +274,7 @@ void OtlpMetricUtils::ConvertGaugeMetric(const opentelemetry::sdk::metrics::Metr
274274
for (auto &kv_attr : point_data_with_attributes.attributes)
275275
{
276276
OtlpPopulateAttributeUtils::PopulateAttribute(proto_gauge_point_data->add_attributes(),
277-
kv_attr.first, kv_attr.second);
277+
kv_attr.first, kv_attr.second, false);
278278
}
279279
}
280280
}

exporters/otlp/src/otlp_populate_attribute_utils.cc

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const int kOwnedAttributeValueSize = 15;
4040

4141
void OtlpPopulateAttributeUtils::PopulateAnyValue(
4242
opentelemetry::proto::common::v1::AnyValue *proto_value,
43-
const opentelemetry::common::AttributeValue &value) noexcept
43+
const opentelemetry::common::AttributeValue &value,
44+
bool allow_bytes) noexcept
4445
{
4546
if (nullptr == proto_value)
4647
{
@@ -89,10 +90,19 @@ void OtlpPopulateAttributeUtils::PopulateAnyValue(
8990
}
9091
else if (nostd::holds_alternative<nostd::span<const uint8_t>>(value))
9192
{
92-
auto array_value = proto_value->mutable_array_value();
93-
for (const auto &val : nostd::get<nostd::span<const uint8_t>>(value))
93+
if (allow_bytes)
9494
{
95-
array_value->add_values()->set_int_value(val);
95+
proto_value->set_bytes_value(
96+
reinterpret_cast<const void *>(nostd::get<nostd::span<const uint8_t>>(value).data()),
97+
nostd::get<nostd::span<const uint8_t>>(value).size());
98+
}
99+
else
100+
{
101+
auto array_value = proto_value->mutable_array_value();
102+
for (const auto &val : nostd::get<nostd::span<const uint8_t>>(value))
103+
{
104+
array_value->add_values()->set_int_value(val);
105+
}
96106
}
97107
}
98108
else if (nostd::holds_alternative<nostd::span<const bool>>(value))
@@ -156,7 +166,8 @@ void OtlpPopulateAttributeUtils::PopulateAnyValue(
156166

157167
void OtlpPopulateAttributeUtils::PopulateAnyValue(
158168
opentelemetry::proto::common::v1::AnyValue *proto_value,
159-
const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept
169+
const opentelemetry::sdk::common::OwnedAttributeValue &value,
170+
bool allow_bytes) noexcept
160171
{
161172
if (nullptr == proto_value)
162173
{
@@ -194,6 +205,23 @@ void OtlpPopulateAttributeUtils::PopulateAnyValue(
194205
{
195206
proto_value->set_double_value(nostd::get<double>(value));
196207
}
208+
else if (nostd::holds_alternative<std::vector<uint8_t>>(value))
209+
{
210+
if (allow_bytes)
211+
{
212+
const std::vector<uint8_t> &byte_array = nostd::get<std::vector<uint8_t>>(value);
213+
proto_value->set_bytes_value(reinterpret_cast<const void *>(byte_array.data()),
214+
byte_array.size());
215+
}
216+
else
217+
{
218+
auto array_value = proto_value->mutable_array_value();
219+
for (const auto &val : nostd::get<std::vector<uint8_t>>(value))
220+
{
221+
array_value->add_values()->set_int_value(val);
222+
}
223+
}
224+
}
197225
else if (nostd::holds_alternative<std::string>(value))
198226
{
199227
proto_value->set_string_value(nostd::get<std::string>(value));
@@ -261,7 +289,8 @@ void OtlpPopulateAttributeUtils::PopulateAnyValue(
261289
void OtlpPopulateAttributeUtils::PopulateAttribute(
262290
opentelemetry::proto::common::v1::KeyValue *attribute,
263291
nostd::string_view key,
264-
const opentelemetry::common::AttributeValue &value) noexcept
292+
const opentelemetry::common::AttributeValue &value,
293+
bool allow_bytes) noexcept
265294
{
266295
if (nullptr == attribute)
267296
{
@@ -275,14 +304,15 @@ void OtlpPopulateAttributeUtils::PopulateAttribute(
275304
"AttributeValue contains unknown type");
276305

277306
attribute->set_key(key.data(), key.size());
278-
PopulateAnyValue(attribute->mutable_value(), value);
307+
PopulateAnyValue(attribute->mutable_value(), value, allow_bytes);
279308
}
280309

281310
/** Maps from C++ attribute into OTLP proto attribute. */
282311
void OtlpPopulateAttributeUtils::PopulateAttribute(
283312
opentelemetry::proto::common::v1::KeyValue *attribute,
284313
nostd::string_view key,
285-
const opentelemetry::sdk::common::OwnedAttributeValue &value) noexcept
314+
const opentelemetry::sdk::common::OwnedAttributeValue &value,
315+
bool allow_bytes) noexcept
286316
{
287317
if (nullptr == attribute)
288318
{
@@ -296,7 +326,7 @@ void OtlpPopulateAttributeUtils::PopulateAttribute(
296326
"OwnedAttributeValue contains unknown type");
297327

298328
attribute->set_key(key.data(), key.size());
299-
PopulateAnyValue(attribute->mutable_value(), value);
329+
PopulateAnyValue(attribute->mutable_value(), value, allow_bytes);
300330
}
301331

302332
void OtlpPopulateAttributeUtils::PopulateAttribute(
@@ -310,7 +340,8 @@ void OtlpPopulateAttributeUtils::PopulateAttribute(
310340

311341
for (const auto &kv : resource.GetAttributes())
312342
{
313-
OtlpPopulateAttributeUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second);
343+
OtlpPopulateAttributeUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second,
344+
false);
314345
}
315346
}
316347

@@ -321,7 +352,8 @@ void OtlpPopulateAttributeUtils::PopulateAttribute(
321352
{
322353
for (const auto &kv : instrumentation_scope.GetAttributes())
323354
{
324-
OtlpPopulateAttributeUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second);
355+
OtlpPopulateAttributeUtils::PopulateAttribute(proto->add_attributes(), kv.first, kv.second,
356+
false);
325357
}
326358
}
327359

exporters/otlp/src/otlp_recordable.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void OtlpRecordable::SetAttribute(nostd::string_view key,
121121
const common::AttributeValue &value) noexcept
122122
{
123123
auto *attribute = span_.add_attributes();
124-
OtlpPopulateAttributeUtils::PopulateAttribute(attribute, key, value);
124+
OtlpPopulateAttributeUtils::PopulateAttribute(attribute, key, value, false);
125125
}
126126

127127
void OtlpRecordable::AddEvent(nostd::string_view name,
@@ -133,7 +133,7 @@ void OtlpRecordable::AddEvent(nostd::string_view name,
133133
event->set_time_unix_nano(timestamp.time_since_epoch().count());
134134

135135
attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept {
136-
OtlpPopulateAttributeUtils::PopulateAttribute(event->add_attributes(), key, value);
136+
OtlpPopulateAttributeUtils::PopulateAttribute(event->add_attributes(), key, value, false);
137137
return true;
138138
});
139139
}
@@ -148,7 +148,7 @@ void OtlpRecordable::AddLink(const trace::SpanContext &span_context,
148148
trace::SpanId::kSize);
149149
link->set_trace_state(span_context.trace_state()->ToHeader());
150150
attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept {
151-
OtlpPopulateAttributeUtils::PopulateAttribute(link->add_attributes(), key, value);
151+
OtlpPopulateAttributeUtils::PopulateAttribute(link->add_attributes(), key, value, false);
152152
return true;
153153
});
154154
}

exporters/otlp/test/otlp_log_recordable_test.cc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <gtest/gtest.h>
55
#include <stdint.h>
66
#include <chrono>
7+
#include <cstring>
78
#include <string>
89
#include <utility>
910

@@ -73,6 +74,16 @@ TEST(OtlpLogRecordable, Basic)
7374
EXPECT_EQ(rec.log_record().body().string_value(), name);
7475
EXPECT_EQ(rec.log_record().trace_id(), expected_trace_id_bytes);
7576
EXPECT_EQ(rec.log_record().span_id(), expected_span_id_bytes);
77+
78+
// Test bytes body
79+
uint8_t byte_arr[] = {'T', 'e', '\0', 's', 't'};
80+
common::AttributeValue byte_val(
81+
nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>(byte_arr), 5});
82+
rec.SetBody(byte_val);
83+
EXPECT_TRUE(0 ==
84+
memcmp(reinterpret_cast<const void *>(rec.log_record().body().bytes_value().data()),
85+
reinterpret_cast<const void *>(byte_arr), 5));
86+
EXPECT_EQ(rec.log_record().body().bytes_value().size(), 5);
7687
}
7788

7889
TEST(OtlpLogRecordable, GetResource)
@@ -111,6 +122,12 @@ TEST(OtlpLogRecordable, SetSingleAttribute)
111122
common::AttributeValue str_val(nostd::string_view("Test"));
112123
rec.SetAttribute(str_key, str_val);
113124

125+
nostd::string_view byte_key = "byte_attr";
126+
uint8_t byte_arr[] = {'T', 'e', 's', 't'};
127+
common::AttributeValue byte_val(
128+
nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>(byte_arr), 4});
129+
rec.SetAttribute(byte_key, byte_val);
130+
114131
int checked_attributes = 0;
115132
for (auto &attribute : rec.log_record().attributes())
116133
{
@@ -129,8 +146,16 @@ TEST(OtlpLogRecordable, SetSingleAttribute)
129146
++checked_attributes;
130147
EXPECT_EQ(attribute.value().string_value(), nostd::get<nostd::string_view>(str_val).data());
131148
}
149+
else if (attribute.key() == byte_key)
150+
{
151+
++checked_attributes;
152+
EXPECT_TRUE(0 ==
153+
memcmp(reinterpret_cast<const void *>(attribute.value().bytes_value().data()),
154+
reinterpret_cast<const void *>(byte_arr), 4));
155+
EXPECT_EQ(attribute.value().bytes_value().size(), 4);
156+
}
132157
}
133-
EXPECT_EQ(3, checked_attributes);
158+
EXPECT_EQ(4, checked_attributes);
134159
}
135160

136161
// Test non-int array types. Int array types are tested using templates (see IntAttributeTest)

0 commit comments

Comments
 (0)