From 1b9ff8aae3a54e74c3a3fabf5a519503d1457437 Mon Sep 17 00:00:00 2001 From: duncanpo Date: Sat, 26 Oct 2024 08:17:05 -0400 Subject: [PATCH 1/3] enable specifying folders in AutoTrace options, closes #163 --- .../+autoinstrument/AutoTrace.m | 53 +++++++++++++------ test/autotrace_examples/example2/example2.m | 9 ++++ .../example2/helpers/ex2helper1.m | 6 +++ .../example2/helpers/ex2helper2.m | 6 +++ test/tautotrace.m | 52 ++++++++++++++++++ 5 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 test/autotrace_examples/example2/example2.m create mode 100644 test/autotrace_examples/example2/helpers/ex2helper1.m create mode 100644 test/autotrace_examples/example2/helpers/ex2helper2.m diff --git a/auto-instrumentation/+opentelemetry/+autoinstrument/AutoTrace.m b/auto-instrumentation/+opentelemetry/+autoinstrument/AutoTrace.m index 27b75a3..11aa03f 100644 --- a/auto-instrumentation/+opentelemetry/+autoinstrument/AutoTrace.m +++ b/auto-instrumentation/+opentelemetry/+autoinstrument/AutoTrace.m @@ -58,9 +58,15 @@ options.AdditionalFiles {mustBeText} options.AutoDetectFiles (1,1) {mustBeNumericOrLogical} = true end + % check for anonymous function + fs = functions(startfun); + if fs.type == "anonymous" + error("opentelemetry:autoinstrument:AutoTrace:AnonymousFunction", ... + "Anonymous functions are not supported."); + end obj.StartFunction = startfun; startfunname = func2str(startfun); - processFileInput(startfunname); % validate startfun + startfunname = processFileInput(startfunname); % validate startfun if options.AutoDetectFiles if isdeployed % matlab.codetools.requiredFilesAndProducts is not @@ -76,15 +82,16 @@ end else % only include the input file, not its dependencies - files = string(which(startfunname)); + files = startfunname; end % add extra files, this is intended for files % matlab.codetools.requiredFilesAndProducts somehow missed if isfield(options, "AdditionalFiles") - incfiles = string(options.AdditionalFiles); - for i = 1:numel(incfiles) - incfiles(i) = which(incfiles(i)); % get the full path - processFileInput(incfiles(i)); % validate additional file + incinput = string(options.AdditionalFiles); + incfiles = []; + for i = 1:numel(incinput) + % validate additional file + incfiles = [incfiles; processFileOrFolderInput(incinput(i))]; %#ok end files = union(files, incfiles); end @@ -94,9 +101,11 @@ % filter out excluded files if isfield(options, "ExcludeFiles") - excfiles = string(options.ExcludeFiles); - for i = 1:numel(excfiles) - excfiles(i) = which(excfiles(i)); % get the full path + excinput = string(options.ExcludeFiles); + excfiles = []; + for i = 1:numel(excinput) + % validate exclude file + excfiles = [excfiles; processFileOrFolderInput(excinput(i))]; %#ok end files = setdiff(files, excfiles); end @@ -155,15 +164,13 @@ function handleError(obj, ME) end % check input file is valid -function processFileInput(f) +function f = processFileInput(f) f = string(f); % force into a string -if startsWith(f, '@') % check for anonymous function - error("opentelemetry:autoinstrument:AutoTrace:AnonymousFunction", ... - replace(f, "\", "\\") + " is an anonymous function and is not supported."); -end [~,~,fext] = fileparts(f); % check file extension filetype = exist(f, "file"); % check file type -if ~(filetype == 2 && ismember(fext, ["" ".m" ".mlx"])) +if filetype == 2 && ismember(fext, ["" ".m" ".mlx"]) + f = string(which(f)); +else if exist(f, "builtin") error("opentelemetry:autoinstrument:AutoTrace:BuiltinFunction", ... replace(f, "\", "\\") + " is a builtin function and is not supported."); @@ -172,4 +179,20 @@ function processFileInput(f) replace(f, "\", "\\") + " is not found or is not a valid MATLAB file with a .m or .mlx extension."); end end +end + +% check input file or folder is valid +function f = processFileOrFolderInput(f) +f = string(f); % force into a string +if isfolder(f) + % expand the directory + mfileinfo = dir(fullfile(f, "*.m")); + mfiles = fullfile(string({mfileinfo.folder}), string({mfileinfo.name})); + mlxfileinfo = dir(fullfile(f, "*.mlx")); + mlxfiles = fullfile(string({mlxfileinfo.folder}), string({mlxfileinfo.name})); + f = [mfiles; mlxfiles]; +else + % file + f = processFileInput(f); +end end \ No newline at end of file diff --git a/test/autotrace_examples/example2/example2.m b/test/autotrace_examples/example2/example2.m new file mode 100644 index 0000000..b3649b4 --- /dev/null +++ b/test/autotrace_examples/example2/example2.m @@ -0,0 +1,9 @@ +function x = example2 +% example code for testing auto instrumentation. + +% Copyright 2024 The MathWorks, Inc. + +x = 10; +x = ex2helper1(x); +x = ex2helper2(x); + diff --git a/test/autotrace_examples/example2/helpers/ex2helper1.m b/test/autotrace_examples/example2/helpers/ex2helper1.m new file mode 100644 index 0000000..14b12a4 --- /dev/null +++ b/test/autotrace_examples/example2/helpers/ex2helper1.m @@ -0,0 +1,6 @@ +function x = ex2helper1(x) +% example code for testing auto instrumentation + +% Copyright 2024 The MathWorks, Inc. + +x = x * 2; diff --git a/test/autotrace_examples/example2/helpers/ex2helper2.m b/test/autotrace_examples/example2/helpers/ex2helper2.m new file mode 100644 index 0000000..31415ca --- /dev/null +++ b/test/autotrace_examples/example2/helpers/ex2helper2.m @@ -0,0 +1,6 @@ +function x = ex2helper2(x) +% example code for testing auto instrumentation + +% Copyright 2024 The MathWorks, Inc. + +x = x * 3; \ No newline at end of file diff --git a/test/tautotrace.m b/test/tautotrace.m index 63f9387..7fb7198 100644 --- a/test/tautotrace.m +++ b/test/tautotrace.m @@ -24,6 +24,10 @@ function setupOnce(testCase) % add the example folders to the path example1folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example1"); testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example1folder)); + example2folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2folder)); + example2helpersfolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2", "helpers"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2helpersfolder)); commonSetupOnce(testCase); % configure the global tracer provider @@ -115,6 +119,54 @@ function testDisableFileDetection(testCase) verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example1"); end + function testIncludeFolder(testCase) + % testIncludeFolder: specify a folder in AdditionalFiles + + % set up AutoTrace + example2helpers = fullfile(fileparts(mfilename('fullpath')), ... + "autotrace_examples", "example2", "helpers"); + % turn off automatic detection and specify dependencies using + % their folder name + at = opentelemetry.autoinstrument.AutoTrace(@example2, ... + "AutoDetectFiles", false, "AdditionalFiles", example2helpers); + + % run the example + [~] = beginTrace(at); + + % perform test comparisons + results = readJsonResults(testCase); + verifyNumElements(testCase, results, 3); + + % check span names + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "ex2helper1"); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "ex2helper2"); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "example2"); + + % check parent children relationship + verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{3}.resourceSpans.scopeSpans.spans.spanId); + verifyEqual(testCase, results{2}.resourceSpans.scopeSpans.spans.parentSpanId, results{3}.resourceSpans.scopeSpans.spans.spanId); + end + + function testExcludeFolder(testCase) + % testExcludeFolder: specify a folder in ExcludeFiles + + % set up AutoTrace + example2helpers = fullfile(fileparts(mfilename('fullpath')), ... + "autotrace_examples", "example2", "helpers"); + at = opentelemetry.autoinstrument.AutoTrace(@example2, ... + "ExcludeFiles", example2helpers); + + % run the example + [~] = beginTrace(at); + + % perform test comparisons + results = readJsonResults(testCase); + verifyNumElements(testCase, results, 1); + + % check span names + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example2"); + end + function testNonFileOptions(testCase) % testNonFileOptions: other options not related to files, % "TracerName", "TracerVersion", "TracerSchema", "Attributes", From 40211f0e82132844364a355ae367c8d7b998f489 Mon Sep 17 00:00:00 2001 From: duncanpo Date: Mon, 28 Oct 2024 17:08:40 -0400 Subject: [PATCH 2/3] Add a test for combining auto and manual instrumentation and clean up AutoTrace test examples --- test/autotrace_examples/example2/example2.m | 9 - .../example2/helpers/ex2helper1.m | 6 - .../example2/helpers/ex2helper2.m | 6 - .../best_fit_line.m | 2 +- .../generate_data.m | 4 +- .../linearfit_example.m} | 4 +- .../linearfit_example_trycatch.m} | 4 +- .../best_fit_line.m | 14 ++ .../generate_data.m | 22 +++ .../manual_instrumented_example.m | 8 + .../helpers/subfolder_helper1.m | 6 + .../helpers/subfolder_helper2.m | 6 + .../subfolder_example/subfolder_example.m | 10 ++ test/tautotrace.m | 166 +++++++++++++----- 14 files changed, 195 insertions(+), 72 deletions(-) delete mode 100644 test/autotrace_examples/example2/example2.m delete mode 100644 test/autotrace_examples/example2/helpers/ex2helper1.m delete mode 100644 test/autotrace_examples/example2/helpers/ex2helper2.m rename test/autotrace_examples/{example1 => linearfit_example}/best_fit_line.m (69%) rename test/autotrace_examples/{example1 => linearfit_example}/generate_data.m (67%) rename test/autotrace_examples/{example1/example1.m => linearfit_example/linearfit_example.m} (52%) rename test/autotrace_examples/{example1/example1_trycatch.m => linearfit_example/linearfit_example_trycatch.m} (63%) create mode 100644 test/autotrace_examples/manual_instrumented_example/best_fit_line.m create mode 100644 test/autotrace_examples/manual_instrumented_example/generate_data.m create mode 100644 test/autotrace_examples/manual_instrumented_example/manual_instrumented_example.m create mode 100644 test/autotrace_examples/subfolder_example/helpers/subfolder_helper1.m create mode 100644 test/autotrace_examples/subfolder_example/helpers/subfolder_helper2.m create mode 100644 test/autotrace_examples/subfolder_example/subfolder_example.m diff --git a/test/autotrace_examples/example2/example2.m b/test/autotrace_examples/example2/example2.m deleted file mode 100644 index b3649b4..0000000 --- a/test/autotrace_examples/example2/example2.m +++ /dev/null @@ -1,9 +0,0 @@ -function x = example2 -% example code for testing auto instrumentation. - -% Copyright 2024 The MathWorks, Inc. - -x = 10; -x = ex2helper1(x); -x = ex2helper2(x); - diff --git a/test/autotrace_examples/example2/helpers/ex2helper1.m b/test/autotrace_examples/example2/helpers/ex2helper1.m deleted file mode 100644 index 14b12a4..0000000 --- a/test/autotrace_examples/example2/helpers/ex2helper1.m +++ /dev/null @@ -1,6 +0,0 @@ -function x = ex2helper1(x) -% example code for testing auto instrumentation - -% Copyright 2024 The MathWorks, Inc. - -x = x * 2; diff --git a/test/autotrace_examples/example2/helpers/ex2helper2.m b/test/autotrace_examples/example2/helpers/ex2helper2.m deleted file mode 100644 index 31415ca..0000000 --- a/test/autotrace_examples/example2/helpers/ex2helper2.m +++ /dev/null @@ -1,6 +0,0 @@ -function x = ex2helper2(x) -% example code for testing auto instrumentation - -% Copyright 2024 The MathWorks, Inc. - -x = x * 3; \ No newline at end of file diff --git a/test/autotrace_examples/example1/best_fit_line.m b/test/autotrace_examples/linearfit_example/best_fit_line.m similarity index 69% rename from test/autotrace_examples/example1/best_fit_line.m rename to test/autotrace_examples/linearfit_example/best_fit_line.m index 55a404a..c46c97f 100644 --- a/test/autotrace_examples/example1/best_fit_line.m +++ b/test/autotrace_examples/linearfit_example/best_fit_line.m @@ -1,5 +1,5 @@ function yf = best_fit_line(x, y) -% example code for testing auto instrumentation +% Fit a straight line on input data % Copyright 2024 The MathWorks, Inc. diff --git a/test/autotrace_examples/example1/generate_data.m b/test/autotrace_examples/linearfit_example/generate_data.m similarity index 67% rename from test/autotrace_examples/example1/generate_data.m rename to test/autotrace_examples/linearfit_example/generate_data.m index 82fb09b..9d0daa2 100644 --- a/test/autotrace_examples/example1/generate_data.m +++ b/test/autotrace_examples/linearfit_example/generate_data.m @@ -1,11 +1,11 @@ function [x, y] = generate_data(n) -% example code for testing auto instrumentation +% Generate random data with n data points % Copyright 2024 The MathWorks, Inc. % check input is valid if ~(isnumeric(n) && isscalar(n)) - error("autotrace_examples:example1:generate_data:InvalidN", ... + error("autotrace_examples:linearfit_example:generate_data:InvalidN", ... "Input must be a numeric scalar"); end diff --git a/test/autotrace_examples/example1/example1.m b/test/autotrace_examples/linearfit_example/linearfit_example.m similarity index 52% rename from test/autotrace_examples/example1/example1.m rename to test/autotrace_examples/linearfit_example/linearfit_example.m index f47f8aa..2a6e9d4 100644 --- a/test/autotrace_examples/example1/example1.m +++ b/test/autotrace_examples/linearfit_example/linearfit_example.m @@ -1,5 +1,5 @@ -function yf = example1(n) -% example code for testing auto instrumentation. Input n is the number of +function yf = linearfit_example(n) +% Example code for testing auto instrumentation. Input n is the number of % data points. % Copyright 2024 The MathWorks, Inc. diff --git a/test/autotrace_examples/example1/example1_trycatch.m b/test/autotrace_examples/linearfit_example/linearfit_example_trycatch.m similarity index 63% rename from test/autotrace_examples/example1/example1_trycatch.m rename to test/autotrace_examples/linearfit_example/linearfit_example_trycatch.m index 2d58fc1..394d47c 100644 --- a/test/autotrace_examples/example1/example1_trycatch.m +++ b/test/autotrace_examples/linearfit_example/linearfit_example_trycatch.m @@ -1,5 +1,5 @@ -function yf = example1_trycatch(at, n) -% example code for testing auto instrumentation. This example should not +function yf = linearfit_example_trycatch(at, n) +% Example code for testing auto instrumentation. This example should not % use beginTrace method and instead should be called directly. % Copyright 2024 The MathWorks, Inc. diff --git a/test/autotrace_examples/manual_instrumented_example/best_fit_line.m b/test/autotrace_examples/manual_instrumented_example/best_fit_line.m new file mode 100644 index 0000000..4a5d603 --- /dev/null +++ b/test/autotrace_examples/manual_instrumented_example/best_fit_line.m @@ -0,0 +1,14 @@ +function yf = best_fit_line(x, y) +% Fit a straight line on input data and manually start and end two spans. + +% Copyright 2024 The MathWorks, Inc. + +tr = opentelemetry.trace.getTracer("ManualInstrument"); + +sp1 = startSpan(tr, "polyfit"); +coefs = polyfit(x, y, 1); +endSpan(sp1); + +sp2 = startSpan(tr, "polyval"); +yf = polyval(coefs , x); +endSpan(sp2); diff --git a/test/autotrace_examples/manual_instrumented_example/generate_data.m b/test/autotrace_examples/manual_instrumented_example/generate_data.m new file mode 100644 index 0000000..aab07aa --- /dev/null +++ b/test/autotrace_examples/manual_instrumented_example/generate_data.m @@ -0,0 +1,22 @@ +function [x, y] = generate_data(n) +% Generate random data with n data points and manually start and end a span. + +% Copyright 2024 The MathWorks, Inc. + +% check input is valid +if ~(isnumeric(n) && isscalar(n)) + error("autotrace_examples:linearfit_example:generate_data:InvalidN", ... + "Input must be a numeric scalar"); +end + +% generate some random data +a = 1.5; +b = 0.8; +sigma = 5; +x = 1:n; + +% start a span +tr = opentelemetry.trace.getTracer("ManualInstrument"); +sp = startSpan(tr, "compute_y"); +y = a * x + b + sigma * randn(1, n); +endSpan(sp); \ No newline at end of file diff --git a/test/autotrace_examples/manual_instrumented_example/manual_instrumented_example.m b/test/autotrace_examples/manual_instrumented_example/manual_instrumented_example.m new file mode 100644 index 0000000..020f6cb --- /dev/null +++ b/test/autotrace_examples/manual_instrumented_example/manual_instrumented_example.m @@ -0,0 +1,8 @@ +function yf = manual_instrumented_example(n) +% Example code for testing auto and manual instrumentation together. +% Input n is the number of data points. + +% Copyright 2024 The MathWorks, Inc. + +[x, y] = generate_data(n); +yf = best_fit_line(x,y); \ No newline at end of file diff --git a/test/autotrace_examples/subfolder_example/helpers/subfolder_helper1.m b/test/autotrace_examples/subfolder_example/helpers/subfolder_helper1.m new file mode 100644 index 0000000..b56edd7 --- /dev/null +++ b/test/autotrace_examples/subfolder_example/helpers/subfolder_helper1.m @@ -0,0 +1,6 @@ +function x = subfolder_helper1(x) +% example code for testing auto instrumentation, helper function + +% Copyright 2024 The MathWorks, Inc. + +x = x * 2; diff --git a/test/autotrace_examples/subfolder_example/helpers/subfolder_helper2.m b/test/autotrace_examples/subfolder_example/helpers/subfolder_helper2.m new file mode 100644 index 0000000..5a30c00 --- /dev/null +++ b/test/autotrace_examples/subfolder_example/helpers/subfolder_helper2.m @@ -0,0 +1,6 @@ +function x = subfolder_helper2(x) +% example code for testing auto instrumentation, helper function + +% Copyright 2024 The MathWorks, Inc. + +x = x * 3; \ No newline at end of file diff --git a/test/autotrace_examples/subfolder_example/subfolder_example.m b/test/autotrace_examples/subfolder_example/subfolder_example.m new file mode 100644 index 0000000..6ea5bba --- /dev/null +++ b/test/autotrace_examples/subfolder_example/subfolder_example.m @@ -0,0 +1,10 @@ +function x = subfolder_example +% Example code for testing auto instrumentation, with some helper functions +% in a subfolder + +% Copyright 2024 The MathWorks, Inc. + +x = 10; +x = subfolder_helper1(x); +x = subfolder_helper2(x); + diff --git a/test/tautotrace.m b/test/tautotrace.m index 7fb7198..a6b9c2a 100644 --- a/test/tautotrace.m +++ b/test/tautotrace.m @@ -21,13 +21,7 @@ function setupOnce(testCase) % add the utils folder to the path utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); - % add the example folders to the path - example1folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example1"); - testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example1folder)); - example2folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2"); - testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2folder)); - example2helpersfolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2", "helpers"); - testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2helpersfolder)); + commonSetupOnce(testCase); % configure the global tracer provider @@ -52,8 +46,12 @@ function teardown(testCase) function testBasic(testCase) % testBasic: instrument a simple example + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1); + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example); % run the example [~] = beginTrace(at, 100); @@ -66,7 +64,7 @@ function testBasic(testCase) verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), "AutoTrace"); % default name verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "generate_data"); verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "best_fit_line"); - verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "example1"); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "linearfit_example"); % check they belong to the same trace verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.traceId, results{2}.resourceSpans.scopeSpans.spans.traceId); @@ -80,8 +78,12 @@ function testBasic(testCase) function testIncludeExcludeFiles(testCase) % testIncludeExcludeFiles: AdditionalFiles and ExcludeFiles options + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1, ... + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example, ... "AdditionalFiles", "polyfit", "ExcludeFiles", "generate_data"); % run the example @@ -94,7 +96,7 @@ function testIncludeExcludeFiles(testCase) % check span names verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "polyfit"); verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "best_fit_line"); - verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "example1"); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "linearfit_example"); % check parent children relationship verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{2}.resourceSpans.scopeSpans.spans.spanId); @@ -104,8 +106,12 @@ function testIncludeExcludeFiles(testCase) function testDisableFileDetection(testCase) % testDisableFileDetection: AutoDetectFiles set to false + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1, ... + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example, ... "AutoDetectFiles", false); % run the example @@ -116,19 +122,21 @@ function testDisableFileDetection(testCase) % should only be 1 span verifyNumElements(testCase, results, 1); - verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example1"); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "linearfit_example"); end function testIncludeFolder(testCase) % testIncludeFolder: specify a folder in AdditionalFiles - % set up AutoTrace - example2helpers = fullfile(fileparts(mfilename('fullpath')), ... - "autotrace_examples", "example2", "helpers"); - % turn off automatic detection and specify dependencies using - % their folder name - at = opentelemetry.autoinstrument.AutoTrace(@example2, ... - "AutoDetectFiles", false, "AdditionalFiles", example2helpers); + % Add example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "subfolder_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder, ... + "IncludingSubfolders",true)); + + % set up AutoTrace, turn off automatic detection and specify + % dependencies using their folder name + at = opentelemetry.autoinstrument.AutoTrace(@subfolder_example, ... + "AutoDetectFiles", false, "AdditionalFiles", fullfile(examplefolder, "helpers")); % run the example [~] = beginTrace(at); @@ -138,9 +146,9 @@ function testIncludeFolder(testCase) verifyNumElements(testCase, results, 3); % check span names - verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "ex2helper1"); - verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "ex2helper2"); - verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "example2"); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "subfolder_helper1"); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "subfolder_helper2"); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "subfolder_example"); % check parent children relationship verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{3}.resourceSpans.scopeSpans.spans.spanId); @@ -150,11 +158,14 @@ function testIncludeFolder(testCase) function testExcludeFolder(testCase) % testExcludeFolder: specify a folder in ExcludeFiles - % set up AutoTrace - example2helpers = fullfile(fileparts(mfilename('fullpath')), ... - "autotrace_examples", "example2", "helpers"); - at = opentelemetry.autoinstrument.AutoTrace(@example2, ... - "ExcludeFiles", example2helpers); + % Add example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "subfolder_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder, ... + "IncludingSubfolders",true)); + + % set up AutoTrace and exclude helper folder + at = opentelemetry.autoinstrument.AutoTrace(@subfolder_example, ... + "ExcludeFiles", fullfile(examplefolder, "helpers")); % run the example [~] = beginTrace(at); @@ -164,7 +175,7 @@ function testExcludeFolder(testCase) verifyNumElements(testCase, results, 1); % check span names - verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example2"); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "subfolder_example"); end function testNonFileOptions(testCase) @@ -179,8 +190,13 @@ function testNonFileOptions(testCase) attrnames = ["foo" "bar"]; attrvalues = [1 2]; attrs = dictionary(attrnames, attrvalues); + + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1, ... + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example, ... "TracerName", tracername, "TracerVersion", tracerversion, ... "TracerSchema", tracerschema, "SpanKind", spankind, "Attributes", attrs); @@ -214,11 +230,15 @@ function testNonFileOptions(testCase) function testError(testCase) % testError: handling error situation + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1); + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example); % run the example with an invalid input, check for error - verifyError(testCase, @()beginTrace(at, "invalid"), "autotrace_examples:example1:generate_data:InvalidN"); + verifyError(testCase, @()beginTrace(at, "invalid"), "autotrace_examples:linearfit_example:generate_data:InvalidN"); % perform test comparisons results = readJsonResults(testCase); @@ -226,7 +246,7 @@ function testError(testCase) % check span names verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "generate_data"); - verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "example1"); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "linearfit_example"); % check parent children relationship verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{2}.resourceSpans.scopeSpans.spans.spanId); @@ -238,16 +258,21 @@ function testError(testCase) function testHandleError(testCase) % testHandleError: directly call handleError method rather than using - % beginTrace method. This test should use example1_trycatch, which + % beginTrace method. This test should use linearfit_example_trycatch, which % wraps a try-catch in the input function and calls handleError % in the catch block. - % set up AutoTrace, using example1_trycatch - at = opentelemetry.autoinstrument.AutoTrace(@example1_trycatch); + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + + % set up AutoTrace, using linearfit_example_trycatch + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example_trycatch); % call example directly instead of calling beginTrace, and pass % in an invalid input - verifyError(testCase, @()example1_trycatch(at, "invalid"), "autotrace_examples:example1:generate_data:InvalidN"); + verifyError(testCase, @()linearfit_example_trycatch(at, "invalid"), ... + "autotrace_examples:linearfit_example:generate_data:InvalidN"); % perform test comparisons results = readJsonResults(testCase); @@ -255,7 +280,7 @@ function testHandleError(testCase) % check span names verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "generate_data"); - verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "example1_trycatch"); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "linearfit_example_trycatch"); % check parent children relationship verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{2}.resourceSpans.scopeSpans.spans.spanId); @@ -269,29 +294,41 @@ function testMultipleInstances(testCase) % testMultipleInstances: multiple overlapped instances should % return an error + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % set up AutoTrace - at = opentelemetry.autoinstrument.AutoTrace(@example1); %#ok + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example); %#ok % set up another identical instance, check for error - verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@example1), "opentelemetry:autoinstrument:AutoTrace:OverlappedInstances"); + verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@linearfit_example), "opentelemetry:autoinstrument:AutoTrace:OverlappedInstances"); end - function testClearInstance(~) + function testClearInstance(testCase) % testClearInstance: clear an instance and recreate a new instance + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % create and instance and then clear - at = opentelemetry.autoinstrument.AutoTrace(@example1); %#ok + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example); %#ok clear("at") % create a new instance should not result in any error - at = opentelemetry.autoinstrument.AutoTrace(@example1); %#ok + at = opentelemetry.autoinstrument.AutoTrace(@linearfit_example); %#ok end function testInvalidInputFunction(testCase) % testInvalidInputFunction: negative test for invalid input + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "linearfit_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + % anonymous function - verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@()example1), "opentelemetry:autoinstrument:AutoTrace:AnonymousFunction"); + verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@()linearfit_example), "opentelemetry:autoinstrument:AutoTrace:AnonymousFunction"); % builtin function verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@uplus), "opentelemetry:autoinstrument:AutoTrace:BuiltinFunction"); @@ -299,5 +336,46 @@ function testInvalidInputFunction(testCase) % nonexistent function verifyError(testCase, @()opentelemetry.autoinstrument.AutoTrace(@bogus), "opentelemetry:autoinstrument:AutoTrace:InvalidMFile"); end + + function testAutoManualInstrument(testCase) + % testAutoManualInstrument: using both auto and manual + % instrumentation + + % add the example folders to the path + examplefolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "manual_instrumented_example"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(examplefolder)); + + % set up AutoTrace + at = opentelemetry.autoinstrument.AutoTrace(@manual_instrumented_example); + + % run the example + [~] = beginTrace(at, 100); + + % perform test comparisons + results = readJsonResults(testCase); + verifyNumElements(testCase, results, 6); + + % check tracer and span names + tracername = "ManualInstrument"; + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "compute_y"); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "generate_data"); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "polyfit"); + verifyEqual(testCase, string(results{4}.resourceSpans.scopeSpans.spans.name), "polyval"); + verifyEqual(testCase, string(results{5}.resourceSpans.scopeSpans.spans.name), "best_fit_line"); + verifyEqual(testCase, string(results{6}.resourceSpans.scopeSpans.spans.name), "manual_instrumented_example"); + + % check auto and manual spans belong to the same trace + verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.traceId, results{6}.resourceSpans.scopeSpans.spans.traceId); + verifyEqual(testCase, results{3}.resourceSpans.scopeSpans.spans.traceId, results{6}.resourceSpans.scopeSpans.spans.traceId); + verifyEqual(testCase, results{4}.resourceSpans.scopeSpans.spans.traceId, results{6}.resourceSpans.scopeSpans.spans.traceId); + + % check parent children relationship of manual spans + verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{2}.resourceSpans.scopeSpans.spans.spanId); + verifyEqual(testCase, results{3}.resourceSpans.scopeSpans.spans.parentSpanId, results{5}.resourceSpans.scopeSpans.spans.spanId); + verifyEqual(testCase, results{4}.resourceSpans.scopeSpans.spans.parentSpanId, results{5}.resourceSpans.scopeSpans.spans.spanId); + end end end \ No newline at end of file From 961c8245690b96ab005774daf4d3a6032a5898d2 Mon Sep 17 00:00:00 2001 From: duncanpo Date: Tue, 29 Oct 2024 09:54:10 -0400 Subject: [PATCH 3/3] fixes a typo in tautotrace --- test/tautotrace.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/tautotrace.m b/test/tautotrace.m index a6b9c2a..5265595 100644 --- a/test/tautotrace.m +++ b/test/tautotrace.m @@ -358,8 +358,9 @@ function testAutoManualInstrument(testCase) % check tracer and span names tracername = "ManualInstrument"; verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); - verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); - verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{4}.resourceSpans.scopeSpans.scope.name), tracername); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "compute_y"); verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "generate_data"); verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "polyfit");