diff --git a/examples/autotrace/README.md b/examples/autotrace/README.md new file mode 100644 index 0000000..9a21d44 --- /dev/null +++ b/examples/autotrace/README.md @@ -0,0 +1,9 @@ +# AutoTrace Example +This example shows how to use AutoTrace to automatically instrument MATLAB code. The instrumented code in *autotrace_example.m* fits a line through a cluster of data points. Notice that it does not include any instrumentation code. +The function *run_example.m* first configures a tracer provider. This step only needs to be done once in a MATLAB session. Then it creates an AutoTrace object and runs it. The AutoTrace object gets cleaned up at the end. + +## 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 `run_example`. diff --git a/examples/autotrace/autotrace_example.m b/examples/autotrace/autotrace_example.m new file mode 100644 index 0000000..95a7af5 --- /dev/null +++ b/examples/autotrace/autotrace_example.m @@ -0,0 +1,25 @@ +function yf = autotrace_example +% This example shows some simple MATLAB code that fits a line through a +% cluster of data points. It does not include any instrumentation code. + +% Copyright 2024 The MathWorks, Inc. + +[x, y] = generate_data(); +yf = best_fit_line(x,y); +end + +function [x, y] = generate_data +% generate some random data +a = 1.5; +b = 0.8; +sigma = 5; +x = 1:100; +y = a * x + b + sigma * randn(1, 100); +end + +function yf = best_fit_line(x, y) +% fit a line through points defined by inputs x and y +coefs = polyfit(x, y, 1); +yf = polyval(coefs , x); +end + diff --git a/examples/autotrace/run_example.m b/examples/autotrace/run_example.m new file mode 100644 index 0000000..f127e58 --- /dev/null +++ b/examples/autotrace/run_example.m @@ -0,0 +1,16 @@ +function yf = run_example +% Use AutoTrace to automatically instrument an example to produce a trace. + +% Copyright 2024 The MathWorks, Inc. + +% configure tracer provider +resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); +tp = opentelemetry.sdk.trace.TracerProvider(Resource=resource); +setTracerProvider(tp); + +% create AutoTrace object +at = opentelemetry.autoinstrument.AutoTrace(@autotrace_example, ... + TracerName="autotrace_example"); + +% run the example +yf = beginTrace(at); \ No newline at end of file diff --git a/examples/context_propagation/matlab/mymagic.m b/examples/context_propagation/matlab/mymagic.m index 3dd9685..d60ce87 100644 --- a/examples/context_propagation/matlab/mymagic.m +++ b/examples/context_propagation/matlab/mymagic.m @@ -41,8 +41,7 @@ function initTracer % set up global TracerProvider resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); -tp = opentelemetry.sdk.trace.TracerProvider(... - opentelemetry.sdk.trace.SimpleSpanProcessor, Resource=resource); +tp = opentelemetry.sdk.trace.TracerProvider(Resource=resource); setTracerProvider(tp); % set up global propagator diff --git a/examples/logs/logs_example.m b/examples/logs/logs_example.m index 9d7e8af..c3be8a0 100644 --- a/examples/logs/logs_example.m +++ b/examples/logs/logs_example.m @@ -44,8 +44,7 @@ function initLogger % set up global LoggerProvider resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); -lp = opentelemetry.sdk.logs.LoggerProvider(... - opentelemetry.sdk.logs.SimpleLogRecordProcessor, Resource=resource); +lp = opentelemetry.sdk.logs.LoggerProvider(Resource=resource); setLoggerProvider(lp); end diff --git a/examples/metrics/metrics_example.m b/examples/metrics/metrics_example.m index 5b73d04..344714d 100644 --- a/examples/metrics/metrics_example.m +++ b/examples/metrics/metrics_example.m @@ -34,8 +34,7 @@ function metrics_example(iterations) function initMetrics % set up global MeterProvider -exp = opentelemetry.exporters.otlp.defaultMetricExporter(); -reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(exp, ... +reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... "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); diff --git a/examples/parallel/parfor_example.m b/examples/parallel/parfor_example.m index e64dfdd..6509e2e 100644 --- a/examples/parallel/parfor_example.m +++ b/examples/parallel/parfor_example.m @@ -50,8 +50,7 @@ function initTracer % set up global TracerProvider resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); -tp = opentelemetry.sdk.trace.TracerProvider(... - opentelemetry.sdk.trace.SimpleSpanProcessor, Resource=resource); +tp = opentelemetry.sdk.trace.TracerProvider(Resource=resource); setTracerProvider(tp); % set up global propagator diff --git a/examples/trace/trace_example.m b/examples/trace/trace_example.m index 909a887..72361f2 100644 --- a/examples/trace/trace_example.m +++ b/examples/trace/trace_example.m @@ -42,8 +42,7 @@ function initTracer % set up global TracerProvider resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); -tp = opentelemetry.sdk.trace.TracerProvider(... - opentelemetry.sdk.trace.SimpleSpanProcessor, Resource=resource); +tp = opentelemetry.sdk.trace.TracerProvider(Resource=resource); setTracerProvider(tp); end diff --git a/examples/webread/matlab/webread_example.m b/examples/webread/matlab/webread_example.m index 00ce65d..9451995 100644 --- a/examples/webread/matlab/webread_example.m +++ b/examples/webread/matlab/webread_example.m @@ -27,8 +27,7 @@ function initTracer % set up global TracerProvider resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); -tp = opentelemetry.sdk.trace.TracerProvider(... - opentelemetry.sdk.trace.SimpleSpanProcessor, Resource=resource); +tp = opentelemetry.sdk.trace.TracerProvider(Resource=resource); setTracerProvider(tp); % set up global propagator diff --git a/test/texamples.m b/test/texamples.m index 63da86d..58ea329 100644 --- a/test/texamples.m +++ b/test/texamples.m @@ -370,5 +370,63 @@ function testParallel(testCase) verifyLessThanOrEqual(testCase, str2double(worker2.resourceSpans.scopeSpans.spans.endTimeUnixNano), ... str2double(toplevel.resourceSpans.scopeSpans.spans.endTimeUnixNano)); end + + function testAutoTrace(testCase) + % testAutoTrace: AutoTrace example in examples/autotrace folder + + % add the example folder to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "..", "examples", "autotrace"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + + % run the example + run_example; + + % perform test comparisons + results = readJsonResults(testCase); + verifyNumElements(testCase, results, 3); + + % check generate_data span + gendata = results{1}; + verifyEqual(testCase, gendata.resourceSpans.scopeSpans.scope.name, 'autotrace_example'); + verifyEqual(testCase, gendata.resourceSpans.scopeSpans.spans.name, 'generate_data'); + verifyEqual(testCase, gendata.resourceSpans.scopeSpans.spans.kind, 1); + service_name_idx = find(string({gendata.resourceSpans.resource.attributes.key}) == "service.name"); + verifyNotEmpty(testCase, service_name_idx); + verifyEqual(testCase, gendata.resourceSpans.resource.attributes(service_name_idx).value.stringValue, ... + 'OpenTelemetry-Matlab_examples'); + + % check best_fit_line span + bestfitline = results{2}; + verifyEqual(testCase, bestfitline.resourceSpans.scopeSpans.scope.name, 'autotrace_example'); + verifyEqual(testCase, bestfitline.resourceSpans.scopeSpans.spans.name, 'best_fit_line'); + verifyEqual(testCase, bestfitline.resourceSpans.scopeSpans.spans.kind, 1); + + % check top level function span + toplevel = results{3}; + verifyEqual(testCase, toplevel.resourceSpans.scopeSpans.scope.name, 'autotrace_example'); + verifyEqual(testCase, toplevel.resourceSpans.scopeSpans.spans.name, 'autotrace_example'); + verifyEqual(testCase, toplevel.resourceSpans.scopeSpans.spans.kind, 1); + + % check parent child relationships + verifyEqual(testCase, gendata.resourceSpans.scopeSpans.spans.parentSpanId, ... + toplevel.resourceSpans.scopeSpans.spans.spanId); + verifyEqual(testCase, bestfitline.resourceSpans.scopeSpans.spans.parentSpanId, ... + toplevel.resourceSpans.scopeSpans.spans.spanId); + verifyEmpty(testCase, toplevel.resourceSpans.scopeSpans.spans.parentSpanId); + + % check all spans belong to the same trace + verifyEqual(testCase, gendata.resourceSpans.scopeSpans.spans.traceId, ... + toplevel.resourceSpans.scopeSpans.spans.traceId); + verifyEqual(testCase, bestfitline.resourceSpans.scopeSpans.spans.traceId, ... + toplevel.resourceSpans.scopeSpans.spans.traceId); + + % check for expected timing + verifyLessThanOrEqual(testCase, str2double(toplevel.resourceSpans.scopeSpans.spans.startTimeUnixNano), ... + str2double(gendata.resourceSpans.scopeSpans.spans.startTimeUnixNano)); + verifyLessThanOrEqual(testCase, str2double(gendata.resourceSpans.scopeSpans.spans.endTimeUnixNano), ... + str2double(bestfitline.resourceSpans.scopeSpans.spans.startTimeUnixNano)); + verifyLessThanOrEqual(testCase, str2double(bestfitline.resourceSpans.scopeSpans.spans.endTimeUnixNano), ... + str2double(toplevel.resourceSpans.scopeSpans.spans.endTimeUnixNano)); + end end end