Skip to content

Commit

Permalink
Merge pull request #44 from mathworks/changes_after_v_1_3_0
Browse files Browse the repository at this point in the history
Changes after v 1 3 0
  • Loading branch information
duncanpo authored Nov 1, 2023
2 parents e2525ed + ac78aac commit bb15a99
Show file tree
Hide file tree
Showing 41 changed files with 1,368 additions and 407 deletions.
9 changes: 1 addition & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ jobs:
build-and-run-tests:
runs-on: ubuntu-latest
env:
OPENTELEMETRY_CPP_INSTALL: "${{ github.workspace }}/otel_cpp_install"
OPENTELEMETRY_MATLAB_INSTALL: "${{ github.workspace }}/otel_matlab_install"
OPENTELEMETRY_COLLECTOR_INSTALL: "${{ github.workspace }}/otelcol"
SYSTEM_LIBSTDCPP_PATH: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
steps:
- name: Download OpenTelemetry-Matlab source
Expand All @@ -17,15 +15,10 @@ jobs:
path: opentelemetry-matlab
- name: Install MATLAB
uses: matlab-actions/setup-matlab@v1
- name: Download OpenTelemetry Collector binary
run: |
mkdir otelcol && cd otelcol
wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.75.0/otelcol_0.75.0_linux_amd64.tar.gz
tar -xzf otelcol_0.75.0_linux_amd64.tar.gz
- name: Build OpenTelemetry-Matlab
run: |
cd opentelemetry-matlab
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${{ env.OPENTELEMETRY_MATLAB_INSTALL }}
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DWITH_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=${{ env.OPENTELEMETRY_MATLAB_INSTALL }}
cmake --build build --config Release --target install
- name: Run tests
env:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# build directory
# build directories
build

# Autosave files
Expand Down
21 changes: 16 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ else()
endif()

if(NOT DEFINED VCPKG_INSTALLED_DIR)
set(DVCPKG_INSTALLED_DIR ${CMAKE_BINARY_DIR}/vcpkg_installed)
set(VCPKG_INSTALLED_DIR ${CMAKE_BINARY_DIR}/vcpkg_installed)
endif()

# ######################################
Expand All @@ -71,6 +71,7 @@ endif()
if(APPLE)
option(SKIP_OTEL_CPP_PATCH "Whether to skip patching OpenTelemetry-cpp" OFF)
endif()
option(WITH_EXAMPLES "Whether to build examples" OFF)

# set vcpkg features depending on specified options
set(VCPKG_MANIFEST_FEATURES "") # start with empty
Expand Down Expand Up @@ -269,7 +270,7 @@ endif()
target_compile_options(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTLP_MACROS} ${CUSTOM_CXX_FLAGS})

