diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
commit | c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /fluent-bit/lib/ctraces/src | |
parent | Adding upstream version 1.43.2. (diff) | |
download | netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.tar.xz netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.zip |
Adding upstream version 1.44.3.upstream/1.44.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fluent-bit/lib/ctraces/src')
-rw-r--r-- | fluent-bit/lib/ctraces/src/CMakeLists.txt | 39 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_attributes.c | 88 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_decode_msgpack.c | 715 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_decode_opentelemetry.c | 593 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_encode_msgpack.c | 528 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_encode_opentelemetry.c | 1322 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_encode_text.c | 449 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_id.c | 255 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_link.c | 142 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_log.c | 88 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_mpack_utils.c | 488 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_random.c | 86 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_resource.c | 159 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_scope.c | 129 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_span.c | 434 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_utils.c | 0 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctr_version.c | 26 | ||||
-rw-r--r-- | fluent-bit/lib/ctraces/src/ctraces.c | 72 |
18 files changed, 5613 insertions, 0 deletions
diff --git a/fluent-bit/lib/ctraces/src/CMakeLists.txt b/fluent-bit/lib/ctraces/src/CMakeLists.txt new file mode 100644 index 000000000..5a6392464 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/CMakeLists.txt @@ -0,0 +1,39 @@ +set(src + ctraces.c + ctr_resource.c + ctr_span.c + ctr_link.c + ctr_scope.c + ctr_log.c + ctr_id.c + ctr_random.c + ctr_utils.c + ctr_attributes.c + ctr_version.c + ctr_mpack_utils.c + # encoders + ctr_encode_text.c + ctr_encode_msgpack.c + ctr_encode_opentelemetry.c + # decoders + ctr_decode_msgpack.c + ctr_decode_opentelemetry.c + ) + +# Static Library +add_library(ctraces-static STATIC ${src}) +target_link_libraries(ctraces-static mpack-static cfl-static fluent-otel-proto) + +# Install Library +if(MSVC) + # Rename the output for Windows environment to avoid naming issues + set_target_properties(ctraces-static PROPERTIES OUTPUT_NAME libctraces) +else() + set_target_properties(ctraces-static PROPERTIES OUTPUT_NAME ctraces) +endif(MSVC) + +install(TARGETS ctraces-static + RUNTIME DESTINATION ${CTR_INSTALL_BINDIR} + LIBRARY DESTINATION ${CTR_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CTR_INSTALL_LIBDIR} + COMPONENT library) diff --git a/fluent-bit/lib/ctraces/src/ctr_attributes.c b/fluent-bit/lib/ctraces/src/ctr_attributes.c new file mode 100644 index 000000000..44bb13853 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_attributes.c @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +struct ctrace_attributes *ctr_attributes_create() +{ + struct ctrace_attributes *attr; + + attr = malloc(sizeof(struct ctrace_attributes)); + if (!attr) { + ctr_errno(); + return NULL; + } + + attr->kv = cfl_kvlist_create(128); + if (!attr->kv) { + free(attr); + return NULL; + } + + return attr; +} + +void ctr_attributes_destroy(struct ctrace_attributes *attr) +{ + if (attr->kv) { + cfl_kvlist_destroy(attr->kv); + } + free(attr); +} + +int ctr_attributes_count(struct ctrace_attributes *attr) +{ + return cfl_kvlist_count(attr->kv); +} + +int ctr_attributes_set_string(struct ctrace_attributes *attr, char *key, char *value) +{ + return cfl_kvlist_insert_string(attr->kv, key, value); +} + +int ctr_attributes_set_bool(struct ctrace_attributes *attr, char *key, int b) +{ + if (b != CTR_TRUE && b != CTR_FALSE) { + return -1; + } + + return cfl_kvlist_insert_bool(attr->kv, key, b); +} + +int ctr_attributes_set_int64(struct ctrace_attributes *attr, char *key, int64_t value) +{ + return cfl_kvlist_insert_int64(attr->kv, key, value); +} + +int ctr_attributes_set_double(struct ctrace_attributes *attr, char *key, double value) +{ + return cfl_kvlist_insert_double(attr->kv, key, value); +} + +int ctr_attributes_set_array(struct ctrace_attributes *attr, char *key, + struct cfl_array *value) +{ + return cfl_kvlist_insert_array(attr->kv, key, value); +} + +int ctr_attributes_set_kvlist(struct ctrace_attributes *attr, char *key, + struct cfl_kvlist *value) +{ + return cfl_kvlist_insert_kvlist(attr->kv, key, value); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_decode_msgpack.c b/fluent-bit/lib/ctraces/src/ctr_decode_msgpack.c new file mode 100644 index 000000000..f1df5c325 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_decode_msgpack.c @@ -0,0 +1,715 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 Eduardo Silva <eduardo@calyptia.com> + * + * 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. + */ + +#include <ctraces/ctraces.h> +#include <ctraces/ctr_mpack_utils.h> +#include <ctraces/ctr_decode_msgpack.h> +#include <cfl/cfl_sds.h> +#include <ctraces/ctr_variant_utils.h> + + +/* Resource callbacks */ + +static int unpack_resource_dropped_attributes_count(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint32_tag( + reader, &context->resource->dropped_attr_count); +} + +static int unpack_resource_attributes(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct cfl_kvlist *attributes; + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + result = ctr_mpack_consume_nil_tag(reader); + } + else { + result = unpack_cfl_kvlist(reader, &attributes); + + if (result == 0) { + cfl_kvlist_destroy(context->resource->attr->kv); + + context->resource->attr->kv = attributes; + } + } + + return result; +} + +static int unpack_resource(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"attributes", unpack_resource_attributes}, + {"dropped_attributes_count", unpack_resource_dropped_attributes_count}, + {NULL, NULL} + }; + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + + +/* Instrumentation scope callbacks */ + +static int unpack_instrumentation_scope_name(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_string_or_nil_tag( + reader, + &context->scope_span->instrumentation_scope->name); +} + +static int unpack_instrumentation_scope_version(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_string_or_nil_tag( + reader, + &context->scope_span->instrumentation_scope->version); +} + +static int unpack_instrumentation_scope_dropped_attribute_count(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint32_tag( + reader, + &context->scope_span->instrumentation_scope->dropped_attr_count); +} + +static int unpack_instrumentation_scope_attributes(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctrace_attributes *attributes; + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + result = ctr_mpack_consume_nil_tag(reader); + } + else { + attributes = ctr_attributes_create(); + if (attributes == NULL) { + return CTR_DECODE_MSGPACK_VARIANT_DECODE_ERROR; + } + + cfl_kvlist_destroy(attributes->kv); + + attributes->kv = NULL; + + result = unpack_cfl_kvlist(reader, &attributes->kv); + + if (result != 0) { + ctr_attributes_destroy(attributes); + return CTR_DECODE_MSGPACK_VARIANT_DECODE_ERROR; + } + + context->scope_span->instrumentation_scope->attr = attributes; + } + + return CTR_DECODE_MSGPACK_SUCCESS; +} + +static int unpack_scope_span_instrumentation_scope(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctrace_instrumentation_scope *instrumentation_scope; + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"name", unpack_instrumentation_scope_name}, + {"version", unpack_instrumentation_scope_version}, + {"attributes", unpack_instrumentation_scope_attributes}, + {"dropped_attributes_count", unpack_instrumentation_scope_dropped_attribute_count}, + {NULL, NULL} + }; + + instrumentation_scope = ctr_instrumentation_scope_create(NULL, NULL, 0, NULL); + + if (instrumentation_scope == NULL) { + return CTR_DECODE_MSGPACK_ALLOCATION_ERROR; + } + + ctr_scope_span_set_instrumentation_scope(context->scope_span, instrumentation_scope); + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Event callbacks */ + +static int unpack_event_name(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + if (context->event->name != NULL) { + cfl_sds_destroy(context->event->name); + + context->event->name = NULL; + } + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->event->name); +} + +static int unpack_event_time_unix_nano(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint64_tag(reader, &context->event->time_unix_nano); +} + +static int unpack_event_attributes(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct cfl_kvlist *attributes; + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + ctr_mpack_consume_nil_tag(reader); + + return CTR_DECODE_MSGPACK_SUCCESS; + } + + result = unpack_cfl_kvlist(reader, &attributes); + + if (result != 0) { + return CTR_DECODE_MSGPACK_VARIANT_DECODE_ERROR; + } + + cfl_kvlist_destroy(context->event->attr->kv); + context->event->attr->kv = attributes; + + return CTR_DECODE_MSGPACK_SUCCESS; +} + +static int unpack_event_dropped_attributes_count(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint32_tag(reader, &context->event->dropped_attr_count); +} + +static int unpack_event(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"name", unpack_event_name}, + {"time_unix_nano", unpack_event_time_unix_nano}, + {"attributes", unpack_event_attributes}, + {"dropped_attributes_count", unpack_event_dropped_attributes_count}, + {NULL, NULL} + }; + + context->event = ctr_span_event_add(context->span, ""); + + if (context->event == NULL) { + return CTR_DECODE_MSGPACK_ALLOCATION_ERROR; + } + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Link callbacks */ + +static int unpack_link_trace_id(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + int result; + cfl_sds_t value; + + result = ctr_mpack_consume_string_or_nil_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS && value != NULL) { + context->link->trace_id = ctr_id_from_base16(value); + + if (context->link->trace_id == NULL) { + result = CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + cfl_sds_destroy(value); + } + + return result; +} + +static int unpack_link_span_id(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + int result; + cfl_sds_t value; + + result = ctr_mpack_consume_string_or_nil_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS && value != NULL) { + context->link->span_id = ctr_id_from_base16(value); + + if (context->link->span_id == NULL) { + result = CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + cfl_sds_destroy(value); + } + + return result; +} + +static int unpack_link_trace_state(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->link->trace_state); +} + +static int unpack_link_dropped_attributes_count(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint32_tag(reader, &context->link->dropped_attr_count); +} + +static int unpack_link_attributes(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct cfl_kvlist *attributes; + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + result = ctr_mpack_consume_nil_tag(reader); + } + else { + result = unpack_cfl_kvlist(reader, &attributes); + + if (result == 0) { + if (context->link->attr == NULL) { + context->link->attr = ctr_attributes_create(); + } + + if (context->link->attr->kv != NULL) { + cfl_kvlist_destroy(context->link->attr->kv); + } + + context->link->attr->kv = attributes; + + result = CTR_DECODE_MSGPACK_SUCCESS; + } + else { + result = CTR_DECODE_MSGPACK_VARIANT_DECODE_ERROR; + } + } + + return result; +} + +static int unpack_link(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"trace_id", unpack_link_trace_id}, + {"span_id", unpack_link_span_id}, + {"trace_state", unpack_link_trace_state}, + {"attributes", unpack_link_attributes}, + {"dropped_attributes_count", unpack_link_dropped_attributes_count}, + {NULL, NULL} + }; + + context->link = ctr_link_create(context->span, NULL, 0, NULL, 0); + + if (context->link == NULL) { + return CTR_MPACK_ALLOCATION_ERROR; + } + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Span callbacks */ + +static int unpack_span_trace_id(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctrace_id *decoded_id; + int result; + cfl_sds_t value; + + result = ctr_mpack_consume_string_or_nil_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS && value != NULL) { + decoded_id = ctr_id_from_base16(value); + + if (decoded_id != NULL) { + ctr_span_set_trace_id_with_cid(context->span, decoded_id); + + ctr_id_destroy(decoded_id); + } + else { + result = CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + cfl_sds_destroy(value); + } + + return result; +} + +static int unpack_span_span_id(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctrace_id *decoded_id; + int result; + cfl_sds_t value; + + result = ctr_mpack_consume_string_or_nil_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS && value != NULL) { + decoded_id = ctr_id_from_base16(value); + + if (decoded_id != NULL) { + ctr_span_set_span_id_with_cid(context->span, decoded_id); + + ctr_id_destroy(decoded_id); + } + else { + result = CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + cfl_sds_destroy(value); + } + + return result; +} + +static int unpack_span_parent_span_id(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctrace_id *decoded_id; + int result; + cfl_sds_t value; + + result = ctr_mpack_consume_string_or_nil_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS && value != NULL) { + decoded_id = ctr_id_from_base16(value); + + if (decoded_id != NULL) { + ctr_span_set_parent_span_id_with_cid(context->span, decoded_id); + + ctr_id_destroy(decoded_id); + } + else { + result = CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + cfl_sds_destroy(value); + } + + return result; +} + +static int unpack_span_trace_state(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + if (context->span->trace_state != NULL) { + cfl_sds_destroy(context->span->trace_state); + + context->span->trace_state = NULL; + } + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->span->trace_state); +} + +static int unpack_span_name(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + if (context->span->name != NULL) { + cfl_sds_destroy(context->span->name); + + context->span->name = NULL; + } + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->span->name); +} + +static int unpack_span_kind(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_int32_tag(reader, &context->span->kind); +} + +static int unpack_span_start_time_unix_nano(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint64_tag(reader, &context->span->start_time_unix_nano); +} + +static int unpack_span_end_time_unix_nano(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint64_tag(reader, &context->span->end_time_unix_nano); +} + +static int unpack_span_attributes(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct cfl_kvlist *attributes; + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + ctr_mpack_consume_nil_tag(reader); + + return CTR_DECODE_MSGPACK_SUCCESS; + } + + result = unpack_cfl_kvlist(reader, &attributes); + + if (result != 0) { + return CTR_DECODE_MSGPACK_VARIANT_DECODE_ERROR; + } + + cfl_kvlist_destroy(context->span->attr->kv); + context->span->attr->kv = attributes; + + return CTR_DECODE_MSGPACK_SUCCESS; +} + +static int unpack_span_dropped_attributes_count(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_uint32_tag(reader, &context->span->dropped_attr_count); +} + +static int unpack_span_events(mpack_reader_t *reader, size_t index, void *ctx) +{ + return ctr_mpack_unpack_array(reader, unpack_event, ctx); +} + + +static int unpack_span_links(mpack_reader_t *reader, size_t index, void *ctx) +{ + return ctr_mpack_unpack_array(reader, unpack_link, ctx); +} + +static int unpack_span_status_code(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_int32_tag(reader, &context->span->status.code); +} + +static int unpack_span_status_message(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->span->status.message); +} + +static int unpack_span_status(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"code", unpack_span_status_code}, + {"message", unpack_span_status_message}, + {NULL, NULL} + }; + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +static int unpack_span(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"trace_id", unpack_span_trace_id}, + {"span_id", unpack_span_span_id}, + {"parent_span_id", unpack_span_parent_span_id}, + {"trace_state", unpack_span_trace_state}, + {"name", unpack_span_name}, + {"kind", unpack_span_kind}, + {"start_time_unix_nano", unpack_span_start_time_unix_nano}, + {"end_time_unix_nano", unpack_span_end_time_unix_nano}, + {"attributes", unpack_span_attributes}, + {"dropped_attributes_count", unpack_span_dropped_attributes_count}, + {"events", unpack_span_events}, + {"links", unpack_span_links}, + {"status", unpack_span_status}, + {NULL, NULL} + }; + + context->span = ctr_span_create(context->trace, context->scope_span, "", NULL); + + if (context->span == NULL) { + return CTR_DECODE_MSGPACK_ALLOCATION_ERROR; + } + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Scope span callbacks */ + +static int unpack_scope_span_spans(mpack_reader_t *reader, size_t index, void *ctx) +{ + return ctr_mpack_unpack_array(reader, unpack_span, ctx); +} + +static int unpack_scope_span_schema_url(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + if (context->scope_span->schema_url != NULL) { + cfl_sds_destroy(context->scope_span->schema_url); + + context->scope_span->schema_url = NULL; + } + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->scope_span->schema_url); +} + +static int unpack_scope_span(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"scope", unpack_scope_span_instrumentation_scope}, + {"spans", unpack_scope_span_spans}, + {"schema_url", unpack_scope_span_schema_url}, + {NULL, NULL} + }; + + context->scope_span = ctr_scope_span_create(context->resource_span); + + if (context->scope_span == NULL) { + return CTR_DECODE_MSGPACK_ALLOCATION_ERROR; + } + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Resource span callbacks */ + +static int unpack_resource_span_scope_spans(mpack_reader_t *reader, size_t index, void *ctx) +{ + return ctr_mpack_unpack_array(reader, unpack_scope_span, ctx); +} + +static int unpack_resource_span_schema_url(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + + if (context->resource_span->schema_url != NULL) { + cfl_sds_destroy(context->resource_span->schema_url); + + context->resource_span->schema_url = NULL; + } + + return ctr_mpack_consume_string_or_nil_tag(reader, &context->resource_span->schema_url); +} + +static int unpack_resource_span(mpack_reader_t *reader, size_t index, void *ctx) +{ + struct ctr_msgpack_decode_context *context = ctx; + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"resource", unpack_resource}, + {"schema_url", unpack_resource_span_schema_url}, + {"scope_spans", unpack_resource_span_scope_spans}, + {NULL, NULL} + }; + + context->resource_span = ctr_resource_span_create(context->trace); + + if (context->resource_span == NULL) { + return CTR_DECODE_MSGPACK_ALLOCATION_ERROR; + } + + context->resource = context->resource_span->resource; + + return ctr_mpack_unpack_map(reader, callbacks, ctx); +} + +/* Outermost block callbacks*/ + +static int unpack_resource_spans(mpack_reader_t *reader, size_t index, void *ctx) +{ + return ctr_mpack_unpack_array(reader, unpack_resource_span, ctx); +} + +static int unpack_context(mpack_reader_t *reader, struct ctr_msgpack_decode_context *ctx) +{ + struct ctr_mpack_map_entry_callback_t callbacks[] = \ + { + {"resourceSpans", unpack_resource_spans}, + {NULL, NULL} + }; + + return ctr_mpack_unpack_map(reader, callbacks, (void *) ctx); +} + +int ctr_decode_msgpack_create(struct ctrace **out_context, char *in_buf, size_t in_size, size_t *offset) +{ + size_t remainder; + struct ctr_msgpack_decode_context context; + mpack_reader_t reader; + int result; + + memset(&context, 0, sizeof(context)); + + context.trace = ctr_create(NULL); + + if (context.trace == NULL) { + return -1; + } + + in_size -= *offset; + + mpack_reader_init_data(&reader, &in_buf[*offset], in_size); + + result = unpack_context(&reader, &context); + + remainder = mpack_reader_remaining(&reader, NULL); + + *offset += in_size - remainder; + + mpack_reader_destroy(&reader); + + if (result != CTR_DECODE_MSGPACK_SUCCESS) { + ctr_destroy(context.trace); + + context.trace = NULL; + } + + *out_context = context.trace; + + return result; +} + +void ctr_decode_msgpack_destroy(struct ctrace *context) +{ + if (context != NULL) { + ctr_destroy(context); + } +} diff --git a/fluent-bit/lib/ctraces/src/ctr_decode_opentelemetry.c b/fluent-bit/lib/ctraces/src/ctr_decode_opentelemetry.c new file mode 100644 index 000000000..139ae2cd9 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_decode_opentelemetry.c @@ -0,0 +1,593 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> +#include <cfl/cfl_array.h> +#include <fluent-otel-proto/fluent-otel.h> + +static int convert_any_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, char *key, + Opentelemetry__Proto__Common__V1__AnyValue *val); + +static int convert_string_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, char *val) +{ + int result; + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_string(ctr_val->ctr_attr, key, val); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_string(ctr_val->cfl_arr, val); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_string(ctr_val->cfl_kvlist, key, val); + break; + + } + + if (result == -2) { + printf("convert_string_value: unknown value type"); + } + + return result; +} + +static int convert_bool_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, protobuf_c_boolean val) +{ + int result; + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_bool(ctr_val->ctr_attr, key, val); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_bool(ctr_val->cfl_arr, val); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_bool(ctr_val->cfl_kvlist, key, val); + break; + + } + + if (result == -2) { + printf("convert_bool_value: unknown value type"); + } + + return result; +} + +static int convert_int_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, int64_t val) +{ + int result; + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_int64(ctr_val->ctr_attr, key, val); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_int64(ctr_val->cfl_arr, val); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_int64(ctr_val->cfl_kvlist, key, val); + break; + + } + + if (result == -2) { + printf("convert_int_value: unknown value type"); + } + + return result; +} + +static int convert_double_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, double val) +{ + int result; + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_double(ctr_val->ctr_attr, key, val); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_double(ctr_val->cfl_arr, val); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_double(ctr_val->cfl_kvlist, key, val); + break; + + } + + if (result == -2) { + printf("convert_double_value: unknown value type"); + } + + return result; +} + +static int convert_array_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, Opentelemetry__Proto__Common__V1__ArrayValue *otel_arr) +{ + int array_index; + int result; + struct opentelemetry_decode_value *ctr_arr_val; + Opentelemetry__Proto__Common__V1__AnyValue *val; + + ctr_arr_val = malloc(sizeof(struct opentelemetry_decode_value)); + if (!ctr_arr_val) { + ctr_errno(); + return -1; + } + ctr_arr_val->cfl_arr = cfl_array_create(otel_arr->n_values); + + result = 0; + + for (array_index = 0; + array_index < otel_arr->n_values && result == 0; + array_index++) { + val = otel_arr->values[array_index]; + result = convert_any_value(ctr_arr_val, CTR_OPENTELEMETRY_TYPE_ARRAY, NULL, val); + } + + if (result < 0) { + cfl_array_destroy(ctr_arr_val->cfl_arr); + free(ctr_arr_val); + return result; + } + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_array(ctr_val->ctr_attr, key, ctr_arr_val->cfl_arr); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_array(ctr_val->cfl_arr, ctr_arr_val->cfl_arr); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_array(ctr_val->cfl_kvlist, key, ctr_arr_val->cfl_arr); + break; + + } + + free(ctr_arr_val); + if (result == -2) { + fprintf(stderr, "convert_array_value: unknown value type\n"); + } + + return result; +} + +static int convert_kvlist_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, Opentelemetry__Proto__Common__V1__KeyValueList *otel_kvlist) +{ + int kvlist_index; + int result; + struct opentelemetry_decode_value *ctr_kvlist_val; + Opentelemetry__Proto__Common__V1__KeyValue *kv; + + ctr_kvlist_val = malloc(sizeof(struct opentelemetry_decode_value)); + if (!ctr_kvlist_val) { + ctr_errno(); + return -1; + } + ctr_kvlist_val->cfl_kvlist = cfl_kvlist_create(); + + result = 0; + for (kvlist_index = 0; + kvlist_index < otel_kvlist->n_values && result ==0; + kvlist_index++) { + + kv = otel_kvlist->values[kvlist_index]; + result = convert_any_value(ctr_kvlist_val, CTR_OPENTELEMETRY_TYPE_KVLIST, kv->key, kv->value); + } + + if (result < 0){ + cfl_kvlist_destroy(ctr_kvlist_val->cfl_kvlist); + free(ctr_kvlist_val); + return result; + } + + result = -2; + + switch (value_type) { + + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = ctr_attributes_set_kvlist(ctr_val->ctr_attr, key, ctr_kvlist_val->cfl_kvlist); + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_kvlist(ctr_val->cfl_arr, ctr_kvlist_val->cfl_kvlist); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_kvlist(ctr_val->cfl_kvlist, key, ctr_kvlist_val->cfl_kvlist); + break; + + } + + free(ctr_kvlist_val); + + if (result == -2) { + printf("convert_kvlist_value: unknown value type"); + } + + return result; +} + +static int convert_bytes_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, + char *key, void *buf, size_t len) +{ + int result; + + result = -2; + + switch (value_type) { + case CTR_OPENTELEMETRY_TYPE_ATTRIBUTE: + result = -1; + break; + + case CTR_OPENTELEMETRY_TYPE_ARRAY: + result = cfl_array_append_bytes(ctr_val->cfl_arr, buf, len); + break; + + case CTR_OPENTELEMETRY_TYPE_KVLIST: + result = cfl_kvlist_insert_bytes(ctr_val->cfl_kvlist, key, buf, len); + break; + + } + + if (result == -2) { + printf("convert_bytes_value: unknown value type"); + } + + return result; +} + +static int convert_any_value(struct opentelemetry_decode_value *ctr_val, + opentelemetry_decode_value_type value_type, char *key, + Opentelemetry__Proto__Common__V1__AnyValue *val) +{ + int result; + + switch (val->value_case) { + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_STRING_VALUE: + result = convert_string_value(ctr_val, value_type, key, val->string_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_BOOL_VALUE: + result = convert_bool_value(ctr_val, value_type, key, val->bool_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_INT_VALUE: + result = convert_int_value(ctr_val, value_type, key, val->int_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_DOUBLE_VALUE: + result = convert_double_value(ctr_val, value_type, key, val->double_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_ARRAY_VALUE: + result = convert_array_value(ctr_val, value_type, key, val->array_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_KVLIST_VALUE: + result = convert_kvlist_value(ctr_val, value_type, key, val->kvlist_value); + break; + + case OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_BYTES_VALUE: + result = convert_bytes_value(ctr_val, value_type, key, val->bytes_value.data, val->bytes_value.len); + break; + + default: + result = -1; + break; + } + + return result; +} + +static struct ctrace_attributes *convert_otel_attrs(size_t n_attributes, + Opentelemetry__Proto__Common__V1__KeyValue **otel_attr) +{ + int index_kv; + int result; + char *key; + struct opentelemetry_decode_value *ctr_decoded_attributes; + struct ctrace_attributes *attr; + + Opentelemetry__Proto__Common__V1__KeyValue *kv; + Opentelemetry__Proto__Common__V1__AnyValue *val; + + ctr_decoded_attributes = malloc(sizeof(struct opentelemetry_decode_value)); + ctr_decoded_attributes->ctr_attr = ctr_attributes_create(); + + result = 0; + + for (index_kv = 0; index_kv < n_attributes && result == 0; index_kv++) { + kv = otel_attr[index_kv]; + + key = kv->key; + val = kv->value; + + result = convert_any_value(ctr_decoded_attributes, + CTR_OPENTELEMETRY_TYPE_ATTRIBUTE, + key, val); + } + + if (result < 0) { + ctr_attributes_destroy(ctr_decoded_attributes->ctr_attr); + free(ctr_decoded_attributes); + return NULL; + } + + attr = ctr_decoded_attributes->ctr_attr; + free(ctr_decoded_attributes); + return attr; +} + +static int ctr_span_set_attributes(struct ctrace_span *span, + size_t n_attributes, + Opentelemetry__Proto__Common__V1__KeyValue **attributes) +{ + struct ctrace_attributes *ctr_attributes; + + ctr_attributes = convert_otel_attrs(n_attributes, attributes); + if (ctr_attributes == NULL) { + return -1; + } + + if (span->attr) { + ctr_attributes_destroy(span->attr); + } + span->attr = ctr_attributes; + return 0; +} + +static int ctr_span_set_events(struct ctrace_span *span, + size_t n_events, + Opentelemetry__Proto__Trace__V1__Span__Event **events) +{ + int index_event; + struct ctrace_span_event *ctr_event; + struct ctrace_attributes *ctr_attributes; + Opentelemetry__Proto__Trace__V1__Span__Event *event; + + cfl_list_init(&span->events); + + for (index_event = 0; index_event < n_events; index_event++) { + event = events[index_event]; + + ctr_event = ctr_span_event_add_ts(span, event->name, event->time_unix_nano); + + if (ctr_event == NULL) { + return -1; + } + + ctr_attributes = convert_otel_attrs(event->n_attributes, event->attributes); + + if (ctr_attributes == NULL) { + return -1; + } + + if (ctr_event->attr) { + ctr_attributes_destroy(ctr_event->attr); + } + + ctr_event->attr = ctr_attributes; + ctr_span_event_set_dropped_attributes_count(ctr_event, event->dropped_attributes_count); + } + + return 0; +} + +static int resource_set_data(struct ctrace_resource *resource, + Opentelemetry__Proto__Resource__V1__Resource *otel_resource) +{ + struct ctrace_attributes *attributes; + + attributes = convert_otel_attrs(otel_resource->n_attributes, otel_resource->attributes); + + if (attributes == NULL) { + return -1; + } + + ctr_resource_set_attributes(resource, attributes); + ctr_resource_set_dropped_attr_count(resource, otel_resource->dropped_attributes_count); + + return 0; +} + +void ctr_scope_span_set_scope(struct ctrace_scope_span *scope_span, + Opentelemetry__Proto__Common__V1__InstrumentationScope *scope) +{ + struct ctrace_attributes *ctr_attributes; + struct ctrace_instrumentation_scope *ins_scope; + + ctr_attributes = convert_otel_attrs(scope->n_attributes, scope->attributes); + if (ctr_attributes == NULL) { + return; + } + + ins_scope = ctr_instrumentation_scope_create(scope->name, scope->version, + scope->dropped_attributes_count, + ctr_attributes); + if (!ins_scope) { + ctr_attributes_destroy(ctr_attributes); + return; + } + + ctr_scope_span_set_instrumentation_scope(scope_span, ins_scope); +} + +void ctr_span_set_links(struct ctrace_span *ctr_span, size_t n_links, + Opentelemetry__Proto__Trace__V1__Span__Link **links) +{ + int index_link; + struct ctrace_link *ctr_link; + struct ctrace_attributes *ctr_attributes; + Opentelemetry__Proto__Trace__V1__Span__Link *link; + + for (index_link = 0; index_link < n_links; index_link++) { + link = links[index_link]; + + ctr_link = ctr_link_create(ctr_span, + link->trace_id.data, link->trace_id.len, + link->span_id.data, link->span_id.len); + + if (ctr_link == NULL) { + return; + } + + ctr_attributes = convert_otel_attrs(link->n_attributes, link->attributes); + + if (ctr_attributes == NULL) { + return; + } + + ctr_link->attr = ctr_attributes; + ctr_link_set_dropped_attr_count(ctr_link, link->dropped_attributes_count); + } + +} + +int ctr_decode_opentelemetry_create(struct ctrace **out_ctr, + char *in_buf, + size_t in_size, size_t *offset) +{ + size_t resource_span_index; + size_t scope_span_index; + size_t span_index; + struct ctrace *ctr; + struct ctrace_span *span; + struct ctrace_resource *resource; + struct ctrace_resource_span *resource_span; + struct ctrace_scope_span *scope_span; + + Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *service_request; + Opentelemetry__Proto__Trace__V1__ResourceSpans *otel_resource_span; + Opentelemetry__Proto__Trace__V1__ScopeSpans *otel_scope_span; + Opentelemetry__Proto__Trace__V1__Span *otel_span; + + service_request = opentelemetry__proto__collector__trace__v1__export_trace_service_request__unpack(NULL, + in_size - *offset, + (unsigned char *) &in_buf[*offset]); + if (service_request == NULL) { + return -1; + } + + ctr = ctr_create(NULL); + + for (resource_span_index = 0; resource_span_index < service_request->n_resource_spans; resource_span_index++) { + otel_resource_span = service_request->resource_spans[resource_span_index]; + if (otel_resource_span == NULL) { + opentelemetry__proto__collector__trace__v1__export_trace_service_request__free_unpacked(service_request, NULL); + return -1; + } + + /* resource span */ + resource_span = ctr_resource_span_create(ctr); + ctr_resource_span_set_schema_url(resource_span, otel_resource_span->schema_url); + + /* resource */ + resource = ctr_resource_span_get_resource(resource_span); + resource_set_data(resource, otel_resource_span->resource); + + for (scope_span_index = 0; scope_span_index < otel_resource_span->n_scope_spans; scope_span_index++) { + otel_scope_span = otel_resource_span->scope_spans[scope_span_index]; + if (otel_scope_span == NULL) { + opentelemetry__proto__collector__trace__v1__export_trace_service_request__free_unpacked(service_request, NULL); + return -1; + } + + scope_span = ctr_scope_span_create(resource_span); + ctr_scope_span_set_schema_url(scope_span, otel_scope_span->schema_url); + ctr_scope_span_set_scope(scope_span, otel_scope_span->scope); + + for (span_index = 0; span_index < otel_scope_span->n_spans; span_index++) { + otel_span = otel_scope_span->spans[span_index]; + if (otel_span == NULL) { + opentelemetry__proto__collector__trace__v1__export_trace_service_request__free_unpacked(service_request, NULL); + return -1; + } + + span = ctr_span_create(ctr, scope_span, otel_span->name, NULL); + + /* copy data from otel span to ctraces span representation */ + ctr_span_set_trace_id(span, otel_span->trace_id.data, otel_span->trace_id.len); + ctr_span_set_span_id(span, otel_span->span_id.data, otel_span->span_id.len); + ctr_span_set_parent_span_id(span, otel_span->parent_span_id.data, otel_span->parent_span_id.len); + ctr_span_kind_set(span, otel_span->kind); + ctr_span_start_ts(ctr, span, otel_span->start_time_unix_nano); + ctr_span_end_ts(ctr, span, otel_span->end_time_unix_nano); + ctr_span_set_status(span, otel_span->status->code, otel_span->status->message); + ctr_span_set_attributes(span, otel_span->n_attributes, otel_span->attributes); + ctr_span_set_events(span, otel_span->n_events, otel_span->events); + ctr_span_set_dropped_attributes_count(span, otel_span->dropped_attributes_count); + ctr_span_set_dropped_events_count(span, otel_span->dropped_events_count); + ctr_span_set_links(span, otel_span->n_links, otel_span->links); + } + } + } + + opentelemetry__proto__collector__trace__v1__export_trace_service_request__free_unpacked(service_request, NULL); + *out_ctr = ctr; + + return 0; +} + +void ctr_decode_opentelemetry_destroy(struct ctrace *ctr) +{ + ctr_destroy(ctr); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_encode_msgpack.c b/fluent-bit/lib/ctraces/src/ctr_encode_msgpack.c new file mode 100644 index 000000000..bd3d187bf --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_encode_msgpack.c @@ -0,0 +1,528 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +/* local declarations */ +static void pack_variant(mpack_writer_t *writer, struct cfl_variant *variant); + +static void pack_bool(mpack_writer_t *writer, int b) +{ + if (b) { + mpack_write_true(writer); + } + else { + mpack_write_false(writer); + } +} + +static void pack_string(mpack_writer_t *writer, cfl_sds_t str) +{ + mpack_write_str(writer, str, cfl_sds_len(str)); +} + +static void pack_int64(mpack_writer_t *writer, int64_t val) +{ + mpack_write_i64(writer, val); +} + +static void pack_double(mpack_writer_t *writer, double val) +{ + mpack_write_double(writer, val); +} + +static void pack_array(mpack_writer_t *writer, struct cfl_array *array) +{ + int i; + struct cfl_variant *entry; + + mpack_start_array(writer, array->entry_count); + + for (i = 0; i < array->entry_count; i++) { + entry = array->entries[i]; + pack_variant(writer, entry); + } + mpack_finish_array(writer); +} + +static void pack_kvlist(mpack_writer_t *writer, struct cfl_kvlist *kvlist) +{ + int count; + struct cfl_list *head; + struct cfl_list *list; + struct cfl_kvpair *kvpair; + + list = &kvlist->list; + count = cfl_list_size(list); + + mpack_start_map(writer, count); + + cfl_list_foreach(head, list) { + kvpair = cfl_list_entry(head, struct cfl_kvpair, _head); + + /* key */ + mpack_write_str(writer, kvpair->key, cfl_sds_len(kvpair->key)); + + /* value */ + pack_variant(writer, kvpair->val); + } + mpack_finish_map(writer); +} + +static void pack_bytes(mpack_writer_t *writer, cfl_sds_t bytes) +{ + size_t len; + + len = cfl_sds_len(bytes); + + // mpack_start_bin(writer, len); + mpack_write_bin(writer, bytes, len); + // mpack_finish_bin(writer); +} + +static void pack_variant(mpack_writer_t *writer, struct cfl_variant *variant) +{ + int type = variant->type; + + if (type == CFL_VARIANT_STRING) { + pack_string(writer, variant->data.as_string); + } + else if (type == CFL_VARIANT_BOOL) { + pack_bool(writer, variant->data.as_bool); + } + else if (type == CFL_VARIANT_INT) { + pack_int64(writer, variant->data.as_int64); + } + else if (type == CFL_VARIANT_DOUBLE) { + pack_double(writer, variant->data.as_double); + } + else if (type == CFL_VARIANT_ARRAY) { + pack_array(writer, variant->data.as_array); + } + else if (type == CFL_VARIANT_KVLIST) { + pack_kvlist(writer, variant->data.as_kvlist); + } + else if (type == CFL_VARIANT_BYTES) { + pack_bytes(writer, variant->data.as_bytes); + } + else if (type == CFL_VARIANT_REFERENCE) { + /* unsupported */ + } +} + +static void pack_attributes(mpack_writer_t *writer, struct ctrace_attributes *attr) +{ + struct cfl_kvlist *kvlist; + + kvlist = attr->kv; + pack_kvlist(writer, kvlist); +} + +static void pack_instrumentation_scope(mpack_writer_t *writer, struct ctrace_instrumentation_scope *ins_scope) +{ + mpack_start_map(writer, 4); + + /* name */ + mpack_write_cstr(writer, "name"); + if (ins_scope->name) { + mpack_write_str(writer, ins_scope->name, cfl_sds_len(ins_scope->name)); + } + else { + mpack_write_nil(writer); + } + + /* version */ + mpack_write_cstr(writer, "version"); + if (ins_scope->version) { + mpack_write_str(writer, ins_scope->version, cfl_sds_len(ins_scope->version)); + } + else { + mpack_write_nil(writer); + } + + /* attributes */ + mpack_write_cstr(writer, "attributes"); + if (ins_scope->attr) { + pack_attributes(writer, ins_scope->attr); + } + else { + mpack_write_nil(writer); + } + + /* dropped_attributes_count */ + mpack_write_cstr(writer, "dropped_attributes_count"); + mpack_write_u32(writer, ins_scope->dropped_attr_count); + + /* finish */ + mpack_finish_map(writer); +} + +static void pack_id(mpack_writer_t *writer, struct ctrace_id *id) +{ + cfl_sds_t encoded_id; + + + if (id) { + encoded_id = ctr_id_to_lower_base16(id); + + if (encoded_id != NULL) { + mpack_write_cstr(writer, encoded_id); + + cfl_sds_destroy(encoded_id); + } + else { + /* we should be able to report this but at the moment + * we are not. + */ + + mpack_write_nil(writer); + } + } + else { + mpack_write_nil(writer); + } +} + +static void pack_events(mpack_writer_t *writer, struct cfl_list *events) +{ + int count; + struct cfl_list *head; + struct ctrace_span_event *event; + + count = cfl_list_size(events); + mpack_start_array(writer, count); + + cfl_list_foreach(head, events) { + event = cfl_list_entry(head, struct ctrace_span_event, _head); + + /* start event map */ + mpack_start_map(writer, 4); + + /* time_unix_nano */ + mpack_write_cstr(writer, "time_unix_nano"); + mpack_write_u64(writer, event->time_unix_nano); + + /* name */ + mpack_write_cstr(writer, "name"); + if (event->name) { + mpack_write_str(writer, event->name, cfl_sds_len(event->name)); + } + else { + mpack_write_nil(writer); + } + + /* attributes */ + mpack_write_cstr(writer, "attributes"); + if (event->attr) { + pack_attributes(writer, event->attr); + } + else { + mpack_write_nil(writer); + } + + /* dropped_attributes_count */ + mpack_write_cstr(writer, "dropped_attributes_count"); + mpack_write_u32(writer, event->dropped_attr_count); + + /* finish event map */ + mpack_finish_map(writer); + } + + mpack_finish_array(writer); +} + +static void pack_links(mpack_writer_t *writer, struct cfl_list *links) +{ + int count; + struct cfl_list *head; + struct ctrace_link *link; + + count = cfl_list_size(links); + mpack_start_array(writer, count); + + cfl_list_foreach(head, links) { + link = cfl_list_entry(head, struct ctrace_link, _head); + + /* start map */ + mpack_start_map(writer, 5); + + /* trace_id */ + mpack_write_cstr(writer, "trace_id"); + pack_id(writer, link->trace_id); + + /* span_id */ + mpack_write_cstr(writer, "span_id"); + pack_id(writer, link->span_id); + + /* trace_state */ + mpack_write_cstr(writer, "trace_state"); + if (link->trace_state) { + mpack_write_str(writer, link->trace_state, cfl_sds_len(link->trace_state)); + } + else { + mpack_write_nil(writer); + } + + /* attributes */ + mpack_write_cstr(writer, "attributes"); + if (link->attr) { + pack_attributes(writer, link->attr); + } + else { + mpack_write_nil(writer); + } + + /* dropped_attributes_count */ + mpack_write_cstr(writer, "dropped_attributes_count"); + mpack_write_u32(writer, link->dropped_attr_count); + + /* end map */ + mpack_finish_map(writer); + } + + mpack_finish_array(writer); +} + +static void pack_span(mpack_writer_t *writer, struct ctrace_span *span) +{ + mpack_start_map(writer, 13); + + /* trace_id */ + mpack_write_cstr(writer, "trace_id"); + pack_id(writer, span->trace_id); + + /* span_id */ + mpack_write_cstr(writer, "span_id"); + pack_id(writer, span->span_id); + + /* parent_span_id */ + mpack_write_cstr(writer, "parent_span_id"); + pack_id(writer, span->parent_span_id); + + /* trace_state */ + mpack_write_cstr(writer, "trace_state"); + if (span->trace_state) { + mpack_write_str(writer, span->trace_state, cfl_sds_len(span->trace_state)); + } + else { + mpack_write_nil(writer); + } + + /* name */ + mpack_write_cstr(writer, "name"); + if (span->name) { + mpack_write_str(writer, span->name, cfl_sds_len(span->name)); + } + else { + mpack_write_nil(writer); + } + + /* kind */ + mpack_write_cstr(writer, "kind"); + mpack_write_u32(writer, span->kind); + + /* start_time_unix_nano */ + mpack_write_cstr(writer, "start_time_unix_nano"); + mpack_write_u64(writer, span->start_time_unix_nano); + + /* end_time_unix_nano */ + mpack_write_cstr(writer, "end_time_unix_nano"); + mpack_write_u64(writer, span->end_time_unix_nano); + + /* attributes */ + mpack_write_cstr(writer, "attributes"); + if (span->attr) { + pack_attributes(writer, span->attr); + } + else { + mpack_write_nil(writer); + } + + /* dropped_attributes_count */ + mpack_write_cstr(writer, "dropped_attributes_count"); + mpack_write_u32(writer, span->dropped_attr_count); + + /* events */ + mpack_write_cstr(writer, "events"); + pack_events(writer, &span->events); + + /* links */ + mpack_write_cstr(writer, "links"); + pack_links(writer, &span->links); + + /* span_status */ + mpack_write_cstr(writer, "status"); + mpack_start_map(writer, 2); + mpack_write_cstr(writer, "code"); + mpack_write_i32(writer, span->status.code); + mpack_write_cstr(writer, "message"); + if (span->status.message) { + mpack_write_str(writer, span->status.message, cfl_sds_len(span->status.message)); + } + else { + mpack_write_nil(writer); + } + mpack_finish_map(writer); + + mpack_finish_map(writer); +} + +static void pack_spans(mpack_writer_t *writer, struct cfl_list *spans) +{ + int count; + struct cfl_list *head; + struct ctrace_span *span; + + count = cfl_list_size(spans); + mpack_start_array(writer, count); + + cfl_list_foreach(head, spans) { + span = cfl_list_entry(head, struct ctrace_span, _head); + pack_span(writer, span); + } + + mpack_finish_array(writer); +} + +static void pack_scope_spans(mpack_writer_t *writer, struct cfl_list *scope_spans) +{ + int count; + struct cfl_list *head; + struct ctrace_scope_span *scope_span; + + count = cfl_list_size(scope_spans); + + mpack_write_cstr(writer, "scope_spans"); + mpack_start_array(writer, count); + + cfl_list_foreach(head, scope_spans) { + scope_span = cfl_list_entry(head, struct ctrace_scope_span, _head); + + mpack_start_map(writer, 3); + + /* scope */ + mpack_write_cstr(writer, "scope"); + pack_instrumentation_scope(writer, scope_span->instrumentation_scope); + + /* spans */ + mpack_write_cstr(writer, "spans"); + pack_spans(writer, &scope_span->spans); + + /* schema_url */ + mpack_write_cstr(writer, "schema_url"); + if (scope_span->schema_url) { + mpack_write_str(writer, scope_span->schema_url, cfl_sds_len(scope_span->schema_url)); + } + else { + mpack_write_nil(writer); + } + + mpack_finish_map(writer); + } + + mpack_finish_array(writer); +} + +int ctr_encode_msgpack_create(struct ctrace *ctx, char **out_buf, size_t *out_size) +{ + int count; + char *data; + size_t size; + mpack_writer_t writer; + struct cfl_list *head; + struct ctrace_resource_span *resource_span; + struct ctrace_resource *resource; + + if (ctx == NULL) { + return -1; + } + + mpack_writer_init_growable(&writer, &data, &size); + + /* root map */ + mpack_start_map(&writer, 1); + + /* resourceSpan */ + mpack_write_cstr(&writer, "resourceSpans"); + + /* array */ + count = cfl_list_size(&ctx->resource_spans); + mpack_start_array(&writer, count); + + cfl_list_foreach(head, &ctx->resource_spans) { + resource_span = cfl_list_entry(head, struct ctrace_resource_span, _head); + + /* resourceSpans is an array of maps, each maps containers a 'resource', 'schema_url' and 'scopeSpans' entry */ + mpack_start_map(&writer, 3); + + /* resource key */ + resource = resource_span->resource; + mpack_write_cstr(&writer, "resource"); + + /* resource val */ + mpack_start_map(&writer, 2); + + /* resource[0]: attributes */ + mpack_write_cstr(&writer, "attributes"); + if (resource->attr) { + pack_attributes(&writer, resource->attr); + } + else { + mpack_write_nil(&writer); + } + + /* resource[1]: dropped_attributes_count */ + mpack_write_cstr(&writer, "dropped_attributes_count"); + mpack_write_u32(&writer, resource->dropped_attr_count); + + mpack_finish_map(&writer); + + /* schema_url */ + mpack_write_cstr(&writer, "schema_url"); + if (resource_span->schema_url) { + mpack_write_str(&writer, resource_span->schema_url, cfl_sds_len(resource_span->schema_url)); + } + else { + mpack_write_nil(&writer); + } + + /* scopeSpans */ + pack_scope_spans(&writer, &resource_span->scope_spans); + + mpack_finish_map(&writer); /* !resourceSpans map value */ + } + + mpack_finish_array(&writer); + mpack_finish_map(&writer); + + if (mpack_writer_destroy(&writer) != mpack_ok) { + fprintf(stderr, "An error occurred encoding the data!\n"); + return -1; + } + + *out_buf = data; + *out_size = size; + + return 0; +} + +void ctr_encode_msgpack_destroy(char *buf) +{ + free(buf); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_encode_opentelemetry.c b/fluent-bit/lib/ctraces/src/ctr_encode_opentelemetry.c new file mode 100644 index 000000000..e8a95f149 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_encode_opentelemetry.c @@ -0,0 +1,1322 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> +#include <fluent-otel-proto/fluent-otel.h> + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_to_otlp_any_value(struct cfl_variant *value); +static inline Opentelemetry__Proto__Common__V1__KeyValue *ctr_variant_kvpair_to_otlp_kvpair(struct cfl_kvpair *input_pair); +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_kvlist_to_otlp_any_value(struct cfl_variant *value); + +static inline void otlp_any_value_destroy(Opentelemetry__Proto__Common__V1__AnyValue *value); +static inline void otlp_kvpair_destroy(Opentelemetry__Proto__Common__V1__KeyValue *kvpair); +static inline void otlp_kvlist_destroy(Opentelemetry__Proto__Common__V1__KeyValueList *kvlist); +static inline void otlp_array_destroy(Opentelemetry__Proto__Common__V1__ArrayValue *array); + +static inline void otlp_kvpair_list_destroy(Opentelemetry__Proto__Common__V1__KeyValue **pair_list, size_t entry_count); + +static inline void otlp_kvpair_destroy(Opentelemetry__Proto__Common__V1__KeyValue *kvpair) +{ + if (kvpair != NULL) { + if (kvpair->key != NULL) { + free(kvpair->key); + } + + if (kvpair->value != NULL) { + otlp_any_value_destroy(kvpair->value); + } + + free(kvpair); + } +} + +static inline void otlp_kvlist_destroy(Opentelemetry__Proto__Common__V1__KeyValueList *kvlist) +{ + size_t index; + + if (kvlist != NULL) { + if (kvlist->values != NULL) { + for (index = 0 ; index < kvlist->n_values ; index++) { + otlp_kvpair_destroy(kvlist->values[index]); + } + + free(kvlist->values); + } + + free(kvlist); + } +} + +static inline void otlp_array_destroy(Opentelemetry__Proto__Common__V1__ArrayValue *array) +{ + size_t index; + + if (array != NULL) { + if (array->values != NULL) { + for (index = 0 ; index < array->n_values ; index++) { + otlp_any_value_destroy(array->values[index]); + } + + free(array->values); + } + + free(array); + } +} + +static inline void otlp_any_value_destroy(Opentelemetry__Proto__Common__V1__AnyValue *value) +{ + if (value != NULL) { + if (value->value_case == OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_STRING_VALUE) { + if (value->string_value != NULL) { + free(value->string_value); + value->string_value = NULL; + } + } + else if (value->value_case == OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_ARRAY_VALUE) { + if (value->array_value != NULL) { + otlp_array_destroy(value->array_value); + } + } + else if (value->value_case == OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_KVLIST_VALUE) { + if (value->kvlist_value != NULL) { + otlp_kvlist_destroy(value->kvlist_value); + } + } + else if (value->value_case == OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_BYTES_VALUE) { + if (value->bytes_value.data != NULL) { + free(value->bytes_value.data); + } + } + + free(value); + value = NULL; + } +} + +static inline Opentelemetry__Proto__Common__V1__KeyValue **otlp_kvpair_list_initialize(size_t entry_count) +{ + Opentelemetry__Proto__Common__V1__KeyValue **result; + + result = \ + calloc(entry_count, sizeof(Opentelemetry__Proto__Common__V1__KeyValue *)); + + if (result == NULL) { + ctr_errno(); + return NULL; + } + + return result; +} + + +static Opentelemetry__Proto__Common__V1__ArrayValue *otlp_array_value_initialize(size_t entry_count) +{ + Opentelemetry__Proto__Common__V1__ArrayValue *value; + + value = calloc(1, sizeof(Opentelemetry__Proto__Common__V1__ArrayValue)); + + if (value != NULL) { + opentelemetry__proto__common__v1__array_value__init(value); + + if (entry_count > 0) { + value->values = \ + calloc(entry_count, + sizeof(Opentelemetry__Proto__Common__V1__AnyValue *)); + + if (value->values == NULL) { + free(value); + + value = NULL; + } + else { + value->n_values = entry_count; + } + } + } + + return value; +} + +static Opentelemetry__Proto__Common__V1__KeyValue *otlp_kvpair_value_initialize() +{ + Opentelemetry__Proto__Common__V1__KeyValue *value; + + value = calloc(1, sizeof(Opentelemetry__Proto__Common__V1__KeyValue)); + + if (value != NULL) { + opentelemetry__proto__common__v1__key_value__init(value); + } + + return value; +} + +static Opentelemetry__Proto__Common__V1__KeyValueList *otlp_kvlist_value_initialize(size_t entry_count) +{ + Opentelemetry__Proto__Common__V1__KeyValueList *value; + + value = calloc(1, sizeof(Opentelemetry__Proto__Common__V1__KeyValueList)); + + if (value != NULL) { + opentelemetry__proto__common__v1__key_value_list__init(value); + + if (entry_count > 0) { + value->values = \ + calloc(entry_count, + sizeof(Opentelemetry__Proto__Common__V1__KeyValue *)); + + if (value->values == NULL) { + free(value); + + value = NULL; + } + else { + value->n_values = entry_count; + } + } + } + + return value; +} + +static Opentelemetry__Proto__Common__V1__AnyValue *otlp_any_value_initialize(int data_type, size_t entry_count) +{ + Opentelemetry__Proto__Common__V1__AnyValue *value; + + value = calloc(1, sizeof(Opentelemetry__Proto__Common__V1__AnyValue)); + + if (value == NULL) { + return NULL; + } + + opentelemetry__proto__common__v1__any_value__init(value); + + if (data_type == CFL_VARIANT_STRING) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_STRING_VALUE; + } + else if (data_type == CFL_VARIANT_BOOL) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_BOOL_VALUE; + } + else if (data_type == CFL_VARIANT_INT) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_INT_VALUE; + } + else if (data_type == CFL_VARIANT_DOUBLE) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_DOUBLE_VALUE; + } + else if (data_type == CFL_VARIANT_ARRAY) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_ARRAY_VALUE; + + value->array_value = otlp_array_value_initialize(entry_count); + + if (value->array_value == NULL) { + free(value); + + value = NULL; + } + } + else if (data_type == CFL_VARIANT_KVLIST) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_KVLIST_VALUE; + + value->kvlist_value = otlp_kvlist_value_initialize(entry_count); + + if (value->kvlist_value == NULL) { + free(value); + + value = NULL; + } + } + else if (data_type == CFL_VARIANT_BYTES) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_BYTES_VALUE; + } + else if (data_type == CFL_VARIANT_REFERENCE) { + value->value_case = OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_STRING_VALUE; + } + else { + free(value); + + value = NULL; + } + + return value; +} + +static inline Opentelemetry__Proto__Common__V1__KeyValue *ctr_variant_kvpair_to_otlp_kvpair(struct cfl_kvpair *input_pair) +{ + Opentelemetry__Proto__Common__V1__KeyValue *kv; + + kv = otlp_kvpair_value_initialize(); + if (kv == NULL) { + ctr_errno(); + return NULL; + } + + kv->key = strdup(input_pair->key); + if (kv->key == NULL) { + ctr_errno(); + free(kv); + return NULL; + } + + kv->value = ctr_variant_to_otlp_any_value(input_pair->val); + if (kv->value == NULL) { + ctr_errno(); + free(kv->key); + free(kv); + return NULL; + } + + return kv; +} + +static inline void otlp_kvpair_list_destroy(Opentelemetry__Proto__Common__V1__KeyValue **pair_list, size_t entry_count) +{ + size_t index; + + if (pair_list != NULL) { + for (index = 0 ; index < entry_count ; index++) { + otlp_kvpair_destroy(pair_list[index]); + } + + free(pair_list); + pair_list = NULL; + } +} + +static inline Opentelemetry__Proto__Common__V1__KeyValue **ctr_kvlist_to_otlp_kvpair_list(struct cfl_kvlist *kvlist) +{ + size_t entry_count; + Opentelemetry__Proto__Common__V1__KeyValue *keyvalue; + struct cfl_list *iterator; + Opentelemetry__Proto__Common__V1__KeyValue **result; + struct cfl_kvpair *kvpair; + size_t index; + + entry_count = cfl_kvlist_count(kvlist); + + result = otlp_kvpair_list_initialize(entry_count); + + if (result != NULL) { + index = 0; + + cfl_list_foreach(iterator, &kvlist->list) { + kvpair = cfl_list_entry(iterator, struct cfl_kvpair, _head); + + keyvalue = ctr_variant_kvpair_to_otlp_kvpair(kvpair); + + if (keyvalue == NULL) { + otlp_kvpair_list_destroy(result, entry_count); + + result = NULL; + + break; + } + + result[index++] = keyvalue; + } + } + + return result; +} + + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_kvlist_to_otlp_any_value(struct cfl_variant *value) +{ + size_t entry_count; + Opentelemetry__Proto__Common__V1__KeyValue *keyvalue; + struct cfl_list *iterator; + Opentelemetry__Proto__Common__V1__AnyValue *result; + struct cfl_kvpair *kvpair; + struct cfl_kvlist *kvlist; + size_t index; + + + kvlist = value->data.as_kvlist; + + entry_count = cfl_kvlist_count(kvlist); + + result = otlp_any_value_initialize(CFL_VARIANT_KVLIST, entry_count); + + if (result != NULL) { + index = 0; + + cfl_list_foreach(iterator, &kvlist->list) { + kvpair = cfl_list_entry(iterator, struct cfl_kvpair, _head); + + keyvalue = ctr_variant_kvpair_to_otlp_kvpair(kvpair); + + if (keyvalue == NULL) { + otlp_any_value_destroy(result); + + result = NULL; + + break; + } + + result->kvlist_value->values[index++] = keyvalue; + } + } + + return result; +} + + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_array_to_otlp_any_value(struct cfl_variant *value) +{ + size_t entry_count; + Opentelemetry__Proto__Common__V1__AnyValue *entry_value; + Opentelemetry__Proto__Common__V1__AnyValue *result; + struct cfl_array *array; + size_t index; + + array = value->data.as_array; + + entry_count = array->entry_count; + + result = otlp_any_value_initialize(CFL_VARIANT_ARRAY, entry_count); + + if (result != NULL) { + index = 0; + + for (index = 0 ; index < entry_count ; index++) { + entry_value = ctr_variant_to_otlp_any_value(cfl_array_fetch_by_index(array, index)); + + if (entry_value == NULL) { + otlp_any_value_destroy(result); + + result = NULL; + + break; + } + + result->array_value->values[index] = entry_value; + } + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_string_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + result = otlp_any_value_initialize(CFL_VARIANT_STRING, 0); + + if (result != NULL) { + result->string_value = strdup(value->data.as_string); + + if (result->string_value == NULL) { + otlp_any_value_destroy(result); + + result = NULL; + } + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_boolean_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + result = otlp_any_value_initialize(CFL_VARIANT_BOOL, 0); + + if (result != NULL) { + result->bool_value = value->data.as_bool; + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_int64_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + result = otlp_any_value_initialize(CFL_VARIANT_INT, 0); + + if (result != NULL) { + result->int_value = value->data.as_int64; + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_double_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + result = otlp_any_value_initialize(CFL_VARIANT_DOUBLE, 0); + + if (result != NULL) { + result->double_value = value->data.as_double; + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_binary_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + result = otlp_any_value_initialize(CFL_VARIANT_BYTES, 0); + + if (result != NULL) { + result->bytes_value.len = cfl_sds_len(value->data.as_bytes); + result->bytes_value.data = calloc(result->bytes_value.len, sizeof(char)); + + if (result->bytes_value.data == NULL) { + otlp_any_value_destroy(result); + + result = NULL; + } + + memcpy(result->bytes_value.data, value->data.as_bytes, result->bytes_value.len); + } + + return result; +} + +static inline Opentelemetry__Proto__Common__V1__AnyValue *ctr_variant_to_otlp_any_value(struct cfl_variant *value) +{ + Opentelemetry__Proto__Common__V1__AnyValue *result; + + if (value->type == CFL_VARIANT_STRING) { + result = ctr_variant_string_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_BOOL) { + result = ctr_variant_boolean_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_INT) { + result = ctr_variant_int64_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_DOUBLE) { + result = ctr_variant_double_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_ARRAY) { + result = ctr_variant_array_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_KVLIST) { + result = ctr_variant_kvlist_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_BYTES) { + result = ctr_variant_binary_to_otlp_any_value(value); + } + else if (value->type == CFL_VARIANT_REFERENCE) { + result = ctr_variant_string_to_otlp_any_value(value); + } + else { + result = NULL; + } + + return result; +} + +static Opentelemetry__Proto__Common__V1__KeyValue **set_attributes_from_ctr(struct ctrace_attributes *attr) +{ + if(attr == NULL) { + return NULL; + } + + return ctr_kvlist_to_otlp_kvpair_list(attr->kv); +} + +static Opentelemetry__Proto__Resource__V1__Resource *initialize_resource() +{ + Opentelemetry__Proto__Resource__V1__Resource *resource; + + resource = calloc(1, sizeof(Opentelemetry__Proto__Resource__V1__Resource)); + + if (!resource) { + ctr_errno(); + return NULL; + } + + opentelemetry__proto__resource__v1__resource__init(resource); + + return resource; +} + +static size_t get_attributes_count(struct ctrace_attributes *attr) +{ + if (attr == NULL) { + return 0; + } + + return cfl_kvlist_count(attr->kv); +} + +static Opentelemetry__Proto__Resource__V1__Resource *ctr_set_resource(struct ctrace_resource *resource) +{ + Opentelemetry__Proto__Resource__V1__Resource *otel_resource; + + otel_resource = initialize_resource(); + if (!otel_resource) { + return NULL; + } + + otel_resource->n_attributes = get_attributes_count(resource->attr); + otel_resource->attributes = set_attributes_from_ctr(resource->attr); + otel_resource->dropped_attributes_count = resource->dropped_attr_count; + + return otel_resource; +} + +static void otel_span_set_trace_id(Opentelemetry__Proto__Trace__V1__Span *span, + struct ctrace_id *trace_id) +{ + size_t len; + uint8_t *trace_id_str; + + if (!trace_id) { + return; + } + + len = ctr_id_get_len(trace_id); + trace_id_str = ctr_id_get_buf(trace_id); + + span->trace_id.len = len; + span->trace_id.data = trace_id_str; +} + +static void otel_span_set_span_id(Opentelemetry__Proto__Trace__V1__Span *span, + struct ctrace_id *span_id) +{ + size_t len; + uint8_t *span_id_str; + + if (!span_id) { + return; + } + + len = ctr_id_get_len(span_id); + span_id_str = ctr_id_get_buf(span_id); + + span->span_id.len = len; + span->span_id.data = span_id_str; +} + +static void otel_span_set_parent_span_id(Opentelemetry__Proto__Trace__V1__Span *span, + struct ctrace_id *parent) +{ + size_t len; + uint8_t *parent_id_str; + + if (!parent) { + return; + } + + len = ctr_id_get_len(parent); + parent_id_str = ctr_id_get_buf(parent); + + span->parent_span_id.len = len; + span->parent_span_id.data = parent_id_str; +} + +static void otel_span_set_kind(Opentelemetry__Proto__Trace__V1__Span *otel_span, + int kind) +{ + switch (kind) { + case CTRACE_SPAN_INTERNAL: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_INTERNAL; + break; + case CTRACE_SPAN_SERVER: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_SERVER; + break; + case CTRACE_SPAN_CLIENT: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_CLIENT; + break; + case CTRACE_SPAN_PRODUCER: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_PRODUCER; + break; + case CTRACE_SPAN_CONSUMER: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_CONSUMER; + break; + default: + otel_span->kind = OPENTELEMETRY__PROTO__TRACE__V1__SPAN__SPAN_KIND__SPAN_KIND_UNSPECIFIED; + break; + } +} + +static void otel_span_set_start_time(Opentelemetry__Proto__Trace__V1__Span *span, + uint64_t start_time) +{ + span->start_time_unix_nano = start_time; +} + +static void otel_span_set_end_time(Opentelemetry__Proto__Trace__V1__Span *span, + uint64_t end_time) +{ + span->end_time_unix_nano = end_time; +} + +static void otel_span_set_attributes(Opentelemetry__Proto__Trace__V1__Span *span, + struct ctrace_attributes *attr) +{ + span->n_attributes = get_attributes_count(attr); + span->attributes = set_attributes_from_ctr(attr); +} + +static void otel_span_set_dropped_attributes_count(Opentelemetry__Proto__Trace__V1__Span *span, + uint32_t dropped_attr_count) +{ + span->dropped_attributes_count = dropped_attr_count; +} + +static Opentelemetry__Proto__Trace__V1__Span__Event *set_event(struct ctrace_span_event *ctr_event) +{ + Opentelemetry__Proto__Trace__V1__Span__Event *event; + + event = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__Span__Event)); + opentelemetry__proto__trace__v1__span__event__init(event); + + event->time_unix_nano = ctr_event->time_unix_nano; + event->name = ctr_event->name; + event->n_attributes = ctr_attributes_count(ctr_event->attr); + event->attributes = set_attributes_from_ctr(ctr_event->attr); + event->dropped_attributes_count = ctr_event->dropped_attr_count; + + return event; +} + +static Opentelemetry__Proto__Trace__V1__Span__Event **set_events_from_ctr(struct cfl_list *events) +{ + int count; + int event_index; + struct cfl_list *head; + struct ctrace_span_event *ctr_event; + + count = cfl_list_size(events); + + Opentelemetry__Proto__Trace__V1__Span__Event **event_arr; + + event_arr = calloc(count, sizeof(Opentelemetry__Proto__Trace__V1__Span__Event *)); + + event_index = 0; + cfl_list_foreach(head, events) { + ctr_event = cfl_list_entry(head, struct ctrace_span_event, _head); + event_arr[event_index++] = set_event(ctr_event); + } + + return event_arr; +} + +static void otel_span_set_events(Opentelemetry__Proto__Trace__V1__Span *otel_span, + struct cfl_list *events) +{ + otel_span->n_events = cfl_list_size(events); + otel_span->events = set_events_from_ctr(events); +} + +static void otel_span_set_dropped_events_count(Opentelemetry__Proto__Trace__V1__Span *span, + uint32_t dropped_events_count) +{ + span->dropped_events_count = dropped_events_count; +} + +static void otel_span_set_name(Opentelemetry__Proto__Trace__V1__Span *otel_span, + char *name) +{ + otel_span->name = name; +} + +static void otel_span_set_trace_state(Opentelemetry__Proto__Trace__V1__Span *otel_span, + char *trace_state) +{ + otel_span->trace_state = trace_state; +} + +static void otel_span_set_status(Opentelemetry__Proto__Trace__V1__Span *otel_span, + struct ctrace_span_status status) +{ + Opentelemetry__Proto__Trace__V1__Status *otel_status; + + otel_status = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__Status)); + opentelemetry__proto__trace__v1__status__init(otel_status); + + otel_status->code = status.code; + otel_status->message = status.message; + + otel_span->status = otel_status; +} + +static void otel_span_set_links(Opentelemetry__Proto__Trace__V1__Span *otel_span, + struct cfl_list *links) +{ + int count; + int link_index; + struct cfl_list *head; + struct ctrace_link *link; + size_t link_span_id_size; + size_t link_trace_id_size; + uint8_t *link_trace_id; + uint8_t *link_span_id; + + count = cfl_list_size(links); + + Opentelemetry__Proto__Trace__V1__Span__Link **otel_links; + Opentelemetry__Proto__Trace__V1__Span__Link *otel_link; + + otel_links = calloc(count, sizeof(Opentelemetry__Proto__Trace__V1__Span__Link *)); + + link_index = 0; + + cfl_list_foreach(head, links) { + link = cfl_list_entry(head, struct ctrace_link, _head); + + otel_link = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__Span__Link)); + opentelemetry__proto__trace__v1__span__link__init(otel_link); + + if (link->trace_id) { + link_trace_id_size = ctr_id_get_len(link->trace_id); + link_trace_id = ctr_id_get_buf(link->trace_id); + + otel_link->trace_id.len = link_trace_id_size; + otel_link->trace_id.data = link_trace_id; + } + + if (link->span_id) { + link_span_id_size = ctr_id_get_len(link->span_id); + link_span_id = ctr_id_get_buf(link->span_id); + + otel_link->span_id.len = link_span_id_size; + otel_link->span_id.data = link_span_id; + } + + otel_link->trace_state = link->trace_state; + + otel_link->n_attributes = get_attributes_count(link->attr); + otel_link->attributes = set_attributes_from_ctr(link->attr); + otel_link->dropped_attributes_count = link->dropped_attr_count; + + otel_links[link_index++] = otel_link; + } + + otel_span->n_links = count; + otel_span->links = otel_links; +} + +static void set_span(Opentelemetry__Proto__Trace__V1__Span *otel_span, + struct ctrace_span *span) +{ + otel_span_set_name(otel_span, span->name); + otel_span_set_trace_id(otel_span, span->trace_id); + otel_span_set_span_id(otel_span, span->span_id); + otel_span_set_parent_span_id(otel_span, span->parent_span_id); + otel_span_set_kind(otel_span, span->kind); + otel_span_set_trace_state(otel_span, span->trace_state); + otel_span_set_start_time(otel_span, span->start_time_unix_nano); + otel_span_set_end_time(otel_span, span->end_time_unix_nano); + otel_span_set_status(otel_span, span->status); + + otel_span_set_attributes(otel_span, span->attr); + otel_span_set_dropped_attributes_count(otel_span, span->dropped_attr_count); + otel_span_set_events(otel_span, &span->events); + otel_span_set_dropped_events_count(otel_span, span->dropped_events_count); + otel_span_set_links(otel_span, &span->links); +} + +static Opentelemetry__Proto__Trace__V1__Span **initialize_spans(size_t span_count) +{ + Opentelemetry__Proto__Trace__V1__Span **spans; + + spans = calloc(span_count, sizeof(Opentelemetry__Proto__Trace__V1__Span *)); + if (!spans) { + ctr_errno(); + return NULL; + } + + return spans; +} + +static Opentelemetry__Proto__Trace__V1__Span *initialize_span() +{ + Opentelemetry__Proto__Trace__V1__Span *span; + + span = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__Span)); + if (!span) { + ctr_errno(); + return NULL; + } + + opentelemetry__proto__trace__v1__span__init(span); + + return span; +} + +static Opentelemetry__Proto__Trace__V1__Span **set_spans(struct ctrace_scope_span *scope_span) +{ + int span_count; + int span_index; + struct cfl_list *head; + struct ctrace_span *span; + + Opentelemetry__Proto__Trace__V1__Span **spans; + Opentelemetry__Proto__Trace__V1__Span *otel_span; + + span_count = cfl_list_size(&scope_span->spans); + spans = initialize_spans(span_count); + if (!spans) { + return NULL; + } + + span_index = 0; + + cfl_list_foreach(head, &scope_span->spans) { + span = cfl_list_entry(head, struct ctrace_span, _head); + + otel_span = initialize_span(); + if (!otel_span) { + return NULL; + } + + set_span(otel_span, span); + spans[span_index++] = otel_span; + } + + return spans; +} + +static Opentelemetry__Proto__Common__V1__InstrumentationScope *initialize_instrumentation_scope() +{ + Opentelemetry__Proto__Common__V1__InstrumentationScope *instrumentation_scope; + + instrumentation_scope = calloc(1, sizeof(Opentelemetry__Proto__Common__V1__InstrumentationScope)); + if (!instrumentation_scope) { + ctr_errno(); + return NULL; + } + opentelemetry__proto__common__v1__instrumentation_scope__init(instrumentation_scope); + + return instrumentation_scope; +} + +static Opentelemetry__Proto__Common__V1__InstrumentationScope *set_instrumentation_scope(struct ctrace_instrumentation_scope *instrumentation_scope) +{ + Opentelemetry__Proto__Common__V1__InstrumentationScope *otel_scope; + + otel_scope = initialize_instrumentation_scope(); + if (!otel_scope) { + return NULL; + } + + otel_scope->name = instrumentation_scope->name; + otel_scope->version = instrumentation_scope->version; + otel_scope->n_attributes = get_attributes_count(instrumentation_scope->attr); + otel_scope->dropped_attributes_count = instrumentation_scope->dropped_attr_count; + otel_scope->attributes = set_attributes_from_ctr(instrumentation_scope->attr);; + + return otel_scope; +} + +static Opentelemetry__Proto__Trace__V1__ScopeSpans **initialize_scope_spans(size_t count) +{ + Opentelemetry__Proto__Trace__V1__ScopeSpans **scope_spans; + + scope_spans = calloc(count, sizeof(Opentelemetry__Proto__Trace__V1__ScopeSpans *)); + if (!scope_spans) { + ctr_errno(); + return NULL; + } + + return scope_spans; +} + +static Opentelemetry__Proto__Trace__V1__ScopeSpans *initialize_scope_span() +{ + Opentelemetry__Proto__Trace__V1__ScopeSpans *scope_span; + + scope_span = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__ScopeSpans)); + if (!scope_span) { + ctr_errno(); + return NULL; + } + + opentelemetry__proto__trace__v1__scope_spans__init(scope_span); + + return scope_span; +} + +static Opentelemetry__Proto__Trace__V1__ScopeSpans **set_scope_spans(struct ctrace_resource_span *resource_span) +{ + int span_count; + int scope_span_count; + int scope_span_index; + struct cfl_list *head; + struct ctrace_scope_span *scope_span; + + Opentelemetry__Proto__Trace__V1__ScopeSpans **scope_spans; + Opentelemetry__Proto__Trace__V1__ScopeSpans *otel_scope_span; + + + scope_span_count = cfl_list_size(&resource_span->scope_spans); + scope_spans = initialize_scope_spans(scope_span_count); + if (!scope_spans) { + return NULL; + } + + scope_span_index = 0; + + cfl_list_foreach(head, &resource_span->scope_spans) { + scope_span = cfl_list_entry(head, struct ctrace_scope_span, _head); + + otel_scope_span = initialize_scope_span(); + if (!otel_scope_span) { + return NULL; + } + + otel_scope_span->schema_url = scope_span->schema_url; + otel_scope_span->scope = set_instrumentation_scope(scope_span->instrumentation_scope); + + span_count = cfl_list_size(&scope_span->spans); + otel_scope_span->n_spans = span_count; + otel_scope_span->spans = set_spans(scope_span); + + scope_spans[scope_span_index++] = otel_scope_span; + } + + return scope_spans; +} + +static Opentelemetry__Proto__Trace__V1__ResourceSpans **initialize_resource_spans(size_t count) +{ + Opentelemetry__Proto__Trace__V1__ResourceSpans **resource_spans; + + resource_spans = calloc(count, sizeof(Opentelemetry__Proto__Trace__V1__ResourceSpans *)); + if (!resource_spans) { + ctr_errno(); + return NULL; + } + + return resource_spans; +} + +static Opentelemetry__Proto__Trace__V1__ResourceSpans *initialize_resource_span() +{ + Opentelemetry__Proto__Trace__V1__ResourceSpans *resource_span; + + resource_span = calloc(1, sizeof(Opentelemetry__Proto__Trace__V1__ResourceSpans)); + if (!resource_span) { + ctr_errno(); + return NULL; + } + + opentelemetry__proto__trace__v1__resource_spans__init(resource_span); + + return resource_span; +} + + +static Opentelemetry__Proto__Trace__V1__ResourceSpans **set_resource_spans(struct ctrace *ctr) +{ + struct ctrace_resource_span *resource_span; + struct cfl_list *head; + int resource_span_count; + int resource_span_index; + + Opentelemetry__Proto__Trace__V1__ResourceSpans **rs; + Opentelemetry__Proto__Trace__V1__ResourceSpans *otel_resource_span; + Opentelemetry__Proto__Trace__V1__ScopeSpans **scope_spans; + + resource_span_count = cfl_list_size(&ctr->resource_spans); + rs = initialize_resource_spans(resource_span_count); + + resource_span_index = 0; + + cfl_list_foreach(head, &ctr->resource_spans) { + resource_span = cfl_list_entry(head, struct ctrace_resource_span, _head); + + otel_resource_span = initialize_resource_span(); + if (!otel_resource_span) { + return NULL; + } + otel_resource_span->resource = ctr_set_resource(resource_span->resource); + + otel_resource_span->n_scope_spans = cfl_list_size(&resource_span->scope_spans); + scope_spans = set_scope_spans(resource_span); + otel_resource_span->scope_spans = scope_spans; + + otel_resource_span->schema_url = resource_span->schema_url; + rs[resource_span_index++] = otel_resource_span; + } + + return rs; + +} + +static Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *initialize_export_service_request() +{ + Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *req; + + req = malloc(sizeof(Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest)); + if (!req) { + ctr_errno(); + return NULL; + } + opentelemetry__proto__collector__trace__v1__export_trace_service_request__init(req); + + return req; +} + +static Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *create_export_service_request(struct ctrace *ctr) +{ + Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *req; + Opentelemetry__Proto__Trace__V1__ResourceSpans **rs; + + req = initialize_export_service_request(); + if (!req) { + return NULL; + } + + req->n_resource_spans = cfl_list_size(&ctr->resource_spans); + rs = set_resource_spans(ctr); + req->resource_spans = rs; + + return req; +} + +static void destroy_attributes(Opentelemetry__Proto__Common__V1__KeyValue **attributes, size_t count) +{ + otlp_kvpair_list_destroy(attributes, count); +} + +static void destroy_resource(Opentelemetry__Proto__Resource__V1__Resource *resource) +{ + destroy_attributes(resource->attributes, resource->n_attributes); + + resource->attributes = NULL; + resource->n_attributes = 0; + resource->dropped_attributes_count = 0; + + free(resource); +} + +static void destroy_id(ProtobufCBinaryData id){ + id.len = 0; + + if (id.data) { + id.data = NULL; + } +} + +static void destroy_event(Opentelemetry__Proto__Trace__V1__Span__Event *event) +{ + destroy_attributes(event->attributes, event->n_attributes); + + event->time_unix_nano = 0; + event->name = NULL; + event->attributes = NULL; + event->n_attributes = 0; + event->dropped_attributes_count = 0; + + free(event); +} + +static void destroy_events(Opentelemetry__Proto__Trace__V1__Span__Event **events, size_t count) +{ + int event_index; + Opentelemetry__Proto__Trace__V1__Span__Event *event; + + for (event_index = 0; event_index < count; event_index++) { + event = events[event_index]; + destroy_event(event); + } + + free(events); +} + +static void destroy_link(Opentelemetry__Proto__Trace__V1__Span__Link *link) +{ + destroy_attributes(link->attributes, link->n_attributes); + + destroy_id(link->trace_id); + destroy_id(link->span_id); + + link->trace_state = NULL; + link->attributes = NULL; + link->n_attributes = 0; + link->dropped_attributes_count = 0; + + free(link); +} + + +static void destroy_links(Opentelemetry__Proto__Trace__V1__Span__Link **links, size_t count) +{ + int link_index; + Opentelemetry__Proto__Trace__V1__Span__Link *link; + + for (link_index = 0; link_index < count; link_index++) { + link = links[link_index]; + destroy_link(link); + } + + free(links); +} + +static void destroy_span(Opentelemetry__Proto__Trace__V1__Span *span) +{ + destroy_events(span->events, span->n_events); + destroy_attributes(span->attributes, span->n_attributes); + destroy_links(span->links, span->n_links); + + span->attributes = NULL; + span->n_attributes = 0; + span->dropped_attributes_count = 0; + + span->events = NULL; + span->n_events = 0; + span->dropped_events_count = 0; + + span->links = NULL; + span->n_links = 0; + span->dropped_links_count = 0; + + span->start_time_unix_nano = 0; + span->end_time_unix_nano = 0; + + destroy_id(span->trace_id); + destroy_id(span->span_id); + destroy_id(span->parent_span_id); + span->trace_state = NULL; + + span->name = NULL; + span->kind = 0; + + span->status->message = NULL; + span->status->code = 0; + free(span->status); + + free(span); +} + +static void destroy_spans(Opentelemetry__Proto__Trace__V1__Span **spans, size_t count) +{ + int span_index; + + for (span_index = 0; span_index < count; span_index++) { + destroy_span(spans[span_index]); + } + + free(spans); +} + +static void destroy_scope(Opentelemetry__Proto__Common__V1__InstrumentationScope *scope) +{ + if (scope->name) { + scope->name = NULL; + } + + scope->version = NULL; + + destroy_attributes(scope->attributes, scope->n_attributes); + scope->attributes = NULL; + scope->n_attributes = 0; + scope->dropped_attributes_count = 0; + + free(scope); +} + +static void destroy_scope_span(Opentelemetry__Proto__Trace__V1__ScopeSpans *scope_span) +{ + if (scope_span->schema_url) { + scope_span->schema_url = NULL; + } + + if (scope_span->scope) { + destroy_scope(scope_span->scope); + } + + destroy_spans(scope_span->spans, scope_span->n_spans); + scope_span->spans = NULL; + scope_span->n_spans = 0; + + free(scope_span); +} + +static void destroy_scope_spans(Opentelemetry__Proto__Trace__V1__ScopeSpans **scope_spans, + size_t count) +{ + int scope_span_index; + Opentelemetry__Proto__Trace__V1__ScopeSpans *scope_span; + + for (scope_span_index = 0; scope_span_index < count; scope_span_index++) { + scope_span = scope_spans[scope_span_index]; + destroy_scope_span(scope_span); + } + + free(scope_spans); +} + +static void destroy_resource_spans(Opentelemetry__Proto__Trace__V1__ResourceSpans **rs, + int resource_span_count) +{ + Opentelemetry__Proto__Trace__V1__ResourceSpans *resource_span; + int resource_span_index; + + for(resource_span_index = 0; resource_span_index < resource_span_count; resource_span_index++) { + resource_span = rs[resource_span_index]; + + destroy_resource(resource_span->resource); + resource_span->resource = NULL; + + destroy_scope_spans(resource_span->scope_spans, resource_span->n_scope_spans); + resource_span->scope_spans = NULL; + resource_span->n_scope_spans = 0; + resource_span->schema_url = NULL; + + free(resource_span); + } + free(rs); +} + +static void destroy_export_service_request(Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *req) +{ + destroy_resource_spans(req->resource_spans, req->n_resource_spans); + req->n_resource_spans = 0; + req->resource_spans = NULL; + + free(req); + req = NULL; +} + +cfl_sds_t ctr_encode_opentelemetry_create(struct ctrace *ctr) +{ + cfl_sds_t buf; + size_t len; + Opentelemetry__Proto__Collector__Trace__V1__ExportTraceServiceRequest *req; + + req = create_export_service_request(ctr); + + len = opentelemetry__proto__collector__trace__v1__export_trace_service_request__get_packed_size(req); + buf = cfl_sds_create_size(len); + if (!buf) { + return NULL; + } + cfl_sds_set_len(buf, len); + + opentelemetry__proto__collector__trace__v1__export_trace_service_request__pack(req, (uint8_t *)buf); + + destroy_export_service_request(req); + + return buf; +} + +void ctr_encode_opentelemetry_destroy(cfl_sds_t text) +{ + cfl_sds_destroy(text); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_encode_text.c b/fluent-bit/lib/ctraces/src/ctr_encode_text.c new file mode 100644 index 000000000..aebfd9d76 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_encode_text.c @@ -0,0 +1,449 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +static inline void sds_cat_safe(cfl_sds_t *buf, char *str) +{ + int len; + + len = strlen(str); + cfl_sds_cat_safe(buf, str, len); +} + +static void format_string(cfl_sds_t *buf, cfl_sds_t val, int level) +{ + char tmp[1024]; + + snprintf(tmp, sizeof(tmp) - 1, "'%s'", val); + sds_cat_safe(buf, tmp); +} + +static void format_int64(cfl_sds_t *buf, int64_t val, int level) +{ + char tmp[1024]; + + snprintf(tmp, sizeof(tmp) - 1, "%" PRIi64, val); + sds_cat_safe(buf, tmp); +} + +static void format_double(cfl_sds_t *buf, double val, int level) +{ + char tmp[1024]; + + snprintf(tmp, sizeof(tmp) - 1, "%.17g", val); + sds_cat_safe(buf, tmp); +} + +static void format_bool(cfl_sds_t *buf, int val, int level) +{ + if (val) { + sds_cat_safe(buf, "true"); + } + else { + sds_cat_safe(buf, "false"); + } +} + +static void format_array(cfl_sds_t *buf, struct cfl_array *array, int level) +{ + int i; + int off = level + 4; + char tmp[128]; + struct cfl_variant *v; + + sds_cat_safe(buf, "[\n"); + + snprintf(tmp, sizeof(tmp) - 1, "%*s", off, ""); + + for (i = 0; i < array->entry_count; i++) { + v = array->entries[i]; + + sds_cat_safe(buf, tmp); + + if (v->type == CFL_VARIANT_STRING) { + format_string(buf, v->data.as_string, off); + } + else if (v->type == CFL_VARIANT_BOOL) { + format_bool(buf, v->data.as_bool, off); + } + else if (v->type == CFL_VARIANT_INT) { + format_int64(buf, v->data.as_int64, off); + } + else if (v->type == CFL_VARIANT_DOUBLE) { + format_double(buf, v->data.as_double, off); + } + else if (v->type == CFL_VARIANT_ARRAY) { + format_array(buf, v->data.as_array, off); + } + + if (i + 1 < array->entry_count) { + sds_cat_safe(buf, ",\n"); + } + } + + off = level; + snprintf(tmp, sizeof(tmp) - 1, "\n%*s]", off, ""); + sds_cat_safe(buf, tmp); +} + +static void format_attributes(cfl_sds_t *buf, struct cfl_kvlist *kv, int level) +{ + int off = level + 4; + char tmp[1024]; + struct cfl_list *head; + struct cfl_kvpair *p; + struct cfl_variant *v; + + sds_cat_safe(buf, "\n"); + + cfl_list_foreach(head, &kv->list) { + p = cfl_list_entry(head, struct cfl_kvpair, _head); + + /* key */ + snprintf(tmp, sizeof(tmp) - 1, "%*s- %s: ", off, "", p->key); + sds_cat_safe(buf, tmp); + + /* value */ + v = p->val; + if (v->type == CFL_VARIANT_STRING) { + format_string(buf, v->data.as_string, off); + } + else if (v->type == CFL_VARIANT_BOOL) { + format_bool(buf, v->data.as_bool, off); + } + else if (v->type == CFL_VARIANT_INT) { + format_int64(buf, v->data.as_int64, off); + } + else if (v->type == CFL_VARIANT_DOUBLE) { + format_double(buf, v->data.as_double, off); + } + else if (v->type == CFL_VARIANT_ARRAY) { + format_array(buf, v->data.as_array, off); + } + else if (v->type == CFL_VARIANT_KVLIST) { + format_attributes(buf, v->data.as_kvlist, off); + } + + sds_cat_safe(buf, "\n"); + } +} + +static void format_event(cfl_sds_t *buf, struct ctrace_span_event *event, int level) +{ + int off = level + 4; + char tmp[1024]; + + sds_cat_safe(buf, "\n"); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- name: %s\n", off, "", event->name); + sds_cat_safe(buf, tmp); + off += 4; + + snprintf(tmp, sizeof(tmp) - 1, "%*s- timestamp : %" PRIu64 "\n", off, "", event->time_unix_nano); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- dropped_attributes_count: %" PRIu32 "\n", off, "", event->dropped_attr_count); + sds_cat_safe(buf, tmp); + + if (ctr_attributes_count(event->attr) > 0) { + + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes:", off, ""); + sds_cat_safe(buf, tmp); + + format_attributes(buf, event->attr->kv, off); + } + else { + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes: none\n", off, ""); + sds_cat_safe(buf, tmp); + } + +} + +static void format_span(cfl_sds_t *buf, struct ctrace *ctx, struct ctrace_span *span, int level) +{ + int min; + int off = 1 + (level * 4); + char tmp[1024]; + cfl_sds_t id_hex; + struct ctrace_span_event *event; + struct ctrace_link *link; + struct cfl_list *head; + + min = off + 4; + + snprintf(tmp, sizeof(tmp) - 1, "%*s[span '%s']\n", off, "", span->name); + sds_cat_safe(buf, tmp); + + /* trace_id */ + if (span->trace_id) { + id_hex = ctr_id_to_lower_base16(span->trace_id); + } + else { + id_hex = cfl_sds_create(CTR_ID_TRACE_DEFAULT); + } + snprintf(tmp, sizeof(tmp) - 1, "%*s- trace_id : %s\n", min, "", id_hex); + sds_cat_safe(buf, tmp); + cfl_sds_destroy(id_hex); + + /* span_id */ + if (span->span_id) { + id_hex = ctr_id_to_lower_base16(span->span_id); + } + else { + id_hex = cfl_sds_create(CTR_ID_SPAN_DEFAULT); + } + snprintf(tmp, sizeof(tmp) - 1, "%*s- span_id : %s\n", min, "", id_hex); + sds_cat_safe(buf, tmp); + cfl_sds_destroy(id_hex); + + /* parent_span_id */ + if (span->parent_span_id) { + id_hex = ctr_id_to_lower_base16(span->parent_span_id); + } + else { + id_hex = cfl_sds_create("undefined"); + } + snprintf(tmp, sizeof(tmp) - 1, "%*s- parent_span_id : %s\n", min, "", id_hex); + sds_cat_safe(buf, tmp); + cfl_sds_destroy(id_hex); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- kind : %i (%s)\n", min, "", + span->kind, ctr_span_kind_string(span)); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- start_time : %" PRIu64 "\n", min, "", + span->start_time_unix_nano); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- end_time : %" PRIu64 "\n", min, "", + span->end_time_unix_nano); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- dropped_attributes_count: %" PRIu32 "\n", min, "", + span->dropped_attr_count); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- dropped_events_count : %" PRIu32 "\n", min, "", + span->dropped_events_count); + sds_cat_safe(buf, tmp); + + /* Status */ + snprintf(tmp, sizeof(tmp) - 1, "%*s- status:\n", min, ""); + sds_cat_safe(buf, tmp); + snprintf(tmp, sizeof(tmp) - 1, "%*s- code : %i\n", min + 4, "", span->status.code); + sds_cat_safe(buf, tmp); + + if (span->status.message) { + snprintf(tmp, sizeof(tmp) - 1, "%*s- message : '%s'\n", min + 4, "", span->status.message); + } + + /* span attributes */ + if (ctr_attributes_count(span->attr) == 0) { + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes: none\n", min, ""); + sds_cat_safe(buf, tmp); + } + else { + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes: ", min, ""); + sds_cat_safe(buf, tmp); + format_attributes(buf, span->attr->kv, min); + } + + /* events */ + if (cfl_list_size(&span->events) == 0) { + snprintf(tmp, sizeof(tmp) - 1, "%*s- events: none\n", min, ""); + sds_cat_safe(buf, tmp); + } + else { + snprintf(tmp, sizeof(tmp) - 1, "%*s- events: ", min, ""); + sds_cat_safe(buf, tmp); + + cfl_list_foreach(head, &span->events) { + event = cfl_list_entry(head, struct ctrace_span_event, _head); + format_event(buf, event, min); + } + } + + /* links */ + snprintf(tmp, sizeof(tmp) - 1, "%*s- [links]\n", min, ""); + sds_cat_safe(buf, tmp); + + cfl_list_foreach(head, &span->links) { + link = cfl_list_entry(head, struct ctrace_link, _head); + + off = min + 4; + + snprintf(tmp, sizeof(tmp) - 1, "%*s- link:\n", off, ""); + sds_cat_safe(buf, tmp); + + off += 4; + + /* trace_id */ + if (link->trace_id) { + id_hex = ctr_id_to_lower_base16(link->trace_id); + } + else { + id_hex = cfl_sds_create(CTR_ID_TRACE_DEFAULT); + } + snprintf(tmp, sizeof(tmp) - 1, "%*s- trace_id : %s\n", off, "", id_hex); + sds_cat_safe(buf, tmp); + cfl_sds_destroy(id_hex); + + /* span_id */ + if (link->span_id) { + id_hex = ctr_id_to_lower_base16(link->span_id); + } + else { + id_hex = cfl_sds_create(CTR_ID_SPAN_DEFAULT); + } + snprintf(tmp, sizeof(tmp) - 1, "%*s- span_id : %s\n", off, "", id_hex); + sds_cat_safe(buf, tmp); + cfl_sds_destroy(id_hex); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- trace_state : %s\n", off, "", link->trace_state); + sds_cat_safe(buf, tmp); + + snprintf(tmp, sizeof(tmp) - 1, "%*s- dropped_events_count : %" PRIu32 "\n", off, "", link->dropped_attr_count); + sds_cat_safe(buf, tmp); + + /* link attributes */ + if (!link->attr) { + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes : none\n", off, ""); + sds_cat_safe(buf, tmp); + } + else { + snprintf(tmp, sizeof(tmp) - 1, "%*s- attributes : ", off, ""); + sds_cat_safe(buf, tmp); + format_attributes(buf, span->attr->kv, off); + } + } +} + +static void format_spans(cfl_sds_t *buf, struct ctrace *ctx, struct cfl_list *spans) +{ + struct cfl_list *head; + struct ctrace_span *span; + + cfl_sds_printf(buf, " [spans]\n"); + + /* look for spans that belongs to the given resource */ + cfl_list_foreach(head, spans){ + span = cfl_list_entry(head, struct ctrace_span, _head); + + /* skip resource if there is no match */ + format_span(buf, ctx, span, 2); + } +} + +static void format_instrumentation_scope(cfl_sds_t *buf, + struct ctrace_instrumentation_scope *scope) +{ + cfl_sds_printf(buf, " instrumentation scope:\n"); + cfl_sds_printf(buf, " - name : %s\n", scope->name); + cfl_sds_printf(buf, " - version : %s\n", scope->version); + cfl_sds_printf(buf, " - dropped_attributes_count: %i\n", scope->dropped_attr_count); + + if (scope->attr) { + cfl_sds_printf(buf, " - attributes:\n"); + format_attributes(buf, scope->attr->kv, 8); + } + else { + cfl_sds_printf(buf, " - attributes: undefined\n"); + } +} + +static void format_resource(cfl_sds_t *buf, struct ctrace *ctx, struct ctrace_resource *resource) +{ + cfl_sds_printf(buf, " resource:\n"); + cfl_sds_printf(buf, " - attributes:"); + format_attributes(buf, resource->attr->kv, 8); + cfl_sds_printf(buf, " - dropped_attributes_count: %" PRIu32 "\n", resource->dropped_attr_count); +} + +static void format_scope_spans(cfl_sds_t *buf, struct ctrace *ctx, struct cfl_list *scope_spans) +{ + struct cfl_list *head; + struct ctrace_scope_span *scope_span; + + cfl_list_foreach(head, scope_spans) { + scope_span = cfl_list_entry(head, struct ctrace_scope_span, _head); + + cfl_sds_printf(buf, " [scope_span]\n"); + + /* format 'instrumentation_scope' if set */ + if (scope_span->instrumentation_scope) { + format_instrumentation_scope(buf, scope_span->instrumentation_scope); + } + + /* schema_url */ + if (scope_span->schema_url) { + cfl_sds_printf(buf, " schema_url: %s\n", scope_span->schema_url); + } + else { + cfl_sds_printf(buf, " schema_url: \"\"\n"); + } + + /* spans */ + format_spans(buf, ctx, &scope_span->spans); + } +} + +cfl_sds_t ctr_encode_text_create(struct ctrace *ctx) +{ + cfl_sds_t buf; + struct cfl_list *head; + struct ctrace_resource_span *resource_span; + + buf = cfl_sds_create_size(1024); + if (!buf) { + return NULL; + } + + /* iterate resource_spans */ + cfl_list_foreach(head, &ctx->resource_spans) { + resource_span = cfl_list_entry(head, struct ctrace_resource_span, _head); + + sds_cat_safe(&buf, "|-------------------- RESOURCE SPAN --------------------|\n"); + + if (resource_span->resource) { + format_resource(&buf, ctx, resource_span->resource); + } + else { + cfl_sds_printf(&buf, " resource: {}\n"); + } + + /* schema_url */ + if (resource_span->schema_url) { + cfl_sds_printf(&buf, " schema_url: %s\n", resource_span->schema_url); + } + else { + cfl_sds_printf(&buf, " schema_url: \"\"\n"); + } + + /* scope spans */ + format_scope_spans(&buf, ctx, &resource_span->scope_spans); + } + + return buf; +} + +void ctr_encode_text_destroy(cfl_sds_t text) +{ + cfl_sds_destroy(text); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_id.c b/fluent-bit/lib/ctraces/src/ctr_id.c new file mode 100644 index 000000000..0c2299fcd --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_id.c @@ -0,0 +1,255 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +/* create an ID with random bytes of length CTR_ID_BUFFER_SIZE (16 bytes) */ +struct ctrace_id *ctr_id_create_random(size_t size) +{ + char *buf; + ssize_t ret; + struct ctrace_id *cid; + + if (size <= 0) { + size = CTR_ID_DEFAULT_SIZE; + } + + buf = calloc(1, size); + if (!buf) { + ctr_errno(); + return NULL; + } + + ret = ctr_random_get(buf, size); + if (ret < 0) { + free(buf); + return NULL; + } + + cid = ctr_id_create(buf, size); + free(buf); + + return cid; +} + +void ctr_id_destroy(struct ctrace_id *cid) +{ + cfl_sds_destroy(cid->buf); + free(cid); +} + +struct ctrace_id *ctr_id_create(void *buf, size_t len) +{ + int ret; + struct ctrace_id *cid; + + if (len <= 0) { + return NULL; + } + + cid = calloc(1, sizeof(struct ctrace_id)); + if (!cid) { + ctr_errno(); + return NULL; + } + + ret = ctr_id_set(cid, buf, len); + if (ret == -1) { + free(cid); + return NULL; + } + + return cid; +} + +int ctr_id_set(struct ctrace_id *cid, void *buf, size_t len) +{ + if (cid->buf) { + cfl_sds_destroy(cid->buf); + } + + cid->buf = cfl_sds_create_len(buf, len); + if (!cid->buf) { + return -1; + } + + return 0; +} + +int ctr_id_cmp(struct ctrace_id *cid1, struct ctrace_id *cid2) +{ + int len1; + int len2; + + if (!cid1 || !cid2) { + return -1; + } + + len1 = cfl_sds_len(cid1->buf); + len2 = cfl_sds_len(cid2->buf); + + if (len1 != len2) { + return -1; + } + + if (memcmp(cid1->buf, cid2->buf, len1) == 0) { + return 0; + } + + return -1; +} + +size_t ctr_id_get_len(struct ctrace_id *cid) +{ + return cfl_sds_len(cid->buf); +} + +void *ctr_id_get_buf(struct ctrace_id *cid) +{ + return cid->buf; +} + +cfl_sds_t ctr_id_to_lower_base16(struct ctrace_id *cid) +{ + int i; + int len; + cfl_sds_t out; + const char hex[] = "0123456789abcdef"; + + if (!cid->buf) { + return NULL; + } + + len = cfl_sds_len(cid->buf); + out = cfl_sds_create_size(len * 2 + 1); + if (!out) { + return NULL; + } + + for (i = 0; i < len; i++) { + out[i * 2] = hex[(cid->buf[i] >> 4) & 0xF]; + out[i * 2 + 1] = hex[(cid->buf[i] >> 0) & 0xF]; + } + + out[i * 2] = 0; + + return out; +} + +/* This function returns CFL_TRUE on success and CFL_FALSE on + * failure. + */ +static int decode_hex_digit(char *digit) +{ + if (*digit >= '0' && *digit <= '9') { + *digit -= '0'; + } + else if (*digit >= 'a' && *digit <= 'f') { + *digit -= 'a'; + *digit += 10; + } + else if (*digit >= 'A' && *digit <= 'F') { + *digit -= 'A'; + *digit += 10; + } + else { + return CFL_FALSE; + } + + return CFL_TRUE; +} + +struct ctrace_id *ctr_id_from_base16(cfl_sds_t id) +{ + size_t output_index; + size_t input_index; + cfl_sds_t decoded_id; + struct ctrace_id *result_id; + int result; + size_t length; + char digit; + char value; + + if (id == NULL) { + return NULL; + } + + length = cfl_sds_len(id); + + if (length < 2) { + return NULL; + } + + if ((length % 2) != 0) { + return NULL; + } + + decoded_id = cfl_sds_create_size(length / 2); + + if (decoded_id == NULL) { + return NULL; + } + + output_index = 0; + input_index = 0; + value = 0; + + /* This loop consumes one character per iteration, + * on each iteration it verifies that the character + * corresponds to the base16 charset and then + * it subtracts the correct base to get a number + * ranging from 0 to 16. + * Then the accumulator is left shifted 4 bits and + * the current value is bitwise ORed to its value. + * If the character index is odd then the accumulator + * value is appended to the decoded id buffer and + * reinitialized to be used on the next iteration. + */ + + while (input_index < length) { + digit = id[input_index]; + result = decode_hex_digit(&digit); + + if (!result) { + break; + } + + digit &= 0xF; + value <<= 4; + value |= digit; + + if ((input_index % 2) == 1) { + decoded_id[output_index++] = value; + value = 0; + } + + input_index++; + } + + if (result) { + result_id = ctr_id_create(decoded_id, length / 2); + } + else { + result_id = NULL; + } + + cfl_sds_destroy(decoded_id); + + return result_id; +} diff --git a/fluent-bit/lib/ctraces/src/ctr_link.c b/fluent-bit/lib/ctraces/src/ctr_link.c new file mode 100644 index 000000000..9f92c3aa5 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_link.c @@ -0,0 +1,142 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +struct ctrace_link *ctr_link_create(struct ctrace_span *span, + void *trace_id_buf, size_t trace_id_len, + void *span_id_buf, size_t span_id_len) +{ + struct ctrace_link *link; + + link = calloc(1, sizeof(struct ctrace_link)); + if (!link) { + ctr_errno(); + return NULL; + } + + /* trace_id */ + if (trace_id_buf && trace_id_len > 0) { + link->trace_id = ctr_id_create(trace_id_buf, trace_id_len); + if (!link->trace_id) { + free(link); + return NULL; + } + } + + /* span_id */ + if (span_id_buf && span_id_len > 0) { + link->span_id = ctr_id_create(span_id_buf, span_id_len); + if (!link->span_id) { + ctr_id_destroy(link->trace_id); + free(link); + return NULL; + } + } + + cfl_list_add(&link->_head, &span->links); + return link; +} + +struct ctrace_link *ctr_link_create_with_cid(struct ctrace_span *span, + struct ctrace_id *trace_id_cid, + struct ctrace_id *span_id_cid) +{ + size_t trace_id_len = 0; + size_t span_id_len = 0; + void *trace_id_buf = NULL; + void *span_id_buf = NULL; + + if (trace_id_cid) { + trace_id_buf = ctr_id_get_buf(trace_id_cid); + trace_id_len = ctr_id_get_len(trace_id_cid); + } + + if (span_id_cid) { + span_id_buf = ctr_id_get_buf(span_id_cid); + span_id_len = ctr_id_get_len(span_id_cid); + } + + return ctr_link_create(span, trace_id_buf, trace_id_len, span_id_buf, span_id_len); +} + +int ctr_link_set_trace_state(struct ctrace_link *link, char *trace_state) +{ + if (!link || !trace_state) { + return -1; + } + + link->trace_state = cfl_sds_create(trace_state); + if (!link->trace_state) { + return -1; + } + + return 0; +} + +int ctr_link_set_attributes(struct ctrace_link *link, struct ctrace_attributes *attr) +{ + if (!attr) { + return -1; + } + + link->attr = attr; + return 0; +} + +void ctr_link_set_dropped_attr_count(struct ctrace_link *link, uint32_t count) +{ + link->dropped_attr_count = count; +} + +void ctr_link_destroy(struct ctrace_link *link) +{ + if (link->trace_id) { + ctr_id_destroy(link->trace_id); + } + + if (link->span_id) { + ctr_id_destroy(link->span_id); + } + + if (link->trace_state) { + cfl_sds_destroy(link->trace_state); + } + + if (link->attr) { + ctr_attributes_destroy(link->attr); + } + + cfl_list_del(&link->_head); + free(link); +} + + + + + + + + + + + + + + diff --git a/fluent-bit/lib/ctraces/src/ctr_log.c b/fluent-bit/lib/ctraces/src/ctr_log.c new file mode 100644 index 000000000..d09e11d3a --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_log.c @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +#include <string.h> +#include <stdarg.h> + +#ifdef _WIN32 + #define strerror_r(errnum, buf, buf_size) strerror_s(buf, buf_size, errnum) +#endif + +void ctr_log_print(void *ctx, int level, const char *file, int line, + const char *fmt, ...) +{ + int ret; + char buf[CTR_LOG_BUF_SIZE]; + va_list args; + struct ctrace *ctr = ctx; + + if (!ctr->log_cb) { + return; + } + + if (level > ctr->log_level) { + return; + } + + va_start(args, fmt); + ret = vsnprintf(buf, CTR_LOG_BUF_SIZE - 1, fmt, args); + + if (ret >= 0) { + buf[ret] = '\0'; + } + va_end(args); + + ctr->log_cb(ctx, level, file, line, buf); +} + +int ctr_errno_print(int errnum, const char *file, int line) +{ + char buf[256]; + + strerror_r(errnum, buf, sizeof(buf) - 1); + fprintf(stderr, "[%s:%i errno=%i] %s\n", + file, line, errnum, buf); + return 0; +} + +#ifdef _WIN32 +void ctr_winapi_error_print(const char *func, int line) +{ + int error = GetLastError(); + char buf[256]; + int success; + + success = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + LANG_SYSTEM_DEFAULT, + buf, + sizeof(buf), + NULL); + if (success) { + fprintf(stderr, "[%s() line=%i error=%i] %s\n", func, line, error, buf); + } + else { + fprintf(stderr, "[%s() line=%i error=%i] Win32 API failed\n", func, line, error); + } +} +#endif diff --git a/fluent-bit/lib/ctraces/src/ctr_mpack_utils.c b/fluent-bit/lib/ctraces/src/ctr_mpack_utils.c new file mode 100644 index 000000000..222e2664f --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_mpack_utils.c @@ -0,0 +1,488 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 Eduardo Silva <eduardo@calyptia.com> + * + * 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. + */ + +#include <ctraces/ctr_mpack_utils.h> +#include <cfl/cfl_sds.h> +#include <mpack/mpack.h> + +int ctr_mpack_consume_string_or_nil_tag(mpack_reader_t *reader, cfl_sds_t *output_buffer) +{ + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_str) { + result = ctr_mpack_consume_string_tag(reader, output_buffer); + } + else if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + result = ctr_mpack_consume_nil_tag(reader); + + *output_buffer = NULL; + } + else { + result = CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + return result; +} + +int ctr_mpack_consume_binary_or_nil_tag(mpack_reader_t *reader, cfl_sds_t *output_buffer) +{ + int result; + + if (ctr_mpack_peek_type(reader) == mpack_type_bin) { + result = ctr_mpack_consume_binary_tag(reader, output_buffer); + } + else if (ctr_mpack_peek_type(reader) == mpack_type_nil) { + result = ctr_mpack_consume_nil_tag(reader); + + *output_buffer = NULL; + } + else { + result = CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + return result; +} + +int ctr_mpack_consume_nil_tag(mpack_reader_t *reader) +{ + mpack_tag_t tag; + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_nil != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_consume_double_tag(mpack_reader_t *reader, double *output_buffer) +{ + mpack_tag_t tag; + + if (NULL == output_buffer) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_double != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + *output_buffer = mpack_tag_double_value(&tag); + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_consume_uint_tag(mpack_reader_t *reader, uint64_t *output_buffer) +{ + mpack_tag_t tag; + + if (NULL == output_buffer) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_int == mpack_tag_type(&tag)) { + *output_buffer = (uint64_t) mpack_tag_int_value(&tag); + } + else if (mpack_type_uint == mpack_tag_type(&tag)) { + *output_buffer = (uint64_t) mpack_tag_uint_value(&tag); + } + else { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_consume_uint32_tag(mpack_reader_t *reader, uint32_t *output_buffer) +{ + int result; + uint64_t value; + + result = ctr_mpack_consume_uint_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS) { + *output_buffer = (uint32_t) value; + } + + return result; +} + +int ctr_mpack_consume_uint64_tag(mpack_reader_t *reader, uint64_t *output_buffer) +{ + return ctr_mpack_consume_uint_tag(reader, output_buffer); +} + +int ctr_mpack_consume_int_tag(mpack_reader_t *reader, int64_t *output_buffer) +{ + mpack_tag_t tag; + + if (NULL == output_buffer) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_int == mpack_tag_type(&tag)) { + *output_buffer = (int64_t) mpack_tag_int_value(&tag); + } + else if (mpack_type_uint == mpack_tag_type(&tag)) { + *output_buffer = (int64_t) mpack_tag_uint_value(&tag); + } + else { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_consume_int32_tag(mpack_reader_t *reader, int32_t *output_buffer) +{ + int result; + int64_t value; + + result = ctr_mpack_consume_int_tag(reader, &value); + + if (result == CTR_MPACK_SUCCESS) { + *output_buffer = (int32_t) value; + } + + return result; +} + +int ctr_mpack_consume_int64_tag(mpack_reader_t *reader, int64_t *output_buffer) +{ + return ctr_mpack_consume_int_tag(reader, output_buffer); +} + +int ctr_mpack_consume_string_tag(mpack_reader_t *reader, cfl_sds_t *output_buffer) +{ + uint32_t string_length; + mpack_tag_t tag; + + if (NULL == output_buffer) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_str != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + string_length = mpack_tag_str_length(&tag); + + /* This validation only applies to cmetrics and its use cases, we know + * for a fact that our label names and values are not supposed to be really + * long so a huge value here probably means that the data stream got corrupted. + */ + + if (CTR_MPACK_MAX_STRING_LENGTH < string_length) { + return CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + *output_buffer = cfl_sds_create_size(string_length + 1); + + if (NULL == *output_buffer) { + return CTR_MPACK_ALLOCATION_ERROR; + } + + cfl_sds_set_len(*output_buffer, string_length); + + mpack_read_cstr(reader, *output_buffer, string_length + 1, string_length); + + if (mpack_ok != mpack_reader_error(reader)) { + cfl_sds_destroy(*output_buffer); + + *output_buffer = NULL; + + return CTR_MPACK_ENGINE_ERROR; + } + + mpack_done_str(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + cfl_sds_destroy(*output_buffer); + + *output_buffer = NULL; + + return CTR_MPACK_ENGINE_ERROR; + } + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_consume_binary_tag(mpack_reader_t *reader, cfl_sds_t *output_buffer) +{ + uint32_t string_length; + mpack_tag_t tag; + + if (NULL == output_buffer) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + if (NULL == reader) { + return CTR_MPACK_INVALID_ARGUMENT_ERROR; + } + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_bin != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + string_length = mpack_tag_bin_length(&tag); + + *output_buffer = cfl_sds_create_size(string_length); + + if (NULL == *output_buffer) { + return CTR_MPACK_ALLOCATION_ERROR; + } + + cfl_sds_set_len(*output_buffer, string_length); + + mpack_read_bytes(reader, *output_buffer, string_length); + + if (mpack_ok != mpack_reader_error(reader)) { + cfl_sds_destroy(*output_buffer); + + *output_buffer = NULL; + + return CTR_MPACK_ENGINE_ERROR; + } + + mpack_done_bin(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + cfl_sds_destroy(*output_buffer); + + *output_buffer = NULL; + + return CTR_MPACK_ENGINE_ERROR; + } + + return CTR_MPACK_SUCCESS; +} + +int ctr_mpack_unpack_map(mpack_reader_t *reader, + struct ctr_mpack_map_entry_callback_t *callback_list, + void *context) +{ + struct ctr_mpack_map_entry_callback_t *callback_entry; + uint32_t entry_index; + uint32_t entry_count; + cfl_sds_t key_name; + int result; + mpack_tag_t tag; + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_map != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + entry_count = mpack_tag_map_count(&tag); + + /* This validation only applies to cmetrics and its use cases, we know + * how our schema looks and how many entries the different fields have and none + * of those exceed the number we set CTR_MPACK_MAX_MAP_ENTRY_COUNT to which is 10. + * Making these sanity checks optional or configurable in runtime might be worth + * the itme and complexity cost but that's something I don't know at the moment. + */ + + if (CTR_MPACK_MAX_MAP_ENTRY_COUNT < entry_count) { + return CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + result = 0; + + for (entry_index = 0 ; 0 == result && entry_index < entry_count ; entry_index++) { + result = ctr_mpack_consume_string_tag(reader, &key_name); + + if (CTR_MPACK_SUCCESS == result) { + callback_entry = callback_list; + result = CTR_MPACK_UNEXPECTED_KEY_ERROR; + + while (CTR_MPACK_UNEXPECTED_KEY_ERROR == result && + NULL != callback_entry->identifier) { + + if (0 == strcmp(callback_entry->identifier, key_name)) { + result = callback_entry->handler(reader, entry_index, context); + } + + callback_entry++; + } + + cfl_sds_destroy(key_name); + } + } + + if (CTR_MPACK_SUCCESS == result) { + mpack_done_map(reader); + + if (mpack_ok != mpack_reader_error(reader)) + { + return CTR_MPACK_PENDING_MAP_ENTRIES; + } + } + + return result; +} + +int ctr_mpack_unpack_array(mpack_reader_t *reader, + ctr_mpack_unpacker_entry_callback_fn_t entry_processor_callback, + void *context) +{ + uint32_t entry_index; + uint32_t entry_count; + mpack_tag_t tag; + int result; + + tag = mpack_read_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) + { + return CTR_MPACK_ENGINE_ERROR; + } + + if (mpack_type_array != mpack_tag_type(&tag)) { + return CTR_MPACK_UNEXPECTED_DATA_TYPE_ERROR; + } + + entry_count = mpack_tag_array_count(&tag); + + /* This validation only applies to cmetrics and its use cases, we know + * that in our schema we have the following arrays : + * label text dictionary (strings) + * dimension labels (indexes) + * metric values + * dimension values + * + * IMO none of these arrays should be huge so I think using 65535 as a limit + * gives us more than enough wiggle space (in reality I don't expect any of these + * arrays to hold more than 128 values but I could be wrong as that probably depends + * on the flush interval) + */ + + if (CTR_MPACK_MAX_ARRAY_ENTRY_COUNT < entry_count) { + return CTR_MPACK_CORRUPT_INPUT_DATA_ERROR; + } + + result = CTR_MPACK_SUCCESS; + + for (entry_index = 0 ; + CTR_MPACK_SUCCESS == result && entry_index < entry_count ; + entry_index++) { + result = entry_processor_callback(reader, entry_index, context); + } + + if (CTR_MPACK_SUCCESS == result) { + mpack_done_array(reader); + + if (mpack_ok != mpack_reader_error(reader)) + { + return CTR_MPACK_PENDING_ARRAY_ENTRIES; + } + } + + return result; +} + +int ctr_mpack_peek_array_length(mpack_reader_t *reader) +{ + mpack_tag_t tag; + + tag = mpack_peek_tag(reader); + + if (mpack_ok != mpack_reader_error(reader)) + { + return 0; + } + + if (mpack_type_array != mpack_tag_type(&tag)) { + return 0; + } + + return mpack_tag_array_count(&tag); +} + +mpack_type_t ctr_mpack_peek_type(mpack_reader_t *reader) +{ + mpack_tag_t tag; + + tag = mpack_peek_tag(reader); + + if (mpack_reader_error(reader) != mpack_ok) { + return mpack_type_missing; + } + + return mpack_tag_type(&tag); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_random.c b/fluent-bit/lib/ctraces/src/ctr_random.c new file mode 100644 index 000000000..0274c238b --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_random.c @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +#if defined(unix) || defined (__unix) || defined(__unix__) || defined(__linux__) || \ + defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__ANDROID__) +#define ITS_A_UNIX_FRIEND +#endif + +#ifdef CTR_HAVE_GETRANDOM +#include <sys/random.h> +#endif + +#ifdef ITS_A_UNIX_FRIEND +#include <fcntl.h> +#include <unistd.h> +#else +// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the +// "Community Additions" comment on MSDN here: +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +#define SystemFunction036 NTAPI SystemFunction036 +#include <ntsecapi.h> +#undef SystemFunction036 + +#endif + +#include <time.h> + +ssize_t ctr_random_get(void *buf, size_t len) +{ + int i; + ssize_t ret = 0; + unsigned int s; + char *tmp; + +#ifdef CTR_HAVE_GETRANDOM + /* + * On Linux systems getrandom() is preferred, note that our use case it's pretty + * simple (no security stuff). + */ + ret = getrandom(buf, len, GRND_NONBLOCK); + return ret; +#endif + + /* if getrandom() is not available and we are on Linux, macOS or BSD, try out /dev/urandom */ +#ifdef ITS_A_UNIX_FRIEND + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if (fd > 0) { + ret = read(fd, buf, len); + close(fd); + return ret; + } + + s = time(NULL); + + /* fallback... a very slow way to compose a random buffer */ + tmp = buf; + for (i = 0; i < len; i++) { + /* fixme: we need a good entropy here */ + tmp[i] = rand_r(&s); + } +#else /* Windows ? */ + ret = RtlGenRandom(buf, len); +#endif + + return ret; +} diff --git a/fluent-bit/lib/ctraces/src/ctr_resource.c b/fluent-bit/lib/ctraces/src/ctr_resource.c new file mode 100644 index 000000000..718ef7bc4 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_resource.c @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> +#include <ctraces/ctr_resource.h> + +struct ctrace_resource *ctr_resource_create() +{ + struct ctrace_resource *res; + struct ctrace_attributes *attr; + + res = calloc(1, sizeof(struct ctrace_resource)); + if (!res) { + ctr_errno(); + return NULL; + } + + attr = ctr_attributes_create(); + if (!attr) { + ctr_resource_destroy(res); + return NULL; + } + res->attr = attr; + + return res; +} + +struct ctrace_resource *ctr_resource_create_default() +{ + struct ctrace_resource *res; + + res = ctr_resource_create(); + if (!res) { + return NULL; + } + + /* some default attributes */ + ctr_attributes_set_string(res->attr, "service.name", "Fluent Bit"); + ctr_attributes_set_int64(res->attr, "release_year", 2014); + + return res; +} + +int ctr_resource_set_attributes(struct ctrace_resource *res, struct ctrace_attributes *attr) +{ + if (!attr) { + return -1; + } + + if (res->attr) { + ctr_attributes_destroy(res->attr); + } + + res->attr = attr; + return 0; +} + +void ctr_resource_set_dropped_attr_count(struct ctrace_resource *res, uint32_t count) +{ + res->dropped_attr_count = count; +} + +void ctr_resource_destroy(struct ctrace_resource *res) +{ + if (res->attr) { + ctr_attributes_destroy(res->attr); + } + free(res); +} + +/* + * resource_span API + * ----------------- + */ + +/* creates a resource_span context */ +struct ctrace_resource_span *ctr_resource_span_create(struct ctrace *ctx) +{ + struct ctrace_resource_span *resource_span; + + resource_span = calloc(1, sizeof(struct ctrace_resource_span)); + if (!resource_span) { + ctr_errno(); + return NULL; + } + cfl_list_init(&resource_span->scope_spans); + + /* link to ctraces context */ + cfl_list_add(&resource_span->_head, &ctx->resource_spans); + + /* create an empty resource */ + resource_span->resource = ctr_resource_create(); + if (!resource_span->resource) { + free(resource_span); + return NULL; + } + + return resource_span; +} + +struct ctrace_resource *ctr_resource_span_get_resource(struct ctrace_resource_span *resource_span) +{ + return resource_span->resource; +} + +/* Set the schema_url for a resource_span */ +int ctr_resource_span_set_schema_url(struct ctrace_resource_span *resource_span, char *url) +{ + if (resource_span->schema_url) { + cfl_sds_destroy(resource_span->schema_url); + } + + resource_span->schema_url = cfl_sds_create(url); + if (!resource_span->schema_url) { + return -1; + } + + return 0; +} + +void ctr_resource_span_destroy(struct ctrace_resource_span *resource_span) +{ + struct cfl_list *tmp; + struct cfl_list *head; + struct ctrace_scope_span *scope_span; + + /* release resource if set */ + if (resource_span->resource) { + ctr_resource_destroy(resource_span->resource); + } + + if (resource_span->schema_url) { + cfl_sds_destroy(resource_span->schema_url); + } + + /* remove scope spans */ + cfl_list_foreach_safe(head, tmp, &resource_span->scope_spans) { + scope_span = cfl_list_entry(head, struct ctrace_scope_span, _head); + ctr_scope_span_destroy(scope_span); + } + + free(resource_span); +} diff --git a/fluent-bit/lib/ctraces/src/ctr_scope.c b/fluent-bit/lib/ctraces/src/ctr_scope.c new file mode 100644 index 000000000..fcb83435a --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_scope.c @@ -0,0 +1,129 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +struct ctrace_scope_span *ctr_scope_span_create(struct ctrace_resource_span *resource_span) +{ + struct ctrace_scope_span *scope_span; + + scope_span = calloc(1, sizeof(struct ctrace_scope_span)); + if (!scope_span) { + ctr_errno(); + return NULL; + } + cfl_list_init(&scope_span->spans); + cfl_list_add(&scope_span->_head, &resource_span->scope_spans); + + return scope_span; +} + +void ctr_scope_span_destroy(struct ctrace_scope_span *scope_span) +{ + struct cfl_list *tmp; + struct cfl_list *head; + struct ctrace_span *span; + + /* release instrumentation scope if set */ + if (scope_span->instrumentation_scope) { + ctr_instrumentation_scope_destroy(scope_span->instrumentation_scope); + } + + /* remove linked spans */ + cfl_list_foreach_safe(head, tmp, &scope_span->spans) { + span = cfl_list_entry(head, struct ctrace_span, _head); + ctr_span_destroy(span); + } + + if (scope_span->schema_url) { + cfl_sds_destroy(scope_span->schema_url); + } + + cfl_list_del(&scope_span->_head); + free(scope_span); +} + +/* Set the schema_url for a resource_span */ +int ctr_scope_span_set_schema_url(struct ctrace_scope_span *scope_span, char *url) +{ + if (scope_span->schema_url) { + cfl_sds_destroy(scope_span->schema_url); + } + + scope_span->schema_url = cfl_sds_create(url); + if (!scope_span->schema_url) { + return -1; + } + + return 0; +} + +void ctr_scope_span_set_instrumentation_scope(struct ctrace_scope_span *scope_span, + struct ctrace_instrumentation_scope *scope) +{ + /* Safeguard against leaks */ + if (scope_span->instrumentation_scope != NULL) { + ctr_instrumentation_scope_destroy(scope_span->instrumentation_scope); + } + + scope_span->instrumentation_scope = scope; +} + +struct ctrace_instrumentation_scope *ctr_instrumentation_scope_create(char *name, char *version, + uint32_t dropped_attr_count, + struct ctrace_attributes *attr) +{ + struct ctrace_instrumentation_scope *ins_scope; + + ins_scope = calloc(1, sizeof(struct ctrace_instrumentation_scope)); + if (!ins_scope) { + ctr_errno(); + return NULL; + } + + if (name) { + ins_scope->name = cfl_sds_create(name); + } + if (version) { + ins_scope->version = cfl_sds_create(version); + } + + ins_scope->dropped_attr_count = dropped_attr_count; + ins_scope->attr = attr; + + return ins_scope; +} + +void ctr_instrumentation_scope_destroy(struct ctrace_instrumentation_scope *ins_scope) +{ + if (ins_scope->name) { + cfl_sds_destroy(ins_scope->name); + } + + if (ins_scope->version) { + cfl_sds_destroy(ins_scope->version); + } + + if (ins_scope->attr) { + ctr_attributes_destroy(ins_scope->attr); + } + + free(ins_scope); +} + diff --git a/fluent-bit/lib/ctraces/src/ctr_span.c b/fluent-bit/lib/ctraces/src/ctr_span.c new file mode 100644 index 000000000..d93935a72 --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_span.c @@ -0,0 +1,434 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +#include <cfl/cfl.h> +#include <cfl/cfl_time.h> +#include <cfl/cfl_kvlist.h> + +struct ctrace_span *ctr_span_create(struct ctrace *ctx, struct ctrace_scope_span *scope_span, cfl_sds_t name, + struct ctrace_span *parent) +{ + struct ctrace_span *span; + + if (!ctx || !scope_span || !name) { + return NULL; + } + + /* allocate a spanc context */ + span = calloc(1, sizeof(struct ctrace_span)); + if (!span) { + ctr_errno(); + return NULL; + } + + /* references */ + span->scope_span = scope_span; + span->ctx = ctx; + + /* name */ + span->name = cfl_sds_create(name); + if (!span->name) { + free(span); + return NULL; + } + + /* attributes */ + span->attr = ctr_attributes_create(); + if (!span->attr) { + free(span); + return NULL; + } + cfl_list_init(&span->events); + cfl_list_init(&span->links); + + /* dropped attributes count */ + span->dropped_attr_count = 0; + + /* if a parent context was given, populate the span parent id */ + if (parent && parent->span_id) { + ctr_span_set_parent_span_id_with_cid(span, parent->span_id); + } + + /* link span to struct scope_span->spans */ + cfl_list_add(&span->_head, &scope_span->spans); + + /* link span to the struct ctrace->span_list */ + cfl_list_add(&span->_head_global, &ctx->span_list); + + /* set default kind */ + ctr_span_kind_set(span, CTRACE_SPAN_INTERNAL); + + /* always start a span by default, the start can be overriden later if needed */ + ctr_span_start(ctx, span); + return span; +} + +/* Set the Span ID with a given buffer and length */ +int ctr_span_set_trace_id(struct ctrace_span *span, void *buf, size_t len) +{ + if (!buf || len <= 0) { + return -1; + } + + /* If trace_id is already set, free it first */ + if (span->trace_id != NULL) { + ctr_id_destroy(span->trace_id); + span->trace_id = NULL; + } + + span->trace_id = ctr_id_create(buf, len); + if (!span->trace_id) { + return -1; + } + + return 0; +} + +/* Set the Span ID by using a ctrace_id context */ +int ctr_span_set_trace_id_with_cid(struct ctrace_span *span, struct ctrace_id *cid) +{ + return ctr_span_set_trace_id(span, + ctr_id_get_buf(cid), + ctr_id_get_len(cid)); +} + +/* Set the Span ID with a given buffer and length */ +int ctr_span_set_span_id(struct ctrace_span *span, void *buf, size_t len) +{ + if (!buf || len <= 0) { + return -1; + } + + span->span_id = ctr_id_create(buf, len); + if (!span->span_id) { + return -1; + } + + return 0; +} + +/* Set the Span ID by using a ctrace_id context */ +int ctr_span_set_span_id_with_cid(struct ctrace_span *span, struct ctrace_id *cid) +{ + return ctr_span_set_span_id(span, + ctr_id_get_buf(cid), + ctr_id_get_len(cid)); +} + +/* Set the Span Parent ID with a given buffer and length */ +int ctr_span_set_parent_span_id(struct ctrace_span *span, void *buf, size_t len) +{ + if (!buf || len <= 0) { + return -1; + } + + if (span->parent_span_id) { + ctr_id_destroy(span->parent_span_id); + } + + span->parent_span_id = ctr_id_create(buf, len); + if (!span->parent_span_id) { + return -1; + } + + return 0; +} + +/* Set the Span ID by using a ctrace_id context */ +int ctr_span_set_parent_span_id_with_cid(struct ctrace_span *span, struct ctrace_id *cid) +{ + return ctr_span_set_parent_span_id(span, + ctr_id_get_buf(cid), + ctr_id_get_len(cid)); +} + +int ctr_span_kind_set(struct ctrace_span *span, int kind) +{ + if (kind < CTRACE_SPAN_UNSPECIFIED || kind > CTRACE_SPAN_CONSUMER) { + return -1; + } + + span->kind = kind; + return 0; +} + +/* returns a read-only version of the Span kind */ +char *ctr_span_kind_string(struct ctrace_span *span) +{ + switch (span->kind) { + case CTRACE_SPAN_INTERNAL: + return "internal"; + case CTRACE_SPAN_SERVER: + return "server"; + case CTRACE_SPAN_CLIENT: + return "client"; + case CTRACE_SPAN_PRODUCER: + return "producer"; + case CTRACE_SPAN_CONSUMER: + return "consumer"; + default: + return "unspecified"; + }; +} + +/* + * Span attributes + * --------------- + */ +int ctr_span_set_attribute_string(struct ctrace_span *span, char *key, char *value) +{ + return ctr_attributes_set_string(span->attr, key, value); +} + +int ctr_span_set_attribute_bool(struct ctrace_span *span, char *key, int b) +{ + return ctr_attributes_set_bool(span->attr, key, b); +} + +int ctr_span_set_attribute_int64(struct ctrace_span *span, char *key, int64_t value) +{ + return ctr_attributes_set_int64(span->attr, key, value); +} + +int ctr_span_set_attribute_double(struct ctrace_span *span, char *key, double value) +{ + return ctr_attributes_set_double(span->attr, key, value); +} + +int ctr_span_set_attribute_array(struct ctrace_span *span, char *key, + struct cfl_array *value) +{ + return ctr_attributes_set_array(span->attr, key, value); +} + +int ctr_span_set_attribute_kvlist(struct ctrace_span *span, char *key, + struct cfl_kvlist *value) +{ + + return ctr_attributes_set_kvlist(span->attr, key, value); +} + +void ctr_span_start(struct ctrace *ctx, struct ctrace_span *span) +{ + uint64_t ts; + + ts = cfl_time_now(); + ctr_span_start_ts(ctx, span, ts); +} + +void ctr_span_start_ts(struct ctrace *ctx, struct ctrace_span *span, uint64_t ts) +{ + /* set the initial timestamp */ + span->start_time_unix_nano = ts; + + /* always set the span end time as the start time, so duration can be zero */ + ctr_span_end_ts(ctx, span, ts); +} + +void ctr_span_end(struct ctrace *ctx, struct ctrace_span *span) +{ + uint64_t ts; + + ts = cfl_time_now(); + ctr_span_end_ts(ctx, span, ts); +} + +void ctr_span_end_ts(struct ctrace *ctx, struct ctrace_span *span, uint64_t ts) +{ + span->end_time_unix_nano = ts; +} + +int ctr_span_set_status(struct ctrace_span *span, int code, char *message) +{ + struct ctrace_span_status *status; + + status = &span->status; + if (status->message) { + cfl_sds_destroy(status->message); + } + + if (message) { + status->message = cfl_sds_create(message); + if (!status->message) { + return -1; + } + } + + status->code = code; + return 0; +} + +void ctr_span_set_dropped_events_count(struct ctrace_span *span, uint32_t count) +{ + span->dropped_events_count = count; +} + +void ctr_span_set_dropped_attributes_count(struct ctrace_span *span, uint32_t count) +{ + span->dropped_attr_count = count; +} + +void ctr_span_destroy(struct ctrace_span *span) +{ + struct cfl_list *tmp; + struct cfl_list *head; + struct ctrace_span_event *event; + struct ctrace_span_status *status; + struct ctrace_link *link; + + if (span->name) { + cfl_sds_destroy(span->name); + } + + if (span->trace_id) { + ctr_id_destroy(span->trace_id); + } + + if (span->span_id) { + ctr_id_destroy(span->span_id); + } + + if (span->parent_span_id) { + ctr_id_destroy(span->parent_span_id); + } + + /* attributes */ + if (span->attr) { + ctr_attributes_destroy(span->attr); + } + + /* events */ + cfl_list_foreach_safe(head, tmp, &span->events) { + event = cfl_list_entry(head, struct ctrace_span_event, _head); + ctr_span_event_delete(event); + } + + /* links */ + cfl_list_foreach_safe(head, tmp, &span->links) { + link = cfl_list_entry(head, struct ctrace_link, _head); + ctr_link_destroy(link); + } + + /* status */ + status = &span->status; + if (status->message) { + cfl_sds_destroy(status->message); + } + + cfl_list_del(&span->_head); + cfl_list_del(&span->_head_global); + free(span); +} + +/* + * Span Events + * ----------- + */ +struct ctrace_span_event *ctr_span_event_add_ts(struct ctrace_span *span, char *name, uint64_t ts) +{ + struct ctrace_span_event *ev; + + if (!name) { + return NULL; + } + + ev = calloc(1, sizeof(struct ctrace_span_event)); + if (!ev) { + ctr_errno(); + return NULL; + } + ev->name = cfl_sds_create(name); + if (!ev->name) { + free(ev); + return NULL; + } + ev->attr = ctr_attributes_create(128); + ev->dropped_attr_count = 0; + + /* if no timestamp is given, use the current time */ + if (ts == 0) { + ev->time_unix_nano = cfl_time_now(); + } + else { + ev->time_unix_nano = ts; + } + + cfl_list_add(&ev->_head, &span->events); + return ev; +} + +struct ctrace_span_event *ctr_span_event_add(struct ctrace_span *span, char *name) +{ + return ctr_span_event_add_ts(span, name, 0); +} + +int ctr_span_event_set_attribute_string(struct ctrace_span_event *event, char *key, char *value) +{ + return ctr_attributes_set_string(event->attr, key, value); +} + +int ctr_span_event_set_attribute_bool(struct ctrace_span_event *event, char *key, int b) +{ + return ctr_attributes_set_bool(event->attr, key, b); +} + +int ctr_span_event_set_attribute_int64(struct ctrace_span_event *event, char *key, int64_t value) +{ + return ctr_attributes_set_int64(event->attr, key, value); +} + +int ctr_span_event_set_attribute_double(struct ctrace_span_event *event, char *key, double value) +{ + return ctr_attributes_set_double(event->attr, key, value); +} + +int ctr_span_event_set_attribute_array(struct ctrace_span_event *event, char *key, + struct cfl_array *value) +{ + return ctr_attributes_set_array(event->attr, key, value); +} + +int ctr_span_event_set_attribute_kvlist(struct ctrace_span_event *event, char *key, + struct cfl_kvlist *value) +{ + + return ctr_attributes_set_kvlist(event->attr, key, value); +} + +void ctr_span_event_set_dropped_attributes_count(struct ctrace_span_event *event, uint32_t count) +{ + event->dropped_attr_count = count; +} + +void ctr_span_event_delete(struct ctrace_span_event *event) +{ + if (event->name) { + cfl_sds_destroy(event->name); + } + + if (event->attr) { + ctr_attributes_destroy(event->attr); + } + + cfl_list_del(&event->_head); + free(event); +} + diff --git a/fluent-bit/lib/ctraces/src/ctr_utils.c b/fluent-bit/lib/ctraces/src/ctr_utils.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_utils.c diff --git a/fluent-bit/lib/ctraces/src/ctr_version.c b/fluent-bit/lib/ctraces/src/ctr_version.c new file mode 100644 index 000000000..923e6d89b --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctr_version.c @@ -0,0 +1,26 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + + +char *ctr_version() +{ + return CTR_VERSION_STR; +}
\ No newline at end of file diff --git a/fluent-bit/lib/ctraces/src/ctraces.c b/fluent-bit/lib/ctraces/src/ctraces.c new file mode 100644 index 000000000..d2258be5d --- /dev/null +++ b/fluent-bit/lib/ctraces/src/ctraces.c @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* CTraces + * ======= + * Copyright 2022 The CTraces 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. + */ + +#include <ctraces/ctraces.h> + +void ctr_opts_init(struct ctrace_opts *opts) +{ + memset(opts, '\0', sizeof(struct ctrace_opts)); +} + +void ctr_opts_set(struct ctrace_opts *opts, int value, char *val) +{ + /* unused */ + (void) opts; + (void) value; + (void) val; +} + +void ctr_opts_exit(struct ctrace_opts *opts) +{ + if (!opts) { + return; + } +} + +/* Create a CTrace context */ +struct ctrace *ctr_create(struct ctrace_opts *opts) +{ + struct ctrace *ctx; + + ctx = calloc(1, sizeof(struct ctrace)); + if (!ctx) { + ctr_errno(); + return NULL; + } + cfl_list_init(&ctx->resource_spans); + cfl_list_init(&ctx->span_list); + + return ctx; +} + +void ctr_destroy(struct ctrace *ctx) +{ + struct cfl_list *head; + struct cfl_list *tmp; + struct ctrace_resource_span *resource_span; + + /* delete resources */ + cfl_list_foreach_safe(head, tmp, &ctx->resource_spans) { + resource_span = cfl_list_entry(head, struct ctrace_resource_span, _head); + ctr_resource_span_destroy(resource_span); + } + + free(ctx); +} + |