diff --git a/CMakeLists.txt b/CMakeLists.txt index 2147f62..cfab06a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,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 "bc2b9f2") +set(LIBMEXCLASS_FETCH_CONTENT_GIT_TAG "3a3b581") set(LIBMEXCLASS_FETCH_CONTENT_SOURCE_SUBDIR "libmexclass/cpp") @@ -546,3 +546,4 @@ install(FILES ${OPENTELEMETRY_PROXY_RUNTIME_LIBRARIES} DESTINATION ${LIBMEXCLASS if(WITH_EXAMPLES) add_subdirectory(examples) endif() + diff --git a/test/callbacks/callbackWithAttributes3.m b/test/callbacks/callbackWithAttributes3.m new file mode 100644 index 0000000..0756373 --- /dev/null +++ b/test/callbacks/callbackWithAttributes3.m @@ -0,0 +1,8 @@ +function result = callbackWithAttributes3() +% Test callback function for asynchronous instruments that uses attributes +% +% Copyright 2024 The MathWorks, Inc. + +value = 30; +result = opentelemetry.metrics.ObservableResult; +result = result.observe(value, dictionary({"Level1"}, {"D"},{"Level2"},{"E"})); \ No newline at end of file diff --git a/test/tformat.m b/test/tformat.m new file mode 100644 index 0000000..f784e6c --- /dev/null +++ b/test/tformat.m @@ -0,0 +1,147 @@ +classdef tformat < matlab.unittest.TestCase + % tests for setting format in the exporter + + % Copyright 2023-2024 The MathWorks, Inc. + + properties + OtelConfigFile + JsonFile + PidFile + OtelcolName + Otelcol + ListPid + ReadPidList + ExtractPid + Sigint + Sigterm + end + + methods (TestClassSetup) + function setupOnce(testCase) + % add the utils folder to the path + utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); + commonSetupOnce(testCase); + end + end + + methods (TestMethodSetup) + function setup(testCase) + config = fullfile(fileparts(mfilename("fullpath")), "config", "otelcol_config.yml"); + commonSetup(testCase, config); + end + end + + methods (TestMethodTeardown) + function teardown(testCase) + commonTeardown(testCase); + end + end + + methods (Test) + function testNondefaultFormat(testCase) + % testNondefaultFormat: using an alternative format + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpSpanExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpHttpSpanExporter(... + "Format", "binary"); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function testNondefaultGrpcFormat(testCase) + % testNondefaultGrpcFormat: using an alternative format + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcSpanExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpGrpcSpanExporter(... + "Format", "binary"); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function NondefaultMetricsFormat(testCase) + % testNondefaultMetricsFormat: using an alternative format + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(... + "Format", "binary"); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 4; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + function NondefaultGrpcMetricsFormat(testCase) + % testNondefaultGrpcMetricsFormat: using an alternative format + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcMetricExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter(... + "Format", "binary"); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 8; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + end +end \ No newline at end of file diff --git a/test/thttpheaders.m b/test/thttpheaders.m new file mode 100644 index 0000000..cb99502 --- /dev/null +++ b/test/thttpheaders.m @@ -0,0 +1,147 @@ +classdef thttpheaders < matlab.unittest.TestCase + % tests for setting HTTPHeaders in the exporter + + % Copyright 2023-2024 The MathWorks, Inc. + + properties + OtelConfigFile + JsonFile + PidFile + OtelcolName + Otelcol + ListPid + ReadPidList + ExtractPid + Sigint + Sigterm + end + + methods (TestClassSetup) + function setupOnce(testCase) + % add the utils folder to the path + utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); + commonSetupOnce(testCase); + end + end + + methods (TestMethodSetup) + function setup(testCase) + config = fullfile(fileparts(mfilename("fullpath")), "config", "otelcol_config.yml"); + commonSetup(testCase, config); + end + end + + methods (TestMethodTeardown) + function teardown(testCase) + commonTeardown(testCase); + end + end + + methods (Test) + function testNondefaultHTTPHeaders(testCase) + % testNondefaultHTTPHeaders: using an alternative HTTPHeaders + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpSpanExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpHttpSpanExporter(... + "HTTPHeaders", dictionary("new","header")); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function testNondefaultGrpcHTTPHeaders(testCase) + % testNondefaultGrpcHTTPHeaders: using an alternative HTTPHeaders + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcSpanExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpGrpcSpanExporter(... + "HTTPHeaders", dictionary("new","header")); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function NondefaultMetricsHTTPHeaders(testCase) + % testNondefaultMetricsHTTPHeaders: using an alternative HTTPHeaders + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(... + "HTTPHeaders", dictionary("new","header")); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 4; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + function NondefaultGrpcMetricsHTTPHeaders(testCase) + % testNondefaultGrpcMetricsHTTPHeaders: using an alternative HTTPHeaders + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcMetricExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter(... + "HTTPHeaders", dictionary("new","header")); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 8; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + end +end \ No newline at end of file diff --git a/test/tjsonbytesmapping.m b/test/tjsonbytesmapping.m new file mode 100644 index 0000000..17ebae6 --- /dev/null +++ b/test/tjsonbytesmapping.m @@ -0,0 +1,147 @@ +classdef tjsonbytesmapping < matlab.unittest.TestCase + % tests for setting JsonBytesMapping in the exporter + + % Copyright 2023-2024 The MathWorks, Inc. + + properties + OtelConfigFile + JsonFile + PidFile + OtelcolName + Otelcol + ListPid + ReadPidList + ExtractPid + Sigint + Sigterm + end + + methods (TestClassSetup) + function setupOnce(testCase) + % add the utils folder to the path + utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); + commonSetupOnce(testCase); + end + end + + methods (TestMethodSetup) + function setup(testCase) + config = fullfile(fileparts(mfilename("fullpath")), "config", "otelcol_config.yml"); + commonSetup(testCase, config); + end + end + + methods (TestMethodTeardown) + function teardown(testCase) + commonTeardown(testCase); + end + end + + methods (Test) + function testNondefaultJsonBytesMapping(testCase) + % testNondefaultJsonBytesMapping: using an alternative JsonBytesMapping + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpSpanExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpHttpSpanExporter(... + "JsonBytesMapping", "base64"); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function testNondefaultGrpcJsonBytesMapping(testCase) + % testNondefaultGrpcJsonBytesMapping: using an alternative JsonBytesMapping + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcSpanExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpGrpcSpanExporter(... + "JsonBytesMapping", "base64"); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function NondefaultMetricsJsonBytesMapping(testCase) + % testNondefaultMetricsJsonBytesMapping: using an alternative JsonBytesMapping + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(... + "JsonBytesMapping", "base64"); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 4; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + function NondefaultGrpcMetricsJsonBytesMapping(testCase) + % testNondefaultGrpcMetricsJsonBytesMapping: using an alternative JsonBytesMapping + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcMetricExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter(... + "JsonBytesMapping", "base64"); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 8; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + end +end \ No newline at end of file diff --git a/test/tlogs_sdk.m b/test/tlogs_sdk.m index eabe95e..858448d 100644 --- a/test/tlogs_sdk.m +++ b/test/tlogs_sdk.m @@ -76,6 +76,32 @@ function testOtlpFileExporter(testCase) verifyEqual(testCase, string(results.resourceLogs.scopeLogs.logRecords.severityText), upper(logseverity)); verifyEqual(testCase, string(results.resourceLogs.scopeLogs.logRecords.body.stringValue), logmessage); end + + function testHttpExporter(testCase) + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpLogRecordExporter", "class")), ... + "Otlp HTTP Log record exporter must be installed."); + + processor1 = opentelemetry.sdk.logs.SimpleLogRecordProcessor; + + HttpExporter = processor1.LogRecordExporter; + + HttpExporter.Endpoint = "endpoint"; + HttpExporter.Format = "JSON"; + HttpExporter.JsonBytesMapping = "base64"; + HttpExporter.UseJsonName = 1; + HttpExporter.Timeout = seconds(10); + HttpExporter.HttpHeaders = dictionary("new","header"); + + exp = opentelemetry.exporters.otlp.OtlpHttpLogRecordExporter("Endpoint","endpoint","Format","JSON","JsonBytesMapping","base64","UseJsonName",1,"Timeout",seconds(10),"HttpHeaders",dictionary("new","header")); + + % Validate that set methods create a OtlpHttpLogRecordExporter + % with expected properties + HttpExporter = rmfield(struct(HttpExporter),"Proxy"); + exp = rmfield(struct(exp),"Proxy"); + testCase.verifyEqual(HttpExporter,exp); + + + end function testAddLogRecordProcessor(testCase) % testAddLogRecordProcessor: addLogRecordProcessor method diff --git a/test/tmetrics.m b/test/tmetrics.m index 0b11a93..018c074 100644 --- a/test/tmetrics.m +++ b/test/tmetrics.m @@ -747,6 +747,37 @@ function testAsynchronousInstrumentMultipleCallbacks(testCase, create_async, dat verifyEqual(testCase, string(dp(idxC).attributes.value.stringValue), "C"); end + function testAsynchronousInstrumentDictionaryCallback(testCase, create_async, datapoint_name) + % removeCallback method + %callback = @callbackNoAttributes3; + + p = opentelemetry.sdk.metrics.MeterProvider(testCase.ShortIntervalReader); + mt = p.getMeter("foo"); + ct = create_async(mt, @callbackWithAttributes3, "bar", "", "", testCase.CallbackTimeout); + + % wait for collector response + pause(testCase.WaitTime); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter name + verifyEqual(testCase, string(results{1}.resourceMetrics.scopeMetrics.metrics.name), "bar"); + + % verify counter values and attributes + dp = results{1}.resourceMetrics.scopeMetrics.metrics.(datapoint_name).dataPoints.attributes; + attrvals = arrayfun(@(x)string(x.value.stringValue),dp); + idxD = (attrvals == "D"); + idxE = (attrvals == "E"); + verifyEqual(testCase, results{1}.resourceMetrics.scopeMetrics.metrics.(datapoint_name).dataPoints.asDouble, 30); + verifyEqual(testCase, string(dp(idxD).key), "Level1"); + verifyEqual(testCase, string(dp(idxD).value.stringValue), "D"); + verifyEqual(testCase, string(dp(idxE).key), "Level2"); + verifyEqual(testCase, string(dp(idxE).value.stringValue), "E"); + + end + function testAsynchronousInstrumentRemoveCallback(testCase, create_async) % removeCallback method callback = @callbackNoAttributes; diff --git a/test/tmetrics_sdk.m b/test/tmetrics_sdk.m index 57901c5..49dd084 100644 --- a/test/tmetrics_sdk.m +++ b/test/tmetrics_sdk.m @@ -229,6 +229,55 @@ function testViewBasic(testCase) verifyEqual(testCase, dp.asDouble, val); end + function testViewProperties(testCase) + % testViewProperties: check view object changes the name and + % description of output metrics when schema, version, and units + view_name = "counter_view"; + view_description = "view_description"; + view = opentelemetry.sdk.metrics.View(Name=view_name, .... + Description=view_description, InstrumentType="Counter",MeterSchema="http://schema.org",MeterVersion="1.0.0",InstrumentUnit="ms"); + mp = opentelemetry.sdk.metrics.MeterProvider(... + testCase.ShortIntervalReader, View=view); + + m = getMeter(mp, "mymeter", "1.0.0", "http://schema.org"); + c = createCounter(m, "mycounter","Counter for meter with view properties","ms"); + + m2 = getMeter(mp, "mymeter2", "2.0.0", "http://schema.org"); + c2 = createCounter(m2, "mycounter","Counter for meter with different version","ms"); + + m3 = getMeter(mp, "mymeter3","1.0.0","http://notmyschema.org"); + c3 = createCounter(m3, "mycounter","Counter for meter with different schema","ms"); + + m4 = getMeter(mp, "mymeter4", "1.0.0", "http://schema.org"); + c4 = createCounter(m4, "mycounter","Counter for meter with view properties different units","s"); + + m4 = getMeter(mp, "mymeter5", "1.0.0", "http://schema.org"); + u = createUpDownCounter(m4, "updowncounter","UpDownCounter for meter with view properties","ms"); + + + + % add value and attributes + val = 10; + c.add(val); + c2.add(val); + c3.add(val); + c4.add(val); + u.add(val); + + pause(testCase.WaitTime); + + clear mp; + results = readJsonResults(testCase); + results = results{end}; + + % verify view name only on meter with matching properties + verifyEqual(testCase, string(results.resourceMetrics.scopeMetrics(1).metrics.name), view_name); + verifyNotEqual(testCase, string(results.resourceMetrics.scopeMetrics(2).metrics.name), view_name); + verifyNotEqual(testCase, string(results.resourceMetrics.scopeMetrics(3).metrics.name), view_name); + verifyNotEqual(testCase, string(results.resourceMetrics.scopeMetrics(4).metrics.name), view_name); + verifyNotEqual(testCase, string(results.resourceMetrics.scopeMetrics(5).metrics.name), view_name); + end + function testViewHistogram(testCase) % testViewHistogram: Change histogram bins mp = opentelemetry.sdk.metrics.MeterProvider(testCase.ShortIntervalReader); diff --git a/test/ttimeout.m b/test/ttimeout.m new file mode 100644 index 0000000..02ac242 --- /dev/null +++ b/test/ttimeout.m @@ -0,0 +1,147 @@ +classdef ttimeout < matlab.unittest.TestCase + % tests for setting Timeout in the exporter + + % Copyright 2023-2024 The MathWorks, Inc. + + properties + OtelConfigFile + JsonFile + PidFile + OtelcolName + Otelcol + ListPid + ReadPidList + ExtractPid + Sigint + Sigterm + end + + methods (TestClassSetup) + function setupOnce(testCase) + % add the utils folder to the path + utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); + commonSetupOnce(testCase); + end + end + + methods (TestMethodSetup) + function setup(testCase) + config = fullfile(fileparts(mfilename("fullpath")), "config", "otelcol_config.yml"); + commonSetup(testCase, config); + end + end + + methods (TestMethodTeardown) + function teardown(testCase) + commonTeardown(testCase); + end + end + + methods (Test) + function testNondefaultTimeout(testCase) + % testNondefaultTimeout: using an alternative Timeout + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpSpanExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpHttpSpanExporter(... + "Timeout", seconds(10)); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function testNondefaultGrpcTimeout(testCase) + % testNondefaultGrpcTimeout: using an alternative Timeout + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcSpanExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpGrpcSpanExporter(... + "Timeout", seconds(10)); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function NondefaultMetricsTimeout(testCase) + % testNondefaultMetricsTimeout: using an alternative Timeout + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(... + "Timeout", seconds(10)); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 4; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + function NondefaultGrpcMetricsTimeout(testCase) + % testNondefaultGrpcMetricsTimeout: using an alternative Timeout + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcMetricExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter(... + "Timeout", seconds(10)); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 8; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + end +end \ No newline at end of file diff --git a/test/ttrace_sdk.m b/test/ttrace_sdk.m index 2634a62..4ee110c 100644 --- a/test/ttrace_sdk.m +++ b/test/ttrace_sdk.m @@ -111,6 +111,54 @@ function testAlwaysOnSampler(testCase) verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); end + function testParentBasedSampler(testCase) + % testAlwaysOnSampler: should produce all spans + tracername = "tracer - AlwaysOnSampler"; + spanname = "span - AlwaysOnSampler"; + + tp = opentelemetry.sdk.trace.TracerProvider( ... + "Sampler", opentelemetry.sdk.trace.ParentBasedSampler(opentelemetry.sdk.trace.AlwaysOnSampler)); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + tracername1 = "tracer - AlwaysOffSampler"; + spanname1 = "span - AlwaysOffSampler"; + tp = opentelemetry.sdk.trace.TracerProvider( ... + "Sampler", opentelemetry.sdk.trace.ParentBasedSampler(opentelemetry.sdk.trace.AlwaysOffSampler)); + tr = getTracer(tp, tracername1); + sp = startSpan(tr, spanname1); + pause(1); + endSpan(sp); + + tracername2 = "tracer - TraceIdRatioBasedSampler"; + spanname2 = "span - TraceIdRatioBasedSampler"; + tp = opentelemetry.sdk.trace.TracerProvider( ... + "Sampler", opentelemetry.sdk.trace.ParentBasedSampler(opentelemetry.sdk.trace.TraceIdRatioBasedSampler(1))); + tr = getTracer(tp, tracername2); + sp = startSpan(tr, spanname2); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + + % check span and tracer names of an AlwaysOnSampler + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results{1}.resourceSpans.scopeSpans.scope.name), tracername); + + % AlwaysOffSampler should return no results + + % check span and tracer names of an TraceIdRatioBasedSampler + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.spans.name), spanname2); + verifyEqual(testCase, string(results{2}.resourceSpans.scopeSpans.scope.name), tracername2); + + % check ParentBasedSampler doesn't accept other inputs + verifyError(testCase, @() opentelemetry.sdk.trace.TracerProvider( ... + "Sampler", opentelemetry.sdk.trace.ParentBasedSampler(opentelemetry.sdk.trace.ParentBasedSampler("not a sampler"))), "MATLAB:validators:mustBeA"); + end + function testTraceIdRatioBasedSampler(testCase) % testTraceIdRatioBasedSampler: filter spans based on a ratio s = opentelemetry.sdk.trace.TraceIdRatioBasedSampler(0); % equivalent to always off diff --git a/test/tusejsonname.m b/test/tusejsonname.m new file mode 100644 index 0000000..015179b --- /dev/null +++ b/test/tusejsonname.m @@ -0,0 +1,147 @@ +classdef tusejsonname < matlab.unittest.TestCase + % tests for setting UseJsonName in the exporter + + % Copyright 2023-2024 The MathWorks, Inc. + + properties + OtelConfigFile + JsonFile + PidFile + OtelcolName + Otelcol + ListPid + ReadPidList + ExtractPid + Sigint + Sigterm + end + + methods (TestClassSetup) + function setupOnce(testCase) + % add the utils folder to the path + utilsfolder = fullfile(fileparts(mfilename('fullpath')), "utils"); + testCase.applyFixture(matlab.unittest.fixtures.PathFixture(utilsfolder)); + commonSetupOnce(testCase); + end + end + + methods (TestMethodSetup) + function setup(testCase) + config = fullfile(fileparts(mfilename("fullpath")), "config", "otelcol_config.yml"); + commonSetup(testCase, config); + end + end + + methods (TestMethodTeardown) + function teardown(testCase) + commonTeardown(testCase); + end + end + + methods (Test) + function testNondefaultUseJsonName(testCase) + % testNondefaultUseJsonName: using an alternative UseJsonName + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpSpanExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpHttpSpanExporter(... + "UseJsonName", true); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function testNondefaultGrpcUseJsonName(testCase) + % testNondefaultGrpcUseJsonName: using an alternative UseJsonName + + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcSpanExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + tracername = "foo"; + spanname = "bar"; + + exp = opentelemetry.exporters.otlp.OtlpGrpcSpanExporter(... + "UseJsonName", true); + processor = opentelemetry.sdk.trace.SimpleSpanProcessor(exp); + tp = opentelemetry.sdk.trace.TracerProvider(processor); + tr = getTracer(tp, tracername); + sp = startSpan(tr, spanname); + pause(1); + endSpan(sp); + + % perform test comparisons + results = readJsonResults(testCase); + results = results{1}; + + % check span and tracer names + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.spans.name), spanname); + verifyEqual(testCase, string(results.resourceSpans.scopeSpans.scope.name), tracername); + end + + function NondefaultMetricsUseJsonName(testCase) + % testNondefaultMetricsUseJsonName: using an alternative UseJsonName + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpHttpMetricExporter", "class")), ... + "Otlp HTTP exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(... + "UseJsonName", true); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 4; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + function NondefaultGrpcMetricsUseJsonName(testCase) + % testNondefaultGrpcMetricsUseJsonName: using an alternative UseJsonName + testCase.assumeTrue(logical(exist("opentelemetry.exporters.otlp.OtlpGrpcMetricExporter", "class")), ... + "Otlp gRPC exporter must be installed."); + + exp = opentelemetry.exporters.otlp.OtlpGrpcMetricExporter(... + "UseJsonName", true); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(... + exp, "Interval", seconds(2), "Timeout", seconds(1)); + p = opentelemetry.sdk.metrics.MeterProvider(reader); + mt = p.getMeter("foo"); + ct = mt.createCounter("bar"); + + val = 8; + ct.add(val); + pause(2.5); + + % fetch result + clear p; + results = readJsonResults(testCase); + + % verify counter value + verifyEqual(testCase, results{end}.resourceMetrics.scopeMetrics.metrics.sum.dataPoints.asDouble, val); + end + + end +end \ No newline at end of file