# link against OpenTelemetry-cpp libraries and their dependencies
target_link_libraries(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_common${CMAKE_STATIC_LIBRARY_SUFFIX}
set(OTEL_CPP_LINK_LIBRARIES ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_common${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_otlp_recordable${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}opentelemetry_proto${OTEL_PROTO_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_resources${CMAKE_STATIC_LIBRARY_SUFFIX}
Expand All @@ -278,19 +279,21 @@ target_link_libraries(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTEL_CPP_PRE
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_logs${CMAKE_STATIC_LIBRARY_SUFFIX}
${Protobuf_LIBRARIES})
if(WITH_OTLP_HTTP)
target_link_libraries(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_http${CMAKE_STATIC_LIBRARY_SUFFIX}
set(OTEL_CPP_LINK_LIBRARIES ${OTEL_CPP_LINK_LIBRARIES} ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_http${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_http_client${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_http_client_curl${CMAKE_STATIC_LIBRARY_SUFFIX}
${CURL_LIBRARIES})
endif()
if(WITH_OTLP_GRPC)
target_link_libraries(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_grpc${CMAKE_STATIC_LIBRARY_SUFFIX}
set(OTEL_CPP_LINK_LIBRARIES ${OTEL_CPP_LINK_LIBRARIES} ${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_grpc${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}opentelemetry_exporter_otlp_grpc_client${CMAKE_STATIC_LIBRARY_SUFFIX}
${OTEL_CPP_PREFIX}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}opentelemetry_proto_grpc${OTEL_PROTO_LIBRARY_SUFFIX}
gRPC::grpc++
absl::synchronization)
endif()

target_link_libraries(${OPENTELEMETRY_PROXY_LIBRARY_NAME} PRIVATE ${OTEL_CPP_LINK_LIBRARIES})

# On Linux, when linking with certain static libraries, need to force include entire archive to avoid the linker mistakenly leaving out symbols
if(UNIX AND NOT APPLE AND NOT CYGWIN)
set(OPENTELEMETRY_PROXY_LINK_OPTIONS -Wl,--whole-archive
Expand Down Expand Up @@ -394,4 +397,12 @@ if(WITH_OTLP_GRPC)
endif()

# Install dependent runtime libraries
install(FILES ${OPENTELEMETRY_PROXY_RUNTIME_LIBRARIES} DESTINATION +libmexclass/+proxy)
set(LIBMEXCLASS_PROXY_INSTALLED_DIR +libmexclass/+proxy)
install(FILES ${OPENTELEMETRY_PROXY_RUNTIME_LIBRARIES} DESTINATION ${LIBMEXCLASS_PROXY_INSTALLED_DIR})

# ##############################
# Subdirectories
# ##############################
if(WITH_EXAMPLES)
add_subdirectory(examples)
endif()
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# MATLAB Interface to OpenTelemetry
[![View OpenTelemetry-Matlab on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/130979-opentelemetry-matlab) [![MATLAB](https://github.com/mathworks/OpenTelemetry-Matlab/actions/workflows/build.yml/badge.svg)](https://github.com/mathworks/OpenTelemetry-Matlab/actions/workflows/build.yml)

MATLAB® interface to [OpenTelemetry™](https://opentelemetry.io/), based on the [OpenTelemetry Specification](https://opentelemetry.io/docs/reference/specification/). OpenTelemetry is an observability framework for creating and managing telemetry data, such as traces, metrics, and logs. This data can then be sent to an observability back-end for monitoring, alerts, and analysis.

Expand All @@ -12,7 +13,8 @@ Requires MATLAB release R2022b or newer
- [MATLAB](https://www.mathworks.com/products/matlab.html)

### 3rd Party Products:
- [Opentelemetry C++](https://github.com/open-telemetry/opentelemetry-cpp)
- [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector-releases/releases)
- [OpenTelemetry C++](https://github.com/open-telemetry/opentelemetry-cpp)
- [vcpkg C/C++ dependency manager](https://vcpkg.io)

## Installation
Expand Down Expand Up @@ -57,6 +59,8 @@ otelcol --config <otelcol-config-yaml>
```
4. If your collector is configured to display the data, you should see your span displayed.

For more examples, see the "examples" folder.

## Help
To view documentation of individual function, type "help \<function_name>\". For example,
```
Expand Down
10 changes: 7 additions & 3 deletions api/trace/+opentelemetry/+trace/Span.m
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ function setStatus(obj, status, description)
% new status is not valid, ignore
return
end
description = opentelemetry.common.mustBeScalarString(description);
if nargin < 3
description = "";
else
description = opentelemetry.common.mustBeScalarString(description);
end
obj.Proxy.setStatus(status, description);
end

Expand Down Expand Up @@ -181,8 +185,7 @@ function setStatus(obj, status, description)
function attrs = processAttributes(attrsin)
import opentelemetry.trace.Span.processAttribute

nin = length(attrsin);
if nin == 1 && isa(attrsin{1}, "dictionary")
if isscalar(attrsin) && isa(attrsin{1}, "dictionary")
% dictionary case
attrtbl = entries(attrsin{1});
nattr = height(attrtbl);
Expand All @@ -203,6 +206,7 @@ function setStatus(obj, status, description)
attrs = attrs(:);
else
% NV pairs
nin = length(attrsin);
if rem(nin,2) ~= 0
% Mismatched name-value pairs. Ignore all attributes.
attrs = cell(1,0);
Expand Down
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

add_subdirectory(context_propagation)
add_subdirectory(webread)
29 changes: 29 additions & 0 deletions examples/context_propagation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

# C++ target
set(CONTEXTPROP_EXAMPLE_TARGET contextprop_example_client)
add_executable(${CONTEXTPROP_EXAMPLE_TARGET} cpp/client.cc)

target_include_directories(${CONTEXTPROP_EXAMPLE_TARGET} PRIVATE ${OTEL_CPP_PREFIX}/include)
target_link_libraries(${CONTEXTPROP_EXAMPLE_TARGET} PRIVATE ${OTEL_CPP_LINK_LIBRARIES})
if(UNIX AND NOT APPLE AND NOT CYGWIN)
target_link_options(${CONTEXTPROP_EXAMPLE_TARGET} PRIVATE ${OPENTELEMETRY_PROXY_LINK_OPTIONS})
elseif(APPLE)
set_target_properties(${CONTEXTPROP_EXAMPLE_TARGET} PROPERTIES BUILD_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBMEXCLASS_PROXY_INSTALLED_DIR}")
endif()
# use the same C++ standard as OpenTelemetry-cpp
target_compile_features(${CONTEXTPROP_EXAMPLE_TARGET} PRIVATE cxx_std_${OTEL_CPP_CXX_STANDARD})

# MATLAB target
find_package(Matlab REQUIRED COMPONENTS MCC_COMPILER MAIN_PROGRAM)

set(CONTEXTPROP_EXAMPLE_DEPLOYNAME mymagic)
set(CONTEXTPROP_EXAMPLE_MATLAB_SOURCE ${CMAKE_CURRENT_LIST_DIR}/matlab/${CONTEXTPROP_EXAMPLE_DEPLOYNAME}.m)
set(CONTEXTPROP_EXAMPLE_ROUTES ../../../examples/context_propagation/matlab/routes.json) #somehow, only relative paths are allowed
matlab_get_version_from_matlab_run(${Matlab_MAIN_PROGRAM} Matlab_LIST_VERSION)
if(DEFINED Matlab_LIST_VERSION AND ${Matlab_LIST_VERSION} VERSION_GREATER_EQUAL 23.2.0)
# since MATLAB R2023b, route mapping can be specified at the archive level
set(ARCHIVE_ROUTES ",ROUTES:${CONTEXTPROP_EXAMPLE_ROUTES}")
else()
set(ARCHIVE_ROUTES "")
endif()
install(CODE "execute_process(COMMAND ${Matlab_MCC_COMPILER} -W CTF:${CONTEXTPROP_EXAMPLE_DEPLOYNAME}${ARCHIVE_ROUTES} -U ${CONTEXTPROP_EXAMPLE_MATLAB_SOURCE} -a ${CMAKE_INSTALL_PREFIX} -a ${CMAKE_INSTALL_PREFIX}/+libmexclass/+proxy WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
20 changes: 20 additions & 0 deletions examples/context_propagation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Context Propagation Example

In this example, a C++ client calls a MATLAB function hosted on MATLAB Production Server that returns a magic square matrix. Both the C++ client and the MATLAB code are instrumented with OpenTelemetry, and their generated spans form a single trace.

## Building the Example
1. Enable WITH_EXAMPLES when building OpenTelemetry-Matlab
```
cmake -S . -B build -DWITH_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=<opentelemetry-matlab-installdir>
cmake --build build --config Release
```
The built examples can be found in build/examples/context_propagation and subdirectories.
2. [Create](https://www.mathworks.com/help/mps/server/creating-a-server.html) and [start](https://www.mathworks.com/help/mps/qs/starting-and-stopping.html) a MATLAB Production Server instance.
3. [Deploy](https://www.mathworks.com/help/mps/qs/share-a-ctf-archive-on-the-server-instance.html) archive to server instance by copying to the auto_deploy directory.
4. If using a MATLAB release before R2023b, [copy](https://www.mathworks.com/help/mps/server/use-web-handler-for-custom-routes-and-custom-payloads.html) matlab/routes.json to the config directory of the server instance.
6. Start an instance of [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector).
7. Start the C++ client.
```
cd cpp/build/Release
http_client
```
39 changes: 39 additions & 0 deletions examples/context_propagation/cpp/HttpTextMapCarrier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 The MathWorks, Inc.

#pragma once

#include <string>
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"

namespace
{

template <typename T>
class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCarrier
{
public:
HttpTextMapCarrier(T &headers) : headers_(headers) {}
HttpTextMapCarrier() = default;
virtual opentelemetry::nostd::string_view Get(
opentelemetry::nostd::string_view key) const noexcept override
{
std::string key_to_compare = key.data();
auto it = headers_.find(key_to_compare);
if (it != headers_.end())
{
return it->second;
}
return "";
}

virtual void Set(opentelemetry::nostd::string_view key,
opentelemetry::nostd::string_view value) noexcept override
{
headers_.insert(std::pair<std::string, std::string>(std::string(key), std::string(value)));
}

T headers_;
};

} // namespace
145 changes: 145 additions & 0 deletions examples/context_propagation/cpp/client.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2023 The MathWorks, Inc.

#include "opentelemetry/ext/http/client/http_client_factory.h"
#include "opentelemetry/ext/http/common/url_parser.h"
#include "opentelemetry/trace/semantic_conventions.h"
#include "HttpTextMapCarrier.h"

#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_context.h"
#include "opentelemetry/sdk/trace/tracer_context_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/provider.h"

#include "opentelemetry/context/propagation/global_propagator.h"
#include "opentelemetry/context/propagation/text_map_propagator.h"

#include <vector>
#include "opentelemetry/ext/http/client/http_client.h"
#include "opentelemetry/nostd/shared_ptr.h"

namespace
{

using namespace opentelemetry::trace;
namespace http_client = opentelemetry::ext::http::client;
namespace context = opentelemetry::context;
namespace nostd = opentelemetry::nostd;

void InitTracer()
{
auto exporter = opentelemetry::exporter::otlp::OtlpHttpExporterFactory::Create();
auto processor =
opentelemetry::sdk::trace::SimpleSpanProcessorFactory::Create(std::move(exporter));
std::vector<std::unique_ptr<opentelemetry::sdk::trace::SpanProcessor>> processors;
processors.push_back(std::move(processor));
std::unique_ptr<opentelemetry::sdk::trace::TracerContext> context =
opentelemetry::sdk::trace::TracerContextFactory::Create(std::move(processors));
std::shared_ptr<opentelemetry::trace::TracerProvider> provider =
opentelemetry::sdk::trace::TracerProviderFactory::Create(std::move(context));
// Set the global trace provider
opentelemetry::trace::Provider::SetTracerProvider(provider);

// set global propagator
opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator(
opentelemetry::nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>(
new opentelemetry::trace::propagation::HttpTraceContext()));
}

opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> get_tracer(std::string tracer_name)
{
auto provider = opentelemetry::trace::Provider::GetTracerProvider();
return provider->GetTracer(tracer_name);
}

void sendRequest(const std::string &url)
{
auto http_client = http_client::HttpClientFactory::CreateSync();
// define input to post to destination
std::vector<uint8_t> body;
uint8_t magic_square_size = 3; // request 3x3 magic square
body.push_back(magic_square_size);

// start active span
StartSpanOptions options;
options.kind = SpanKind::kClient; // client
opentelemetry::ext::http::common::UrlParser url_parser(url);

std::string span_name = url_parser.path_;
auto span = get_tracer("http-client")
->StartSpan(span_name,
{{SemanticConventions::kUrlFull, url_parser.url_},
{SemanticConventions::kUrlScheme, url_parser.scheme_},
{SemanticConventions::kHttpRequestMethod, "POST"}},
options);
auto scope = get_tracer("http-client")->WithActiveSpan(span);

// inject current context into http header
auto current_ctx = context::RuntimeContext::GetCurrent();
HttpTextMapCarrier<http_client::Headers> carrier;
auto prop = context::propagation::GlobalTextMapPropagator::GetGlobalPropagator();
prop->Inject(carrier, current_ctx);

// send http request
http_client::Result result = http_client->Post(url, body, carrier.headers_);
if (result)
{
// set span attributes
auto status_code = result.GetResponse().GetStatusCode();
span->SetAttribute(SemanticConventions::kHttpResponseStatusCode, status_code);
result.GetResponse().ForEachHeader(
[&span](nostd::string_view header_name, nostd::string_view header_value) {
span->SetAttribute("http.header." + std::string(header_name.data()), header_value);
return true;
});

if (status_code >= 400)
{
span->SetStatus(StatusCode::kError);
}
}
else
{
span->SetStatus(
StatusCode::kError,
"Response Status :" +
std::to_string(
static_cast<typename std::underlying_type<http_client::SessionState>::type>(
result.GetSessionState())));
}
// end span and export data
span->End();
}

void CleanupTracer()
{
std::shared_ptr<opentelemetry::trace::TracerProvider> none;
opentelemetry::trace::Provider::SetTracerProvider(none);
}

} // namespace

int main(int argc, char *argv[])
{
InitTracer();
constexpr char default_host[] = "localhost";
constexpr char default_path[] = "/mymagic/magic";
constexpr uint16_t default_port = 9910;
uint16_t port;

// The port the validation service listens to can be specified via the command line.
if (argc > 1)
{
port = (uint16_t)(atoi(argv[1]));
}
else
{
port = default_port;
}

std::string url = "http://" + std::string(default_host) + ":" + std::to_string(port) +
std::string(default_path);
sendRequest(url);
CleanupTracer();
}
Loading

0 comments on commit bb15a99

Please sign in to comment.