diff --git a/CMakeLists.txt b/CMakeLists.txt index ad8b889..ce462a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -397,6 +397,7 @@ set(BAGGAGE_API_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/api/baggage/+opentele set(COMMON_API_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/api/common/+opentelemetry) set(TRACE_SDK_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sdk/trace/+opentelemetry) set(METRICS_SDK_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sdk/metrics/+opentelemetry) +set(COMMON_SDK_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sdk/common/+opentelemetry) set(DEFAULT_EXPORTER_MATLAB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/exporters/otlp/+opentelemetry/+exporters/+otlp/defaultSpanExporter.m ${CMAKE_CURRENT_SOURCE_DIR}/exporters/otlp/+opentelemetry/+exporters/+otlp/defaultMetricExporter.m) @@ -417,6 +418,7 @@ install(DIRECTORY ${BAGGAGE_API_MATLAB_SOURCES} DESTINATION .) install(DIRECTORY ${COMMON_API_MATLAB_SOURCES} DESTINATION .) install(DIRECTORY ${TRACE_SDK_MATLAB_SOURCES} DESTINATION .) install(DIRECTORY ${METRICS_SDK_MATLAB_SOURCES} DESTINATION .) +install(DIRECTORY ${COMMON_SDK_MATLAB_SOURCES} DESTINATION .) install(FILES ${DEFAULT_EXPORTER_MATLAB_SOURCES} DESTINATION ${OTLP_EXPORTERS_DIR}) if(WITH_OTLP_HTTP) install(FILES ${OTLP_HTTP_EXPORTER_MATLAB_SOURCES} DESTINATION ${OTLP_EXPORTERS_DIR}) diff --git a/api/metrics/+opentelemetry/+metrics/MeterProvider.m b/api/metrics/+opentelemetry/+metrics/MeterProvider.m index bfb8a3b..8c06c11 100644 --- a/api/metrics/+opentelemetry/+metrics/MeterProvider.m +++ b/api/metrics/+opentelemetry/+metrics/MeterProvider.m @@ -4,7 +4,7 @@ % Copyright 2023 The MathWorks, Inc. - properties (Access={?opentelemetry.sdk.metrics.MeterProvider, ?opentelemetry.sdk.metrics.Cleanup}) + properties (Access={?opentelemetry.sdk.metrics.MeterProvider, ?opentelemetry.sdk.common.Cleanup}) Proxy % Proxy object to interface C++ code end @@ -60,7 +60,7 @@ function setMeterProvider(obj) end end - methods(Access=?opentelemetry.sdk.metrics.Cleanup) + methods(Access=?opentelemetry.sdk.common.Cleanup) function postShutdown(obj) % POSTSHUTDOWN Handle post-shutdown tasks obj.Proxy.postShutdown(); diff --git a/api/trace/+opentelemetry/+trace/TracerProvider.m b/api/trace/+opentelemetry/+trace/TracerProvider.m index 6cccc5a..a5cfbdc 100644 --- a/api/trace/+opentelemetry/+trace/TracerProvider.m +++ b/api/trace/+opentelemetry/+trace/TracerProvider.m @@ -5,7 +5,7 @@ % Copyright 2023 The MathWorks, Inc. properties (Access={?opentelemetry.sdk.trace.TracerProvider, ... - ?opentelemetry.sdk.trace.Cleanup}) + ?opentelemetry.sdk.common.Cleanup}) Proxy % Proxy object to interface C++ code end @@ -61,7 +61,7 @@ function setTracerProvider(obj) end end - methods(Access=?opentelemetry.sdk.trace.Cleanup) + methods(Access=?opentelemetry.sdk.common.Cleanup) function postShutdown(obj) % POSTSHUTDOWN Handle post-shutdown tasks obj.Proxy.postShutdown(); diff --git a/sdk/common/+opentelemetry/+sdk/+common/Cleanup.m b/sdk/common/+opentelemetry/+sdk/+common/Cleanup.m new file mode 100644 index 0000000..c7fe244 --- /dev/null +++ b/sdk/common/+opentelemetry/+sdk/+common/Cleanup.m @@ -0,0 +1,95 @@ +classdef Cleanup +% Clean up methods for TracerProvider and MeterProvider + +% Copyright 2023 The MathWorks, Inc. + + methods (Static) + function success = shutdown(p) + % SHUTDOWN Shutdown + % SUCCESS = SHUTDOWN(P) shuts down all processors/readers + % associated with P. P may be a tracer provider or a meter + % provider. Returns a logical that indicates whether + % shutdown was successful. + % + % See also FORCEFLUSH + + success = true; + % return false if input is not the right type + issdk = isa(p, "opentelemetry.sdk.trace.TracerProvider") || ... + isa(p, "opentelemetry.sdk.metrics.MeterProvider"); + if issdk + psdk = p; + elseif isa(p, "opentelemetry.trace.TracerProvider") + % convert to TracerProvider class in sdk + try + psdk = opentelemetry.sdk.trace.TracerProvider(p.Proxy); + catch + success = false; + end + elseif isa(p, "opentelemetry.metrics.MeterProvider") + % convert to MeterProvider class in sdk + try + psdk = opentelemetry.sdk.metrics.MeterProvider(p.Proxy); + catch + success = false; + end + else + success = false; + end + + if success % still not yet set to false, proceed to shutdown + success = psdk.shutdown; + if ~issdk + % API classes need extra work to swap to a no-op object + postShutdown(p); + end + end + end + + function success = forceFlush(p, timeout) + % FORCEFLUSH Force flush + % SUCCESS = FORCEFLUSH(P) immediately exports all spans + % or metrics that have not yet been exported. Returns a + % logical that indicates whether force flush was successful. + % + % SUCCESS = FORCEFLUSH(P, TIMEOUT) specifies a TIMEOUT + % duration. Force flush must be completed within this time, + % or else it will fail. + % + % See also SHUTDOWN + + success = true; + + % return false if input is not the right type + if isa(p, "opentelemetry.sdk.trace.TracerProvider") || ... + isa(p, "opentelemetry.sdk.metrics.MeterProvider") + psdk = p; + elseif isa(p, "opentelemetry.trace.TracerProvider") + % convert to TracerProvider class in sdk + try + psdk = opentelemetry.sdk.trace.TracerProvider(p.Proxy); + catch + success = false; + end + elseif isa(p, "opentelemetry.metrics.MeterProvider") + % convert to MeterProvider class in sdk + try + psdk = opentelemetry.sdk.metrics.MeterProvider(p.Proxy); + catch + success = false; + end + else + success = false; + end + + if success % still not yet set to false, proceed to force flush + if nargin < 2 || ~isa(timeout, "duration") + success = psdk.forceFlush; + else + success = psdk.forceFlush(timeout); + end + end + end + end + +end diff --git a/sdk/metrics/+opentelemetry/+sdk/+metrics/Cleanup.m b/sdk/metrics/+opentelemetry/+sdk/+metrics/Cleanup.m deleted file mode 100644 index 0f31c4b..0000000 --- a/sdk/metrics/+opentelemetry/+sdk/+metrics/Cleanup.m +++ /dev/null @@ -1,63 +0,0 @@ -classdef Cleanup -% Clean up methods for MeterProvider in the API - -% Copyright 2023 The MathWorks, Inc. - - methods (Static) - function success = shutdown(mp) - % SHUTDOWN Shutdown - % SUCCESS = SHUTDOWN(MP) shuts down all metric readers associated with - % API meter provider MP and return a logical that indicates - % whether shutdown was successful. - % - % See also FORCEFLUSH - - % return false if input is not the right type - if isa(mp, "opentelemetry.metrics.MeterProvider") - % convert to MeterProvider class in sdk - try - mpsdk = opentelemetry.sdk.metrics.MeterProvider(mp.Proxy); - catch - success = false; - return - end - success = mpsdk.shutdown; - postShutdown(mp); - else - success = false; - end - end - - function success = forceFlush(mp, timeout) - % FORCEFLUSH Force flush - % SUCCESS = FORCEFLUSH(MP) immediately exports all metrics - % that have not yet been exported. Returns a logical that - % indicates whether force flush was successful. - % - % SUCCESS = FORCEFLUSH(MP, TIMEOUT) specifies a TIMEOUT - % duration. Force flush must be completed within this time, - % or else it will fail. - % - % See also SHUTDOWN - - % return false if input is not the right type - if isa(mp, "opentelemetry.metrics.MeterProvider") - % convert to MeterProvider class in sdk - try - mpsdk = opentelemetry.sdk.metrics.MeterProvider(mp.Proxy); - catch - success = false; - return - end - if nargin < 2 || ~isa(timeout, "duration") - success = mpsdk.forceFlush; - else - success = mpsdk.forceFlush(timeout); - end - else - success = false; - end - end - end - -end diff --git a/sdk/trace/+opentelemetry/+sdk/+trace/Cleanup.m b/sdk/trace/+opentelemetry/+sdk/+trace/Cleanup.m deleted file mode 100644 index d0f6e17..0000000 --- a/sdk/trace/+opentelemetry/+sdk/+trace/Cleanup.m +++ /dev/null @@ -1,63 +0,0 @@ -classdef Cleanup -% Clean up methods for TracerProvider in the API - -% Copyright 2023 The MathWorks, Inc. - - methods (Static) - function success = shutdown(tp) - % SHUTDOWN Shutdown - % SUCCESS = SHUTDOWN(TP) shuts down all span processors associated with - % API tracer provider TP and return a logical that indicates - % whether shutdown was successful. - % - % See also FORCEFLUSH - - % return false if input is not the right type - if isa(tp, "opentelemetry.trace.TracerProvider") - % convert to TracerProvider class in sdk - try - tpsdk = opentelemetry.sdk.trace.TracerProvider(tp.Proxy); - catch - success = false; - return - end - success = tpsdk.shutdown; - postShutdown(tp); - else - success = false; - end - end - - function success = forceFlush(tp, timeout) - % FORCEFLUSH Force flush - % SUCCESS = FORCEFLUSH(TP) immediately exports all spans - % that have not yet been exported. Returns a logical that - % indicates whether force flush was successful. - % - % SUCCESS = FORCEFLUSH(TP, TIMEOUT) specifies a TIMEOUT - % duration. Force flush must be completed within this time, - % or else it will fail. - % - % See also SHUTDOWN - - % return false if input is not the right type - if isa(tp, "opentelemetry.trace.TracerProvider") - % convert to TracerProvider class in sdk - try - tpsdk = opentelemetry.sdk.trace.TracerProvider(tp.Proxy); - catch - success = false; - return - end - if nargin < 2 || ~isa(timeout, "duration") - success = tpsdk.forceFlush; - else - success = tpsdk.forceFlush(timeout); - end - else - success = false; - end - end - end - -end diff --git a/test/performance/traceTest.m b/test/performance/traceTest.m index 91ed707..d9dbe41 100644 --- a/test/performance/traceTest.m +++ b/test/performance/traceTest.m @@ -37,7 +37,7 @@ function setup(testCase) function teardown(testCase) % Flush all spans that have not yet been exported tp = opentelemetry.trace.Provider.getTracerProvider(); - opentelemetry.sdk.trace.Cleanup.forceFlush(tp); + opentelemetry.sdk.common.Cleanup.forceFlush(tp); commonTeardown(testCase); end diff --git a/test/tmetrics_sdk.m b/test/tmetrics_sdk.m index 0f27729..d68e1b4 100644 --- a/test/tmetrics_sdk.m +++ b/test/tmetrics_sdk.m @@ -67,5 +67,85 @@ function testCustomResource(testCase) end end + function testShutdown(testCase) + % testShutdown: shutdown method should stop exporting + % of metrics + commonSetup(testCase) + + exporter = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(exporter, ... + "Interval", seconds(2), "Timeout", seconds(1)); + mp = opentelemetry.sdk.metrics.MeterProvider(reader); + + % shutdown the meter provider + verifyTrue(testCase, shutdown(mp)); + + % create an instrument and add some values + m = getMeter(mp, "foo"); + c = createCounter(m, "bar"); + c.add(5); + + % wait a little and then gather results, verify no metrics are + % generated + pause(2.5); + clear mp; + results = readJsonResults(testCase); + verifyEmpty(testCase, results); + end + + function testCleanupSdk(testCase) + % testCleanupSdk: shutdown an SDK meter provider through the Cleanup class + commonSetup(testCase) + + % Shut down an SDK meter provider instance + exporter = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(exporter, ... + "Interval", seconds(2), "Timeout", seconds(1)); + mp = opentelemetry.sdk.metrics.MeterProvider(reader); + + % shutdown the meter provider through the Cleanup class + verifyTrue(testCase, opentelemetry.sdk.common.Cleanup.shutdown(mp)); + + % create an instrument and add some values + m = getMeter(mp, "foo"); + c = createCounter(m, "bar"); + c.add(5); + + % wait a little and then gather results, verify no metrics are + % generated + pause(2.5); + clear mp; + results = readJsonResults(testCase); + verifyEmpty(testCase, results); + end + + function testCleanupApi(testCase) + % testCleanupApi: shutdown an API meter provider through the Cleanup class + commonSetup(testCase) + + % Shut down an API meter provider instance + exporter = opentelemetry.exporters.otlp.OtlpHttpMetricExporter(); + reader = opentelemetry.sdk.metrics.PeriodicExportingMetricReader(exporter, ... + "Interval", seconds(2), "Timeout", seconds(1)); + mp = opentelemetry.sdk.metrics.MeterProvider(reader); + setMeterProvider(mp); + clear("mp"); + mp_api = opentelemetry.metrics.Provider.getMeterProvider(); + + % shutdown the API meter provider through the Cleanup class + verifyTrue(testCase, opentelemetry.sdk.common.Cleanup.shutdown(mp_api)); + + % create an instrument and add some values + m = getMeter(mp_api, "foo"); + c = createCounter(m, "bar"); + c.add(5); + + % wait a little and then gather results, verify no metrics are + % generated + pause(2.5); + clear("mp_api"); + results = readJsonResults(testCase); + verifyEmpty(testCase, results); + end end end \ No newline at end of file