Skip to content
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
5 changes: 3 additions & 2 deletions api/context/+opentelemetry/+context/Context.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
% Copyright 2023-2024 The MathWorks, Inc.

properties (Access={?opentelemetry.context.propagation.TextMapPropagator, ...
?opentelemetry.trace.Span, ?opentelemetry.trace.Tracer, ...
?opentelemetry.logs.Logger, ?opentelemetry.baggage.Baggage})
?opentelemetry.trace.Span, ?opentelemetry.trace.SpanContext, ...
?opentelemetry.trace.Tracer, ?opentelemetry.logs.Logger, ...
?opentelemetry.baggage.Baggage})
Proxy % Proxy object to interface C++ code
end

Expand Down
6 changes: 3 additions & 3 deletions api/trace/+opentelemetry/+trace/Context.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
classdef Context
% Tracing-related actions on context instances

% Copyright 2023 The MathWorks, Inc.
% Copyright 2023-2024 The MathWorks, Inc.

methods (Static)
function sp = extractSpan(context)
Expand All @@ -22,12 +22,12 @@
function context = insertSpan(context, span)
% Insert span into context
% NEWCTXT = OPENTELEMETRY.TRACE.CONTEXT.INSERTSPAN(CTXT, SP) inserts
% span SP into a context object CTXT and returns a new context.
% span or span context SP into a context object CTXT and returns a new context.
%
% See also EXTRACTSPAN, OPENTELEMETRY.CONTEXT.CONTEXT
arguments
context (1,1) opentelemetry.context.Context
span (1,1) opentelemetry.trace.Span
span (1,1) {mustBeA(span, ["opentelemetry.trace.Span", "opentelemetry.trace.SpanContext"])}
end
context = span.insertSpan(context); % call span method
end
Expand Down
4 changes: 2 additions & 2 deletions api/trace/+opentelemetry/+trace/Link.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
classdef Link
% Specifies a link to a span

% Copyright 2023 The MathWorks, Inc.
% Copyright 2023-2024 The MathWorks, Inc.

properties (SetAccess=immutable)
Target (1,1) opentelemetry.trace.SpanContext % Target span
Target % Target span context
end

properties (Access=?opentelemetry.trace.Tracer)
Expand Down
5 changes: 3 additions & 2 deletions api/trace/+opentelemetry/+trace/Scope.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
% Controls the duration when a span is current. Deleting a scope object
% makes the associated span no longer current.

% Copyright 2023 The MathWorks, Inc.
% Copyright 2023-2024 The MathWorks, Inc.

properties (Access=private)
Proxy % Proxy object to interface C++ code
end

methods (Access=?opentelemetry.trace.Span)
methods (Access={?opentelemetry.trace.Span, ...
?opentelemetry.trace.SpanContext})
function obj = Scope(proxy)
obj.Proxy = proxy;
end
Expand Down
111 changes: 104 additions & 7 deletions api/trace/+opentelemetry/+trace/SpanContext.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
classdef SpanContext < handle
% The part of a span that is propagated.

% Copyright 2023 The MathWorks, Inc.
% Copyright 2023-2024 The MathWorks, Inc.

properties (Dependent, SetAccess=private)
TraceId (1,1) string % Trace identifier represented as a string of 32 hexadecimal digits
Expand All @@ -14,14 +14,71 @@
Proxy % Proxy object to interface C++ code
end

methods (Access={?opentelemetry.trace.Span,?opentelemetry.trace.Link})
function obj = SpanContext(proxy)
if nargin < 1
methods
function obj = SpanContext(traceid, spanid, varargin)
% Span context
% SC = OPENTELEMETRY.TRACE.SPANCONTEXT(TRACEID, SPANID)
% creates a span context with the specified trace and span
% IDs. Trace and span IDs must be strings or char vectors
% containing a hexadecimal number. Trace IDs must be 32
% hexadecimal digits long and span IDs must be 16
% hexadecimal digits long. Valid IDs must be non-zero.
%
% SC = OPENTELEMETRY.TRACE.SPANCONTEXT(TRACEID, SPANID,
% PARAM1, VALUE1, PARAM2, VALUE2, ...) specifies optional
% parameter name/value pairs. Parameters are:
% "IsSampled" - Whether span is sampled. Default is
% true.
% "IsRemote" - Whether span is created in a remote
% process. Default is true.

