Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HPCC-30389 Split JTrace getSpanContext function #18161

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 60 additions & 66 deletions system/jlib/jtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,7 @@ class CSpan : public CInterfaceOf<ISpan>

bool getSpanContext(CHPCCHttpTextMapCarrier * carrier) const
{
if (!carrier)
return false;
assertex(carrier);

auto propagator = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();

Expand All @@ -594,66 +593,68 @@ class CSpan : public CInterfaceOf<ISpan>
}

/**
* Retrieves the Span's context as key/value pairs into the provided IProperties.
* Optionally, output follows OpenTelemetry Span context format for propogation
* Retrieves the Span's client headers traceparent and tracestate
* Output follows OpenTelemetry Span context format for propogation
* accross process boundaries.
*
* @param ctxProps IProperties container for span context key/value pairs.
* @param otelFormatted If true, output follows OpenTelemetry Span context format.
* @return True if the span context was successfully retrieved, false otherwise.
* @param clientHeaders IProperties container for client headers.
*/
bool getSpanContext(IProperties * ctxProps, bool otelFormatted) const override
void getClientHeaders(IProperties * clientHeaders) const
{
if (ctxProps == nullptr)
return false;
assertex(clientHeaders);

ctxProps->setNonEmptyProp(kGlobalIdHttpHeaderName, queryGlobalId());
clientHeaders->setNonEmptyProp(kGlobalIdHttpHeaderName, queryGlobalId());

if (otelFormatted)
{
//The localid is passed as the callerid for the client request....
ctxProps->setNonEmptyProp(kCallerIdHttpHeaderName, queryLocalId());
}
else
{
ctxProps->setNonEmptyProp(kCallerIdHttpHeaderName, queryCallerId());
}
//The localid is passed as the callerid for the client request....
clientHeaders->setNonEmptyProp(kCallerIdHttpHeaderName, queryLocalId());

if (span == nullptr)
return false;
return;

if (otelFormatted)
{
if (isEmptyString(traceID.get()) || isEmptyString(spanID.get()) || isEmptyString(traceFlags.get()))
return false;
if (isEmptyString(traceID.get()) || isEmptyString(spanID.get()) || isEmptyString(traceFlags.get()))
return;

//The traceparent header uses the version-trace_id-parent_id-trace_flags format where:
//version is always 00. trace_id is a hex-encoded trace id. span_id is a hex-encoded span id. trace_flags is a hex-encoded 8-bit field that contains tracing flags such as sampling, trace level, etc.
//Example: "traceparent", "00-beca49ca8f3138a2842e5cf21402bfff-4b960b3e4647da3f-01"
//The traceparent header uses the version-trace_id-parent_id-trace_flags format where:
//version is always 00. trace_id is a hex-encoded trace id. span_id is a hex-encoded span id. trace_flags is a hex-encoded 8-bit field that contains tracing flags such as sampling, trace level, etc.
//Example: "traceparent", "00-beca49ca8f3138a2842e5cf21402bfff-4b960b3e4647da3f-01"

StringBuffer contextHTTPHeader;
//https://www.w3.org/TR/trace-context/#header-name
contextHTTPHeader.append("00-").append(traceID.get()).append("-").append(spanID.get()).append("-").append(traceFlags.get());
ctxProps->setProp(opentelemetry::trace::propagation::kTraceParent.data(), contextHTTPHeader.str());
StringBuffer contextHTTPHeader;
//https://www.w3.org/TR/trace-context/#header-name
contextHTTPHeader.append("00-").append(traceID.get()).append("-").append(spanID.get()).append("-").append(traceFlags.get());
clientHeaders->setProp(opentelemetry::trace::propagation::kTraceParent.data(), contextHTTPHeader.str());

//The main purpose of the tracestate HTTP header is to provide additional vendor-specific trace identification
// information across different distributed tracing systems and is a companion header for the traceparent field.
// It also conveys information about the request’s position in multiple distributed tracing graphs.
//The main purpose of the tracestate HTTP header is to provide additional vendor-specific trace identification
// information across different distributed tracing systems and is a companion header for the traceparent field.
// It also conveys information about the request’s position in multiple distributed tracing graphs.

//https://www.w3.org/TR/trace-context/#trace-context-http-headers-format
//StringBuffer traceStateHTTPHeader;
//traceStateHTTPHeader.append("hpcc=").append(spanID.get());
//https://www.w3.org/TR/trace-context/#trace-context-http-headers-format
//StringBuffer traceStateHTTPHeader;
//traceStateHTTPHeader.append("hpcc=").append(spanID.get());

ctxProps->setNonEmptyProp(opentelemetry::trace::propagation::kTraceState.data(), span->GetContext().trace_state()->ToHeader().c_str());
}
else
{
ctxProps->setNonEmptyProp("traceID", traceID.get());
ctxProps->setNonEmptyProp("spanID", spanID.get());
ctxProps->setNonEmptyProp("traceFlags", traceFlags.get());
}
clientHeaders->setNonEmptyProp(opentelemetry::trace::propagation::kTraceState.data(), span->GetContext().trace_state()->ToHeader().c_str());
}

