Skip to content

Commit 34edd62

Browse files
committed
Add bytes support for OTLP recordables
1 parent 1d41125 commit 34edd62

File tree

4 files changed

+130
-18
lines changed

4 files changed

+130
-18
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/src/otlp_populate_attribute_utils.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
#include <stdint.h>
5+
#include <memory>
56
#include <string>
67
#include <unordered_map>
78
#include <utility>
@@ -89,11 +90,9 @@ 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))
94-
{
95-
array_value->add_values()->set_int_value(val);
96-
}
93+
proto_value->set_bytes_value(
94+
reinterpret_cast<const void *>(nostd::get<nostd::span<const uint8_t>>(value).data()),
95+
nostd::get<nostd::span<const uint8_t>>(value).size());
9796
}
9897
else if (nostd::holds_alternative<nostd::span<const bool>>(value))
9998
{
@@ -194,6 +193,12 @@ void OtlpPopulateAttributeUtils::PopulateAnyValue(
194193
{
195194
proto_value->set_double_value(nostd::get<double>(value));
196195
}
196+
else if (nostd::holds_alternative<std::vector<uint8_t>>(value))
197+
{
198+
const std::vector<uint8_t> &byte_array = nostd::get<std::vector<uint8_t>>(value);
199+
proto_value->set_bytes_value(reinterpret_cast<const void *>(byte_array.data()),
200+
byte_array.size());
201+
}
197202
else if (nostd::holds_alternative<std::string>(value))
198203
{
199204
proto_value->set_string_value(nostd::get<std::string>(value));

exporters/otlp/test/otlp_log_recordable_test.cc

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ TEST(OtlpLogRecordable, Basic)
7373
EXPECT_EQ(rec.log_record().body().string_value(), name);
7474
EXPECT_EQ(rec.log_record().trace_id(), expected_trace_id_bytes);
7575
EXPECT_EQ(rec.log_record().span_id(), expected_span_id_bytes);
76+
77+
// Test bytes body
78+
uint8_t byte_arr[] = {'T', 'e', '\0', 's', 't'};
79+
common::AttributeValue byte_val(
80+
nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>(byte_arr), 5});
81+
rec.SetBody(byte_val);
82+
EXPECT_TRUE(0 ==
83+
memcmp(reinterpret_cast<const void *>(rec.log_record().body().bytes_value().data()),
84+
reinterpret_cast<const void *>(byte_arr), 5));
85+
EXPECT_EQ(rec.log_record().body().bytes_value().size(), 5);
7686
}
7787

7888
TEST(OtlpLogRecordable, GetResource)
@@ -111,6 +121,12 @@ TEST(OtlpLogRecordable, SetSingleAttribute)
111121
common::AttributeValue str_val(nostd::string_view("Test"));
112122
rec.SetAttribute(str_key, str_val);
113123

124+
nostd::string_view byte_key = "byte_attr";
125+
uint8_t byte_arr[] = {'T', 'e', 's', 't'};
126+
common::AttributeValue byte_val(
127+
nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>(byte_arr), 4});
128+
rec.SetAttribute(byte_key, byte_val);
129+
114130
int checked_attributes = 0;
115131
for (auto &attribute : rec.log_record().attributes())
116132
{
@@ -129,8 +145,16 @@ TEST(OtlpLogRecordable, SetSingleAttribute)
129145
++checked_attributes;
130146
EXPECT_EQ(attribute.value().string_value(), nostd::get<nostd::string_view>(str_val).data());
131147
}
148+
else if (attribute.key() == byte_key)
149+
{
150+
++checked_attributes;
151+
EXPECT_TRUE(0 ==
152+
memcmp(reinterpret_cast<const void *>(attribute.value().bytes_value().data()),
153+
reinterpret_cast<const void *>(byte_arr), 4));
154+
EXPECT_EQ(attribute.value().bytes_value().size(), 4);
155+
}
132156
}
133-
EXPECT_EQ(3, checked_attributes);
157+
EXPECT_EQ(4, checked_attributes);
134158
}
135159

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

exporters/otlp/test/otlp_recordable_test.cc

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
#include <gtest/gtest.h>
55
#include <stdint.h>
66
#include <chrono>
7+
#include <cstdint>
78
#include <map>
89
#include <string>
10+
#include <type_traits>
911
#include <utility>
1012
#include <vector>
1113

@@ -256,22 +258,93 @@ TEST(OtlpRecordable, AddLink)
256258
TEST(OtlpRecordable, SetResource)
257259
{
258260
OtlpRecordable rec;
259-
const std::string service_name_key = "service.name";
260-
std::string service_name = "test-otlp";
261-
auto resource = resource::Resource::Create({{service_name_key, service_name}});
261+
bool array_bool[] = {true, false, true};
262+
int32_t array_int[] = {1, 2, 3};
263+
double array_double[] = {1.1, 2.2, 3.3};
264+
opentelemetry::nostd::string_view array_string[] = {"str1", "str2", "str3"};
265+
266+
resource::ResourceAttributes attributes{
267+
{"service.name", opentelemetry::nostd::string_view{"test-otlp"}},
268+
{"bool_value", true},
269+
{"int_value", 3},
270+
{"double_value", static_cast<double>(1.4)},
271+
{"bytes_value",
272+
opentelemetry::nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>("\1\0\3abc"),
273+
6}},
274+
{"bool_array", opentelemetry::nostd::span<const bool>{array_bool}},
275+
{"int_array", opentelemetry::nostd::span<const int32_t>{array_int}},
276+
{"double_array", opentelemetry::nostd::span<const double>{array_double}},
277+
{"string_array",
278+
opentelemetry::nostd::span<const opentelemetry::nostd::string_view>{array_string}}};
279+
280+
auto resource = resource::Resource::Create(attributes);
262281
rec.SetResource(resource);
263282

