From f6a1c5535381f05a747c0f2c25d24d76a59545e6 Mon Sep 17 00:00:00 2001 From: Rick Tu Date: Mon, 25 Sep 2023 12:24:10 -0400 Subject: [PATCH] feat: metric_exporter, metric_reader draft version of metric reader and exporter --- .../+exporters/+otlp/OtlpGrpcMetricExporter.m | 135 ++++++++++++++++++ .../+exporters/+otlp/OtlpHttpMetricExporter.m | 131 +++++++++++++++++ .../+exporters/+otlp/defaultMetricExporter.m | 16 +++ .../otlp/OtlpGrpcMetricExporterProxy.h | 32 +++++ .../otlp/OtlpHttpMetricExporterProxy.h | 32 +++++ exporters/otlp/src/OtlpGrpcMetricExporter.cpp | 69 +++++++++ .../otlp/src/OtlpHttpMetricExporterProxy.cpp | 0 .../+sdk/+metrics/MetricExporter.m | 21 +++ .../+metrics/PeriodicExportingMetricReader.m | 58 ++++++++ .../sdk/metrics/MetricExporterProxy.h | 16 +++ .../metrics/PeriodicExportingMetricReader.h | 28 ++++ .../src/PeriodicExportingMetricReader.cpp | 23 +++ 12 files changed, 561 insertions(+) create mode 100644 exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpGrpcMetricExporter.m create mode 100644 exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpHttpMetricExporter.m create mode 100644 exporters/otlp/+opentelemetry/+exporters/+otlp/defaultMetricExporter.m create mode 100644 exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpGrpcMetricExporterProxy.h create mode 100644 exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpHttpMetricExporterProxy.h create mode 100644 exporters/otlp/src/OtlpGrpcMetricExporter.cpp create mode 100644 exporters/otlp/src/OtlpHttpMetricExporterProxy.cpp create mode 100644 sdk/metrics/+opentelemetry/+sdk/+metrics/MetricExporter.m create mode 100644 sdk/metrics/+opentelemetry/+sdk/+metrics/PeriodicExportingMetricReader.m create mode 100644 sdk/metrics/include/opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h create mode 100644 sdk/metrics/include/opentelemetry-matlab/sdk/metrics/PeriodicExportingMetricReader.h create mode 100644 sdk/metrics/src/PeriodicExportingMetricReader.cpp diff --git a/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpGrpcMetricExporter.m b/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpGrpcMetricExporter.m new file mode 100644 index 0000000..2f4a958 --- /dev/null +++ b/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpGrpcMetricExporter.m @@ -0,0 +1,135 @@ +classdef OtlpGrpcMetricExporter < opentelemetry.sdk.metrics.MetricExporter +% OtlpGrpcMetricExporter exports Metrics in OpenTelemetry Protocol format via +% gRPC. By default, it exports to the default address of the OpenTelemetry +% Collector. + +% Copyright 2023 The MathWorks, Inc. + + properties (SetAccess=immutable) + Endpoint (1,1) string % Export destination + UseCredentials (1,1) logical % Whether to use SSL credentials + CertificatePath (1,1) string % Path to .pem file for SSL encryption + CertificateString (1,1) string % In-memory string representation of .pem file for SSL encryption + Timeout (1,1) duration % Maximum time above which exports will abort + HttpHeaders (1,1) dictionary % Additional HTTP headers + end + + methods + function obj = OtlpGrpcMetricExporter(optionnames, optionvalues) + % OtlpGrpcMetricExporter exports Metrics in OpenTelemetry Protocol format via gRPC. + % EXP = OPENTELEMETRY.EXPORTERS.OTLP.OTLPGRPCMetricEXPORTER + % creates an exporter that uses default configurations. + % + % EXP = + % OPENTELEMETRY.EXPORTERS.OTLP.OTLPGRPCMetricEXPORTER(PARAM1, + % VALUE1, PARAM2, VALUE2, ...) specifies optional parameter + % name/value pairs. Parameters are: + % "Endpoint" - Endpoint to export to + % "UseCredentials" - Whether to use SSL credentials. + % Default is false. If true, use + % .pem file specified in + % "CertificatePath" or + % "CertificateString". + % "CertificatePath" - Path to .pem file for SSL encryption + % "CertificateString" - .pem file specified in memory as + % a string + % "Timeout" - Maximum time above which exports + % will abort + % "HTTPHeaders" - Additional HTTP Headers + % + % See also OPENTELEMETRY.EXPORTERS.OTLP.OTLPHTTPMetricEXPORTER + arguments (Repeating) + optionnames (1,:) {mustBeTextScalar} + optionvalues + end + + validnames = ["Endpoint", "UseCredentials ", "CertificatePath", ... + "CertificateString", "Timeout", "HttpHeaders"]; + % set default values to empty or negative + endpoint = ""; + usessl = false; + certificatepath = ""; + certificatestring = ""; + timeout_millis = -1; + headerkeys = string.empty(); + headervalues = string.empty(); + for i = 1:length(optionnames) + namei = validatestring(optionnames{i}, validnames); + valuei = optionvalues{i}; + if strcmp(namei, "Endpoint") + if ~(isStringScalar(valuei) || (ischar(valuei) && isrow(valuei))) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:EndpointNotScalarText", "Endpoint must be a scalar string."); + end + endpoint = string(valuei); + elseif strcmp(namei, "UseCredentials ") + if ~((islogical(valuei) || isnumeric(valuei)) && isscalar(valuei)) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:UseCredentialsNotScalarLogical", "UseCredentials must be a scalar logical.") + end + usessl = logical(valuei); + elseif strcmp(namei, "CertificatePath") + if ~(isStringScalar(valuei) || (ischar(valuei) && isrow(valuei))) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:CertificatePathNotScalarText", "CertificatePath must be a scalar string."); + end + certificatepath = string(valuei); + elseif strcmp(namei, "CertificateString") + if ~(isStringScalar(valuei) || (ischar(valuei) && isrow(valuei))) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:CertificateStringNotScalarText", "CertificateString must be a scalar string."); + end + certificatestring = string(valuei); + elseif strcmp(namei, "Timeout") + if ~(isduration(valuei) && isscalar(valuei)) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:TimeoutNotScalarDuration", "Timeout must be a scalar duration."); + end + timeout = valuei; + timeout_millis = milliseconds(timeout); + else % HttpHeaders + if ~isa(valuei, "dictionary") + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:HttpHeadersNotDictionary", "HttpHeaders input must be a dictionary."); + end + httpheaders = valuei; + headerkeys = keys(valuei); + headervalues = values(valuei); + if ~isstring(headervalues) + error("opentelemetry:exporters:otlp:OtlpGrpcMetricExporter:HttpHeadersNonStringValues", "HttpHeaders dictionary values must be strings.") + end + end + end + + obj = obj@opentelemetry.sdk.metrics.MetricExporter(... + "libmexclass.opentelemetry.exporters.OtlpGrpcMetricExporterProxy", ... + endpoint, usessl, certificatepath, certificatestring, ... + timeout_millis, headerkeys, headervalues); + + % populate immutable properties + [defaultendpoint, defaultcertpath, defaultcertstring, defaultmillis] = ... + getDefaultOptionValues(obj); + if endpoint == "" % not specified, use default value + obj.Endpoint = defaultendpoint; + else + obj.Endpoint = endpoint; + end + obj.UseCredentials = usessl; + if certificatepath == "" % not specified, use default value + obj.CertificatePath = defaultcertpath; + else + obj.CertificatePath = certificatepath; + end + if certificatestring == "" % not specified, use default value + obj.CertificateString = defaultcertstring; + else + obj.CertificateString = certificatestring; + end + if timeout_millis < 0 % not specified, use default value + obj.Timeout = milliseconds(defaultmillis); + else + obj.Timeout = timeout; + end + if isempty(headerkeys) % not specified, return empty dictionary + obj.HttpHeaders = dictionary(headerkeys, headervalues); + else + obj.HttpHeaders = httpheaders; + end + + end + end +end diff --git a/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpHttpMetricExporter.m b/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpHttpMetricExporter.m new file mode 100644 index 0000000..36c35cf --- /dev/null +++ b/exporters/otlp/+opentelemetry/+exporters/+otlp/OtlpHttpMetricExporter.m @@ -0,0 +1,131 @@ +classdef OtlpHttpMetricExporter < opentelemetry.sdk.metrics.MetricExporter +% OtlpHttpMetricExporter exports Metrics in OpenTelemetry Protocol format via +% HTTP. By default, it exports to the default address of the OpenTelemetry +% Collector. + +% Copyright 2023 The MathWorks, Inc. + + properties (SetAccess=immutable) + Endpoint (1,1) string % Export destination + Format (1,1) string % Data format, JSON or binary + JsonBytesMapping (1,1) string % What to convert JSON bytes to + UseJsonName (1,1) logical % Whether to use JSON name of protobuf field to set the key of JSON + Timeout (1,1) duration % Maximum time above which exports will abort + HttpHeaders (1,1) dictionary % Additional HTTP headers + end + + methods + function obj = OtlpHttpMetricExporter(optionnames, optionvalues) + % OtlpHttpMetricExporter exports Metrics in OpenTelemetry Protocol format via HTTP. + % EXP = OPENTELEMETRY.EXPORTERS.OTLP.OTLPHTTPMetricEXPORTER + % creates an exporter that uses default configurations. + % + % EXP = + % OPENTELEMETRY.EXPORTERS.OTLP.OTLPHTTPMetricEXPORTER(PARAM1, + % VALUE1, PARAM2, VALUE2, ...) specifies optional parameter + % name/value pairs. Parameters are: + % "Endpoint" - Endpoint to export to + % "Format" - Data format: "JSON" (default) or "binary" + % "JsonBytesMapping" - What to convert JSON bytes to. Supported + % values are "hex", "hexId" (default), and + % "base64". Default "hexId" + % converts to base 64 except for IDs + % which are converted to hexadecimals. + % "UseJsonName" - Whether to use JSON name of protobuf + % field to set the key of JSON + % "Timeout" - Maximum time above which exports + % will abort + % "HTTPHeaders" - Additional HTTP Headers + % + % See also OPENTELEMETRY.EXPORTERS.OTLP.OTLPGRPCMetricEXPORTER + arguments (Repeating) + optionnames (1,:) {mustBeTextScalar} + optionvalues + end + + validnames = ["Endpoint", "Format", "JsonBytesMapping", ... + "UseJsonName", "Timeout", "HttpHeaders"]; + % set default values to empty or negative + endpoint = ""; + dataformat = ""; + jsonbytesmapping = ""; + usejsonname = false; + timeout_millis = -1; + headerkeys = string.empty(); + headervalues = string.empty(); + for i = 1:length(optionnames) + namei = validatestring(optionnames{i}, validnames); + valuei = optionvalues{i}; + if strcmp(namei, "Endpoint") + if ~(isStringScalar(valuei) || (ischar(valuei) && isrow(valuei))) + error("opentelemetry:exporters:otlp:OtlpHttpMetricExporter:EndpointNotScalarText", "Endpoint must be a scalar string."); + end + endpoint = string(valuei); + elseif strcmp(namei, "Format") + dataformat = validatestring(valuei, ["JSON", "binary"]); + elseif strcmp(namei, "JsonBytesMapping") + jsonbytesmapping = validatestring(valuei, ["hex", "hexId", "base64"]); + elseif strcmp(namei, "UseJsonName") + if ~((islogical(valuei) || isnumeric(valuei)) && isscalar(valuei)) + error("opentelemetry:exporters:otlp:OtlpHttpMetricExporter:UseJsonNameNotScalarLogical", "UseJsonName must be a scalar logical.") + end + usejsonname = logical(valuei); + elseif strcmp(namei, "Timeout") + if ~(isduration(valuei) && isscalar(valuei)) + error("opentelemetry:exporters:otlp:OtlpHttpMetricExporter:TimeoutNotScalarDuration", "Timeout must be a scalar duration."); + end + timeout = valuei; + timeout_millis = milliseconds(timeout); + else % HttpHeaders + if ~isa(valuei, "dictionary") + error("opentelemetry:exporters:otlp:OtlpHttpMetricExporter:HttpHeadersNotDictionary", "HttpHeaders input must be a dictionary."); + end + httpheaders = valuei; + headerkeys = keys(valuei); + headervalues = values(valuei); + if ~isstring(headervalues) + error("opentelemetry:exporters:otlp:OtlpHttpMetricExporter:HttpHeadersNonStringValues", "HttpHeaders dictionary values must be strings.") + end + end + end + + obj = obj@opentelemetry.sdk.metrics.MetricExporter(... + "libmexclass.opentelemetry.exporters.OtlpHttpMetricExporterProxy", ... + endpoint, dataformat, jsonbytesmapping, usejsonname, ... + timeout_millis, headerkeys, headervalues); + + % populate immutable properties + if endpoint == "" || dataformat == "" || jsonbytesmapping == "" || ... + timeout_millis < 0 + [defaultendpoint, defaultformat, defaultmapping, defaultmillis] = ... + getDefaultOptionValues(obj); + end + if endpoint == "" % not specified, use default value + obj.Endpoint = defaultendpoint; + else + obj.Endpoint = endpoint; + end + if dataformat == "" % not specified, use default value + obj.Format = defaultformat; + else + obj.Format = dataformat; + end + if jsonbytesmapping == "" % not specified, use default value + obj.JsonBytesMapping = defaultmapping; + else + obj.JsonBytesMapping = jsonbytesmapping; + end + obj.UseJsonName = usejsonname; + if timeout_millis < 0 % not specified, use default value + obj.Timeout = milliseconds(defaultmillis); + else + obj.Timeout = timeout; + end + if isempty(headerkeys) % not specified, return empty dictionary + obj.HttpHeaders = dictionary(headerkeys, headervalues); + else + obj.HttpHeaders = httpheaders; + end + end + end +end diff --git a/exporters/otlp/+opentelemetry/+exporters/+otlp/defaultMetricExporter.m b/exporters/otlp/+opentelemetry/+exporters/+otlp/defaultMetricExporter.m new file mode 100644 index 0000000..a478fd2 --- /dev/null +++ b/exporters/otlp/+opentelemetry/+exporters/+otlp/defaultMetricExporter.m @@ -0,0 +1,16 @@ +function dexp = defaultMetricExporter +% Get the default Metric exporter depending on installation +% EXP = OPENTELEMETRY.EXPORTERS.OTLP.DEFAULTMetricEXPORTER returns the +% default Metric exporter. OtlpHttpMetricExporter is the default if it is +% installed. Otherwise, OtlpGrpcMetricExporter is the default. +% +% See also OPENTELEMETRY.EXPORTERS.OTLP.OTLPHTTPMetricEXPORTER, +% OPENTELEMETRY.EXPORTERS.OTLP.OTLPGRPCMetricEXPORTER + +% Copyright 2023 The MathWorks, Inc. + +if exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class") + dexp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter; +else + dexp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter; +end diff --git a/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpGrpcMetricExporterProxy.h b/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpGrpcMetricExporterProxy.h new file mode 100644 index 0000000..757de20 --- /dev/null +++ b/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpGrpcMetricExporterProxy.h @@ -0,0 +1,32 @@ +// Copyright 2023 The MathWorks, Inc. + +#pragma once + +#include "opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h" + +#include "libmexclass/proxy/Proxy.h" +#include "libmexclass/proxy/method/Context.h" + +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" +#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h" + +namespace metric_sdk = opentelemetry::sdk::metric; +namespace otlp_exporter = opentelemetry::exporter::otlp; + +namespace libmexclass::opentelemetry::exporters { +class OtlpGrpcMetricExporterProxy: public libmexclass::opentelemetry::sdk::MetricExporterProxy { + public: + OtlpGrpcMetricExporterProxy(otlp_exporter::OtlpGrpcExporterOptions options) : CppOptions(options) { + REGISTER_METHOD(OtlpGrpcMetricExporterProxy, getDefaultOptionValues); + } + + static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments); + + std::unique_ptr getInstance() override; + + void getDefaultOptionValues(libmexclass::proxy::method::Context& context); + + private: + otlp_exporter::OtlpGrpcExporterOptions CppOptions; +}; +} // namespace libmexclass::opentelemetry diff --git a/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpHttpMetricExporterProxy.h b/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpHttpMetricExporterProxy.h new file mode 100644 index 0000000..9f36f9a --- /dev/null +++ b/exporters/otlp/include/opentelemetry-matlab/exporters/otlp/OtlpHttpMetricExporterProxy.h @@ -0,0 +1,32 @@ +// Copyright 2023 The MathWorks, Inc. + +#pragma once + +#include "opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h" + +#include "libmexclass/proxy/Proxy.h" +#include "libmexclass/proxy/method/Context.h" + +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" +#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h" + +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace otlp_exporter = opentelemetry::exporter::otlp; + +namespace libmexclass::opentelemetry::exporters { +class OtlpHttpMetricExporterProxy: public libmexclass::opentelemetry::sdk::MetricExporterProxy { + public: + OtlpHttpMetricExporterProxy(otlp_exporter::OtlpHttpExporterOptions options) : CppOptions(options) { + REGISTER_METHOD(OtlpHttpMetricExporterProxy, getDefaultOptionValues); + } + + static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments); + + std::unique_ptr getInstance() override; + + void getDefaultOptionValues(libmexclass::proxy::method::Context& context); + + private: + otlp_exporter::OtlpHttpExporterOptions CppOptions; +}; +} // namespace libmexclass::opentelemetry diff --git a/exporters/otlp/src/OtlpGrpcMetricExporter.cpp b/exporters/otlp/src/OtlpGrpcMetricExporter.cpp new file mode 100644 index 0000000..e17a4fa --- /dev/null +++ b/exporters/otlp/src/OtlpGrpcMetricExporter.cpp @@ -0,0 +1,69 @@ +// Copyright 2023 The MathWorks, Inc. + +#include "opentelemetry-matlab/exporters/otlp/OtlpGrpcMetricExporterProxy.h" + +#include "libmexclass/proxy/ProxyManager.h" + +#include "opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h" + +namespace otlp_exporter = opentelemetry::exporter::otlp; + +namespace libmexclass::opentelemetry::exporters { +libmexclass::proxy::MakeResult OtlpGrpcMetricExporterProxy::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) { + matlab::data::StringArray endpoint_mda = constructor_arguments[0]; + std::string endpoint = static_cast(endpoint_mda[0]); + matlab::data::TypedArray use_ssl_mda = constructor_arguments[1]; + bool use_ssl = use_ssl_mda[0]; + matlab::data::StringArray certpath_mda = constructor_arguments[2]; + std::string certpath = static_cast(certpath_mda[0]); + matlab::data::StringArray certstring_mda = constructor_arguments[3]; + std::string certstring = static_cast(certstring_mda[0]); + matlab::data::TypedArray timeout_mda = constructor_arguments[4]; + double timeout = timeout_mda[0]; + matlab::data::Array header_mda = constructor_arguments[5]; + size_t nheaders = header_mda.getNumberOfElements(); + matlab::data::StringArray headernames_mda = constructor_arguments[5]; + matlab::data::StringArray headervalues_mda = constructor_arguments[6]; + + otlp_exporter::OtlpGrpcExporterOptions options; + if (!endpoint.empty()) { + options.endpoint = endpoint; + } + // use_ssl + options.use_ssl_credentials = use_ssl; + if (!certpath.empty()) { + options.ssl_credentials_cacert_path = certpath; + } + if (!certstring.empty()) { + options.ssl_credentials_cacert_as_string = certstring; + } + // timeout + if (timeout >= 0) { + options.timeout = std::chrono::milliseconds(static_cast(timeout)); + } + // http headers + for (size_t i = 0; i < nheaders; ++i) { + options.metadata.insert(std::pair{static_cast(headernames_mda[i]), + static_cast(headervalues_mda[i])}); + } + return std::make_shared(options); +} + +std::unique_ptr OtlpGrpcMetricExporterProxy::getInstance() { + return otlp_exporter::OtlpGrpcExporterFactory::Create(CppOptions); +} + +void OtlpGrpcMetricExporterProxy::getDefaultOptionValues(libmexclass::proxy::method::Context& context) { + otlp_exporter::OtlpGrpcExporterOptions options; + matlab::data::ArrayFactory factory; + auto endpoint_mda = factory.createScalar(options.endpoint); + auto certpath_mda = factory.createScalar(options.ssl_credentials_cacert_path); + auto certstring_mda = factory.createScalar(options.ssl_credentials_cacert_as_string); + auto timeout_millis = std::chrono::duration_cast(options.timeout); + auto timeout_mda = factory.createScalar(static_cast(timeout_millis.count())); + context.outputs[0] = endpoint_mda; + context.outputs[1] = certpath_mda; + context.outputs[2] = certstring_mda; + context.outputs[3] = timeout_mda; +} +} // namespace libmexclass::opentelemetry diff --git a/exporters/otlp/src/OtlpHttpMetricExporterProxy.cpp b/exporters/otlp/src/OtlpHttpMetricExporterProxy.cpp new file mode 100644 index 0000000..e69de29 diff --git a/sdk/metrics/+opentelemetry/+sdk/+metrics/MetricExporter.m b/sdk/metrics/+opentelemetry/+sdk/+metrics/MetricExporter.m new file mode 100644 index 0000000..c1fbd49 --- /dev/null +++ b/sdk/metrics/+opentelemetry/+sdk/+metrics/MetricExporter.m @@ -0,0 +1,21 @@ +classdef MetricExporter +% Base class of metric exporters + +% Copyright 2023 The MathWorks, Inc. + + properties (Access=?opentelemetry.sdk.metrics.PeriodicExportingMetricReader) + Proxy % Proxy object to interface C++ code + end + + methods (Access=protected) + function obj = MetricExporter(proxyname, varargin) + % Base class constructor + obj.Proxy = libmexclass.proxy.Proxy("Name", proxyname, ... + "ConstructorArguments", varargin); + end + + function varargout = getDefaultOptionValues(obj) + [varargout{1:nargout}] = obj.Proxy.getDefaultOptionValues(); + end + end +end diff --git a/sdk/metrics/+opentelemetry/+sdk/+metrics/PeriodicExportingMetricReader.m b/sdk/metrics/+opentelemetry/+sdk/+metrics/PeriodicExportingMetricReader.m new file mode 100644 index 0000000..d7604dd --- /dev/null +++ b/sdk/metrics/+opentelemetry/+sdk/+metrics/PeriodicExportingMetricReader.m @@ -0,0 +1,58 @@ +classdef PeriodicExportingMetricReader < matlab.mixin.Heterogeneous +% Base class of metric reader + +% Copyright 2023 The MathWorks, Inc. + + properties (GetAccess=?opentelemetry.sdk.metrics.MeterProvider) + Proxy % Proxy object to interface C++ code + end + + properties (SetAccess=immutable) + MetircExporter % Metric exporter object responsible for exporting telemetry data to an OpenTelemetry Collector or a compatible backend. + Interval (1,1) double % Maximum queue size. After queue size is reached, spans are dropped. + Timeout (1,1) double + end + + methods (Access=protected) + function obj = PeriodicExportingMetricReader(metricexporter, optionnames, optionvalues) + + arguments + metricexporter {mustBeA(metricexporter, "opentelemetry.sdk.metrics.MetricExporter")} = ... + opentelemetry.exporters.otlp.defaultMetricExporter() + end + arguments (Repeating) + optionnames (1,:) {mustBeTextScalar} + optionvalues + end + + validnames = ["Interval", "Timeout"]; + % set default values + intervalmills = 60; + timeoutmills = 30; + for i = 1:length(optionnames) + namei = validatestring(optionnames{i}, validnames); + valuei = optionvalues{i}; + if strcmp(namei, "Interval") + if ~isnumeric(valuei) || ~isscalar(valuei) || valuei <= 0 || ... + round(valuei) ~= valuei + error("opentelemetry:sdk:metrics::PeriodicExportingMetricReader::InvalidInterval", ... + "Interval must be a scalar positive integer."); + end + intervalmills = double(valuei); + elseif strcmp(namei, "Timeout") + if ~isduration(valuei) || ~isscalar(valuei) || valuei <= 0 + error("opentelemetry:sdk:metrics:PeriodicExportingMetricReader:InvalidTimeout", ... + "Timeout must be a positive duration scalar."); + end + timeoutmillis = milliseconds(valuei); + end + + obj.MetricExporter = metricexporter; + obj.Interval = intervalmills; + obj.Timeout = timeoutmillis; + obj.Proxy = libmexclass.proxy.Proxy("Name", "libmexclass.opentelemetry.sdk.PeriodicExportingMetricReaderProxy" , ... + "ConstructorArguments", [metricexporter.Proxy.ID, Interval, Timeout]); + + end + end +end diff --git a/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h b/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h new file mode 100644 index 0000000..0fb9b89 --- /dev/null +++ b/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h @@ -0,0 +1,16 @@ +// Copyright 2023 The MathWorks, Inc. + +#pragma once + +#include "libmexclass/proxy/Proxy.h" + +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +namespace metric_sdk = opentelemetry::sdk::metric; + +namespace libmexclass::opentelemetry::sdk { +class MetricExporterProxy : public libmexclass::proxy::Proxy { + public: + virtual std::unique_ptr getInstance() = 0; +}; +} // namespace libmexclass::opentelemetry diff --git a/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/PeriodicExportingMetricReader.h b/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/PeriodicExportingMetricReader.h new file mode 100644 index 0000000..970996f --- /dev/null +++ b/sdk/metrics/include/opentelemetry-matlab/sdk/metrics/PeriodicExportingMetricReader.h @@ -0,0 +1,28 @@ +// Copyright 2023 The MathWorks, Inc. + +#pragma once + +#include "opentelemetry-matlab/sdk/metrics/MetricExporterProxy.h" + +#include "libmexclass/proxy/Proxy.h" +#include "libmexclass/proxy/method/Context.h" + +#include "opentelemetry/sdk/metrics/periodic_exporting_metric_reader_options.h" + +namespace metric_reader_sdk = opentelemetry::sdk::metrics::MetricReader; + +namespace libmexclass::opentelemetry::sdk { +class PeriodicExportingMetricReaderProxy : public libmexclass::proxy::Proxy { + public: + PeriodicExportingMetricReaderProxy(std::shared_ptr exporter, double interval, double timeout); + + static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments); + + std::unique_ptr getInstance(); + + void getDefaultOptionValues(libmexclass::proxy::method::Context& context); + + private: + metric_reader_sdk::PeriodicExportingMetricReaderOptions CppOptions; +}; +} // namespace libmexclass::opentelemetry diff --git a/sdk/metrics/src/PeriodicExportingMetricReader.cpp b/sdk/metrics/src/PeriodicExportingMetricReader.cpp new file mode 100644 index 0000000..de6d6f9 --- /dev/null +++ b/sdk/metrics/src/PeriodicExportingMetricReader.cpp @@ -0,0 +1,23 @@ +// Copyright 2023 The MathWorks, Inc. + +#pragma once + +#include "opentelemetry-matlab/sdk/metrics/PeriodicExportingMetricReader.h" + + +namespace libmexclass::opentelemetry::sdk { +libmexclass::proxy::MakeResult PeriodicExportingMetricReaderProxy::make(const libmexclass::proxy::FunctionArguments& constructor_arguments){ + + libmexclass::proxy::MakeResult out; + + return out + +} + + +//std::unique_ptr PeriodicExportingMetricReaderProxy::getInstance() + + +//void PeriodicExportingMetricReaderProxy::getDefaultOptionValues(libmexclass::proxy::method::Context& context) + +} // namespace libmexclass::opentelemetry