Skip to content

Commit 1b9ff8a

Browse files
committed
enable specifying folders in AutoTrace options, closes #163
1 parent e81c793 commit 1b9ff8a

File tree

5 files changed

+111
-15
lines changed

5 files changed

+111
-15
lines changed

auto-instrumentation/+opentelemetry/+autoinstrument/AutoTrace.m

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,15 @@
5858
options.AdditionalFiles {mustBeText}
5959
options.AutoDetectFiles (1,1) {mustBeNumericOrLogical} = true
6060
end
61+
% check for anonymous function
62+
fs = functions(startfun);
63+
if fs.type == "anonymous"
64+
error("opentelemetry:autoinstrument:AutoTrace:AnonymousFunction", ...
65+
"Anonymous functions are not supported.");
66+
end
6167
obj.StartFunction = startfun;
6268
startfunname = func2str(startfun);
63-
processFileInput(startfunname); % validate startfun
69+
startfunname = processFileInput(startfunname); % validate startfun
6470
if options.AutoDetectFiles
6571
if isdeployed
6672
% matlab.codetools.requiredFilesAndProducts is not
@@ -76,15 +82,16 @@
7682
end
7783
else
7884
% only include the input file, not its dependencies
79-
files = string(which(startfunname));
85+
files = startfunname;
8086
end
8187
% add extra files, this is intended for files
8288
% matlab.codetools.requiredFilesAndProducts somehow missed
8389
if isfield(options, "AdditionalFiles")
84-
incfiles = string(options.AdditionalFiles);
85-
for i = 1:numel(incfiles)
86-
incfiles(i) = which(incfiles(i)); % get the full path
87-
processFileInput(incfiles(i)); % validate additional file
90+
incinput = string(options.AdditionalFiles);
91+
incfiles = [];
92+
for i = 1:numel(incinput)
93+
% validate additional file
94+
incfiles = [incfiles; processFileOrFolderInput(incinput(i))]; %#ok<AGROW>
8895
end
8996
files = union(files, incfiles);
9097
end
@@ -94,9 +101,11 @@
94101

95102
% filter out excluded files
96103
if isfield(options, "ExcludeFiles")
97-
excfiles = string(options.ExcludeFiles);
98-
for i = 1:numel(excfiles)
99-
excfiles(i) = which(excfiles(i)); % get the full path
104+
excinput = string(options.ExcludeFiles);
105+
excfiles = [];
106+
for i = 1:numel(excinput)
107+
% validate exclude file
108+
excfiles = [excfiles; processFileOrFolderInput(excinput(i))]; %#ok<AGROW>
100109
end
101110
files = setdiff(files, excfiles);
102111
end
@@ -155,15 +164,13 @@ function handleError(obj, ME)
155164
end
156165