if nargin == 1 && isa(traceid, "libmexclass.proxy.Proxy")
% internal calls to constructor with a proxy
obj.Proxy = traceid;
else
narginchk(2, inf);
traceid_len = 32;
spanid_len = 16;
if ~((isstring(traceid) || (ischar(traceid) && isrow(traceid))) && ...
strlength(traceid) == traceid_len && all(isstrprop(traceid, "xdigit")))
traceid = repmat('0', 1, traceid_len); % replace any illegal values with an all-zeros invalid ID
end
if ~((isstring(spanid) || (ischar(spanid) && isrow(spanid))) && ...
strlength(spanid) == spanid_len && all(isstrprop(spanid, "xdigit")))
spanid = repmat('0', 1, spanid_len); % replace any illegal values with an all-zeros invalid ID
end
% convert IDs from string to uint8 array
traceid = uint8(hex2dec(reshape(char(traceid), 2, traceid_len/2).'));
spanid = uint8(hex2dec(reshape(char(spanid), 2, spanid_len/2).'));

% default option values
issampled = true;
isremote = true;
if nargin > 2
optionnames = ["IsSampled", "IsRemote"];
for i = 1:2:length(varargin)
try
namei = validatestring(varargin{i}, optionnames);
catch
% invalid option, ignore
continue
end
valuei = varargin{i+1};
if strcmp(namei, "IsSampled")
if (isnumeric(valuei) || islogical(valuei)) && isscalar(valuei)
issampled = logical(valuei);
end
else % strcmp(namei, "IsRemote")
if (isnumeric(valuei) || islogical(valuei)) && isscalar(valuei)
isremote = logical(valuei);
end
end
end
end

obj.Proxy = libmexclass.proxy.Proxy("Name", ...
"libmexclass.opentelemetry.SpanContextProxy", ...
"ConstructorArguments", {});
else
obj.Proxy = proxy;
"ConstructorArguments", {traceid, spanid, issampled, isremote});
end
end
end
Expand Down Expand Up @@ -70,6 +127,46 @@
% ISSAMPLED, ISVALID
tf = obj.Proxy.isRemote();
end

function scope = makeCurrent(obj)
% MAKECURRENT Make span the current span
% SCOPE = MAKECURRENT(SPCTXT) makes the span represented by
% span context SPCTXT as the current span, by
% inserting it into the current context. Returns a scope
% object SCOPE that determines the duration when span is current.
% When SCOPE is deleted, span will no longer be current.
%
% See also OPENTELEMETRY.CONTEXT.CONTEXT,
% OPENTELEMETRY.GETCURRENTCONTEXT, OPENTELEMETRY.TRACE.SCOPE

% return a warning if no output specified
if nargout == 0
warning("opentelemetry:trace:SpanContext:makeCurrent:NoOutputSpecified", ...
"Calling makeCurrent without specifying an output has no effect.")
end
id = obj.Proxy.makeCurrent();
scopeproxy = libmexclass.proxy.Proxy("Name", ...
"libmexclass.opentelemetry.ScopeProxy", "ID", id);
scope = opentelemetry.trace.Scope(scopeproxy);
end

function context = insertSpan(obj, context)
% INSERTSPAN Insert span into a context and return a new context.
% NEWCTXT = INSERTSPAN(SPCTXT, CTXT) inserts the span
% represented by span context SPCTXT into context CTXT and
% returns a new context.
%
% NEWCTXT = INSERTSPAN(SPCTXT) inserts into the current context.
%
% See also OPENTELEMETRY.TRACE.CONTEXT.EXTRACTSPAN
if nargin < 2
context = opentelemetry.context.getCurrentContext();
end
contextid = obj.Proxy.insertSpan(context.Proxy.ID);
contextproxy = libmexclass.proxy.Proxy("Name", ...
"libmexclass.opentelemetry.ContextProxy", "ID", contextid);
context = opentelemetry.context.Context(contextproxy);
end
end

end
16 changes: 11 additions & 5 deletions api/trace/include/opentelemetry-matlab/trace/SpanContextProxy.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright 2023 The MathWorks, Inc.
// Copyright 2023-2024 The MathWorks, Inc.

#pragma once

#include "libmexclass/proxy/Proxy.h"
#include "libmexclass/proxy/method/Context.h"

#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/trace_id.h"
#include "opentelemetry/trace/span_id.h"
#include "opentelemetry/trace/trace_flags.h"

namespace trace_api = opentelemetry::trace;
namespace nostd = opentelemetry::nostd;
Expand All @@ -22,12 +25,11 @@ class SpanContextProxy : public libmexclass::proxy::Proxy {
REGISTER_METHOD(SpanContextProxy, isSampled);
REGISTER_METHOD(SpanContextProxy, isValid);
REGISTER_METHOD(SpanContextProxy, isRemote);
REGISTER_METHOD(SpanContextProxy, makeCurrent);
REGISTER_METHOD(SpanContextProxy, insertSpan);
}

// dummy make static method, to satisfy proxy registration
static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments) {
return std::make_shared<SpanContextProxy>(trace_api::SpanContext{false, false});
}
static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments);

trace_api::SpanContext getInstance() {
return CppSpanContext;
Expand All @@ -47,6 +49,10 @@ class SpanContextProxy : public libmexclass::proxy::Proxy {

void isRemote(libmexclass::proxy::method::Context& context);

void makeCurrent(libmexclass::proxy::method::Context& context);

void insertSpan(libmexclass::proxy::method::Context& context);

private:

trace_api::SpanContext CppSpanContext;
Expand Down
66 changes: 65 additions & 1 deletion api/trace/src/SpanContextProxy.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
// Copyright 2023 The MathWorks, Inc.
// Copyright 2023-2024 The MathWorks, Inc.

#include "opentelemetry-matlab/trace/SpanContextProxy.h"
#include "opentelemetry-matlab/trace/ScopeProxy.h"
#include "opentelemetry-matlab/context/ContextProxy.h"

#include "libmexclass/proxy/ProxyManager.h"

#include "opentelemetry/trace/default_span.h"
#include "opentelemetry/trace/context.h"
#include "opentelemetry/trace/trace_flags.h"

namespace common = opentelemetry::common;
namespace context_api = opentelemetry::context;

namespace libmexclass::opentelemetry {

libmexclass::proxy::MakeResult SpanContextProxy::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) {
matlab::data::TypedArray<uint8_t> traceid_mda = constructor_arguments[0];
trace_api::TraceId traceid(nostd::span<const uint8_t, trace_api::TraceId::kSize>(&(*traceid_mda.cbegin()), 16));
matlab::data::TypedArray<uint8_t> spanid_mda = constructor_arguments[1];
trace_api::SpanId spanid{nostd::span<const uint8_t, trace_api::SpanId::kSize>(&(*spanid_mda.cbegin()), 8)};
matlab::data::TypedArray<bool> issampled_mda = constructor_arguments[2];
bool issampled = issampled_mda[0];
matlab::data::TypedArray<bool> isremote_mda = constructor_arguments[3];
bool isremote = isremote_mda[0];

uint8_t traceflags = 0;
if (issampled) {
traceflags |= trace_api::TraceFlags::kIsSampled;
}
return std::make_shared<SpanContextProxy>(trace_api::SpanContext{traceid, spanid, trace_api::TraceFlags(traceflags), isremote});
}

void SpanContextProxy::getTraceId(libmexclass::proxy::method::Context& context) {
const trace_api::TraceId& tid = CppSpanContext.trace_id();

Expand Down Expand Up @@ -90,4 +115,43 @@ void SpanContextProxy::isRemote(libmexclass::proxy::method::Context& context) {
context.outputs[0] = remote_mda;
}

void SpanContextProxy::makeCurrent(libmexclass::proxy::method::Context& context) {
// create a default span to associate with span context
auto cppspan = nostd::shared_ptr<trace_api::Span>(new trace_api::DefaultSpan(CppSpanContext));

// instantiate a ScopeProxy instance
auto scproxy = std::shared_ptr<libmexclass::proxy::Proxy>(new ScopeProxy{cppspan});

// obtain a proxy ID
libmexclass::proxy::ID proxyid = libmexclass::proxy::ProxyManager::manageProxy(scproxy);

// return the ID
matlab::data::ArrayFactory factory;
auto proxyid_mda = factory.createScalar<libmexclass::proxy::ID>(proxyid);
context.outputs[0] = proxyid_mda;
}

void SpanContextProxy::insertSpan(libmexclass::proxy::method::Context& context) {
matlab::data::TypedArray<uint64_t> contextid_mda = context.inputs[0];
libmexclass::proxy::ID contextid = contextid_mda[0];

// create a default span to associate with span context
auto cppspan = nostd::shared_ptr<trace_api::Span>(new trace_api::DefaultSpan(CppSpanContext));

context_api::Context ctxt = std::static_pointer_cast<ContextProxy>(
libmexclass::proxy::ProxyManager::getProxy(contextid))->getInstance();
context_api::Context newctxt = trace_api::SetSpan(ctxt, cppspan);

// instantiate a ContextProxy instance
auto ctxtproxy = std::shared_ptr<libmexclass::proxy::Proxy>(new ContextProxy(std::move(newctxt)));

// obtain a proxy ID
libmexclass::proxy::ID proxyid = libmexclass::proxy::ProxyManager::manageProxy(ctxtproxy);

// return the ID
matlab::data::ArrayFactory factory;
auto proxyid_mda = factory.createScalar<libmexclass::proxy::ID>(proxyid);
context.outputs[0] = proxyid_mda;
}

} // namespace libmexclass::opentelemetry
Loading