return true;
/**
* Retrieves the Span's context as key/value pairs into the provided IProperties.
* Optionally, output follows OpenTelemetry Span context format for propogation
* accross process boundaries.
*
* @param ctxProps IProperties container for span context key/value pairs.
*/
void getSpanContext(IProperties * ctxProps) const override
{
if (ctxProps == nullptr)
return;

ctxProps->setNonEmptyProp(kGlobalIdHttpHeaderName, queryGlobalId());
ctxProps->setNonEmptyProp(kCallerIdHttpHeaderName, queryCallerId());

if (span == nullptr)
return;

ctxProps->setNonEmptyProp("traceID", traceID.get());
ctxProps->setNonEmptyProp("spanID", spanID.get());
ctxProps->setNonEmptyProp("traceFlags", traceFlags.get());
}

opentelemetry::v1::trace::SpanContext querySpanContext() const
Expand Down Expand Up @@ -783,7 +784,8 @@ class CNullSpan : public CInterfaceOf<ISpan>
virtual void setSpanAttributes(const IProperties * attributes) override {}
virtual void addSpanEvent(const char * eventName) override {}
virtual void addSpanEvent(const char * eventName, IProperties * attributes) override {};
virtual bool getSpanContext(IProperties * ctxProps, bool otelFormatted) const override { return false; }
virtual void getSpanContext(IProperties * ctxProps) const override {}
virtual void getClientHeaders(IProperties * clientHeaders) const override {}

virtual void toString(StringBuffer & out) const override {}
virtual void getLogPrefix(StringBuffer & out) const override {}
Expand Down Expand Up @@ -818,19 +820,13 @@ class CChildSpan : public CSpan
}

public:
virtual bool getSpanContext(IProperties * ctxProps, bool otelFormatted) const override
virtual void getSpanContext(IProperties * ctxProps) const override
{
//MORE: It is not clear what this return value represents, and whether it would ever be checked.
bool ok = CSpan::getSpanContext(ctxProps, otelFormatted);
CSpan::getSpanContext(ctxProps);

if (ok && !otelFormatted)
{
Owned<IProperties> localParentSpanCtxProps = createProperties();
localParentSpan->getSpanContext(localParentSpanCtxProps, false);
ctxProps->setNonEmptyProp("localParentSpanID", localParentSpanCtxProps->queryProp("spanID"));
}

return ok;
Owned<IProperties> localParentSpanCtxProps = createProperties();
localParentSpan->getSpanContext(localParentSpanCtxProps);
ctxProps->setNonEmptyProp("localParentSpanID", localParentSpanCtxProps->queryProp("spanID"));
}

virtual const char* queryGlobalId() const override
Expand Down Expand Up @@ -951,20 +947,18 @@ class CServerSpan : public CSpan
}
}

bool getSpanContext(IProperties * ctxProps, bool otelFormatted) const override
void getSpanContext(IProperties * ctxProps) const override
{
bool success = CSpan::getSpanContext(ctxProps, otelFormatted);
CSpan::getSpanContext(ctxProps);

if (!otelFormatted && remoteParentSpanCtx.IsValid())
if (remoteParentSpanCtx.IsValid())
{
StringBuffer remoteParentSpanID;
char remoteParentSpanId[16] = {0};
remoteParentSpanCtx.span_id().ToLowerBase16(remoteParentSpanId);
remoteParentSpanID.append(16, remoteParentSpanId);
ctxProps->setProp("remoteParentSpanID", remoteParentSpanID.str());
}

return success;
}

void init(SpanFlags flags)
Expand Down Expand Up @@ -1046,14 +1040,14 @@ class CServerSpan : public CSpan
IProperties * getClientHeaders(const ISpan * span)
{
Owned<IProperties> headers = createProperties(true);
span->getSpanContext(headers, true); // Return value is not helpful
span->getClientHeaders(headers);
return headers.getClear();
}

IProperties * getSpanContext(const ISpan * span)
{
Owned<IProperties> headers = createProperties(true);
span->getSpanContext(headers, false);
span->getSpanContext(headers);
return headers.getClear();
}

Expand Down
3 changes: 2 additions & 1 deletion system/jlib/jtrace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ interface ISpan : extends IInterface
virtual void setSpanAttributes(const IProperties * attributes) = 0;
virtual void addSpanEvent(const char * eventName) = 0;
virtual void addSpanEvent(const char * eventName, IProperties * attributes) = 0;
virtual bool getSpanContext(IProperties * ctxProps, bool otelFormatted) const = 0;
virtual void getSpanContext(IProperties * ctxProps) const = 0;
virtual void getClientHeaders(IProperties * clientHeaders) const = 0;
virtual void toString(StringBuffer & out) const = 0;
virtual void getLogPrefix(StringBuffer & out) const = 0;

Expand Down
Loading
Loading