diff --git a/.gitignore b/.gitignore index ae5b7926b2..d1e2d69f2e 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,8 @@ # Bazel files /bazel-* +/.idea/ +/.idea/.gitignore +/.idea/modules.xml +/.idea/opentelemetry-cpp.iml +/.idea/vcs.xml diff --git a/api/include/opentelemetry/trace/propagation/HttpTraceContext.cc b/api/include/opentelemetry/trace/propagation/HttpTraceContext.cc new file mode 100644 index 0000000000..fdf9543b93 --- /dev/null +++ b/api/include/opentelemetry/trace/propagation/HttpTraceContext.cc @@ -0,0 +1,156 @@ +#include +#include "opentelemetry/trace/propagation/httptextformat.h" +#include "opentelemetry/context/context.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/common/variant.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace trace +{ +namespace propagation +{ +namespace +{ + +static Context SetSpanInContext(common::AttributeValue span, Context &context) { + Context new_values = Context(context); + // I don't know if the SPAN_KEY is defined in the context.h. + // My point is that since each key when it is created is unique in terms of its id even though they may have the same name, + // it would make sense to define those keys in a single file only and had to be referenced by other files to store and retrieve values, + // otherwise I will not be able to access any fields, for example, "current-span" as CreateKey("current-span") will + // not work because the id is different when the value is put into despite the Key is also created from + // CreateKey("current-span"). + // Don't know if I get the correct understanding there. + new_values.setValue(Context.SPAN_KEY,span); + return new_values; +} + +static common::AttributeValue GetCurrentSpan(Context &context) { + common::AttributeValue span = get_value(Context.SPAN_KEY, context); + if (span == NULL) { + return NULL; + } + return span; +} + +// The HttpTraceContext provides methods to extract and inject +// context into headers of HTTP requests with traces. +// Example: +// HttpTraceContext.inject(setter,&carrier,&context); +// HttpTraceContext.extract(getter,&carrier,&context); +class HttpTraceContext : public HTTPTextFormat +{ + public: + List fields() { + static const auto* FIELDS = new std::vector({TRACE_PARENT, TRACE_STATE}); + return FIELDS; + } + + void inject(Setter setter, T &carrier, const Context &context) override { + common::AttributeValue span = GetCurrentSpan(context); + if (span == NULL || !span.getContext().isValid()) { + // We don't have span.getContext() in span.h, should we just use span? As well as acquiring validity. (I do know how to implement them though) + return; + } + injectImpl(span.getContext(), carrier, setter); // span.getContext() function needed + } + + Context extract(Getter getter, const T &carrier, Context &context) override { + SpanContext spanContext = extractImpl(carrier, getter); + return SetSpanInContext(trace.DefaultSpan(spanContext), context); // I actually need a default span class (implemented) here, I don't know who to ask for though. But both python and java version have default span classes though. + } + + private: + static const nostd::string_view TRACE_PARENT = "traceparent"; + static const nostd::string_view TRACE_STATE = "tracestate"; + static const int VERSION_BYTES = 2; + static const int TRACE_ID_BYTES = 32; + static const int PARENT_ID_BYTES = 16; + static const int TRACE_FLAG_BYTES = 2; + static const int TRACE_DELIMITER_BYTES = 3; + static const int HEADER_SIZE = VERSION_BYTES + TRACE_ID_BYTES + PARENT_ID_BYTES + TRACE_FLAG_BYTES + TRACE_DELIMITER_BYTES; + + static Context checkNotNull(Context &arg, nostd::string_view errorMessage) { + if (arg == NULL) { + throw new NullPointerException("error: null " + errorMessage); + } + return arg; + } + + static void injectImpl(Setter setter, T &carrier, const SpanContext &spanContext) { + char hex_string[HEADER_SIZE]; + sprintf(hex_string, "00-%032x-%016x-%02x",span_context.trace_id,span_context.span_id,span_context.trace_flags); + nostd::string_view traceparent_string = nostd::string_view(hex_string, HEADER_SIZE); + setter(carrier, TRACE_PARENT, traceparent_string); + if (spanContext.getTraceState()) { + nostd::string_view tracestate_string = formatTracestate(span_context.getTraceState()); // I need the definition for the type of TraceState(Dictionary or something else) + setter(carrier, TRACE_STATE, tracestate_string); + } + } + + static SpanContext extractContextFromTraceParent(nostd::string_view &traceparent) { + bool isValid = traceparent.length() == HEADER_SIZE + && traceparent[VERSION_BYTES] == "-" + && traceparent[VERSION_BYTES+TRACE_ID_BYTES+1] == "-" + && traceparent[VERSION_BYTES+TRACE_ID_BYTES+PARENT_ID_BYTES+2] == "-"; + if (!isValid) { + std::cout<<"Unparseable traceparent header. Returning INVALID span context."< +#include "opentelemetry/context/context.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace trace +{ +namespace propagation +{ + +// Set the span in the given context. +virtual static Context SetSpanInContext(Span span, Context &context) = 0; +// Retrieve the current span. +virtual static Span GetCurrentSpan(Context &context) = 0; + +// The HTTPTextFormat class provides an interface that enables extracting and injecting +// context into headers of HTTP requests. HTTP frameworks and clients +// can integrate with HTTPTextFormat by providing the object containing the +// headers, and a getter and setter function for the extraction and +// injection of values, respectively. +template +class HTTPTextFormat { + public: + // Rules that manages how context will be extracted from carrier. + using Getter = nostd::string_view(*)(T &carrier, nostd::string_view trace_type); + + // Rules that manages how context will be injected to carrier. + using Setter = void(*)(T &carrier, nostd::string_view trace_type,nostd::string trace_description); + + // Returns the context that is stored in the HTTP header carrier with self defined rules. + virtual Context extract(Getter get_from_carrier, const T &carrier, Context &context) = 0; + + // Sets the context for a HTTP header carrier with self defined rules. + virtual void inject(Setter set_from_carrier, T &carrier, const Context &context) = 0; +}; +} +} +OPENTELEMETRY_END_NAMESPACE