157166
% check input file is valid
158-
function processFileInput(f)
167+
function f = processFileInput(f)
159168
f = string(f); % force into a string
160-
if startsWith(f, '@') % check for anonymous function
161-
error("opentelemetry:autoinstrument:AutoTrace:AnonymousFunction", ...
162-
replace(f, "\", "\\") + " is an anonymous function and is not supported.");
163-
end
164169
[~,~,fext] = fileparts(f); % check file extension
165170
filetype = exist(f, "file"); % check file type
166-
if ~(filetype == 2 && ismember(fext, ["" ".m" ".mlx"]))
171+
if filetype == 2 && ismember(fext, ["" ".m" ".mlx"])
172+
f = string(which(f));
173+
else
167174
if exist(f, "builtin")
168175
error("opentelemetry:autoinstrument:AutoTrace:BuiltinFunction", ...
169176
replace(f, "\", "\\") + " is a builtin function and is not supported.");
@@ -172,4 +179,20 @@ function processFileInput(f)
172179
replace(f, "\", "\\") + " is not found or is not a valid MATLAB file with a .m or .mlx extension.");
173180
end
174181
end
182+
end
183+
184+
% check input file or folder is valid
185+
function f = processFileOrFolderInput(f)
186+
f = string(f); % force into a string
187+
if isfolder(f)
188+
% expand the directory
189+
mfileinfo = dir(fullfile(f, "*.m"));
190+
mfiles = fullfile(string({mfileinfo.folder}), string({mfileinfo.name}));
191+
mlxfileinfo = dir(fullfile(f, "*.mlx"));
192+
mlxfiles = fullfile(string({mlxfileinfo.folder}), string({mlxfileinfo.name}));
193+
f = [mfiles; mlxfiles];
194+
else
195+
% file
196+
f = processFileInput(f);
197+
end
175198
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function x = example2
2+
% example code for testing auto instrumentation.
3+
4+
% Copyright 2024 The MathWorks, Inc.
5+
6+
x = 10;
7+
x = ex2helper1(x);
8+
x = ex2helper2(x);
9+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function x = ex2helper1(x)
2+
% example code for testing auto instrumentation
3+
4+
% Copyright 2024 The MathWorks, Inc.
5+
6+
x = x * 2;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function x = ex2helper2(x)
2+
% example code for testing auto instrumentation
3+
4+
% Copyright 2024 The MathWorks, Inc.
5+
6+
x = x * 3;

test/tautotrace.m

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ function setupOnce(testCase)
2424
% add the example folders to the path
2525
example1folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example1");
2626
testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example1folder));
27+
example2folder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2");
28+
testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2folder));
29+
example2helpersfolder = fullfile(fileparts(mfilename('fullpath')), "autotrace_examples", "example2", "helpers");
30+
testCase.applyFixture(matlab.unittest.fixtures.PathFixture(example2helpersfolder));
2731
commonSetupOnce(testCase);
2832

2933
% configure the global tracer provider
@@ -115,6 +119,54 @@ function testDisableFileDetection(testCase)
115119
verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example1");
116120
end
117121

122+
function testIncludeFolder(testCase)
123+
% testIncludeFolder: specify a folder in AdditionalFiles
124+
125+
% set up AutoTrace
126+
example2helpers = fullfile(fileparts(mfilename('fullpath')), ...
127+
"autotrace_examples", "example2", "helpers");
128+
% turn off automatic detection and specify dependencies using
129+
% their folder name
130+
at = opentelemetry.autoinstrument.AutoTrace(@example2, ...
131+
"AutoDetectFiles", false, "AdditionalFiles", example2helpers);
132+
133+
% run the example
134+
[~] = beginTrace(at);
135+
136+
% perform test comparisons
137+
results = readJsonResults(testCase);
138+
verifyNumElements(testCase, results, 3);
139+
140+
% check span names
141+
verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "ex2helper1");
142+
verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), "ex2helper2");
143+
verifyEqual(testCase, string(results{3}.resourceSpans.scopeSpans.spans.name), "example2");
144+
145+
% check parent children relationship
146+
verifyEqual(testCase, results{1}.resourceSpans.scopeSpans.spans.parentSpanId, results{3}.resourceSpans.scopeSpans.spans.spanId);
147+
verifyEqual(testCase, results{2}.resourceSpans.scopeSpans.spans.parentSpanId, results{3}.resourceSpans.scopeSpans.spans.spanId);
148+
end
149+
150+
function testExcludeFolder(testCase)
151+
% testExcludeFolder: specify a folder in ExcludeFiles
152+
153+
% set up AutoTrace
154+
example2helpers = fullfile(fileparts(mfilename('fullpath')), ...
155+
"autotrace_examples", "example2", "helpers");
156+
at = opentelemetry.autoinstrument.AutoTrace(@example2, ...
157+
"ExcludeFiles", example2helpers);
158+
159+
% run the example
160+
[~] = beginTrace(at);
161+
162+
% perform test comparisons
163+
results = readJsonResults(testCase);
164+
verifyNumElements(testCase, results, 1);
165+
166+
% check span names
167+
verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), "example2");
168+
end
169+
118170
function testNonFileOptions(testCase)
119171
% testNonFileOptions: other options not related to files,
120172
% "TracerName", "TracerVersion", "TracerSchema", "Attributes",

0 commit comments

Comments
 (0)