264-
auto proto_resource = rec.ProtoResource();
265-
bool found_service_name = false;
283+
auto proto_resource = rec.ProtoResource();
284+
size_t found_attribute_count = 0;
266285
for (int i = 0; i < proto_resource.attributes_size(); i++)
267286
{
268287
const auto &attr = proto_resource.attributes(static_cast<int>(i));
269-
if (attr.key() == service_name_key && attr.value().string_value() == service_name)
288+
if (attr.key() == "service.name")
270289
{
271-
found_service_name = true;
290+
EXPECT_EQ(attr.value().string_value(), std::string{"test-otlp"});
291+
++found_attribute_count;
292+
}
293+
else if (attr.key() == "bool_value")
294+
{
295+
EXPECT_EQ(attr.value().bool_value(), true);
296+
++found_attribute_count;
297+
}
298+
else if (attr.key() == "int_value")
299+
{
300+
EXPECT_EQ(attr.value().int_value(), 3);
301+
++found_attribute_count;
302+
}
303+
else if (attr.key() == "double_value")
304+
{
305+
EXPECT_EQ(attr.value().double_value(), static_cast<double>(1.4));
306+
++found_attribute_count;
307+
}
308+
else if (attr.key() == "bytes_value")
309+
{
310+
EXPECT_TRUE(0 == memcmp(attr.value().bytes_value().data(), "\1\0\3abc", 6));
311+
EXPECT_EQ(attr.value().bytes_value().size(), 6);
312+
++found_attribute_count;
313+
}
314+
else if (attr.key() == "bool_array")
315+
{
316+
EXPECT_EQ(attr.value().array_value().values_size(), 3);
317+
EXPECT_EQ(attr.value().array_value().values(0).bool_value(), true);
318+
EXPECT_EQ(attr.value().array_value().values(1).bool_value(), false);
319+
EXPECT_EQ(attr.value().array_value().values(2).bool_value(), true);
320+
++found_attribute_count;
321+
}
322+
else if (attr.key() == "int_array")
323+
{
324+
EXPECT_EQ(attr.value().array_value().values_size(), 3);
325+
EXPECT_EQ(attr.value().array_value().values(0).int_value(), 1);
326+
EXPECT_EQ(attr.value().array_value().values(1).int_value(), 2);
327+
EXPECT_EQ(attr.value().array_value().values(2).int_value(), 3);
328+
++found_attribute_count;
329+
}
330+
else if (attr.key() == "double_array")
331+
{
332+
EXPECT_EQ(attr.value().array_value().values_size(), 3);
333+
EXPECT_EQ(attr.value().array_value().values(0).double_value(), 1.1);
334+
EXPECT_EQ(attr.value().array_value().values(1).double_value(), 2.2);
335+
EXPECT_EQ(attr.value().array_value().values(2).double_value(), 3.3);
336+
++found_attribute_count;
337+
}
338+
else if (attr.key() == "string_array")
339+
{
340+
EXPECT_EQ(attr.value().array_value().values_size(), 3);
341+
EXPECT_EQ(attr.value().array_value().values(0).string_value(), "str1");
342+
EXPECT_EQ(attr.value().array_value().values(1).string_value(), "str2");
343+
EXPECT_EQ(attr.value().array_value().values(2).string_value(), "str3");
344+
++found_attribute_count;
272345
}
273346
}
274-
EXPECT_TRUE(found_service_name);
347+
EXPECT_EQ(found_attribute_count, attributes.size());
275348
}
276349

277350
TEST(OtlpRecordable, SetResourceWithSchemaURL)
@@ -303,6 +376,12 @@ TEST(OtlpRecordable, SetSingleAttribute)
303376
common::AttributeValue str_val(nostd::string_view("Test"));
304377
rec.SetAttribute(str_key, str_val);
305378

379+
nostd::string_view byte_key = "byte_attr";
380+
uint8_t byte_arr[] = {'T', 'e', 's', 't'};
381+
common::AttributeValue byte_val(
382+
nostd::span<const uint8_t>{reinterpret_cast<const uint8_t *>(byte_arr), 4});
383+
rec.SetAttribute(byte_key, byte_val);
384+
306385
EXPECT_EQ(rec.span().attributes(0).key(), bool_key);
307386
EXPECT_EQ(rec.span().attributes(0).value().bool_value(), nostd::get<bool>(bool_val));
308387

@@ -312,6 +391,12 @@ TEST(OtlpRecordable, SetSingleAttribute)
312391
EXPECT_EQ(rec.span().attributes(2).key(), str_key);
313392
EXPECT_EQ(rec.span().attributes(2).value().string_value(),
314393
nostd::get<nostd::string_view>(str_val).data());
394+
395+
EXPECT_EQ(rec.span().attributes(3).key(), byte_key);
396+
EXPECT_EQ(rec.span().attributes(3).value().bytes_value().size(), 4);
397+
EXPECT_TRUE(0 == memcmp(reinterpret_cast<const void *>(
398+
rec.span().attributes(3).value().bytes_value().data()),
399+
reinterpret_cast<const void *>(byte_arr), 4));
315400
}
316401

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

0 commit comments

Comments
 (0)