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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ set(LIBMEXCLASS_FETCH_CONTENT_NAME libmexclass)

set(LIBMEXCLASS_FETCH_CONTENT_GIT_REPOSITORY "https://github.com/mathworks/libmexclass.git")

set(LIBMEXCLASS_FETCH_CONTENT_GIT_TAG "77f3d72")
set(LIBMEXCLASS_FETCH_CONTENT_GIT_TAG "bf16a65")

set(LIBMEXCLASS_FETCH_CONTENT_SOURCE_SUBDIR "libmexclass/cpp")

Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
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.

### Status
- Currently only tracing is supported. Metrics and logs will be in the future.
- Currently only tracing and metrics (synchronous instruments) are supported. Asynchronous metrics instruments and logs will be in the future.
- View class in metrics is only partially supported. The properties **Aggregation** and **AllowedAttributes** are not yet supported.
- This package is supported and has been tested on Windows®, Linux®, and macOS.

### MathWorks Products (https://www.mathworks.com)
Expand Down Expand Up @@ -43,6 +44,7 @@ otelcol --config <otelcol-config-yaml>
>> addpath <OpenTelemetry MATLAB installdir>
```
## Examples
### Tracing
1. Create a default tracer provider and save it.
```
>> p = opentelemetry.sdk.trace.TracerProvider();
Expand All @@ -58,6 +60,22 @@ otelcol --config <otelcol-config-yaml>
>> sp.endSpan();
```
4. If your collector is configured to display the data, you should see your span displayed.
### Metrics
1. Create a default meter provider and save it.
```
>> p = opentelemetry.sdk.metrics.MeterProvider();
>> setMeterProvider(p);
```
2. Create a counter
```
>> m = opentelemetry.metrics.getMeter("First Meter");
>> c = m.createCounter("FirstCounter");
```
3. Increment the counter
```
>> c.add(10);
```
4. If your collector is configured to display the data, you should see your counter displayed after 1 minute.

For more examples, see the "examples" folder.

Expand Down
10 changes: 10 additions & 0 deletions api/metrics/+opentelemetry/+metrics/Counter.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@

methods
function add(obj, value, varargin)
% ADD Add to counter value
% ADD(C, VALUE) adds a nonnegative scalar numeric value to
% the counter.
%
% ADD(C, VALUE, ATTRIBUTES) also specifies attributes as a
% dictionary
%
% ADD(C, VALUE, ATTRNAME1, ATTRVALUE1, ATTRNAME2,
% ATTRVALUE2, ...) specifies attributes as trailing
% name-value pairs.
obj.processValue(value, varargin{:});
end
end
Expand Down
10 changes: 10 additions & 0 deletions api/metrics/+opentelemetry/+metrics/Histogram.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

methods
function record(obj, value, varargin)
% RECORD Aggregate a value into a histogram bin
% RECORD(H, VALUE) determine which bin VALUE falls into and
% increment that bin by 1.
%
% RECORD(H, VALUE, ATTRIBUTES) also specifies attributes as a
% dictionary
%
% RECORD(H, VALUE, ATTRNAME1, ATTRVALUE1, ATTRNAME2,
% ATTRVALUE2, ...) specifies attributes as trailing
% name-value pairs.
obj.processValue(value, varargin{:});
end
end
Expand Down
34 changes: 28 additions & 6 deletions api/metrics/+opentelemetry/+metrics/Meter.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
methods

function counter = createCounter(obj, ctname, ctdescription, ctunit)
% CREATECOUNTER Create a counter
% C = CREATECOUNTER(M, NAME) creates a counter with the specified
% name. A counter's value can only increase but not
% decrease.
%
% C = CREATECOUNTER(M, NAME, DESCRIPTION, UNIT) also
% specifies a description and a unit.
%
% See also CREATEUPDOWNCOUNTER, CREATEHISTOGRAM
arguments
obj
ctname
Expand All @@ -38,8 +47,6 @@
end
import opentelemetry.common.mustBeScalarString
ctname = mustBeScalarString(ctname);
% cpp-opentelemetry end does not allow string input with spaces,
% replace any spaces with underscores as a temporary fix
ctdescription = mustBeScalarString(ctdescription);
ctunit = mustBeScalarString(ctunit);
id = obj.Proxy.createCounter(ctname, ctdescription, ctunit);
Expand All @@ -50,6 +57,15 @@


function updowncounter = createUpDownCounter(obj, ctname, ctdescription, ctunit)
% CREATEUPDOWNCOUNTER Create an UpDownCounter
% C = CREATEUPDOWNCOUNTER(M, NAME) creates an UpDownCounter
% with the specified name. An UpDownCounter's value can
% increase or decrease.
%
% C = CREATEUPDOWNCOUNTER(M, NAME, DESCRIPTION, UNIT) also
% specifies a description and a unit.
%
% See also CREATECOUNTER, CREATEHISTOGRAM
arguments
obj
ctname
Expand All @@ -59,8 +75,6 @@

import opentelemetry.common.mustBeScalarString
ctname = mustBeScalarString(ctname);
% cpp-opentelemetry end does not allow string input with spaces,
% replace any spaces with underscores as a temporary fix
ctdescription = mustBeScalarString(ctdescription);
ctunit = mustBeScalarString(ctunit);
id = obj.Proxy.createUpDownCounter(ctname, ctdescription, ctunit);
Expand All @@ -71,6 +85,16 @@


function histogram = createHistogram(obj, hiname, hidescription, hiunit)
% CREATEHISTOGRAM Create a histogram
% H = CREATEHISTOGRAM(M, NAME) creates a histogram with the specified
% name. A histogram aggregates values into bins. Bins can be
% customized using a View object.
%
% H = CREATEHISTOGRAM(M, NAME, DESCRIPTION, UNIT) also
% specifies a description and a unit.
%
% See also CREATECOUNTER, CREATEUPDOWNCOUNTER,
% OPENTELEMETRY.SDK.METRICS.VIEW
arguments
obj
hiname
Expand All @@ -80,8 +104,6 @@

import opentelemetry.common.mustBeScalarString
hiname = mustBeScalarString(hiname);
% cpp-opentelemetry end does not allow string input with spaces,
% replace any spaces with underscores as a temporary fix
hidescription = mustBeScalarString(hidescription);
hiunit = mustBeScalarString(hiunit);
id = obj.Proxy.createHistogram(hiname, hidescription, hiunit);
Expand Down
10 changes: 10 additions & 0 deletions api/metrics/+opentelemetry/+metrics/UpDownCounter.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

methods
function add(obj, value, varargin)
% ADD Add to UpDownCounter value
% ADD(C, VALUE) adds scalar numeric value to the
% UpDownCounter. VALUE can be positive or negative.
%
% ADD(C, VALUE, ATTRIBUTES) also specifies attributes as a
% dictionary
%
% ADD(C, VALUE, ATTRNAME1, ATTRVALUE1, ATTRNAME2,
% ATTRVALUE2, ...) specifies attributes as trailing
% name-value pairs.
obj.processValue(value, varargin{:});
end
end
Expand Down
10 changes: 10 additions & 0 deletions examples/metrics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Metrics Example
This example shows how to emit OpenTelemetry metrics from MATLAB. It uses all 3 synchronous instruments counter, updowncounter, and histogram.
* At the beginning of the first run, initialization is necessary to create and store a global meter provider.
* The example then enters a loop and at each iteration updates all 3 instruments. The metrics will then be exported periodically at a fixed time interval.

## Running the Example
1. Start an instance of [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector).
2. Start MATLAB.
3. Ensure the installation directory of OpenTelemetry-matlab is on the MATLAB path.
4. Run metrics_example.
45 changes: 45 additions & 0 deletions examples/metrics/metrics_example.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function metrics_example
% This example creates 3 metric instruments including a counter, an
% updowncounter, and a histogram. It then enters a loop and updates the
% value of the instruments at each iteration.

% Copyright 2023 The MathWorks, Inc.

% initialize meter provider during first run
runOnce(@initMetrics);

% create meter and instruments
m = opentelemetry.metrics.getMeter("metrics_example");
c = createCounter(m, "counter");
u = createUpDownCounter(m, "updowncounter");
h = createHistogram(m, "histogram");
iterations = 20; % number of iterations

for i = 1:iterations
c.add(randi(10));
u.add(randi([-10 10]));
h.record(50 + 15*randn); % normal distribution with mean 50 and std 15
pause(5);
end
end


function initMetrics
% set up global MeterProvider
exp = opentelemetry.exporters.otlp.defaultMetricExporter();
reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(exp, ...
"Interval", seconds(5), "Timeout", seconds(2.5)); % exports every 5 seconds
% Use custom histogram bins
v = opentelemetry.sdk.metrics.View(InstrumentType="histogram", HistogramBinEdges=0:10:100);
mp = opentelemetry.sdk.metrics.MeterProvider(reader, View=v);
setMeterProvider(mp);
end

% This helper ensures the input function is only run once
function runOnce(fh)
persistent hasrun
if isempty(hasrun)
feval(fh);
hasrun = 1;
end
end
62 changes: 43 additions & 19 deletions sdk/metrics/+opentelemetry/+sdk/+metrics/MeterProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@
isShutdown (1,1) logical = false
end

properties (Access=public)
MetricReader
View
Resource
properties (SetAccess=private)
MetricReader % Metric reader controls how often metrics are exported
View % View object used to customize collected metrics
Resource % Attributes attached to all metrics
end

methods
function obj = MeterProvider(reader, optionnames, optionvalues)
% SDK implementation of meter provider
% MP = OPENTELEMETRY.SDK.METRICS.METERPROVIDER creates a meter
% MP = OPENTELEMETRY.SDK.METRICS.METERPROVIDER creates a meter
% provider that uses a periodic exporting metric reader and default configurations.
%
% MP = OPENTELEMETRY.SDK.METRICS.METERPROVIDER(R) uses metric
% reader R. Currently, the only supported metric reader is the periodic
% exporting metric reader.
% reader R. Currently, the only supported metric reader is the periodic
% exporting metric reader.
%
% TP = OPENTELEMETRY.SDK.METRICS.METERPROVIDER(R, PARAM1, VALUE1,
% TP = OPENTELEMETRY.SDK.METRICS.METERPROVIDER(R, PARAM1, VALUE1,
% PARAM2, VALUE2, ...) specifies optional parameter name/value pairs.
% Parameters are:
% "View" - View object used to customize collected metrics.
Expand Down Expand Up @@ -59,10 +59,12 @@
"ConstructorArguments", {mpproxy.ID});
% leave other properties unassigned, they won't be used
else
validnames = ["Resource"];
validnames = ["Resource", "View"];
resourcekeys = string.empty();
resourcevalues = {};
resource = dictionary(resourcekeys, resourcevalues);
suppliedview = false;
viewid = 0;
for i = 1:length(optionnames)
namei = validatestring(optionnames{i}, validnames);
valuei = optionvalues{i};
Expand All @@ -79,31 +81,53 @@
if all(cellfun(@iscell, resourcevalues))
resourcevalues = [resourcevalues{:}];
end
elseif strcmp(namei, "View")
suppliedview = true;
view = valuei;
if ~isa(view, "opentelemetry.sdk.metrics.View")
error("opentelemetry:sdk:metrics:MeterProvider:InvalidViewType", ...
"View input must be a opentelemetry.sdk.metrics.View object.");
end
viewid = view.Proxy.ID;
end
end

obj.Proxy = libmexclass.proxy.Proxy("Name", ...
"libmexclass.opentelemetry.sdk.MeterProviderProxy", ...
"ConstructorArguments", {reader.Proxy.ID, resourcekeys, resourcevalues});
"ConstructorArguments", {reader.Proxy.ID, resourcekeys, ...
resourcevalues, suppliedview, viewid});
obj.MetricReader = reader;
obj.Resource = resource;
if suppliedview
obj.View = view;
end
end
end

function addMetricReader(obj, reader)
arguments
obj
reader (1,1) {mustBeA(reader, "opentelemetry.sdk.metrics.PeriodicExportingMetricReader")}
end
% ADDMETRICREADER Add an additional metric reader
% ADDMETRICREADER(MP, R) adds an additional metric reader
% R to the list of metric readers used by meter provider
% MP.
%
% See also ADDVIEW, OPENTELEMETRY.SDK.METRICS.PERIODICEXPORTINGMETRICREADER
arguments
obj
reader (1,1) {mustBeA(reader, "opentelemetry.sdk.metrics.PeriodicExportingMetricReader")}
end
obj.Proxy.addMetricReader(reader.Proxy.ID);
obj.MetricReader = [obj.MetricReader, reader];
end

function addView(obj, view)
arguments
obj
view (1,1) {mustBeA(view, "opentelemetry.sdk.metrics.View")}
end
% ADDVIEW Add an additional view
% ADDVIEW(MP, V) adds an additional view V.
%
% See also ADDMETRICREADER, OPENTELEMETRY.SDK.METRICS.VIEW
arguments
obj
view (1,1) {mustBeA(view, "opentelemetry.sdk.metrics.View")}
end
obj.Proxy.addView(view.Proxy.ID);
obj.View = [obj.View, view];
end
Expand Down
2 changes: 1 addition & 1 deletion sdk/metrics/+opentelemetry/+sdk/+metrics/MetricExporter.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
methods
function obj = set.PreferredAggregationTemporality(obj, temporality)
temporality = validatestring(temporality, ["cumulative", "delta"]);
obj.Proxy.setTemporality(temporality);
obj.Proxy.setTemporality(temporality); %#ok<MCSUP>
obj.PreferredAggregationTemporality = temporality;
end

Expand Down
Loading