summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/opentelemetry-cpp/sdk
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/jaegertracing/opentelemetry-cpp/sdk
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/sdk')
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/BUILD7
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/CHANGELOG.md27
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/CMakeLists.txt44
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/aggregator.h156
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h108
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h169
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h146
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h207
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h159
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h282
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/async_instruments.h286
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/controller.h154
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/exporter.h35
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/instrument.h312
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter.h392
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter_provider.h37
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/processor.h38
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/record.h50
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/sync_instruments.h465
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/ungrouped_processor.h365
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h62
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_unique_ptr.h87
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attribute_utils.h199
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attributemap_hash.h62
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer.h186
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer_range.h93
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/empty_attributes.h34
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/env_variables.h53
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/exporter_utils.h34
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/global_log_handler.h222
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h96
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/batch_log_processor.h128
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/exporter.h62
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/log_record.h193
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger.h77
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_context.h81
-rwxr-xr-xsrc/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_provider.h131
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h69
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_recordable.h104
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/processor.h61
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/recordable.h97
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h146
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/drop_aggregation.h51
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h103
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h63
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/sum_aggregation.h64
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/async_instruments.h115
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h42
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/point_data.h78
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/always_sample_filter.h43
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/data.h45
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/filter.h39
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/never_sample_filter.h43
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/metric_producer.h57
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h72
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/instruments.h70
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter.h156
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_context.h133
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_provider.h95
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h72
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/observer_result.h48
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h95
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h124
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h57
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_storage.h86
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/multi_metric_storage.h68
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h119
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h50
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h127
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h81
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/instrument_selector.h36
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/meter_selector.h47
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate.h82
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate_factory.h45
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view.h57
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h102
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/experimental_semantic_conventions.h141
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource.h86
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource_detector.h38
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h158
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/exporter.h55
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/id_generator.h31
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_recordable.h161
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h187
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/processor.h70
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/random_id_generator.h24
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/recordable.h152
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/sampler.h91
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h48
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h47
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/parent.h45
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/trace_id_ratio.h53
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/simple_processor.h84
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/span_data.h304
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer.h70
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_context.h100
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_provider.h103
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/version/version.h30
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk_config.h7
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/CMakeLists.txt12
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/BUILD26
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/CMakeLists.txt19
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter.cc782
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter_provider.cc29
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/ungrouped_processor.cc178
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/BUILD44
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/CMakeLists.txt21
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/core.cc8
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/fast_random_number_generator.h82
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/global_log_handler.cc57
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/BUILD34
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork.h24
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_unix.cc22
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_windows.cc23
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.cc80
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.h41
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/BUILD28
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/CMakeLists.txt25
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/batch_log_processor.cc208
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger.cc126
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_context.cc54
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_provider.cc142
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_log_processor.cc151
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_recordable.cc140
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/logs/simple_log_processor.cc64
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/BUILD28
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/CMakeLists.txt29
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/histogram_aggregation.cc142
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/lastvalue_aggregation.cc134
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/sum_aggregation.cc111
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/export/periodic_exporting_metric_reader.cc101
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter.cc259
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_context.cc108
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_provider.cc94
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/metric_reader.cc94
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/metric_collector.cc62
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/sync_metric_storage.cc36
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/temporal_metric_storage.cc131
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/sync_instruments.cc202
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/resource/BUILD26
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/resource/CMakeLists.txt16
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource.cc82
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource_detector.cc39
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/BUILD29
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/CMakeLists.txt26
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/batch_span_processor.cc211
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/random_id_generator.cc30
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/parent.cc48
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/trace_id_ratio.cc111
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.cc187
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.h66
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer.cc116
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_context.cc63
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_provider.cc104
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/version/CMakeLists.txt17
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/src/version/version.cc24
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/CMakeLists.txt12
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/BUILD165
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/CMakeLists.txt21
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/controller_test.cc56
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/counter_aggregator_test.cc120
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/exact_aggregator_test.cc229
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/gauge_aggregator_test.cc133
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/histogram_aggregator_test.cc173
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_provider_sdk_test.cc26
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_test.cc297
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/metric_instrument_test.cc487
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/min_max_sum_count_aggregator_test.cc209
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/sketch_aggregator_test.cc254
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/ungrouped_processor_test.cc601
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD153
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt37
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc42
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc53
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc22
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc32
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h88
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc133
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc59
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc161
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc19
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc22
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc67
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc35
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc53
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc35
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/BUILD14
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/CMakeLists.txt11
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc26
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/BUILD75
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/CMakeLists.txt10
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/batch_log_processor_test.cc269
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/log_record_test.cc66
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_provider_sdk_test.cc133
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_sdk_test.cc97
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/logs/simple_log_processor_test.cc152
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/BUILD203
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/CMakeLists.txt34
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/aggregation_test.cc182
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_instruments_test.cc60
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_metric_storage_test.cc132
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_benchmark.cc53
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_test.cc71
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_benchmark.cc27
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_test.cc49
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/BUILD47
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/CMakeLists.txt10
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/always_sample_filter_test.cc19
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/never_sample_filter_test.cc20
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc22
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/meter_provider_sdk_test.cc91
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/metric_reader_test.cc39
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/multi_metric_storage_test.cc62
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/observer_result_test.cc38
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/periodic_exporting_metric_reader_test.cc81
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_instruments_test.cc138
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_metric_storage_test.cc246
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/view_registry_test.cc82
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/resource/BUILD12
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/resource/CMakeLists.txt9
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/resource/resource_test.cc213
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/BUILD155
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/CMakeLists.txt30
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_off_sampler_test.cc42
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_on_sampler_test.cc60
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/batch_span_processor_test.cc291
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/parent_sampler_test.cc73
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc156
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/simple_processor_test.cc75
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/span_data_test.cc135
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/trace_id_ratio_sampler_test.cc258
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_provider_test.cc99
-rw-r--r--src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_test.cc731
238 files changed, 24479 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/BUILD
new file mode 100644
index 000000000..cc62431b5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/BUILD
@@ -0,0 +1,7 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "headers",
+ hdrs = glob(["include/**/*.h"]),
+ strip_include_prefix = "include",
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/CHANGELOG.md b/src/jaegertracing/opentelemetry-cpp/sdk/CHANGELOG.md
new file mode 100644
index 000000000..8463575d2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/CHANGELOG.md
@@ -0,0 +1,27 @@
+# Release History: opentelemetry-sdk
+
+All notable changes to the sdk project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## Guideline to update the version
+
+Increment the:
+
+* MAJOR version when you make incompatible API/ABI changes,
+* MINOR version when you add functionality in a backwards compatible manner, and
+* PATCH version when you make backwards compatible bug fixes.
+
+## [Unreleased]
+
+## [0.1.0] 2020-12-17
+
+### Added
+
+* Trace SDK experimental
+* OTLP Exporter
+
+### Changed
+
+### Removed
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/CMakeLists.txt
new file mode 100644
index 000000000..ca5af6334
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/CMakeLists.txt
@@ -0,0 +1,44 @@
+add_library(opentelemetry_sdk INTERFACE)
+target_include_directories(
+ opentelemetry_sdk
+ INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
+ "$<INSTALL_INTERFACE:include>")
+
+set_target_properties(opentelemetry_sdk PROPERTIES EXPORT_NAME sdk)
+
+install(
+ TARGETS opentelemetry_sdk
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+install(
+ DIRECTORY include/opentelemetry/
+ DESTINATION include/opentelemetry
+ FILES_MATCHING
+ PATTERN "*config.h")
+
+set(LOGS_EXCLUDE_PATTERN "")
+if(NOT WITH_LOGS_PREVIEW)
+ set(LOGS_EXCLUDE_PATTERN "logs")
+endif()
+
+set(METRICS_EXCLUDE_PATTERN "")
+if(NOT WITH_METRICS_PREVIEW)
+ set(METRICS_EXCLUDE_PATTERN "_metrics")
+endif()
+
+install(
+ DIRECTORY include/opentelemetry/sdk
+ DESTINATION include/opentelemetry
+ FILES_MATCHING
+ PATTERN "*.h"
+ PATTERN "${METRICS_EXCLUDE_PATTERN}" EXCLUDE
+ PATTERN "${LOGS_EXCLUDE_PATTERN}" EXCLUDE)
+
+add_subdirectory(src)
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/aggregator.h
new file mode 100644
index 000000000..f6821d731
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/aggregator.h
@@ -0,0 +1,156 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <mutex>
+# include <vector>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+enum class AggregatorKind
+{
+ Counter = 0,
+ MinMaxSumCount = 1,
+ Gauge = 2,
+ Sketch = 3,
+ Histogram = 4,
+ Exact = 5,
+};
+
+/*
+ * Performs calculations necessary to combine updates from instruments into an
+ * insightful value.
+ * Also stores current instrument values and checkpoints collected at intervals
+ * governing the entire pipeline.
+ */
+template <typename T>
+class Aggregator
+{
+public:
+ Aggregator() = default;
+
+ virtual ~Aggregator() = default;
+
+ /**
+ * Receives a captured value from the instrument and applies it to the current aggregator value.
+ *
+ * @param val, the raw value used in aggregation
+ * @return none
+ */
+ virtual void update(T val) = 0;
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ * @param none
+ * @return none
+ */
+ virtual void checkpoint() = 0;
+
+ /**
+ * Merges the values of two aggregators in a semantically accurate manner.
+ * Merging will occur differently for different aggregators depending on the
+ * way values are tracked.
+ *
+ * @param other, the aggregator with merge with
+ * @return none
+ */
+ void merge(Aggregator *other);
+
+ /**
+ * Returns the checkpointed value
+ *
+ * @param none
+ * @return the value of the checkpoint
+ */
+ virtual std::vector<T> get_checkpoint() = 0;
+
+ /**
+ * Returns the current value
+ *
+ * @param none
+ * @return the present aggregator value
+ */
+ virtual std::vector<T> get_values() = 0;
+
+ /**
+ * Returns the instrument kind which this aggregator is associated with
+ *
+ * @param none
+ * @return the InstrumentKind of the aggregator's owner
+ */
+ virtual opentelemetry::metrics::InstrumentKind get_instrument_kind() final { return kind_; }
+
+ /**
+ * Returns the type of this aggregator
+ *
+ * @param none
+ * @return the AggregatorKind of this instrument
+ */
+ virtual AggregatorKind get_aggregator_kind() final { return agg_kind_; }
+
+ /**
+ * Getter function for updated_ protected var
+ *
+ * @return A bool indicating wether or not this aggregator has been updated
+ * in the most recent collection interval.
+ */
+ virtual bool is_updated() final { return updated_; }
+
+ // virtual function to be overridden for the Histogram Aggregator
+ virtual std::vector<double> get_boundaries() { return std::vector<double>(); }
+
+ // virtual function to be overridden for the Histogram Aggregator
+ virtual std::vector<int> get_counts() { return std::vector<int>(); }
+
+ // virtual function to be overridden for Exact and Sketch Aggregators
+ virtual bool get_quant_estimation() { return false; }
+
+ // virtual function to be overridden for Exact and Sketch Aggregators
+ virtual T get_quantiles(double q) { return values_[0]; }
+
+ // virtual function to be overridden for Sketch Aggregator
+ virtual double get_error_bound() { return 0; }
+
+ // virtual function to be overridden for Sketch Aggregator
+ virtual size_t get_max_buckets() { return 0; }
+
+ // virtual function to be overridden for Gauge Aggregator
+ virtual opentelemetry::common::SystemTimestamp get_checkpoint_timestamp()
+ {
+ return opentelemetry::common::SystemTimestamp();
+ }
+
+ // Custom copy constructor to handle the mutex
+ Aggregator(const Aggregator &cp)
+ {
+ values_ = cp.values_;
+ checkpoint_ = cp.checkpoint_;
+ kind_ = cp.kind_;
+ agg_kind_ = cp.agg_kind_;
+ // use default initialized mutex as they cannot be copied
+ }
+
+protected:
+ std::vector<T> values_;
+ std::vector<T> checkpoint_;
+ opentelemetry::metrics::InstrumentKind kind_;
+ std::mutex mu_;
+ AggregatorKind agg_kind_;
+ bool updated_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h
new file mode 100644
index 000000000..b9842e8e0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h
@@ -0,0 +1,108 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <mutex>
+# include <vector>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+template <class T>
+class CounterAggregator final : public Aggregator<T>
+{
+
+public:
+ CounterAggregator(opentelemetry::metrics::InstrumentKind kind)
+ {
+ this->kind_ = kind;
+ this->values_ = std::vector<T>(1, 0);
+ this->checkpoint_ = std::vector<T>(1, 0);
+ this->agg_kind_ = AggregatorKind::Counter;
+ }
+
+ /**
+ * Receives a captured value from the instrument and applies it to the current aggregator value.
+ *
+ * @param val, the raw value used in aggregation
+ * @return none
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+ this->values_[0] += val; // atomic operation
+ this->mu_.unlock();
+ }
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ * @param none
+ * @return none
+ */
+ void checkpoint() override
+ {
+ this->mu_.lock();
+ this->updated_ = false;
+ this->checkpoint_ = this->values_;
+ this->values_[0] = 0;
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges the values of two aggregators in a semantically accurate manner.
+ * In this case, merging only requires the the current values of the two aggregators be summed.
+ *
+ * @param other, the aggregator with merge with
+ * @return none
+ */
+ void merge(CounterAggregator other)
+ {
+ if (this->agg_kind_ == other.agg_kind_)
+ {
+ this->mu_.lock();
+ this->values_[0] += other.values_[0];
+ this->checkpoint_[0] += other.checkpoint_[0];
+ this->mu_.unlock();
+ }
+ else
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Aggregators of different types cannot be merged.");
+# else
+ std::terminate();
+# endif
+ }
+ }
+
+ /**
+ * Returns the checkpointed value
+ *
+ * @param none
+ * @return the value of the checkpoint
+ */
+ virtual std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ /**
+ * Returns the current values
+ *
+ * @param none
+ * @return the present aggregator values
+ */
+ virtual std::vector<T> get_values() override { return this->values_; }
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h
new file mode 100644
index 000000000..44ea717a0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h
@@ -0,0 +1,169 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+# include <cmath>
+# include <memory>
+# include <mutex>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+/**
+ * This aggregator has two modes. In-order and quantile estimation.
+ *
+ * The first mode simply stores all values sent to the Update()
+ * function in a vector and maintains the order they were sent in.
+ *
+ * The second mode also stores all values sent to the Update()
+ * function in a vector but sorts this vector when Checkpoint()
+ * is called. This mode also includes a function, Quantile(),
+ * that estimates the quantiles of the recorded data.
+ *
+ * @tparam T the type of values stored in this aggregator.
+ */
+template <class T>
+class ExactAggregator : public Aggregator<T>
+{
+public:
+ ExactAggregator(opentelemetry::metrics::InstrumentKind kind, bool quant_estimation = false)
+ {
+ static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
+ this->kind_ = kind;
+ this->checkpoint_ = this->values_;
+ this->agg_kind_ = AggregatorKind::Exact;
+ quant_estimation_ = quant_estimation;
+ }
+
+ ~ExactAggregator() = default;
+
+ ExactAggregator(const ExactAggregator &cp)
+ {
+ this->values_ = cp.values_;
+ this->checkpoint_ = cp.checkpoint_;
+ this->kind_ = cp.kind_;
+ this->agg_kind_ = cp.agg_kind_;
+ quant_estimation_ = cp.quant_estimation_;
+ // use default initialized mutex as they cannot be copied
+ }
+
+ /**
+ * Receives a captured value from the instrument and adds it to the values_ vector.
+ *
+ * @param val, the raw value used in aggregation
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+ this->values_.push_back(val);
+ this->mu_.unlock();
+ }
+
+ /**
+ * Checkpoints the current values. This function will overwrite the current checkpoint with the
+ * current value. Sorts the values_ vector if quant_estimation_ == true
+ *
+ */
+ void checkpoint() override
+ {
+ this->mu_.lock();
+ this->updated_ = false;
+ if (quant_estimation_)
+ {
+ std::sort(this->values_.begin(), this->values_.end());
+ }
+ this->checkpoint_ = this->values_;
+ this->values_.clear();
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges two exact aggregators' values_ vectors together.
+ *
+ * @param other the aggregator to merge with this aggregator
+ */
+ void merge(const ExactAggregator &other)
+ {
+ if (this->kind_ == other.kind_)
+ {
+ this->mu_.lock();
+ // First merge values
+ this->values_.insert(this->values_.end(), other.values_.begin(), other.values_.end());
+ // Now merge checkpoints
+ this->checkpoint_.insert(this->checkpoint_.end(), other.checkpoint_.begin(),
+ other.checkpoint_.end());
+ this->mu_.unlock();
+ }
+ else
+ {
+ // Log error
+ return;
+ }
+ }
+
+ /**
+ * Performs quantile estimation on the checkpoint vector in this aggregator.
+ * This function only works if quant_estimation_ == true.
+ * @param q the quantile to estimate. 0 <= q <= 1
+ * @return the nearest value in the vector to the exact quantile.
+ */
+ T get_quantiles(double q) override
+ {
+ if (!quant_estimation_)
+ {
+// Log error
+# if __EXCEPTIONS
+ throw std::domain_error("Exact aggregator is not in quantile estimation mode!");
+# else
+ std::terminate();
+# endif
+ }
+ if (this->checkpoint_.size() == 0 || q < 0 || q > 1)
+ {
+// Log error
+# if __EXCEPTIONS
+ throw std::invalid_argument("Arg 'q' must be between 0 and 1, inclusive");
+# else
+ std::terminate();
+# endif
+ }
+ else if (q == 0 || this->checkpoint_.size() == 1)
+ {
+ return this->checkpoint_[0];
+ }
+ else if (q == 1)
+ {
+ return this->checkpoint_[this->checkpoint_.size() - 1];
+ }
+ else
+ {
+ float position = float(float(this->checkpoint_.size() - 1) * q);
+ int ceiling = int(ceil(position));
+ return this->checkpoint_[ceiling];
+ }
+ }
+
+ //////////////////////////ACCESSOR FUNCTIONS//////////////////////////
+ std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ std::vector<T> get_values() override { return this->values_; }
+
+ bool get_quant_estimation() override { return quant_estimation_; }
+
+private:
+ bool quant_estimation_; // Used to switch between in-order and quantile estimation modes
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h
new file mode 100644
index 000000000..96119386d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h
@@ -0,0 +1,146 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+# include <memory>
+# include <mutex>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+/**
+ * This aggregator stores and maintains a vector of
+ * type T where the contents of the vector simply
+ * include the last value recorded to the aggregator.
+ * The aggregator also maintains a timestamp of when
+ * the last value was recorded.
+ *
+ * @tparam T the type of values stored in this aggregator.
+ */
+template <class T>
+class GaugeAggregator : public Aggregator<T>
+{
+public:
+ explicit GaugeAggregator(opentelemetry::metrics::InstrumentKind kind)
+ {
+ static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
+ this->kind_ = kind;
+ this->values_ = std::vector<T>(1, 0);
+ this->checkpoint_ = this->values_;
+ this->agg_kind_ = AggregatorKind::Gauge;
+ current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
+ }
+
+ ~GaugeAggregator() = default;
+
+ GaugeAggregator(const GaugeAggregator &cp)
+ {
+ this->values_ = cp.values_;
+ this->checkpoint_ = cp.checkpoint_;
+ this->kind_ = cp.kind_;
+ this->agg_kind_ = cp.agg_kind_;
+ current_timestamp_ = cp.current_timestamp_;
+ // use default initialized mutex as they cannot be copied
+ }
+
+ /**
+ * Receives a captured value from the instrument and applies it to the current aggregator value.
+ *
+ * @param val, the raw value used in aggregation
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+ this->values_[0] = val;
+ current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
+ this->mu_.unlock();
+ }
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ * @return none
+ */
+
+ void checkpoint() override
+ {
+ this->mu_.lock();
+
+ this->updated_ = false;
+ this->checkpoint_ = this->values_;
+
+ // Reset the values to default
+ this->values_[0] = 0;
+ checkpoint_timestamp_ = current_timestamp_;
+ current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
+
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges two Gauge aggregators together
+ *
+ * @param other the aggregator to merge with this aggregator
+ */
+ void merge(GaugeAggregator<T> other)
+ {
+ if (this->kind_ == other.kind_)
+ {
+ this->mu_.lock();
+ // First merge values
+ this->values_[0] = other.values_[0];
+ // Now merge checkpoints
+ this->checkpoint_[0] = other.checkpoint_[0];
+ current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
+ this->mu_.unlock();
+ }
+ else
+ {
+ // Log error
+ return;
+ }
+ }
+
+ /**
+ * @return the value of the latest checkpoint
+ */
+ std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ /**
+ * @return the latest checkpointed timestamp
+ */
+ opentelemetry::common::SystemTimestamp get_checkpoint_timestamp() override
+ {
+ return checkpoint_timestamp_;
+ }
+
+ /**
+ * @return the values_ vector stored in this aggregator
+ */
+ std::vector<T> get_values() override { return this->values_; }
+
+ /**
+ * @return the timestamp of when the last value recorded
+ */
+ opentelemetry::common::SystemTimestamp get_timestamp() { return current_timestamp_; }
+
+private:
+ opentelemetry::common::SystemTimestamp current_timestamp_;
+ opentelemetry::common::SystemTimestamp checkpoint_timestamp_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h
new file mode 100644
index 000000000..13e1e1244
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h
@@ -0,0 +1,207 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <algorithm>
+# include <mutex>
+# include <stdexcept>
+# include <vector>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+template <class T>
+class HistogramAggregator final : public Aggregator<T>
+{
+
+public:
+ /**
+ * Constructor for the histogram aggregator. A sorted vector of boundaries is expected and
+ * boundaries are doubles regardless of the aggregator's templated data type.
+ *
+ * Sum is stored in values_[0]
+ * Count is stored in position_[1]
+ */
+ HistogramAggregator(opentelemetry::metrics::InstrumentKind kind, std::vector<double> boundaries)
+ {
+ if (!std::is_sorted(boundaries.begin(), boundaries.end()))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Histogram boundaries must be monotonic.");
+# else
+ std::terminate();
+# endif
+ }
+ this->kind_ = kind;
+ this->agg_kind_ = AggregatorKind::Histogram;
+ boundaries_ = boundaries;
+ this->values_ = std::vector<T>(2, 0);
+ this->checkpoint_ = std::vector<T>(2, 0);
+ bucketCounts_ = std::vector<int>(boundaries_.size() + 1, 0);
+ bucketCounts_ckpt_ = std::vector<int>(boundaries_.size() + 1, 0);
+ }
+
+ /**
+ * Receives a captured value from the instrument and inserts it into the current histogram counts.
+ *
+ * Depending on the use case, a linear search or binary search based implementation may be
+ * preferred. In uniformly distributed datasets, linear search outperforms binary search until 512
+ * buckets. However, if the distribution is strongly skewed right (for example server latency
+ * where most values may be <10ms but the range is from 0 - 1000 ms), a linear search could be
+ * superior even with more than 500 buckets as almost all values inserted would be at the
+ * beginning of the boundaries array and thus found more quickly through linear search.
+ *
+ * @param val, the raw value used in aggregation
+ * @return none
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+ size_t bucketID = boundaries_.size();
+ for (size_t i = 0; i < boundaries_.size(); i++)
+ {
+ if (val < boundaries_[i]) // concurrent read is thread-safe
+ {
+ bucketID = i;
+ break;
+ }
+ }
+
+ // Alternate implementation with binary search
+ // auto pos = std::lower_bound (boundaries_.begin(), boundaries_.end(), val);
+ // bucketCounts_[pos-boundaries_.begin()] += 1;
+
+ this->values_[0] += val;
+ this->values_[1] += 1;
+ bucketCounts_[bucketID] += 1;
+ this->mu_.unlock();
+ }
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ * @param none
+ * @return none
+ */
+ void checkpoint() override
+ {
+ this->mu_.lock();
+ this->updated_ = false;
+ this->checkpoint_ = this->values_;
+ this->values_[0] = 0;
+ this->values_[1] = 0;
+ bucketCounts_ckpt_ = bucketCounts_;
+ std::fill(bucketCounts_.begin(), bucketCounts_.end(), 0);
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges the values of two aggregators in a semantically accurate manner.
+ * A histogram aggregator can only be merged with another histogram aggregator that has the same
+ * boudnaries. A histogram merge first adds the sum and count values then iterates over the adds
+ * the bucket counts element by element.
+ *
+ * @param other, the aggregator with merge with
+ * @return none
+ */
+ void merge(HistogramAggregator other)
+ {
+ this->mu_.lock();
+
+ // Ensure that incorrect types are not merged
+ if (this->agg_kind_ != other.agg_kind_)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Aggregators of different types cannot be merged.");
+# else
+ std::terminate();
+# endif
+ // Reject histogram merges with differing boundary vectors
+ }
+ else if (other.boundaries_ != this->boundaries_)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Histogram boundaries do not match.");
+# else
+ std::terminate();
+# endif
+ }
+
+ this->values_[0] += other.values_[0];
+ this->values_[1] += other.values_[1];
+
+ this->checkpoint_[0] += other.checkpoint_[0];
+ this->checkpoint_[1] += other.checkpoint_[1];
+
+ for (size_t i = 0; i < bucketCounts_.size(); i++)
+ {
+ bucketCounts_[i] += other.bucketCounts_[i];
+ bucketCounts_ckpt_[i] += other.bucketCounts_ckpt_[i];
+ }
+ this->mu_.unlock();
+ }
+
+ /**
+ * Returns the checkpointed value
+ *
+ * @param none
+ * @return the value of the checkpoint
+ */
+ std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ /**
+ * Returns the current values
+ *
+ * @param none
+ * @return the present aggregator values
+ */
+ std::vector<T> get_values() override { return this->values_; }
+
+ /**
+ * Returns the bucket boundaries specified at this aggregator's creation.
+ *
+ * @param none
+ * @return the aggregator boundaries
+ */
+ virtual std::vector<double> get_boundaries() override { return boundaries_; }
+
+ /**
+ * Returns the current counts for each bucket .
+ *
+ * @param none
+ * @return the aggregator bucket counts
+ */
+ virtual std::vector<int> get_counts() override { return bucketCounts_ckpt_; }
+
+ HistogramAggregator(const HistogramAggregator &cp)
+ {
+ this->values_ = cp.values_;
+ this->checkpoint_ = cp.checkpoint_;
+ this->kind_ = cp.kind_;
+ this->agg_kind_ = cp.agg_kind_;
+ boundaries_ = cp.boundaries_;
+ bucketCounts_ = cp.bucketCounts_;
+ bucketCounts_ckpt_ = cp.bucketCounts_ckpt_;
+ // use default initialized mutex as they cannot be copied
+ }
+
+private:
+ std::vector<double> boundaries_;
+ std::vector<int> bucketCounts_;
+ std::vector<int> bucketCounts_ckpt_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h
new file mode 100644
index 000000000..60628b567
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h
@@ -0,0 +1,159 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+# include <memory>
+# include <mutex>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+const int MinValueIndex = 0;
+const int MaxValueIndex = 1;
+const int SumValueIndex = 2;
+const int CountValueIndex = 3;
+/**
+ * This aggregator stores and maintains a vector of
+ * type T where the contents in the vector are made
+ * up of the minimum value recorded to this instrument,
+ * the maximum value, the sum of all values, and the
+ * count of all values.
+ *
+ * @tparam T the type of values stored in this aggregator.
+ */
+template <class T>
+class MinMaxSumCountAggregator : public Aggregator<T>
+{
+public:
+ explicit MinMaxSumCountAggregator(opentelemetry::metrics::InstrumentKind kind)
+ {
+ static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
+ this->kind_ = kind;
+ this->values_ = std::vector<T>(4, 0); // {min, max, sum, count}
+ this->checkpoint_ = this->values_;
+ this->agg_kind_ = AggregatorKind::MinMaxSumCount;
+ }
+
+ ~MinMaxSumCountAggregator() = default;
+
+ MinMaxSumCountAggregator(const MinMaxSumCountAggregator &cp)
+ {
+ this->values_ = cp.values_;
+ this->checkpoint_ = cp.checkpoint_;
+ this->kind_ = cp.kind_;
+ this->agg_kind_ = cp.agg_kind_;
+ // use default initialized mutex as they cannot be copied
+ }
+
+ /**
+ * Receives a captured value from the instrument and applies it to the current aggregator value.
+ *
+ * @param val, the raw value used in aggregation
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+
+ if (this->values_[CountValueIndex] == 0 || val < this->values_[MinValueIndex]) // set min
+ this->values_[MinValueIndex] = val;
+ if (this->values_[CountValueIndex] == 0 || val > this->values_[MaxValueIndex]) // set max
+ this->values_[MaxValueIndex] = val;
+
+ this->values_[SumValueIndex] += val; // compute sum
+ this->values_[CountValueIndex]++; // increment count
+
+ this->mu_.unlock();
+ }
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ */
+ void checkpoint() override
+ {
+ this->mu_.lock();
+ this->updated_ = false;
+ this->checkpoint_ = this->values_;
+ // Reset the values
+ this->values_[MinValueIndex] = 0;
+ this->values_[MaxValueIndex] = 0;
+ this->values_[SumValueIndex] = 0;
+ this->values_[CountValueIndex] = 0;
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges two MinMaxSumCount aggregators together
+ *
+ * @param other the aggregator to merge with this aggregator
+ */
+ void merge(const MinMaxSumCountAggregator &other)
+ {
+ if (this->kind_ == other.kind_)
+ {
+ this->mu_.lock();
+ // First merge values
+ // set min
+ if (this->values_[CountValueIndex] == 0 ||
+ other.values_[MinValueIndex] < this->values_[MinValueIndex])
+ this->values_[MinValueIndex] = other.values_[MinValueIndex];
+ // set max
+ if (this->values_[CountValueIndex] == 0 ||
+ other.values_[MaxValueIndex] > this->values_[MaxValueIndex])
+ this->values_[MaxValueIndex] = other.values_[MaxValueIndex];
+ // set sum
+ this->values_[SumValueIndex] += other.values_[SumValueIndex];
+ // set count
+ this->values_[CountValueIndex] += other.values_[CountValueIndex];
+
+ // Now merge checkpoints
+ if (this->checkpoint_[CountValueIndex] == 0 ||
+ other.checkpoint_[MinValueIndex] < this->checkpoint_[MinValueIndex])
+ this->checkpoint_[MinValueIndex] = other.checkpoint_[MinValueIndex];
+ // set max
+ if (this->checkpoint_[CountValueIndex] == 0 ||
+ other.checkpoint_[MaxValueIndex] > this->checkpoint_[MaxValueIndex])
+ this->checkpoint_[MaxValueIndex] = other.checkpoint_[MaxValueIndex];
+ // set sum
+ this->checkpoint_[SumValueIndex] += other.checkpoint_[SumValueIndex];
+ // set count
+ this->checkpoint_[CountValueIndex] += other.checkpoint_[CountValueIndex];
+
+ this->mu_.unlock();
+ }
+ else
+ {
+ // Log error
+ return;
+ }
+ }
+
+ /**
+ * Returns the checkpointed value
+ *
+ * @return the value of the checkpoint
+ */
+ std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ /**
+ * Returns the values currently held by the aggregator
+ *
+ * @return the values held by the aggregator
+ */
+ std::vector<T> get_values() override { return this->values_; }
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h
new file mode 100644
index 000000000..3942c9550
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h
@@ -0,0 +1,282 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <algorithm>
+# include <cmath>
+# include <limits>
+# include <map>
+# include <mutex>
+# include <stdexcept>
+# include <vector>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+/** Sketch Aggregators implement the DDSketch data type. Note that data is compressed
+ * by the DDSketch algorithm and users should be informed about its behavior before
+ * selecting it as the aggregation type. NOTE: The current implementation can only support
+ * non-negative values.
+ *
+ * Detailed information about the algorithm can be found in the following paper
+ * published by Datadog: http://www.vldb.org/pvldb/vol12/p2195-masson.pdf
+ */
+
+template <class T>
+class SketchAggregator final : public Aggregator<T>
+{
+
+public:
+ /**
+ * Given the distribution of data this aggregator is designed for and its usage, the raw updates
+ *are stored in a map rather than a vector.
+ *
+ *@param kind, the instrument kind creating this aggregator
+ *@param error_bound, what is referred to as "alpha" in the DDSketch algorithm
+ *@param max_buckets, the maximum number of indices in the raw value map
+ */
+ SketchAggregator(opentelemetry::metrics::InstrumentKind kind,
+ double error_bound,
+ size_t max_buckets = 2048)
+ {
+
+ this->kind_ = kind;
+ this->agg_kind_ = AggregatorKind::Sketch;
+ this->values_ = std::vector<T>(2, 0); // Sum in [0], Count in [1]
+ this->checkpoint_ = std::vector<T>(2, 0);
+ max_buckets_ = max_buckets;
+ error_bound_ = error_bound;
+ gamma = (1 + error_bound) / (1 - error_bound);
+ }
+
+ /**
+ * Update the aggregator with the new value. For a DDSketch aggregator, if the addition of this
+ * value creates a new bucket which is in excess of the maximum allowed size, the lowest indexes
+ * buckets are merged.
+ *
+ * @param val, the raw value used in aggregation
+ * @return none
+ */
+ void update(T val) override
+ {
+ this->mu_.lock();
+ this->updated_ = true;
+ int idx;
+ if (val == 0)
+ {
+ idx = (std::numeric_limits<int>::min());
+ }
+ else
+ {
+ idx = static_cast<int>(ceil(log(val) / log(gamma)));
+ }
+ if (raw_.find(idx) != raw_.end())
+ {
+ raw_[idx] += 1;
+ }
+ else
+ {
+ raw_[idx] = 1;
+ }
+ this->values_[1] += 1;
+ this->values_[0] += val;
+ if (raw_.size() > max_buckets_)
+ {
+ int minidx = raw_.begin()->first, minidxval = raw_.begin()->second;
+ raw_.erase(minidx);
+ raw_[raw_.begin()->first] += minidxval;
+ }
+ this->mu_.unlock();
+ }
+
+ /**
+ * Calculate and return the value of a user specified quantile.
+ *
+ * @param q, the quantile to calculate (for example 0.5 is equivalent to the 50th percentile)
+ */
+ virtual T get_quantiles(double q) override
+ {
+ if (q < 0 || q > 1)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Quantile values must fall between 0 and 1");
+# else
+ std::terminate();
+# endif
+ }
+ auto iter = checkpoint_raw_.begin();
+ int idx = iter->first;
+ int count = iter->second;
+
+ while (count < (q * (this->checkpoint_[1] - 1)) && iter != checkpoint_raw_.end())
+ {
+ iter++;
+ idx = iter->first;
+ count += iter->second;
+ }
+ return static_cast<T>(round(2 * pow(gamma, idx) / (gamma + 1)));
+ }
+
+ /**
+ * Checkpoints the current value. This function will overwrite the current checkpoint with the
+ * current value.
+ *
+ * @param none
+ * @return none
+ */
+ void checkpoint() override
+ {
+ this->mu_.lock();
+ this->updated_ = false;
+ this->checkpoint_ = this->values_;
+ checkpoint_raw_ = raw_;
+ this->values_[0] = 0;
+ this->values_[1] = 0;
+ raw_.clear();
+ this->mu_.unlock();
+ }
+
+ /**
+ * Merges this sketch aggregator with another. The same bucket compression used when
+ * updating values is employed here to manage bucket size if the merging of aggregators
+ * results in more buckets than allowed.
+ *
+ * @param other, the aggregator with merge with
+ * @return none
+ */
+ void merge(SketchAggregator other)
+ {
+ if (gamma != other.gamma)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Aggregators must have identical error tolerance");
+# else
+ std::terminate();
+# endif
+ }
+ else if (max_buckets_ != other.max_buckets_)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Aggregators must have the same maximum bucket allowance");
+# else
+ std::terminate();
+# endif
+ }
+
+ this->mu_.lock();
+ this->values_[0] += other.values_[0];
+ this->values_[1] += other.values_[1];
+ this->checkpoint_[0] += other.checkpoint_[0];
+ this->checkpoint_[1] += other.checkpoint_[1];
+ auto other_iter = other.raw_.begin();
+ while (other_iter != other.raw_.end())
+ {
+ raw_[other_iter->first] += other_iter->second;
+ if (raw_.size() > max_buckets_)
+ {
+ int minidx = raw_.begin()->first, minidxval = raw_.begin()->second;
+ raw_.erase(minidx);
+ raw_[raw_.begin()->first] += minidxval;
+ }
+ other_iter++;
+ }
+ auto other_ckpt_iter = other.checkpoint_raw_.begin();
+ while (other_ckpt_iter != other.checkpoint_raw_.end())
+ {
+ checkpoint_raw_[other_ckpt_iter->first] += other_ckpt_iter->second;
+ if (checkpoint_raw_.size() > max_buckets_)
+ {
+ int minidx = checkpoint_raw_.begin()->first, minidxval = checkpoint_raw_.begin()->second;
+ checkpoint_raw_.erase(minidx);
+ checkpoint_raw_[checkpoint_raw_.begin()->first] += minidxval;
+ }
+ other_ckpt_iter++;
+ }
+ this->mu_.unlock();
+ }
+
+ /**
+ * Returns the checkpointed value
+ *
+ * @param none
+ * @return the value of the checkpoint
+ */
+ std::vector<T> get_checkpoint() override { return this->checkpoint_; }
+
+ /**
+ * Returns the current values
+ *
+ * @param none
+ * @return the present aggregator values
+ */
+ std::vector<T> get_values() override { return this->values_; }
+
+ /**
+ * Returns the indices (or values) stored by this sketch aggregator.
+ *
+ * @param none
+ * @return a vector of all values the aggregator is currently tracking
+ */
+ virtual std::vector<double> get_boundaries() override
+ {
+ std::vector<double> ret;
+ for (auto const &x : checkpoint_raw_)
+ {
+ ret.push_back(2 * pow(gamma, x.first) / (gamma + 1));
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the error bound
+ *
+ * @param none
+ * @return the error bound specified during construction
+ */
+ virtual double get_error_bound() override { return error_bound_; }
+
+ /**
+ * Returns the maximum allowed buckets
+ *
+ * @param none
+ * @return the maximum allowed buckets
+ */
+ virtual size_t get_max_buckets() override { return max_buckets_; }
+
+ /**
+ * Returns the count of each value tracked by this sketch aggregator. These are returned
+ * in the same order as the indices returned by the get_boundaries function.
+ *
+ * @param none
+ * @return a vector of all counts for values tracked by the aggregator
+ */
+ virtual std::vector<int> get_counts() override
+ {
+ std::vector<int> ret;
+ for (auto const &x : checkpoint_raw_)
+ {
+ ret.push_back(x.second);
+ }
+ return ret;
+ }
+
+private:
+ double gamma;
+ double error_bound_;
+ size_t max_buckets_;
+ std::map<int, int> raw_;
+ std::map<int, int> checkpoint_raw_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/async_instruments.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/async_instruments.h
new file mode 100644
index 000000000..5213a4e2e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/async_instruments.h
@@ -0,0 +1,286 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <map>
+# include <memory>
+# include <sstream>
+# include <stdexcept>
+# include <vector>
+# include "opentelemetry/_metrics/async_instruments.h"
+# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
+# include "opentelemetry/sdk/_metrics/instrument.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+# if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4250) // inheriting methods via dominance
+# endif
+
+template <class T>
+class ValueObserver : public AsynchronousInstrument<T>,
+ virtual public opentelemetry::metrics::ValueObserver<T>
+{
+
+public:
+ ValueObserver() = default;
+
+ ValueObserver(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T>))
+ : AsynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ callback,
+ opentelemetry::metrics::InstrumentKind::ValueObserver)
+ {}
+
+ /*
+ * Updates the instruments aggregator with the new value. The labels should
+ * contain the keys and values to be associated with this value.
+ *
+ * @param value is the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundAggregators_.find(labelset) == boundAggregators_.end())
+ {
+ auto sp1 = std::shared_ptr<Aggregator<T>>(new MinMaxSumCountAggregator<T>(this->kind_));
+ boundAggregators_.insert(std::make_pair(labelset, sp1));
+ sp1->update(value);
+ }
+ else
+ {
+ boundAggregators_[labelset]->update(value);
+ }
+ this->mu_.unlock();
+ }
+
+ /*
+ * Activate the instrument's callback function to record a measurement. This
+ * function will be called by the specified controller at a regular interval.
+ *
+ * @param none
+ * @return none
+ */
+ virtual void run() override
+ {
+ opentelemetry::metrics::ObserverResult<T> res(this);
+ this->callback_(res);
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ for (auto x : boundAggregators_)
+ {
+ x.second->checkpoint();
+ ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
+ }
+ boundAggregators_.clear();
+ this->mu_.unlock();
+ return ret;
+ }
+
+ // Public mapping from labels (stored as strings) to their respective aggregators
+ std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
+};
+
+template <class T>
+class SumObserver : public AsynchronousInstrument<T>,
+ virtual public opentelemetry::metrics::SumObserver<T>
+{
+
+public:
+ SumObserver() = default;
+
+ SumObserver(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T>))
+ : AsynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ callback,
+ opentelemetry::metrics::InstrumentKind::SumObserver)
+ {}
+
+ /*
+ * Updates the instruments aggregator with the new value. The labels should
+ * contain the keys and values to be associated with this value.
+ *
+ * @param value is the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundAggregators_.find(labelset) == boundAggregators_.end())
+ {
+ auto sp1 = std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(this->kind_));
+ boundAggregators_.insert(std::make_pair(labelset, sp1));
+ if (value < 0)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Counter instrument updates must be non-negative.");
+# else
+ std::terminate();
+# endif
+ }
+ else
+ {
+ sp1->update(value);
+ }
+ }
+ else
+ {
+ if (value < 0)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Counter instrument updates must be non-negative.");
+# else
+ std::terminate();
+# endif
+ }
+ else
+ {
+ boundAggregators_[labelset]->update(value);
+ }
+ }
+ this->mu_.unlock();
+ }
+
+ /*
+ * Activate the intsrument's callback function to record a measurement. This
+ * function will be called by the specified controller at a regular interval.
+ *
+ * @param none
+ * @return none
+ */
+ virtual void run() override
+ {
+ opentelemetry::metrics::ObserverResult<T> res(this);
+ this->callback_(res);
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ for (auto x : boundAggregators_)
+ {
+ x.second->checkpoint();
+ ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
+ }
+ boundAggregators_.clear();
+ this->mu_.unlock();
+ return ret;
+ }
+
+ // Public mapping from labels (stored as strings) to their respective aggregators
+ std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
+};
+
+template <class T>
+class UpDownSumObserver : public AsynchronousInstrument<T>,
+ virtual public opentelemetry::metrics::UpDownSumObserver<T>
+{
+
+public:
+ UpDownSumObserver() = default;
+
+ UpDownSumObserver(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T>))
+ : AsynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ callback,
+ opentelemetry::metrics::InstrumentKind::UpDownSumObserver)
+ {}
+
+ /*
+ * Updates the instruments aggregator with the new value. The labels should
+ * contain the keys and values to be associated with this value.
+ *
+ * @param value is the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundAggregators_.find(labelset) == boundAggregators_.end())
+ {
+ auto sp1 = std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(this->kind_));
+ boundAggregators_.insert(std::make_pair(labelset, sp1));
+ sp1->update(value);
+ }
+ else
+ {
+ boundAggregators_[labelset]->update(value);
+ }
+ this->mu_.unlock();
+ }
+
+ /*
+ * Activate the intsrument's callback function to record a measurement. This
+ * function will be called by the specified controller at a regular interval.
+ *
+ * @param none
+ * @return none
+ */
+ virtual void run() override
+ {
+ opentelemetry::metrics::ObserverResult<T> res(this);
+ this->callback_(res);
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ for (auto x : boundAggregators_)
+ {
+ x.second->checkpoint();
+ ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
+ }
+ boundAggregators_.clear();
+ this->mu_.unlock();
+ return ret;
+ }
+
+ // Public mapping from labels (stored as strings) to their respective aggregators
+ std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
+};
+
+# if defined(_MSC_VER)
+# pragma warning(pop)
+# endif
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/controller.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/controller.h
new file mode 100644
index 000000000..66a57a2ef
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/controller.h
@@ -0,0 +1,154 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <atomic>
+# include <iostream>
+# include <sstream>
+# include <thread>
+# include <vector>
+
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/common/macros.h"
+# include "opentelemetry/nostd/unique_ptr.h"
+# include "opentelemetry/sdk/_metrics/exporter.h"
+# include "opentelemetry/sdk/_metrics/meter.h"
+# include "opentelemetry/sdk/_metrics/processor.h"
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class PushController
+{
+
+public:
+ PushController(nostd::shared_ptr<opentelemetry::metrics::Meter> meter,
+ nostd::unique_ptr<MetricsExporter> exporter,
+ nostd::shared_ptr<MetricsProcessor> processor,
+ double period,
+ int timeout = 30)
+ {
+ meter_ = meter;
+ exporter_ = std::move(exporter);
+ processor_ = processor;
+ timeout_ = (unsigned int)(timeout * 1000000); // convert seconds to microseconds
+ period_ = (unsigned int)(period * 1000000);
+ }
+
+ /*
+ * Used to check if the metrics pipeline is currently active
+ *
+ * @param none
+ * @return true when active, false when on standby. This is a best guess estimate
+ * and the boolean from start() should be used to determine wheher the pipeline
+ * was initiated successfully.
+ */
+ bool isActive() { return active_.load(); }
+
+ /*
+ * Begins the data processing and export pipeline. The function first ensures that the pipeline
+ * is not already running. If not, it begins and detaches a new thread for the Controller's run
+ * function which periodically polls the instruments for their data.
+ *
+ * @param none
+ * @return a boolean which is true when the pipeline is successfully started and false when
+ * already active
+ */
+ bool start()
+ {
+ if (!active_.exchange(true))
+ {
+ runner_ = std::thread(&PushController::run, this);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Ends the processing and export pipeline then exports metrics one last time
+ * before returning.
+ *
+ * @param none
+ * @return none
+ */
+ void stop()
+ {
+ if (active_.exchange(false))
+ {
+ if (runner_.joinable())
+ {
+ runner_.join();
+ }
+ tick(); // flush metrics sitting in the processor
+ }
+ }
+
+private:
+ /*
+ * Run the tick function at a regular interval. This function
+ * should be run in its own thread.
+ *
+ * Used to wait between collection intervals.
+ */
+ void run()
+ {
+ if (!running_.exchange(true))
+ {
+ while (active_.load())
+ {
+ tick();
+ std::this_thread::sleep_for(std::chrono::microseconds(period_));
+ }
+ running_.exchange(false);
+ }
+ }
+
+ /*
+ * Tick
+ *
+ * Called at regular intervals, this function collects all values from the
+ * member variable meter_, then sends them to the processor_ for
+ * processing. After the records have been processed they are sent to the
+ * exporter_ to be exported.
+ *
+ */
+ void tick()
+ {
+ this->mu_.lock();
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::vector<Record> collected = dynamic_cast<Meter *>(meter_.get())->Collect();
+# else
+ std::vector<Record> collected = static_cast<Meter *>(meter_.get())->Collect();
+# endif
+ for (const auto &rec : collected)
+ {
+ processor_->process(rec);
+ }
+ collected = processor_->CheckpointSelf();
+ processor_->FinishedCollection();
+ exporter_->Export(collected);
+ this->mu_.unlock();
+ }
+
+ nostd::shared_ptr<opentelemetry::metrics::Meter> meter_;
+ nostd::unique_ptr<MetricsExporter> exporter_;
+ nostd::shared_ptr<MetricsProcessor> processor_;
+ std::thread runner_;
+ std::mutex mu_;
+ std::atomic<bool> active_ = ATOMIC_VAR_INIT(false);
+ std::atomic<bool> running_ = ATOMIC_VAR_INIT(false);
+ unsigned int period_;
+ unsigned int timeout_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/exporter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/exporter.h
new file mode 100644
index 000000000..aae416527
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/exporter.h
@@ -0,0 +1,35 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <memory>
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/sdk/common/exporter_utils.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+/**
+ * MetricsExporter defines the interface that protocol-specific span exporters must
+ * implement.
+ */
+class MetricsExporter
+{
+public:
+ virtual ~MetricsExporter() = default;
+
+ /**
+ * Exports a vector of Records. This method must not be called
+ * concurrently for the same exporter instance.
+ * @param records a vector of unique pointers to metric records
+ */
+ virtual sdk::common::ExportResult Export(const std::vector<Record> &records) noexcept = 0;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/instrument.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/instrument.h
new file mode 100644
index 000000000..51111be5e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/instrument.h
@@ -0,0 +1,312 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <iostream>
+# include <map>
+# include <memory>
+# include <sstream>
+# include <string>
+# include <unordered_map>
+# include <vector>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+# if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4250) // inheriting methods via dominance
+# endif
+
+class Instrument : virtual public opentelemetry::metrics::Instrument
+{
+
+public:
+ Instrument() = default;
+
+ Instrument(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ opentelemetry::metrics::InstrumentKind kind)
+ : name_(name), description_(description), unit_(unit), enabled_(enabled), kind_(kind)
+ {}
+
+ // Returns true if the instrument is enabled and collecting data
+ virtual bool IsEnabled() override { return enabled_; }
+
+ // Return the instrument name
+ virtual nostd::string_view GetName() override { return name_; }
+
+ // Return the instrument description
+ virtual nostd::string_view GetDescription() override { return description_; }
+
+ // Return the insrument's units of measurement
+ virtual nostd::string_view GetUnits() override { return unit_; }
+
+ virtual opentelemetry::metrics::InstrumentKind GetKind() override { return this->kind_; }
+
+protected:
+ std::string name_;
+ std::string description_;
+ std::string unit_;
+ bool enabled_;
+ std::mutex mu_;
+ opentelemetry::metrics::InstrumentKind kind_;
+};
+
+template <class T>
+class BoundSynchronousInstrument
+ : public Instrument,
+ virtual public opentelemetry::metrics::BoundSynchronousInstrument<T>
+{
+
+public:
+ BoundSynchronousInstrument() = default;
+
+ BoundSynchronousInstrument(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ opentelemetry::metrics::InstrumentKind kind,
+ std::shared_ptr<Aggregator<T>> agg)
+ : Instrument(name, description, unit, enabled, kind), agg_(agg)
+ {
+ this->inc_ref(); // increase reference count when instantiated
+ }
+
+ /**
+ * Frees the resources associated with this Bound Instrument.
+ * The Metric from which this instrument was created is not impacted.
+ *
+ * @param none
+ * @return void
+ */
+ virtual void unbind() override
+ {
+ this->mu_.lock();
+ ref_ -= 1;
+ this->mu_.unlock();
+ }
+
+ /**
+ * Increments the reference count. This function is used when binding or instantiating.
+ *
+ * @param none
+ * @return void
+ */
+ virtual void inc_ref() override
+ {
+ this->mu_.lock();
+ ref_ += 1;
+ this->mu_.unlock();
+ }
+
+ /**
+ * Returns the current reference count of the instrument. This value is used to
+ * later in the pipeline remove stale instruments.
+ *
+ * @param none
+ * @return current ref count of the instrument
+ */
+ virtual int get_ref() override
+ {
+ this->mu_.lock();
+ auto ret = ref_;
+ this->mu_.unlock();
+ return ret;
+ }
+
+ /**
+ * Records a single synchronous metric event via a call to the aggregator.
+ * Since this is a bound synchronous instrument, labels are not required in
+ * metric capture calls.
+ *
+ * @param value is the numerical representation of the metric being captured
+ * @return void
+ */
+ virtual void update(T value) override
+ {
+ this->mu_.lock();
+ agg_->update(value);
+ this->mu_.unlock();
+ }
+
+ /**
+ * Returns the aggregator responsible for meaningfully combining update values.
+ *
+ * @param none
+ * @return the aggregator assigned to this instrument
+ */
+ virtual std::shared_ptr<Aggregator<T>> GetAggregator() final { return agg_; }
+
+private:
+ std::shared_ptr<Aggregator<T>> agg_;
+ int ref_ = 0;
+};
+
+template <class T>
+class SynchronousInstrument : public Instrument,
+ virtual public opentelemetry::metrics::SynchronousInstrument<T>
+{
+
+public:
+ SynchronousInstrument() = default;
+
+ SynchronousInstrument(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ opentelemetry::metrics::InstrumentKind kind)
+ : Instrument(name, description, unit, enabled, kind)
+ {}
+
+ /**
+ * Returns a Bound Instrument associated with the specified labels. Multiples requests
+ * with the same set of labels may return the same Bound Instrument instance.
+ *
+ * It is recommended that callers keep a reference to the Bound Instrument
+ * instead of repeatedly calling this operation.
+ *
+ * @param labels the set of labels, as key-value pairs
+ * @return a Bound Instrument
+ */
+ virtual nostd::shared_ptr<opentelemetry::metrics::BoundSynchronousInstrument<T>> bind(
+ const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ return nostd::shared_ptr<BoundSynchronousInstrument<T>>();
+ }
+
+ // This function is necessary for batch recording and should NOT be called by the user
+ virtual void update(T value, const opentelemetry::common::KeyValueIterable &labels) override = 0;
+
+ /**
+ * Checkpoints instruments and returns a set of records which are ready for processing.
+ * This method should ONLY be called by the Meter Class as part of the export pipeline
+ * as it also prunes bound instruments with no active references.
+ *
+ * @param none
+ * @return vector of Records which hold the data attached to this synchronous instrument
+ */
+ virtual std::vector<Record> GetRecords() = 0;
+};
+
+template <class T>
+class AsynchronousInstrument : public Instrument,
+ virtual public opentelemetry::metrics::AsynchronousInstrument<T>
+{
+
+public:
+ AsynchronousInstrument() = default;
+
+ AsynchronousInstrument(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T>),
+ opentelemetry::metrics::InstrumentKind kind)
+ : Instrument(name, description, unit, enabled, kind)
+ {
+ this->callback_ = callback;
+ }
+
+ /**
+ * Captures data through a manual call rather than the automatic collection process instituted
+ * in the run function. Asynchronous instruments are generally expected to obtain data from
+ * their callbacks rather than direct calls. This function is used by the callback to store data.
+ *
+ * @param value is the numerical representation of the metric being captured
+ * @param labels is the numerical representation of the metric being captured
+ * @return none
+ */
+ virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override = 0;
+
+ virtual std::vector<Record> GetRecords() = 0;
+
+ /**
+ * Captures data by activating the callback function associated with the
+ * instrument and storing its return value. Callbacks for asynchronous
+ * instruments are defined during construction.
+ *
+ * @param none
+ * @return none
+ */
+ virtual void run() override = 0;
+};
+
+// Helper functions for turning a common::KeyValueIterable into a string
+inline void print_value(std::stringstream &ss,
+ opentelemetry::common::AttributeValue &value,
+ bool jsonTypes = false)
+{
+ switch (value.index())
+ {
+ case opentelemetry::common::AttributeType::kTypeString:
+
+ ss << nostd::get<nostd::string_view>(value);
+
+ break;
+ default:
+# if __EXCEPTIONS
+ throw std::invalid_argument("Labels must be strings");
+# else
+ std::terminate();
+# endif
+ break;
+ }
+};
+
+// Utility function which converts maps to strings for better performance
+inline std::string mapToString(const std::map<std::string, std::string> &conv)
+{
+ std::stringstream ss;
+ ss << "{";
+ for (auto i : conv)
+ {
+ ss << i.first << ':' << i.second << ',';
+ }
+ ss << "}";
+ return ss.str();
+}
+
+inline std::string KvToString(const opentelemetry::common::KeyValueIterable &kv) noexcept
+{
+ std::stringstream ss;
+ ss << "{";
+ size_t size = kv.size();
+ if (size)
+ {
+ size_t i = 1;
+ kv.ForEachKeyValue(
+ [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept {
+ ss << key << ":";
+ print_value(ss, value, true);
+ if (size != i)
+ {
+ ss << ",";
+ }
+ i++;
+ return true;
+ });
+ };
+ ss << "}";
+ return ss.str();
+}
+
+# if defined(_MSC_VER)
+# pragma warning(pop)
+# endif
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter.h
new file mode 100644
index 000000000..a91a3ed2b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter.h
@@ -0,0 +1,392 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/_metrics/meter.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/_metrics/async_instruments.h"
+# include "opentelemetry/sdk/_metrics/instrument.h"
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/sdk/_metrics/sync_instruments.h"
+
+# include <unordered_set>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class Meter : public opentelemetry::metrics::Meter
+{
+public:
+ explicit Meter(std::string library_name, std::string library_version = "")
+ {
+ library_name_ = library_name;
+ library_version_ = library_version;
+ }
+
+ /**
+ * Creates a Counter with the passed characteristics and returns a shared_ptr to that Counter.
+ *
+ * @param name the name of the new Counter.
+ * @param description a brief description of what the Counter is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @return a shared pointer to the created Counter.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::Counter<short>> NewShortCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Counter<int>> NewIntCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Counter<float>> NewFloatCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Counter<double>> NewDoubleCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ /**
+ * Creates an UpDownCounter with the passed characteristics and returns a shared_ptr to that
+ * UpDownCounter.
+ *
+ * @param name the name of the new UpDownCounter.
+ * @param description a brief description of what the UpDownCounter is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @return a shared pointer to the created UpDownCounter.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<short>> NewShortUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<int>> NewIntUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<float>> NewFloatUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<double>> NewDoubleUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ /**
+ * Creates a ValueRecorder with the passed characteristics and returns a shared_ptr to that
+ * ValueRecorder.
+ *
+ * @param name the name of the new ValueRecorder.
+ * @param description a brief description of what the ValueRecorder is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @return a shared pointer to the created DoubleValueRecorder.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<short>> NewShortValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<int>> NewIntValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<float>> NewFloatValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<double>> NewDoubleValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled) override;
+
+ /**
+ * Creates a SumObserver with the passed characteristics and returns a shared_ptr to that
+ * SumObserver.
+ *
+ * @param name the name of the new SumObserver.
+ * @param description a brief description of what the SumObserver is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @param callback the function to be observed by the instrument.
+ * @return a shared pointer to the created SumObserver.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::SumObserver<short>> NewShortSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::SumObserver<int>> NewIntSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::SumObserver<float>> NewFloatSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::SumObserver<double>> NewDoubleSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
+
+ /**
+ * Creates an UpDownSumObserver with the passed characteristics and returns a shared_ptr to
+ * that UpDowNSumObserver.
+ *
+ * @param name the name of the new UpDownSumObserver.
+ * @param description a brief description of what the UpDownSumObserver is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @param callback the function to be observed by the instrument.
+ * @return a shared pointer to the created UpDownSumObserver.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<short>> NewShortUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<int>> NewIntUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<float>> NewFloatUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<double>> NewDoubleUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
+
+ /**
+ * Creates a ValueObserver with the passed characteristics and returns a shared_ptr to that
+ * ValueObserver.
+ *
+ * @param name the name of the new ValueObserver.
+ * @param description a brief description of what the ValueObserver is used for.
+ * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
+ * @param enabled a boolean value that turns on or off the metric instrument.
+ * @param callback the function to be observed by the instrument.
+ * @return a shared pointer to the created ValueObserver.
+ * @throws invalid_argument exception if name is null or does not conform to OTel syntax.
+ */
+ nostd::shared_ptr<opentelemetry::metrics::ValueObserver<short>> NewShortValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueObserver<int>> NewIntValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueObserver<float>> NewFloatValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
+
+ nostd::shared_ptr<opentelemetry::metrics::ValueObserver<double>> NewDoubleValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
+
+ /**
+ * Utility method that allows users to atomically record measurements to a set of
+ * synchronous metric instruments with a common set of labels.
+ *
+ * @param labels the set of labels to associate with this recorder.
+ * @param values a span of pairs where the first element of the pair is a metric instrument
+ * to record to, and the second element is the value to update that instrument with.
+ */
+ void RecordShortBatch(
+ const opentelemetry::common::KeyValueIterable &labels,
+ nostd::span<opentelemetry::metrics::SynchronousInstrument<short> *> instruments,
+ nostd::span<const short> values) noexcept override;
+
+ void RecordIntBatch(const opentelemetry::common::KeyValueIterable &labels,
+ nostd::span<opentelemetry::metrics::SynchronousInstrument<int> *> instruments,
+ nostd::span<const int> values) noexcept override;
+
+ void RecordFloatBatch(
+ const opentelemetry::common::KeyValueIterable &labels,
+ nostd::span<opentelemetry::metrics::SynchronousInstrument<float> *> instruments,
+ nostd::span<const float> values) noexcept override;
+
+ void RecordDoubleBatch(
+ const opentelemetry::common::KeyValueIterable &labels,
+ nostd::span<opentelemetry::metrics::SynchronousInstrument<double> *> instruments,
+ nostd::span<const double> values) noexcept override;
+
+ /**
+ * An SDK-only function that checkpoints the aggregators of all instruments created from
+ * this meter, creates a {@code Record} out of them, and sends them for export.
+ *
+ * @return A vector of {@code Records} to be sent to the processor.
+ */
+ std::vector<Record> Collect() noexcept;
+
+private:
+ /**
+ * A private function that creates records from all synchronous instruments created from
+ * this meter.
+ *
+ * @param records A reference to the vector to push the new records to.
+ */
+ void CollectMetrics(std::vector<Record> &records);
+
+ /**
+ * Helper function to collect Records from a single synchronous instrument
+ *
+ * @tparam T The integral type of the instrument to collect from.
+ * @param i A map iterator pointing to the instrument to collect from
+ * @param records The vector to add the new records to.
+ */
+ template <typename T>
+ void CollectSingleSyncInstrument(
+ typename std::map<std::string,
+ std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<T>>>::iterator
+ i,
+ std::vector<Record> &records);
+
+ /**
+ * A private function that creates records from all asynchronous instruments created from
+ * this meter.
+ *
+ * @param records A reference to the vector to push the new records to.
+ */
+ void CollectObservers(std::vector<Record> &records);
+
+ /**
+ * Helper function to collect Records from a single asynchronous instrument
+ *
+ * @tparam T The integral type of the instrument to collect from.
+ * @param i A map iterator pointing to the instrument to collect from
+ * @param records The vector to add the new records to.
+ */
+ template <typename T>
+ void CollectSingleAsyncInstrument(
+ typename std::map<
+ std::string,
+ std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<T>>>::iterator i,
+ std::vector<Record> &records);
+
+ /**
+ * Utility function used by the meter that checks if a user-passed name abides by OpenTelemetry
+ * naming rules. The rules are as follows:
+ * 1. The name must not be empty.
+ * 2. The name must not start with a digit, a space, or any punctuation.
+ * 3. The name must only have the following chaacters:
+ * All alphanumeric characters, '.', '_' and '-'.
+ *
+ * @param name The name to be examined for legality.
+ * @return A bool representing whether the name is valid by the OpenTelemetry syntax rules.
+ */
+ bool IsValidName(nostd::string_view name);
+
+ /**
+ * A utility function used by the meter to determine whether an instrument of a specified
+ * name already exists in this meter.
+ *
+ * @param name The name to examine.
+ * @return A boolean representing whether the name has already been used by this meter.
+ */
+ bool NameAlreadyUsed(nostd::string_view name);
+
+ /*
+ * All instruments must be stored in a map so the meter can collect on these instruments.
+ * Additionally, when creating a new instrument, the meter must check if an instrument of the same
+ * name already exists.
+ */
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<short>>>
+ short_metrics_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<int>>>
+ int_metrics_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<float>>>
+ float_metrics_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<double>>>
+ double_metrics_;
+
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<short>>>
+ short_observers_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<int>>>
+ int_observers_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<float>>>
+ float_observers_;
+ std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<double>>>
+ double_observers_;
+
+ std::unordered_set<std::string> names_;
+
+ std::string library_name_;
+ std::string library_version_;
+
+ std::mutex metrics_lock_;
+ std::mutex observers_lock_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter_provider.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter_provider.h
new file mode 100644
index 000000000..da218ceac
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/meter_provider.h
@@ -0,0 +1,37 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/_metrics/meter_provider.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/_metrics/meter.h"
+
+# include <memory>
+# include <string>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class MeterProvider final : public opentelemetry::metrics::MeterProvider
+{
+public:
+ /**
+ * Initialize a new meter provider
+ */
+ explicit MeterProvider(std::string library_name = "", std::string library_version = "") noexcept;
+
+ opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter> GetMeter(
+ nostd::string_view library_name,
+ nostd::string_view library_version = "") noexcept override;
+
+private:
+ std::shared_ptr<opentelemetry::metrics::Meter> meter_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/processor.h
new file mode 100644
index 000000000..dd6c421fb
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/processor.h
@@ -0,0 +1,38 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/version.h"
+
+# include <iostream>
+# include <string>
+# include <unordered_map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+namespace sdk
+{
+namespace metrics
+{
+
+class MetricsProcessor
+{
+public:
+ virtual ~MetricsProcessor() = default;
+
+ virtual std::vector<opentelemetry::sdk::metrics::Record> CheckpointSelf() noexcept = 0;
+
+ virtual void FinishedCollection() noexcept = 0;
+
+ virtual void process(opentelemetry::sdk::metrics::Record record) noexcept = 0;
+};
+
+} // namespace metrics
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/record.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/record.h
new file mode 100644
index 000000000..a07c1595c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/record.h
@@ -0,0 +1,50 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <memory>
+# include "opentelemetry/_metrics/instrument.h"
+# include "opentelemetry/nostd/variant.h"
+# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+namespace sdk
+{
+namespace metrics
+{
+using AggregatorVariant = nostd::variant<std::shared_ptr<Aggregator<short>>,
+ std::shared_ptr<Aggregator<int>>,
+ std::shared_ptr<Aggregator<float>>,
+ std::shared_ptr<Aggregator<double>>>;
+class Record
+{
+public:
+ explicit Record(nostd::string_view name,
+ nostd::string_view description,
+ std::string labels,
+ AggregatorVariant aggregator)
+ {
+ name_ = std::string(name);
+ description_ = std::string(description);
+ labels_ = labels;
+ aggregator_ = aggregator;
+ }
+
+ std::string GetName() { return name_; }
+ std::string GetDescription() { return description_; }
+ std::string GetLabels() { return labels_; }
+ AggregatorVariant GetAggregator() { return aggregator_; }
+
+private:
+ std::string name_;
+ std::string description_;
+ std::string labels_;
+ AggregatorVariant aggregator_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/sync_instruments.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/sync_instruments.h
new file mode 100644
index 000000000..80d9b6092
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/sync_instruments.h
@@ -0,0 +1,465 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <map>
+# include <memory>
+# include <sstream>
+# include <stdexcept>
+# include <vector>
+
+# include "opentelemetry/_metrics/sync_instruments.h"
+# include "opentelemetry/common/macros.h"
+# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
+# include "opentelemetry/sdk/_metrics/instrument.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+# if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4250) // inheriting methods via dominance
+# endif
+
+template <class T>
+class BoundCounter final : public BoundSynchronousInstrument<T>,
+ public opentelemetry::metrics::BoundCounter<T>
+{
+
+public:
+ BoundCounter() = default;
+
+ BoundCounter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : BoundSynchronousInstrument<T>(
+ name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::Counter,
+ std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(
+ opentelemetry::metrics::InstrumentKind::Counter))) // Aggregator is chosen here
+ {}
+
+ /*
+ * Add adds the value to the counter's sum. The labels are already linked to the instrument
+ * and are not specified.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void add(T value) override
+ {
+ if (value < 0)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Counter instrument updates must be non-negative.");
+# else
+ std::terminate();
+# endif
+ }
+ else
+ {
+ this->update(value);
+ }
+ }
+};
+
+template <class T>
+class Counter final : public SynchronousInstrument<T>, public opentelemetry::metrics::Counter<T>
+{
+
+public:
+ Counter() = default;
+
+ Counter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : SynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::Counter)
+ {}
+
+ /*
+ * Bind creates a bound instrument for this counter. The labels are
+ * associated with values recorded via subsequent calls to Record.
+ *
+ * @param labels the set of labels, as key-value pairs.
+ * @return a BoundCounter tied to the specified labels
+ */
+
+ virtual nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>> bindCounter(
+ const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundInstruments_.find(labelset) == boundInstruments_.end())
+ {
+ auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>>(
+ new BoundCounter<T>(this->name_, this->description_, this->unit_, this->enabled_));
+ boundInstruments_[labelset] = sp1;
+ this->mu_.unlock();
+ return sp1;
+ }
+ else
+ {
+ boundInstruments_[labelset]->inc_ref();
+ auto ret = boundInstruments_[labelset];
+ this->mu_.unlock();
+ return ret;
+ }
+ }
+
+ /*
+ * Add adds the value to the counter's sum. The labels should contain
+ * the keys and values to be associated with this value. Counters only
+ * accept positive valued updates.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void add(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ if (value < 0)
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Counter instrument updates must be non-negative.");
+# else
+ std::terminate();
+# endif
+ }
+ else
+ {
+ auto sp = bindCounter(labels);
+ sp->update(value);
+ sp->unbind();
+ }
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ std::vector<std::string> toDelete;
+ for (const auto &x : boundInstruments_)
+ {
+ if (x.second->get_ref() == 0)
+ {
+ toDelete.push_back(x.first);
+ }
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto agg_ptr = dynamic_cast<BoundCounter<T> *>(x.second.get())->GetAggregator();
+# else
+ auto agg_ptr = static_cast<BoundCounter<T> *>(x.second.get())->GetAggregator();
+# endif
+ if (agg_ptr->is_updated())
+ {
+ agg_ptr->checkpoint();
+ ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
+ }
+ }
+ for (const auto &x : toDelete)
+ {
+ boundInstruments_.erase(x);
+ }
+ this->mu_.unlock();
+ return ret;
+ }
+
+ virtual void update(T val, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ add(val, labels);
+ }
+
+ // A collection of the bound instruments created by this unbound instrument identified by their
+ // labels.
+ std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>>>
+ boundInstruments_;
+};
+
+template <class T>
+class BoundUpDownCounter final : public BoundSynchronousInstrument<T>,
+ virtual public opentelemetry::metrics::BoundUpDownCounter<T>
+{
+
+public:
+ BoundUpDownCounter() = default;
+
+ BoundUpDownCounter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : BoundSynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::UpDownCounter,
+ std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(
+ opentelemetry::metrics::InstrumentKind::UpDownCounter)))
+ {}
+
+ /*
+ * Add adds the value to the counter's sum. The labels are already linked to the instrument
+ * and are not specified.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ virtual void add(T value) override { this->update(value); }
+};
+
+template <class T>
+class UpDownCounter final : public SynchronousInstrument<T>,
+ public opentelemetry::metrics::UpDownCounter<T>
+{
+
+public:
+ UpDownCounter() = default;
+
+ UpDownCounter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : SynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::UpDownCounter)
+ {}
+
+ /*
+ * Bind creates a bound instrument for this counter. The labels are
+ * associated with values recorded via subsequent calls to Record.
+ *
+ * @param labels the set of labels, as key-value pairs.
+ * @return a BoundIntCounter tied to the specified labels
+ */
+ nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>> bindUpDownCounter(
+ const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundInstruments_.find(labelset) == boundInstruments_.end())
+ {
+ auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>>(
+ new BoundUpDownCounter<T>(this->name_, this->description_, this->unit_, this->enabled_));
+ boundInstruments_[labelset] = sp1;
+ this->mu_.unlock();
+ return sp1;
+ }
+ else
+ {
+ boundInstruments_[labelset]->inc_ref();
+ auto ret = boundInstruments_[labelset];
+ this->mu_.unlock();
+ return ret;
+ }
+ }
+
+ /*
+ * Add adds the value to the counter's sum. The labels should contain
+ * the keys and values to be associated with this value. Counters only
+ * accept positive valued updates.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ void add(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ auto sp = bindUpDownCounter(labels);
+ sp->update(value);
+ sp->unbind();
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ std::vector<std::string> toDelete;
+ for (const auto &x : boundInstruments_)
+ {
+ if (x.second->get_ref() == 0)
+ {
+ toDelete.push_back(x.first);
+ }
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto agg_ptr = dynamic_cast<BoundUpDownCounter<T> *>(x.second.get())->GetAggregator();
+# else
+ auto agg_ptr = static_cast<BoundUpDownCounter<T> *>(x.second.get())->GetAggregator();
+# endif
+ if (agg_ptr->is_updated())
+ {
+ agg_ptr->checkpoint();
+ ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
+ }
+ }
+ for (const auto &x : toDelete)
+ {
+ boundInstruments_.erase(x);
+ }
+ this->mu_.unlock();
+ return ret;
+ }
+
+ virtual void update(T val, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ add(val, labels);
+ }
+
+ std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>>>
+ boundInstruments_;
+};
+
+template <class T>
+class BoundValueRecorder final : public BoundSynchronousInstrument<T>,
+ public opentelemetry::metrics::BoundValueRecorder<T>
+{
+
+public:
+ BoundValueRecorder() = default;
+
+ BoundValueRecorder(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : BoundSynchronousInstrument<T>(
+ name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::ValueRecorder,
+ std::shared_ptr<Aggregator<T>>(new MinMaxSumCountAggregator<T>(
+ opentelemetry::metrics::InstrumentKind::ValueRecorder)))
+ {}
+
+ /*
+ * Add adds the value to the counter's sum. The labels are already linked to the instrument
+ * and are not specified.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ void record(T value) { this->update(value); }
+};
+
+template <class T>
+class ValueRecorder final : public SynchronousInstrument<T>,
+ public opentelemetry::metrics::ValueRecorder<T>
+{
+
+public:
+ ValueRecorder() = default;
+
+ ValueRecorder(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ bool enabled)
+ : SynchronousInstrument<T>(name,
+ description,
+ unit,
+ enabled,
+ opentelemetry::metrics::InstrumentKind::ValueRecorder)
+ {}
+
+ /*
+ * Bind creates a bound instrument for this counter. The labels are
+ * associated with values recorded via subsequent calls to Record.
+ *
+ * @param labels the set of labels, as key-value pairs.
+ * @return a BoundIntCounter tied to the specified labels
+ */
+ nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>> bindValueRecorder(
+ const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ this->mu_.lock();
+ std::string labelset = KvToString(labels);
+ if (boundInstruments_.find(labelset) == boundInstruments_.end())
+ {
+ auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>>(
+ new BoundValueRecorder<T>(this->name_, this->description_, this->unit_, this->enabled_));
+ boundInstruments_[labelset] = sp1;
+ this->mu_.unlock();
+ return sp1;
+ }
+ else
+ {
+ boundInstruments_[labelset]->inc_ref();
+ auto ret = boundInstruments_[labelset];
+ this->mu_.unlock();
+ return ret;
+ }
+ }
+
+ /*
+ * Add adds the value to the counter's sum. The labels should contain
+ * the keys and values to be associated with this value. Counters only
+ * accept positive valued updates.
+ *
+ * @param value the numerical representation of the metric being captured
+ * @param labels the set of labels, as key-value pairs
+ */
+ void record(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ auto sp = bindValueRecorder(labels);
+ sp->update(value);
+ sp->unbind();
+ }
+
+ virtual std::vector<Record> GetRecords() override
+ {
+ this->mu_.lock();
+ std::vector<Record> ret;
+ std::vector<std::string> toDelete;
+ for (const auto &x : boundInstruments_)
+ {
+ if (x.second->get_ref() == 0)
+ {
+ toDelete.push_back(x.first);
+ }
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto agg_ptr = dynamic_cast<BoundValueRecorder<T> *>(x.second.get())->GetAggregator();
+# else
+ auto agg_ptr = static_cast<BoundValueRecorder<T> *>(x.second.get())->GetAggregator();
+# endif
+ if (agg_ptr->is_updated())
+ {
+ agg_ptr->checkpoint();
+ ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
+ }
+ }
+ for (const auto &x : toDelete)
+ {
+ boundInstruments_.erase(x);
+ }
+ this->mu_.unlock();
+ return ret;
+ }
+
+ virtual void update(T value, const opentelemetry::common::KeyValueIterable &labels) override
+ {
+ record(value, labels);
+ }
+
+ std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>>>
+ boundInstruments_;
+};
+
+# if defined(_MSC_VER)
+# pragma warning(pop)
+# endif
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/ungrouped_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/ungrouped_processor.h
new file mode 100644
index 000000000..cc13ae52b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/_metrics/ungrouped_processor.h
@@ -0,0 +1,365 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <map>
+
+# include "opentelemetry/common/macros.h"
+# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
+# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
+# include "opentelemetry/sdk/_metrics/processor.h"
+# include "opentelemetry/sdk/_metrics/record.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+namespace sdk
+{
+
+namespace metrics
+{
+
+struct KeyStruct
+{
+ std::string name;
+ std::string description;
+ std::string labels;
+ opentelemetry::metrics::InstrumentKind ins_kind;
+
+ // constructor
+ KeyStruct(std::string name,
+ std::string description,
+ std::string labels,
+ opentelemetry::metrics::InstrumentKind ins_kind)
+ {
+ this->name = name;
+ this->description = description;
+ this->labels = labels;
+ this->ins_kind = ins_kind;
+ }
+
+ // operator== is required to compare keys in case of hash collision
+ bool operator==(const KeyStruct &p) const
+ {
+ return name == p.name && description == p.description && labels == p.labels &&
+ ins_kind == p.ins_kind;
+ }
+};
+
+struct KeyStruct_Hash
+{
+ std::size_t operator()(const KeyStruct &keystruct) const
+ {
+ std::size_t name_size = keystruct.name.length();
+ std::size_t desc_size = keystruct.description.length();
+ std::size_t labels_size = keystruct.labels.length();
+ std::size_t ins_size = (int)keystruct.ins_kind;
+
+ return (name_size ^ desc_size ^ labels_size) + ins_size;
+ }
+};
+
+class UngroupedMetricsProcessor : public MetricsProcessor
+{
+public:
+ explicit UngroupedMetricsProcessor(bool stateful);
+
+ std::vector<opentelemetry::sdk::metrics::Record> CheckpointSelf() noexcept override;
+
+ virtual void FinishedCollection() noexcept override;
+
+ virtual void process(opentelemetry::sdk::metrics::Record record) noexcept override;
+
+private:
+ bool stateful_;
+ std::unordered_map<KeyStruct, opentelemetry::sdk::metrics::AggregatorVariant, KeyStruct_Hash>
+ batch_map_;
+
+ /**
+ * get_instrument returns the instrument from the passed in AggregatorVariant. We have to
+ * unpack the variant then get the instrument from the Aggreagtor.
+ */
+ opentelemetry::metrics::InstrumentKind get_instrument(
+ opentelemetry::sdk::metrics::AggregatorVariant aggregator)
+ {
+ if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
+ aggregator))
+ {
+ return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator)
+ ->get_instrument_kind();
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
+ {
+ return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator)
+ ->get_instrument_kind();
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
+ {
+ return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator)
+ ->get_instrument_kind();
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
+ {
+ return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(
+ aggregator)
+ ->get_instrument_kind();
+ }
+
+ return opentelemetry::metrics::InstrumentKind::Counter;
+ }
+
+ /**
+ * aggregator_copy creates a copy of the aggregtor passed through process() for a
+ * stateful processor. For Sketch, Histogram and Exact we also need to pass in
+ * additional constructor values
+ */
+ template <typename T>
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator_copy(
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator)
+ {
+ auto ins_kind = aggregator->get_instrument_kind();
+ auto agg_kind = aggregator->get_aggregator_kind();
+
+ switch (agg_kind)
+ {
+ case opentelemetry::sdk::metrics::AggregatorKind::Counter:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+
+ case opentelemetry::sdk::metrics::AggregatorKind::MinMaxSumCount:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
+
+ case opentelemetry::sdk::metrics::AggregatorKind::Gauge:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::GaugeAggregator<T>(ins_kind));
+
+ case opentelemetry::sdk::metrics::AggregatorKind::Sketch:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::SketchAggregator<T>(
+ ins_kind, aggregator->get_error_bound(), aggregator->get_max_buckets()));
+
+ case opentelemetry::sdk::metrics::AggregatorKind::Histogram:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::HistogramAggregator<T>(ins_kind,
+ aggregator->get_boundaries()));
+
+ case opentelemetry::sdk::metrics::AggregatorKind::Exact:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::ExactAggregator<T>(
+ ins_kind, aggregator->get_quant_estimation()));
+
+ default:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+ }
+ };
+
+ /**
+ * aggregator_for will return an Aggregator based off the instrument passed in. This should be
+ * the function that we assign Aggreagtors for instruments, but is currently unused in our
+ * pipeline.
+ */
+ template <typename T>
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator_for(
+ opentelemetry::metrics::InstrumentKind ins_kind)
+ {
+ switch (ins_kind)
+ {
+ case opentelemetry::metrics::InstrumentKind::Counter:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+
+ case opentelemetry::metrics::InstrumentKind::UpDownCounter:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+
+ case opentelemetry::metrics::InstrumentKind::ValueRecorder:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
+
+ case opentelemetry::metrics::InstrumentKind::SumObserver:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+
+ case opentelemetry::metrics::InstrumentKind::UpDownSumObserver:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+
+ case opentelemetry::metrics::InstrumentKind::ValueObserver:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
+
+ default:
+ return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
+ new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
+ }
+ };
+
+ /**
+ * merge_aggreagtors takes in two shared pointers to aggregators of the same kind.
+ * We first need to dynamically cast to the actual Aggregator that is held in the
+ * Aggregator<T> wrapper. Then we must get the underlying pointer from the shared
+ * pointer and merge them together.
+ */
+ template <typename T>
+ void merge_aggregators(std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> batch_agg,
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> record_agg)
+ {
+ auto agg_kind = batch_agg->get_aggregator_kind();
+ if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Counter)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_batch_agg_counter =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_record_agg_counter =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_batch_agg_counter =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_record_agg_counter =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(record_agg);
+# endif
+ auto temp_batch_agg_raw_counter = temp_batch_agg_counter.get();
+ auto temp_record_agg_raw_counter = temp_record_agg_counter.get();
+
+ temp_batch_agg_raw_counter->merge(*temp_record_agg_raw_counter);
+ }
+ else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::MinMaxSumCount)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
+ temp_batch_agg_mmsc =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
+ batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
+ temp_record_agg_mmsc =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
+ record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
+ temp_batch_agg_mmsc =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
+ batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
+ temp_record_agg_mmsc =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
+ record_agg);
+# endif
+
+ auto temp_batch_agg_raw_mmsc = temp_batch_agg_mmsc.get();
+ auto temp_record_agg_raw_mmsc = temp_record_agg_mmsc.get();
+
+ temp_batch_agg_raw_mmsc->merge(*temp_record_agg_raw_mmsc);
+ }
+ else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Gauge)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_batch_agg_gauge =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_record_agg_gauge =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_batch_agg_gauge =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_record_agg_gauge =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(record_agg);
+# endif
+
+ auto temp_batch_agg_raw_gauge = temp_batch_agg_gauge.get();
+ auto temp_record_agg_raw_gauge = temp_record_agg_gauge.get();
+
+ temp_batch_agg_raw_gauge->merge(*temp_record_agg_raw_gauge);
+ }
+ else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Sketch)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_batch_agg_sketch =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_record_agg_sketch =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_batch_agg_sketch =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_record_agg_sketch =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(record_agg);
+# endif
+ auto temp_batch_agg_raw_sketch = temp_batch_agg_sketch.get();
+ auto temp_record_agg_raw_sketch = temp_record_agg_sketch.get();
+
+ temp_batch_agg_raw_sketch->merge(*temp_record_agg_raw_sketch);
+ }
+ else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Histogram)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
+ temp_batch_agg_histogram =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
+ batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
+ temp_record_agg_histogram =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
+ record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
+ temp_batch_agg_histogram =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
+ batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
+ temp_record_agg_histogram =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
+ record_agg);
+# endif
+
+ auto temp_batch_agg_raw_histogram = temp_batch_agg_histogram.get();
+ auto temp_record_agg_raw_histogram = temp_record_agg_histogram.get();
+
+ temp_batch_agg_raw_histogram->merge(*temp_record_agg_raw_histogram);
+ }
+ else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Exact)
+ {
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_batch_agg_exact =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_record_agg_exact =
+ std::dynamic_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(record_agg);
+# else
+ std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_batch_agg_exact =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(batch_agg);
+
+ std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_record_agg_exact =
+ std::static_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(record_agg);
+# endif
+
+ auto temp_batch_agg_raw_exact = temp_batch_agg_exact.get();
+ auto temp_record_agg_raw_exact = temp_record_agg_exact.get();
+
+ temp_batch_agg_raw_exact->merge(*temp_record_agg_raw_exact);
+ }
+ }
+};
+} // namespace metrics
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h
new file mode 100644
index 000000000..07e19ac0f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h
@@ -0,0 +1,62 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * A wrapper to provide atomic shared pointers.
+ *
+ * This wrapper relies on a mutex for gcc 4.8, and specializations of
+ * std::atomic_store and std::atomic_load for all other instances.
+ */
+#if (__GNUC__ == 4 && (__GNUC_MINOR__ >= 8))
+template <class T>
+class AtomicSharedPtr
+{
+public:
+ explicit AtomicSharedPtr(std::shared_ptr<T> ptr) noexcept : ptr_{std::move(ptr)} {}
+
+ void store(const std::shared_ptr<T> &other) noexcept
+ {
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ ptr_ = other;
+ }
+
+ std::shared_ptr<T> load() const noexcept
+ {
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ return ptr_;
+ }
+
+private:
+ std::shared_ptr<T> ptr_;
+ mutable std::mutex mu_;
+};
+#else
+template <class T>
+class AtomicSharedPtr
+{
+public:
+ explicit AtomicSharedPtr(std::shared_ptr<T> ptr) noexcept : ptr_{std::move(ptr)} {}
+
+ void store(const std::shared_ptr<T> &other) noexcept { std::atomic_store(&ptr_, other); }
+
+ std::shared_ptr<T> load() const noexcept { return std::atomic_load(&ptr_); }
+
+private:
+ std::shared_ptr<T> ptr_;
+};
+#endif
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_unique_ptr.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_unique_ptr.h
new file mode 100644
index 000000000..5945df98c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/atomic_unique_ptr.h
@@ -0,0 +1,87 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * An owning pointer similar to std::unique_ptr but with methods for atomic
+ * operations.
+ */
+template <class T>
+class AtomicUniquePtr
+{
+public:
+ AtomicUniquePtr() noexcept {}
+
+ explicit AtomicUniquePtr(std::unique_ptr<T> &&other) noexcept : ptr_(other.release()) {}
+
+ ~AtomicUniquePtr() noexcept { Reset(); }
+
+ T &operator*() const noexcept { return *Get(); }
+
+ T *operator->() const noexcept { return Get(); }
+
+ /**
+ * @return the underly pointer managed.
+ */
+ T *Get() const noexcept { return ptr_; }
+
+ /**
+ * @return true if the pointer is null
+ */
+ bool IsNull() const noexcept { return ptr_.load() == nullptr; }
+
+ /**
+ * Atomically swap the pointer only if it's null.
+ * @param owner the pointer to swap with
+ * @return true if the swap was successful
+ */
+ bool SwapIfNull(std::unique_ptr<T> &owner) noexcept
+ {
+ auto ptr = owner.get();
+ T *expected = nullptr;
+ auto was_successful = ptr_.compare_exchange_weak(expected, ptr, std::memory_order_release,
+ std::memory_order_relaxed);
+ if (was_successful)
+ {
+ owner.release();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Atomically swap the pointer with another.
+ * @param ptr the pointer to swap with
+ */
+ void Swap(std::unique_ptr<T> &other) noexcept { other.reset(ptr_.exchange(other.release())); }
+
+ /**
+ * Set the pointer to a new value and delete the current value if non-null.
+ * @param ptr the new pointer value to set
+ */
+ void Reset(T *ptr = nullptr) noexcept
+ {
+ ptr = ptr_.exchange(ptr);
+ if (ptr != nullptr)
+ {
+ delete ptr;
+ }
+ }
+
+private:
+ std::atomic<T *> ptr_{nullptr};
+};
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attribute_utils.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attribute_utils.h
new file mode 100644
index 000000000..68b09f044
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attribute_utils.h
@@ -0,0 +1,199 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include "opentelemetry/common/attribute_value.h"
+#include "opentelemetry/common/key_value_iterable_view.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * A counterpart to AttributeValue that makes sure a value is owned. This
+ * replaces all non-owning references with owned copies.
+ *
+ * The following types are not currently supported by the OpenTelemetry
+ * specification, but reserved for future use:
+ * - uint64_t
+ * - std::vector<uint64_t>
+ * - std::vector<uint8_t>
+ */
+using OwnedAttributeValue = nostd::variant<bool,
+ int32_t,
+ uint32_t,
+ int64_t,
+ double,
+ std::string,
+ std::vector<bool>,
+ std::vector<int32_t>,
+ std::vector<uint32_t>,
+ std::vector<int64_t>,
+ std::vector<double>,
+ std::vector<std::string>,
+ uint64_t,
+ std::vector<uint64_t>,
+ std::vector<uint8_t>>;
+
+enum OwnedAttributeType
+{
+ kTypeBool,
+ kTypeInt,
+ kTypeUInt,
+ kTypeInt64,
+ kTypeDouble,
+ kTypeString,
+ kTypeSpanBool,
+ kTypeSpanInt,
+ kTypeSpanUInt,
+ kTypeSpanInt64,
+ kTypeSpanDouble,
+ kTypeSpanString,
+ kTypeUInt64,
+ kTypeSpanUInt64,
+ kTypeSpanByte
+};
+
+/**
+ * Creates an owned copy (OwnedAttributeValue) of a non-owning AttributeValue.
+ */
+struct AttributeConverter
+{
+ OwnedAttributeValue operator()(bool v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(int32_t v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(uint32_t v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(int64_t v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(uint64_t v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(double v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(nostd::string_view v)
+ {
+ return OwnedAttributeValue(std::string(v));
+ }
+ OwnedAttributeValue operator()(std::string v) { return OwnedAttributeValue(v); }
+ OwnedAttributeValue operator()(const char *v) { return OwnedAttributeValue(std::string(v)); }
+ OwnedAttributeValue operator()(nostd::span<const uint8_t> v) { return convertSpan<uint8_t>(v); }
+ OwnedAttributeValue operator()(nostd::span<const bool> v) { return convertSpan<bool>(v); }
+ OwnedAttributeValue operator()(nostd::span<const int32_t> v) { return convertSpan<int32_t>(v); }
+ OwnedAttributeValue operator()(nostd::span<const uint32_t> v) { return convertSpan<uint32_t>(v); }
+ OwnedAttributeValue operator()(nostd::span<const int64_t> v) { return convertSpan<int64_t>(v); }
+ OwnedAttributeValue operator()(nostd::span<const uint64_t> v) { return convertSpan<uint64_t>(v); }
+ OwnedAttributeValue operator()(nostd::span<const double> v) { return convertSpan<double>(v); }
+ OwnedAttributeValue operator()(nostd::span<const nostd::string_view> v)
+ {
+ return convertSpan<std::string>(v);
+ }
+
+ template <typename T, typename U = T>
+ OwnedAttributeValue convertSpan(nostd::span<const U> vals)
+ {
+ const std::vector<T> copy(vals.begin(), vals.end());
+ return OwnedAttributeValue(std::move(copy));
+ }
+};
+
+/**
+ * Class for storing attributes.
+ */
+class AttributeMap : public std::unordered_map<std::string, OwnedAttributeValue>
+{
+public:
+ // Contruct empty attribute map
+ AttributeMap() : std::unordered_map<std::string, OwnedAttributeValue>(){};
+
+ // Contruct attribute map and populate with attributes
+ AttributeMap(const opentelemetry::common::KeyValueIterable &attributes) : AttributeMap()
+ {
+ attributes.ForEachKeyValue(
+ [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept {
+ SetAttribute(key, value);
+ return true;
+ });
+ }
+
+ // Construct map from initializer list by applying `SetAttribute` transform for every attribute
+ AttributeMap(
+ std::initializer_list<std::pair<nostd::string_view, opentelemetry::common::AttributeValue>>
+ attributes)
+ : AttributeMap()
+ {
+ for (auto &kv : attributes)
+ {
+ SetAttribute(kv.first, kv.second);
+ }
+ }
+
+ // Returns a reference to this map
+ const std::unordered_map<std::string, OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return (*this);
+ }
+
+ // Convert non-owning key-value to owning std::string(key) and OwnedAttributeValue(value)
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept
+ {
+ (*this)[std::string(key)] = nostd::visit(converter_, value);
+ }
+
+private:
+ AttributeConverter converter_;
+};
+
+/**
+ * Class for storing attributes.
+ */
+class OrderedAttributeMap : public std::map<std::string, OwnedAttributeValue>
+{
+public:
+ // Contruct empty attribute map
+ OrderedAttributeMap() : std::map<std::string, OwnedAttributeValue>(){};
+
+ // Contruct attribute map and populate with attributes
+ OrderedAttributeMap(const opentelemetry::common::KeyValueIterable &attributes)
+ : OrderedAttributeMap()
+ {
+ attributes.ForEachKeyValue(
+ [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept {
+ SetAttribute(key, value);
+ return true;
+ });
+ }
+
+ // Construct map from initializer list by applying `SetAttribute` transform for every attribute
+ OrderedAttributeMap(
+ std::initializer_list<std::pair<nostd::string_view, opentelemetry::common::AttributeValue>>
+ attributes)
+ : OrderedAttributeMap()
+ {
+ for (auto &kv : attributes)
+ {
+ SetAttribute(kv.first, kv.second);
+ }
+ }
+
+ // Returns a reference to this map
+ const std::map<std::string, OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return (*this);
+ }
+
+ // Convert non-owning key-value to owning std::string(key) and OwnedAttributeValue(value)
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept
+ {
+ (*this)[std::string(key)] = nostd::visit(converter_, value);
+ }
+
+private:
+ AttributeConverter converter_;
+};
+
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attributemap_hash.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attributemap_hash.h
new file mode 100644
index 000000000..573f57eb1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/attributemap_hash.h
@@ -0,0 +1,62 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <iostream>
+#include <string>
+#include "opentelemetry/sdk/common/attribute_utils.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+
+template <class T>
+inline void GetHashForAttributeValue(size_t &seed, const T arg)
+{
+ std::hash<T> hasher;
+ // reference -
+ // https://www.boost.org/doc/libs/1_37_0/doc/html/hash/reference.html#boost.hash_combine
+ seed ^= hasher(arg) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+template <class T>
+inline void GetHashForAttributeValue(size_t &seed, const std::vector<T> &arg)
+{
+ for (auto v : arg)
+ {
+ GetHashForAttributeValue<T>(seed, v);
+ }
+}
+
+struct GetHashForAttributeValueVisitor
+{
+ GetHashForAttributeValueVisitor(size_t &seed) : seed_(seed) {}
+ template <class T>
+ void operator()(T &v)
+ {
+ GetHashForAttributeValue(seed_, v);
+ }
+ size_t &seed_;
+};
+
+// Calculate hash of keys and values of attribute map
+inline size_t GetHashForAttributeMap(const OrderedAttributeMap &attribute_map)
+{
+ size_t seed = 0UL;
+ for (auto &kv : attribute_map)
+ {
+ std::hash<std::string> hasher;
+ // reference -
+ // https://www.boost.org/doc/libs/1_37_0/doc/html/hash/reference.html#boost.hash_combine
+ seed ^= hasher(kv.first) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ nostd::visit(GetHashForAttributeValueVisitor(seed), kv.second);
+ }
+ return seed;
+}
+
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer.h
new file mode 100644
index 000000000..6af900183
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer.h
@@ -0,0 +1,186 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include <cstdint>
+#include <memory>
+
+#include "opentelemetry/sdk/common/atomic_unique_ptr.h"
+#include "opentelemetry/sdk/common/circular_buffer_range.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/*
+ * A lock-free circular buffer that supports multiple concurrent producers
+ * and a single consumer.
+ */
+template <class T>
+class CircularBuffer
+{
+public:
+ explicit CircularBuffer(size_t max_size)
+ : data_{new AtomicUniquePtr<T>[max_size + 1]}, capacity_{max_size + 1}
+ {}
+
+ /**
+ * @return a range of the elements in the circular buffer
+ *
+ * Note: This method must only be called from the consumer thread.
+ */
+ CircularBufferRange<const AtomicUniquePtr<T>> Peek() const noexcept
+ {
+ return const_cast<CircularBuffer *>(this)->PeekImpl();
+ }
+
+ /**
+ * Consume elements from the circular buffer's tail.
+ * @param n the number of elements to consume
+ * @param callback the callback to invoke with an AtomicUniquePtr to each
+ * consumed element.
+ *
+ * Note: The callback must set the passed AtomicUniquePtr to null.
+ *
+ * Note: This method must only be called from the consumer thread.
+ */
+ template <class Callback>
+ void Consume(size_t n, Callback callback) noexcept
+ {
+ assert(n <= static_cast<size_t>(head_ - tail_));
+ auto range = PeekImpl().Take(n);
+ static_assert(noexcept(callback(range)), "callback not allowed to throw");
+ tail_ += n;
+ callback(range);
+ }
+
+ /**
+ * Consume elements from the circular buffer's tail.
+ * @param n the number of elements to consume
+ *
+ * Note: This method must only be called from the consumer thread.
+ */
+ void Consume(size_t n) noexcept
+ {
+ Consume(n, [](CircularBufferRange<AtomicUniquePtr<T>> &range) noexcept {
+ range.ForEach([](AtomicUniquePtr<T> &ptr) noexcept {
+ ptr.Reset();
+ return true;
+ });
+ });
+ }
+
+ /**
+ * Adds an element into the circular buffer.
+ * @param ptr a pointer to the element to add
+ * @return true if the element was successfully added; false, otherwise.
+ */
+ bool Add(std::unique_ptr<T> &ptr) noexcept
+ {
+ while (true)
+ {
+ uint64_t tail = tail_;
+ uint64_t head = head_;
+
+ // The circular buffer is full, so return false.
+ if (head - tail >= capacity_ - 1)
+ {
+ return false;
+ }
+
+ uint64_t head_index = head % capacity_;
+ if (data_[head_index].SwapIfNull(ptr))
+ {
+ auto new_head = head + 1;
+ auto expected_head = head;
+ if (head_.compare_exchange_weak(expected_head, new_head, std::memory_order_release,
+ std::memory_order_relaxed))
+ {
+ // free the swapped out value
+ ptr.reset();
+
+ return true;
+ }
+
+ // If we reached this point (unlikely), it means that between the last
+ // iteration elements were added and then consumed from the circular
+ // buffer, so we undo the swap and attempt to add again.
+ data_[head_index].Swap(ptr);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Clear the circular buffer.
+ *
+ * Note: This method must only be called from the consumer thread.
+ */
+ void Clear() noexcept { Consume(size()); }
+
+ /**
+ * @return the maximum number of bytes that can be stored in the buffer.
+ */
+ size_t max_size() const noexcept { return capacity_ - 1; }
+
+ /**
+ * @return true if the buffer is empty.
+ */
+ bool empty() const noexcept { return head_ == tail_; }
+
+ /**
+ * @return the number of bytes stored in the circular buffer.
+ *
+ * Note: this method will only return a correct snapshot of the size if called
+ * from the consumer thread.
+ */
+ size_t size() const noexcept
+ {
+ uint64_t tail = tail_;
+ uint64_t head = head_;
+ assert(tail <= head);
+ return head - tail;
+ }
+
+ /**
+ * @return the number of elements consumed from the circular buffer.
+ */
+ uint64_t consumption_count() const noexcept { return tail_; }
+
+ /**
+ * @return the number of elements added to the circular buffer.
+ */
+ uint64_t production_count() const noexcept { return head_; }
+
+private:
+ std::unique_ptr<AtomicUniquePtr<T>[]> data_;
+ size_t capacity_;
+ std::atomic<uint64_t> head_{0};
+ std::atomic<uint64_t> tail_{0};
+
+ CircularBufferRange<AtomicUniquePtr<T>> PeekImpl() noexcept
+ {
+ uint64_t tail_index = tail_ % capacity_;
+ uint64_t head_index = head_ % capacity_;
+ if (head_index == tail_index)
+ {
+ return {};
+ }
+ auto data = data_.get();
+ if (tail_index < head_index)
+ {
+ return CircularBufferRange<AtomicUniquePtr<T>>{nostd::span<AtomicUniquePtr<T>>{
+ data + tail_index, static_cast<std::size_t>(head_index - tail_index)}};
+ }
+ return {nostd::span<AtomicUniquePtr<T>>{data + tail_index,
+ static_cast<std::size_t>(capacity_ - tail_index)},
+ nostd::span<AtomicUniquePtr<T>>{data, static_cast<std::size_t>(head_index)}};
+ }
+};
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer_range.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer_range.h
new file mode 100644
index 000000000..9ef3b66be
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/circular_buffer_range.h
@@ -0,0 +1,93 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * A non-owning view into a range of elements in a circular buffer.
+ */
+template <class T>
+class CircularBufferRange
+{
+public:
+ CircularBufferRange() noexcept = default;
+
+ explicit CircularBufferRange(nostd::span<T> first) noexcept : first_{first} {}
+
+ CircularBufferRange(nostd::span<T> first, nostd::span<T> second) noexcept
+ : first_{first}, second_{second}
+ {}
+
+ operator CircularBufferRange<const T>() const noexcept { return {first_, second_}; }
+
+ /**
+ * Iterate over the elements in the range.
+ * @param callback the callback to call for each element
+ * @return true if we iterated over all elements
+ */
+ template <class Callback>
+ bool ForEach(Callback callback) const
+ noexcept(noexcept(std::declval<Callback>()(std::declval<T &>())))
+ {
+ for (auto &value : first_)
+ {
+ if (!callback(value))
+ {
+ return false;
+ }
+ }
+ for (auto &value : second_)
+ {
+ if (!callback(value))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return the number of elements in the range
+ */
+ size_t size() const noexcept { return first_.size() + second_.size(); }
+
+ /**
+ * @return true if the range is empty
+ */
+ bool empty() const noexcept { return first_.empty(); }
+
+ /**
+ * Return a subrange taken from the start of this range.
+ * @param n the number of element to take in the subrange
+ * @return a subrange of the first n elements in this range
+ */
+ CircularBufferRange Take(size_t n) const noexcept
+ {
+ assert(n <= size());
+ if (first_.size() >= n)
+ {
+ return CircularBufferRange{nostd::span<T>{first_.data(), n}};
+ }
+ return {first_, nostd::span<T>{second_.data(), n - first_.size()}};
+ }
+
+private:
+ nostd::span<T> first_;
+ nostd::span<T> second_;
+};
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/empty_attributes.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/empty_attributes.h
new file mode 100644
index 000000000..4f740bf10
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/empty_attributes.h
@@ -0,0 +1,34 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/common/key_value_iterable_view.h"
+#include "opentelemetry/common/macros.h"
+
+#include <array>
+#include <map>
+#include <string>
+#include <utility>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+/**
+ * Maintain a static empty array of pairs that represents empty (default) attributes.
+ * This helps to avoid constructing a new empty container every time a call is made
+ * with default attributes.
+ */
+OPENTELEMETRY_MAYBE_UNUSED static const opentelemetry::common::KeyValueIterableView<
+ std::array<std::pair<std::string, int>, 0>>
+ &GetEmptyAttributes() noexcept
+{
+ static const std::array<std::pair<std::string, int>, 0> array{};
+ static const opentelemetry::common::KeyValueIterableView<
+ std::array<std::pair<std::string, int>, 0>>
+ kEmptyAttributes(array);
+
+ return kEmptyAttributes;
+}
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/env_variables.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/env_variables.h
new file mode 100644
index 000000000..be955ee86
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/env_variables.h
@@ -0,0 +1,53 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <string>
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+
+#if defined(_MSC_VER)
+inline int setenv(const char *name, const char *value, int)
+{
+ return _putenv_s(name, value);
+}
+
+inline int unsetenv(const char *name)
+{
+ return setenv(name, "", 1);
+}
+#endif
+
+// Returns the env variable set.
+inline const std::string GetEnvironmentVariable(const char *env_var_name)
+{
+#if !defined(NO_GETENV)
+ const char *endpoint_from_env = nullptr;
+# if defined(_MSC_VER)
+ // avoid calling std::getenv which is deprecated in MSVC.
+ size_t required_size = 0;
+ getenv_s(&required_size, nullptr, 0, env_var_name);
+ std::unique_ptr<char> endpoint_buffer;
+ if (required_size > 0)
+ {
+ endpoint_buffer = std::unique_ptr<char>{new char[required_size]};
+ getenv_s(&required_size, endpoint_buffer.get(), required_size, env_var_name);
+ endpoint_from_env = endpoint_buffer.get();
+ }
+# else
+ endpoint_from_env = std::getenv(env_var_name);
+# endif // defined(_MSC_VER)
+ return endpoint_from_env == nullptr ? std::string{} : std::string{endpoint_from_env};
+#else
+ return std::string{};
+#endif // !defined(NO_GETENV)
+}
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/exporter_utils.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/exporter_utils.h
new file mode 100644
index 000000000..091f481f9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/exporter_utils.h
@@ -0,0 +1,34 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * ExportResult is returned as result of exporting a batch of Records.
+ */
+enum class ExportResult
+{
+ // Batch was exported successfully.
+ kSuccess = 0,
+
+ // Batch exporting failed, caller must not retry exporting the same batch
+ // and the batch must be dropped.
+ kFailure = 1,
+
+ // The collection does not have enough space to receive the export batch.
+ kFailureFull = 2,
+
+ // The export() function was passed an invalid argument.
+ kFailureInvalidArgument = 3
+};
+
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/global_log_handler.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/global_log_handler.h
new file mode 100644
index 000000000..99cf48b82
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/common/global_log_handler.h
@@ -0,0 +1,222 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <utility>
+
+#include "opentelemetry/nostd/shared_ptr.h"
+#include "opentelemetry/sdk/common/attribute_utils.h"
+#include "opentelemetry/version.h"
+
+#define OTEL_INTERNAL_LOG_LEVEL_ERROR 0
+#define OTEL_INTERNAL_LOG_LEVEL_WARN 1
+#define OTEL_INTERNAL_LOG_LEVEL_INFO 2
+#define OTEL_INTERNAL_LOG_LEVEL_DEBUG 3
+#ifndef OTEL_INTERNAL_LOG_LEVEL
+// DEBUG by default, we can change log level on runtime
+# define OTEL_INTERNAL_LOG_LEVEL OTEL_INTERNAL_LOG_LEVEL_DEBUG
+#endif
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+namespace internal_log
+{
+
+enum class LogLevel
+{
+ Error = 0,
+ Warning,
+ Info,
+ Debug
+};
+
+inline std::string LevelToString(LogLevel level)
+{
+ switch (level)
+ {
+ case LogLevel::Error:
+ return "Error";
+ case LogLevel::Warning:
+ return "Warning";
+ case LogLevel::Info:
+ return "Info";
+ case LogLevel::Debug:
+ return "Debug";
+ }
+ return {};
+}
+
+class LogHandler
+{
+public:
+ virtual ~LogHandler();
+
+ virtual void Handle(LogLevel level,
+ const char *file,
+ int line,
+ const char *msg,
+ const sdk::common::AttributeMap &attributes) noexcept = 0;
+};
+
+class DefaultLogHandler : public LogHandler
+{
+public:
+ void Handle(LogLevel level,
+ const char *file,
+ int line,
+ const char *msg,
+ const sdk::common::AttributeMap &attributes) noexcept override;
+};
+
+class NoopLogHandler : public LogHandler
+{
+public:
+ void Handle(LogLevel level,
+ const char *file,
+ int line,
+ const char *msg,
+ const sdk::common::AttributeMap &error_attributes) noexcept override;
+};
+
+/**
+ * Stores the singleton global LogHandler.
+ */
+class GlobalLogHandler
+{
+public:
+ /**
+ * Returns the singleton LogHandler.
+ *
+ * By default, a default LogHandler is returned.
+ */
+ static inline const nostd::shared_ptr<LogHandler> &GetLogHandler() noexcept
+ {
+ return GetHandlerAndLevel().first;
+ }
+
+ /**
+ * Changes the singleton LogHandler.
+ * This should be called once at the start of application before creating any Provider
+ * instance.
+ */
+ static inline void SetLogHandler(nostd::shared_ptr<LogHandler> eh) noexcept
+ {
+ GetHandlerAndLevel().first = eh;
+ }
+
+ /**
+ * Returns the singleton log level.
+ *
+ * By default, a default log level is returned.
+ */
+ static inline LogLevel GetLogLevel() noexcept { return GetHandlerAndLevel().second; }
+
+ /**
+ * Changes the singleton Log level.
+ * This should be called once at the start of application before creating any Provider
+ * instance.
+ */
+ static inline void SetLogLevel(LogLevel level) noexcept { GetHandlerAndLevel().second = level; }
+
+private:
+ static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> &GetHandlerAndLevel() noexcept;
+};
+
+} // namespace internal_log
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+
+/**
+ * We can not decide the destroying order of signaltons.
+ * Which means, the destructors of other singletons (GlobalLogHandler,TracerProvider and etc.)
+ * may be called after destroying of global LogHandler and use OTEL_INTERNAL_LOG_* in it.We can do
+ * nothing but ignore the log in this situation.
+ */
+#define OTEL_INTERNAL_LOG_DISPATCH(level, message, attributes) \
+ do \
+ { \
+ using opentelemetry::sdk::common::internal_log::GlobalLogHandler; \
+ using opentelemetry::sdk::common::internal_log::LogHandler; \
+ if (level > GlobalLogHandler::GetLogLevel()) \
+ { \
+ break; \
+ } \
+ const opentelemetry::nostd::shared_ptr<LogHandler> &log_handler = \
+ GlobalLogHandler::GetLogHandler(); \
+ if (!log_handler) \
+ { \
+ break; \
+ } \
+ std::stringstream tmp_stream; \
+ tmp_stream << message; \
+ log_handler->Handle(level, __FILE__, __LINE__, tmp_stream.str().c_str(), attributes); \
+ } while (false);
+
+#define OTEL_INTERNAL_LOG_GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
+
+#if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_ERROR
+# define OTEL_INTERNAL_LOG_ERROR_1_ARGS(message) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Error, message, \
+ {})
+# define OTEL_INTERNAL_LOG_ERROR_2_ARGS(message, attributes) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Error, message, \
+ attributes)
+# define OTEL_INTERNAL_LOG_ERROR_MACRO(...) \
+ OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_ERROR_2_ARGS, \
+ OTEL_INTERNAL_LOG_ERROR_1_ARGS)
+# define OTEL_INTERNAL_LOG_ERROR(...) OTEL_INTERNAL_LOG_ERROR_MACRO(__VA_ARGS__)(__VA_ARGS__)
+#else
+# define OTEL_INTERNAL_LOG_ERROR(...)
+#endif
+
+#if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_WARN
+# define OTEL_INTERNAL_LOG_WARN_1_ARGS(message) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warning, \
+ message, {})
+# define OTEL_INTERNAL_LOG_WARN_2_ARGS(message, attributes) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warning, \
+ message, attributes)
+# define OTEL_INTERNAL_LOG_WARN_MACRO(...) \
+ OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_WARN_2_ARGS, \
+ OTEL_INTERNAL_LOG_WARN_1_ARGS)
+# define OTEL_INTERNAL_LOG_WARN(...) OTEL_INTERNAL_LOG_WARN_MACRO(__VA_ARGS__)(__VA_ARGS__)
+#else
+# define OTEL_INTERNAL_LOG_ERROR(...)
+#endif
+
+#if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_DEBUG
+# define OTEL_INTERNAL_LOG_DEBUG_1_ARGS(message) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Debug, message, \
+ {})
+# define OTEL_INTERNAL_LOG_DEBUG_2_ARGS(message, attributes) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Debug, message, \
+ attributes)
+# define OTEL_INTERNAL_LOG_DEBUG_MACRO(...) \
+ OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_DEBUG_2_ARGS, \
+ OTEL_INTERNAL_LOG_DEBUG_1_ARGS)
+# define OTEL_INTERNAL_LOG_DEBUG(...) OTEL_INTERNAL_LOG_DEBUG_MACRO(__VA_ARGS__)(__VA_ARGS__)
+#else
+# define OTEL_INTERNAL_LOG_DEBUG(...)
+#endif
+
+#if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_INFO
+# define OTEL_INTERNAL_LOG_INFO_1_ARGS(message) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Info, message, \
+ {})
+# define OTEL_INTERNAL_LOG_INFO_2_ARGS(message, attributes) \
+ OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Info, message, \
+ attributes)
+# define OTEL_INTERNAL_LOG_INFO_MACRO(...) \
+ OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_INFO_2_ARGS, \
+ OTEL_INTERNAL_LOG_INFO_1_ARGS)
+# define OTEL_INTERNAL_LOG_INFO(...) OTEL_INTERNAL_LOG_INFO_MACRO(__VA_ARGS__)(__VA_ARGS__)
+#else
+# define OTEL_INTERNAL_LOG_INFO(...)
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h
new file mode 100644
index 000000000..20f82a5d1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h
@@ -0,0 +1,96 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/nostd/unique_ptr.h"
+#include "opentelemetry/version.h"
+
+#include <functional>
+#include <string>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+namespace sdk
+{
+namespace instrumentationlibrary
+{
+
+class InstrumentationLibrary
+{
+public:
+ InstrumentationLibrary(const InstrumentationLibrary &) = default;
+
+ /**
+ * Returns a newly created InstrumentationLibrary with the specified library name and version.
+ * @param name name of the instrumentation library.
+ * @param version version of the instrumentation library.
+ * @param schema_url schema url of the telemetry emitted by the library.
+ * @returns the newly created InstrumentationLibrary.
+ */
+ static nostd::unique_ptr<InstrumentationLibrary> Create(nostd::string_view name,
+ nostd::string_view version = "",
+ nostd::string_view schema_url = "")
+ {
+ return nostd::unique_ptr<InstrumentationLibrary>(
+ new InstrumentationLibrary{name, version, schema_url});
+ }
+
+ std::size_t HashCode() const noexcept { return hash_code_; }
+
+ /**
+ * Compare 2 instrumentation libraries.
+ * @param other the instrumentation library to compare to.
+ * @returns true if the 2 instrumentation libraries are equal, false otherwise.
+ */
+ bool operator==(const InstrumentationLibrary &other) const
+ {
+ return equal(other.name_, other.version_, other.schema_url_);
+ }
+
+ /**
+ * Check whether the instrumentation library has given name and version.
+ * This could be used to check version equality and avoid heap allocation.
+ * @param name name of the instrumentation library to compare.
+ * @param version version of the instrumentatoin library to compare.
+ * @param schema_url schema url of the telemetry emitted by the library.
+ * @returns true if name and version in this instrumentation library are equal with the given name
+ * and version.
+ */
+ bool equal(const nostd::string_view name,
+ const nostd::string_view version,
+ const nostd::string_view schema_url = "") const
+ {
+ return this->name_ == name && this->version_ == version && this->schema_url_ == schema_url;
+ }
+
+ const std::string &GetName() const { return name_; }
+ const std::string &GetVersion() const { return version_; }
+ const std::string &GetSchemaURL() const { return schema_url_; }
+
+private:
+ InstrumentationLibrary(nostd::string_view name,
+ nostd::string_view version,
+ nostd::string_view schema_url = "")
+ : name_(name), version_(version), schema_url_(schema_url)
+ {
+ std::string hash_data;
+ hash_data.reserve(name_.size() + version_.size() + schema_url_.size());
+ hash_data += name_;
+ hash_data += version_;
+ hash_data += schema_url_;
+ hash_code_ = std::hash<std::string>{}(hash_data);
+ }
+
+private:
+ std::string name_;
+ std::string version_;
+ std::string schema_url_;
+ std::size_t hash_code_;
+};
+
+} // namespace instrumentationlibrary
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/batch_log_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/batch_log_processor.h
new file mode 100644
index 000000000..1b6d443c8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/batch_log_processor.h
@@ -0,0 +1,128 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/common/circular_buffer.h"
+# include "opentelemetry/sdk/logs/exporter.h"
+# include "opentelemetry/sdk/logs/processor.h"
+
+# include <atomic>
+# include <condition_variable>
+# include <thread>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+
+namespace logs
+{
+
+/**
+ * This is an implementation of the LogProcessor which creates batches of finished logs and passes
+ * the export-friendly log data representations to the configured LogExporter.
+ */
+class BatchLogProcessor : public LogProcessor
+{
+public:
+ /**
+ * Creates a batch log processor by configuring the specified exporter and other parameters
+ * as per the official, language-agnostic opentelemetry specs.
+ *
+ * @param exporter - The backend exporter to pass the logs to
+ * @param max_queue_size - The maximum buffer/queue size. After the size is reached, logs are
+ * dropped.
+ * @param scheduled_delay_millis - The time interval between two consecutive exports.
+ * @param max_export_batch_size - The maximum batch size of every export. It must be smaller or
+ * equal to max_queue_size
+ */
+ explicit BatchLogProcessor(
+ std::unique_ptr<LogExporter> &&exporter,
+ const size_t max_queue_size = 2048,
+ const std::chrono::milliseconds scheduled_delay_millis = std::chrono::milliseconds(5000),
+ const size_t max_export_batch_size = 512);
+
+ /** Makes a new recordable **/
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override;
+
+ /**
+ * Called when the Logger's log method creates a log record
+ * @param record the log record
+ */
+
+ void OnReceive(std::unique_ptr<Recordable> &&record) noexcept override;
+
+ /**
+ * Export all log records that have not been exported yet.
+ *
+ * NOTE: Timeout functionality not supported yet.
+ */
+ bool ForceFlush(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ /**
+ * Shuts down the processor and does any cleanup required. Completely drains the buffer/queue of
+ * all its logs and passes them to the exporter. Any subsequent calls to
+ * ForceFlush or Shutdown will return immediately without doing anything.
+ *
+ * NOTE: Timeout functionality not supported yet.
+ */
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ /**
+ * Class destructor which invokes the Shutdown() method.
+ */
+ virtual ~BatchLogProcessor() override;
+
+private:
+ /**
+ * The background routine performed by the worker thread.
+ */
+ void DoBackgroundWork();
+
+ /**
+ * Exports all logs to the configured exporter.
+ *
+ * @param was_force_flush_called - A flag to check if the current export is the result
+ * of a call to ForceFlush method. If true, then we have to
+ * notify the main thread to wake it up in the ForceFlush
+ * method.
+ */
+ void Export(const bool was_for_flush_called);
+
+ /**
+ * Called when Shutdown() is invoked. Completely drains the queue of all log records and
+ * passes them to the exporter.
+ */
+ void DrainQueue();
+
+ /* The configured backend log exporter */
+ std::unique_ptr<LogExporter> exporter_;
+
+ /* Configurable parameters as per the official *trace* specs */
+ const size_t max_queue_size_;
+ const std::chrono::milliseconds scheduled_delay_millis_;
+ const size_t max_export_batch_size_;
+
+ /* Synchronization primitives */
+ std::condition_variable cv_, force_flush_cv_;
+ std::mutex cv_m_, force_flush_cv_m_, shutdown_m_;
+
+ /* The buffer/queue to which the ended logs are added */
+ common::CircularBuffer<Recordable> buffer_;
+
+ /* Important boolean flags to handle the workflow of the processor */
+ std::atomic<bool> is_shutdown_{false};
+ std::atomic<bool> is_force_flush_{false};
+ std::atomic<bool> is_force_flush_notified_{false};
+
+ /* The background worker thread */
+ std::thread worker_thread_;
+};
+
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/exporter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/exporter.h
new file mode 100644
index 000000000..85c58e9f1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/exporter.h
@@ -0,0 +1,62 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <memory>
+# include <vector>
+# include "opentelemetry/nostd/span.h"
+# include "opentelemetry/sdk/common/exporter_utils.h"
+# include "opentelemetry/sdk/logs/processor.h"
+# include "opentelemetry/sdk/logs/recordable.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * LogExporter defines the interface that log exporters must implement.
+ */
+class LogExporter
+{
+public:
+ virtual ~LogExporter() = default;
+
+ /**
+ * Create a log recordable. This object will be used to record log data and
+ * will subsequently be passed to LogExporter::Export. Vendors can implement
+ * custom recordables or use the default LogRecord recordable provided by the
+ * SDK.
+ * @return a newly initialized Recordable object
+ *
+ * Note: This method must be callable from multiple threads.
+ */
+ virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0;
+
+ /**
+ * Exports the batch of log records to their export destination.
+ * This method must not be called concurrently for the same exporter instance.
+ * The exporter may attempt to retry sending the batch, but should drop
+ * and return kFailure after a certain timeout.
+ * @param records a span of unique pointers to log records
+ * @returns an ExportResult code (whether export was success or failure)
+ */
+ virtual sdk::common::ExportResult Export(
+ const nostd::span<std::unique_ptr<Recordable>> &records) noexcept = 0;
+
+ /**
+ * Marks the exporter as ShutDown and cleans up any resources as required.
+ * Shutdown should be called only once for each Exporter instance.
+ * @param timeout minimum amount of microseconds to wait for shutdown before giving up and
+ * returning failure.
+ * @return true if the exporter shutdown succeeded, false otherwise
+ */
+ virtual bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/log_record.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/log_record.h
new file mode 100644
index 000000000..2a3a78289
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/log_record.h
@@ -0,0 +1,193 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <map>
+# include <unordered_map>
+# include "opentelemetry/sdk/common/attribute_utils.h"
+# include "opentelemetry/sdk/logs/recordable.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+/**
+ * A default Recordable implemenation to be passed in log statements,
+ * matching the 10 fields of the Log Data Model.
+ * (https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#log-and-event-record-definition)
+ *
+ */
+class LogRecord final : public Recordable
+{
+private:
+ // Default values are set by the respective data structures' constructors for all fields,
+ // except the severity field, which must be set manually (an enum with no default value).
+ opentelemetry::logs::Severity severity_ = opentelemetry::logs::Severity::kInvalid;
+ const opentelemetry::sdk::resource::Resource *resource_ = nullptr;
+ common::AttributeMap attributes_map_;
+ std::string body_; // Currently a simple string, but should be changed to "Any" type
+ opentelemetry::trace::TraceId trace_id_;
+ opentelemetry::trace::SpanId span_id_;
+ opentelemetry::trace::TraceFlags trace_flags_;
+ opentelemetry::common::SystemTimestamp timestamp_; // uint64 nanoseconds since Unix epoch
+
+public:
+ /********** Setters for each field (overrides methods from the Recordable interface) ************/
+
+ /**
+ * Set the severity for this log.
+ * @param severity the severity of the event
+ */
+ void SetSeverity(opentelemetry::logs::Severity severity) noexcept override
+ {
+ severity_ = severity;
+ }
+
+ /**
+ * Set body field for this log.
+ * @param message the body to set
+ */
+ void SetBody(nostd::string_view message) noexcept override { body_ = std::string(message); }
+
+ /**
+ * Set Resource of this log
+ * @param Resource the resource to set
+ */
+ void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override
+ {
+ resource_ = &resource;
+ }
+
+ /**
+ * Set an attribute of a log.
+ * @param name the name of the attribute
+ * @param value the attribute value
+ */
+
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept override
+ {
+ attributes_map_.SetAttribute(key, value);
+ }
+
+ /**
+ * Set trace id for this log.
+ * @param trace_id the trace id to set
+ */
+ void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept override
+ {
+ trace_id_ = trace_id;
+ }
+
+ /**
+ * Set span id for this log.
+ * @param span_id the span id to set
+ */
+ virtual void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept override
+ {
+ span_id_ = span_id;
+ }
+
+ /**
+ * Inject a trace_flags for this log.
+ * @param trace_flags the span id to set
+ */
+ void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept override
+ {
+ trace_flags_ = trace_flags;
+ }
+
+ /**
+ * Set the timestamp for this log.
+ * @param timestamp the timestamp of the event
+ */
+ void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept override
+ {
+ timestamp_ = timestamp;
+ }
+
+ /************************** Getters for each field ****************************/
+
+ /**
+ * Get the severity for this log
+ * @return the severity for this log
+ */
+ opentelemetry::logs::Severity GetSeverity() const noexcept { return severity_; }
+
+ /**
+ * Get the body of this log
+ * @return the body of this log
+ */
+ std::string GetBody() const noexcept { return body_; }
+
+ /**
+ * Get the resource for this log
+ * @return the resource for this log
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept
+ {
+ if (nullptr == resource_)
+ {
+ return sdk::resource::Resource::GetDefault();
+ }
+ return *resource_;
+ }
+
+ /**
+ * Get the attributes for this log
+ * @return the attributes for this log
+ */
+ const std::unordered_map<std::string, common::OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return attributes_map_.GetAttributes();
+ }
+
+ /**
+ * Get the trace id for this log
+ * @return the trace id for this log
+ */
+ opentelemetry::trace::TraceId GetTraceId() const noexcept { return trace_id_; }
+
+ /**
+ * Get the span id for this log
+ * @return the span id for this log
+ */
+ opentelemetry::trace::SpanId GetSpanId() const noexcept { return span_id_; }
+
+ /**
+ * Get the trace flags for this log
+ * @return the trace flags for this log
+ */
+ opentelemetry::trace::TraceFlags GetTraceFlags() const noexcept { return trace_flags_; }
+
+ /**
+ * Get the timestamp for this log
+ * @return the timestamp for this log
+ */
+ opentelemetry::common::SystemTimestamp GetTimestamp() const noexcept { return timestamp_; }
+
+ /**
+ * Set instrumentation_library for this log.
+ * @param instrumentation_library the instrumentation library to set
+ */
+ void SetInstrumentationLibrary(
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library) noexcept
+ {
+ instrumentation_library_ = &instrumentation_library;
+ }
+
+private:
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ *instrumentation_library_ = nullptr;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger.h
new file mode 100644
index 000000000..4eeca2da1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger.h
@@ -0,0 +1,77 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/logs/logger.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/logs/logger_context.h"
+# include "opentelemetry/sdk/logs/logger_provider.h"
+
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+class LoggerProvider;
+
+class Logger final : public opentelemetry::logs::Logger
+{
+public:
+ /**
+ * Initialize a new logger.
+ * @param name The name of this logger instance
+ * @param context The logger provider that owns this logger.
+ */
+ explicit Logger(
+ opentelemetry::nostd::string_view name,
+ std::shared_ptr<LoggerContext> context,
+ std::unique_ptr<instrumentationlibrary::InstrumentationLibrary> instrumentation_library =
+ instrumentationlibrary::InstrumentationLibrary::Create("")) noexcept;
+
+ /**
+ * Returns the name of this logger.
+ */
+ const opentelemetry::nostd::string_view GetName() noexcept override;
+
+ /**
+ * Writes a log record into the processor.
+ * @param severity the severity level of the log event.
+ * @param message the string message of the log (perhaps support std::fmt or fmt-lib format).
+ * with the log event.
+ * @param attributes the attributes, stored as a 2D list of key/value pairs, that are associated
+ * with the log event.
+ * @param trace_id the trace id associated with the log event.
+ * @param span_id the span id associate with the log event.
+ * @param trace_flags the trace flags associated with the log event.
+ * @param timestamp the timestamp the log record was created.
+ * @throws No exceptions under any circumstances. */
+ void Log(opentelemetry::logs::Severity severity,
+ nostd::string_view body,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ opentelemetry::trace::TraceId trace_id,
+ opentelemetry::trace::SpanId span_id,
+ opentelemetry::trace::TraceFlags trace_flags,
+ opentelemetry::common::SystemTimestamp timestamp) noexcept override;
+
+ /** Returns the associated instruementation library */
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary &
+ GetInstrumentationLibrary() const noexcept;
+
+private:
+ // The name of this logger
+ std::string logger_name_;
+
+ // order of declaration is important here - instrumentation library should destroy after
+ // logger-context.
+ std::unique_ptr<instrumentationlibrary::InstrumentationLibrary> instrumentation_library_;
+ std::shared_ptr<LoggerContext> context_;
+};
+
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_context.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_context.h
new file mode 100644
index 000000000..01c2f7dd8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_context.h
@@ -0,0 +1,81 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/processor.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * A class which stores the LoggerContext context.
+ *
+ * This class meets the following design criteria:
+ * - A shared reference between LoggerProvider and Logger instantiated.
+ * - A thread-safe class that allows updating/altering processor/exporter pipelines
+ * and sampling config.
+ * - The owner/destroyer of Processors/Exporters. These will remain active until
+ * this class is destroyed. I.e. Sampling, Exporting, flushing, Custom Iterator etc. are all ok
+ * if this object is alive, and they will work together. If this object is destroyed, then no shared
+ * references to Processor, Exporter, Recordable, Custom Iterator etc. should exist, and all
+ * associated pipelines will have been flushed.
+ */
+class LoggerContext
+{
+public:
+ explicit LoggerContext(std::vector<std::unique_ptr<LogProcessor>> &&processors,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({})) noexcept;
+
+ /**
+ * Attaches a log processor to list of configured processors to this tracer context.
+ * Processor once attached can't be removed.
+ * @param processor The new log processor for this tracer. This must not be
+ * a nullptr. Ownership is given to the `TracerContext`.
+ *
+ * Note: This method is not thread safe.
+ */
+ void AddProcessor(std::unique_ptr<LogProcessor> processor) noexcept;
+
+ /**
+ * Obtain the configured (composite) processor.
+ *
+ * Note: When more than one processor is active, this will
+ * return an "aggregate" processor
+ */
+ LogProcessor &GetProcessor() const noexcept;
+
+ /**
+ * Obtain the resource associated with this tracer context.
+ * @return The resource for this tracer context.
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Force all active LogProcessors to flush any buffered logs
+ * within the given timeout.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+ /**
+ * Shutdown the log processor associated with this tracer provider.
+ */
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept;
+
+private:
+ // order of declaration is important here - resource object should be destroyed after processor.
+ opentelemetry::sdk::resource::Resource resource_;
+ std::unique_ptr<LogProcessor> processor_;
+};
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_provider.h
new file mode 100755
index 000000000..9afb67ba0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/logger_provider.h
@@ -0,0 +1,131 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0/
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <memory>
+# include <mutex>
+# include <string>
+# include <vector>
+
+# include "opentelemetry/logs/logger_provider.h"
+# include "opentelemetry/logs/noop.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/common/atomic_shared_ptr.h"
+# include "opentelemetry/sdk/logs/logger.h"
+# include "opentelemetry/sdk/logs/logger_context.h"
+# include "opentelemetry/sdk/logs/processor.h"
+
+// Define the maximum number of loggers that are allowed to be registered to the loggerprovider.
+// TODO: Add link to logging spec once this is added to it
+# define MAX_LOGGER_COUNT 100
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+class Logger;
+
+class LoggerProvider final : public opentelemetry::logs::LoggerProvider
+{
+public:
+ /**
+ * Initialize a new logger provider
+ * @param processor The span processor for this logger provider. This must
+ * not be a nullptr.
+ * @param resource The resources for this logger provider.
+ * @param sampler The sampler for this logger provider. This must
+ * not be a nullptr.
+ * @param id_generator The custom id generator for this logger provider. This must
+ * not be a nullptr
+ */
+ explicit LoggerProvider(std::unique_ptr<LogProcessor> &&processor,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({})) noexcept;
+
+ explicit LoggerProvider(std::vector<std::unique_ptr<LogProcessor>> &&processors,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({})) noexcept;
+
+ /**
+ * Initialize a new logger provider. A processor must later be assigned
+ * to this logger provider via the AddProcessor() method.
+ */
+ explicit LoggerProvider() noexcept;
+
+ /**
+ * Initialize a new logger provider with a specified context
+ * @param context The shared logger configuration/pipeline for this provider.
+ */
+ explicit LoggerProvider(std::shared_ptr<sdk::logs::LoggerContext> context) noexcept;
+
+ ~LoggerProvider();
+
+ /**
+ * Creates a logger with the given name, and returns a shared pointer to it.
+ * If a logger with that name already exists, return a shared pointer to it
+ * @param logger_name The name of the logger to be created.
+ * @param options The options for the logger. TODO: Once the logging spec defines it,
+ * give a list of options that the logger supports.
+ * @param library_name The version of the library.
+ * @param library_version The version of the library.
+ * @param schema_url The schema URL.
+ */
+ nostd::shared_ptr<opentelemetry::logs::Logger> GetLogger(
+ nostd::string_view logger_name,
+ nostd::string_view options,
+ nostd::string_view library_name,
+ nostd::string_view library_version = "",
+ nostd::string_view schema_url = "") noexcept override;
+ /**
+ * Creates a logger with the given name, and returns a shared pointer to it.
+ * If a logger with that name already exists, return a shared pointer to it
+ * @param name The name of the logger to be created.
+ * @param args The arguments for the logger. TODO: Once the logging spec defines it,
+ * give a list of arguments that the logger supports.
+ * @param library_name The version of the library.
+ * @param library_version The version of the library.
+ * @param schema_url The schema URL.
+ */
+ nostd::shared_ptr<opentelemetry::logs::Logger> GetLogger(
+ nostd::string_view logger_name,
+ nostd::span<nostd::string_view> args,
+ nostd::string_view library_name,
+ nostd::string_view library_version = "",
+ nostd::string_view schema_url = "") noexcept override;
+
+ /**
+ * Add the processor that is stored internally in the logger provider.
+ * @param processor The processor to be stored inside the logger provider.
+ * This must not be a nullptr.
+ */
+ void AddProcessor(std::unique_ptr<LogProcessor> processor) noexcept;
+
+ /**
+ * Obtain the resource associated with this logger provider.
+ * @return The resource for this logger provider.
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Shutdown the log processor associated with this log provider.
+ */
+ bool Shutdown() noexcept;
+
+ /**
+ * Force flush the log processor associated with this log provider.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+private:
+ // order of declaration is important here - loggers should destroy only after context.
+ std::vector<std::shared_ptr<opentelemetry::sdk::logs::Logger>> loggers_;
+ std::shared_ptr<sdk::logs::LoggerContext> context_;
+ std::mutex lock_;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h
new file mode 100644
index 000000000..c1bda24a0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_log_processor.h
@@ -0,0 +1,69 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <memory>
+# include <vector>
+
+# include "opentelemetry/sdk/logs/multi_recordable.h"
+# include "opentelemetry/sdk/logs/processor.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+/**
+ * Log processor allow hooks for receive method invocations.
+ *
+ * Built-in log processors are responsible for batching and conversion of
+ * logs to exportable representation and passing batches to exporters.
+ */
+class MultiLogProcessor : public LogProcessor
+{
+public:
+ MultiLogProcessor(std::vector<std::unique_ptr<LogProcessor>> &&processors);
+ ~MultiLogProcessor();
+
+ void AddProcessor(std::unique_ptr<LogProcessor> &&processor);
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override;
+
+ /**
+ * OnReceive is called by the SDK once a log record has been successfully created.
+ * @param record the log record
+ */
+ void OnReceive(std::unique_ptr<Recordable> &&record) noexcept override;
+
+ /**
+ * Exports all log records that have not yet been exported to the configured Exporter.
+ * @param timeout that the forceflush is required to finish within.
+ * @return a result code indicating whether it succeeded, failed or timed out
+ */
+ bool ForceFlush(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ /**
+ * Shuts down the processor and does any cleanup required.
+ * ShutDown should only be called once for each processor.
+ * @param timeout minimum amount of microseconds to wait for
+ * shutdown before giving up and returning failure.
+ * @return true if the shutdown succeeded, false otherwise
+ */
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+private:
+ std::vector<std::unique_ptr<LogProcessor>> processors_;
+};
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_recordable.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_recordable.h
new file mode 100644
index 000000000..db3df9622
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/multi_recordable.h
@@ -0,0 +1,104 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <cstddef>
+# include <memory>
+# include <unordered_map>
+
+# include "opentelemetry/sdk/logs/processor.h"
+# include "opentelemetry/sdk/logs/recordable.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+class MultiRecordable final : public Recordable
+{
+public:
+ void AddRecordable(const LogProcessor &processor,
+ std::unique_ptr<Recordable> recordable) noexcept;
+
+ const std::unique_ptr<Recordable> &GetRecordable(const LogProcessor &processor) const noexcept;
+
+ std::unique_ptr<Recordable> ReleaseRecordable(const LogProcessor &processor) noexcept;
+
+ /**
+ * Set the timestamp for this log.
+ * @param timestamp the timestamp to set
+ */
+ void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept override;
+
+ /**
+ * Set the severity for this log.
+ * @param severity the severity of the event
+ */
+ void SetSeverity(opentelemetry::logs::Severity severity) noexcept override;
+
+ /**
+ * Set body field for this log.
+ * @param message the body to set
+ */
+ void SetBody(nostd::string_view message) noexcept override;
+
+ /**
+ * Set Resource of this log
+ * @param Resource the resource to set
+ */
+ void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override;
+
+ /**
+ * Set an attribute of a log.
+ * @param key the name of the attribute
+ * @param value the attribute value
+ */
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept override;
+
+ /**
+ * Set the trace id for this log.
+ * @param trace_id the trace id to set
+ */
+ void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept override;
+
+ /**
+ * Set the span id for this log.
+ * @param span_id the span id to set
+ */
+ void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept override;
+
+ /**
+ * Inject trace_flags for this log.
+ * @param trace_flags the trace flags to set
+ */
+ void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept override;
+
+ /**
+ * Set instrumentation_library for this log.
+ * @param instrumentation_library the instrumentation library to set
+ */
+ void SetInstrumentationLibrary(
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library) noexcept override;
+
+ /** Returns the associated instruementation library */
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary &
+ GetInstrumentationLibrary() const noexcept;
+
+private:
+ std::unordered_map<std::size_t, std::unique_ptr<Recordable>> recordables_;
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ *instrumentation_library_ = nullptr;
+};
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/processor.h
new file mode 100644
index 000000000..36da036f3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/processor.h
@@ -0,0 +1,61 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <chrono>
+# include <memory>
+# include "opentelemetry/sdk/logs/recordable.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * The Log Processor is responsible for passing log records
+ * to the configured exporter.
+ */
+class LogProcessor
+{
+public:
+ virtual ~LogProcessor() = default;
+
+ /**
+ * Create a log recordable. This requests a new log recordable from the
+ * associated exporter.
+ * @return a newly initialized recordable
+ *
+ * Note: This method must be callable from multiple threads.
+ */
+ virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0;
+
+ /**
+ * OnReceive is called by the SDK once a log record has been successfully created.
+ * @param record the log record
+ */
+ virtual void OnReceive(std::unique_ptr<Recordable> &&record) noexcept = 0;
+
+ /**
+ * Exports all log records that have not yet been exported to the configured Exporter.
+ * @param timeout that the forceflush is required to finish within.
+ * @return a result code indicating whether it succeeded, failed or timed out
+ */
+ virtual bool ForceFlush(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0;
+
+ /**
+ * Shuts down the processor and does any cleanup required.
+ * ShutDown should only be called once for each processor.
+ * @param timeout minimum amount of microseconds to wait for
+ * shutdown before giving up and returning failure.
+ * @return true if the shutdown succeeded, false otherwise
+ */
+ virtual bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/recordable.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/recordable.h
new file mode 100644
index 000000000..4a3227373
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/recordable.h
@@ -0,0 +1,97 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/common/attribute_value.h"
+# include "opentelemetry/common/key_value_iterable.h"
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/logs/severity.h"
+# include "opentelemetry/sdk/common/empty_attributes.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/trace/span.h"
+# include "opentelemetry/trace/span_context.h"
+# include "opentelemetry/trace/span_id.h"
+# include "opentelemetry/trace/trace_flags.h"
+# include "opentelemetry/trace/trace_id.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * Maintains a representation of a log in a format that can be processed by a recorder.
+ *
+ * This class is thread-compatible.
+ */
+class Recordable
+{
+public:
+ virtual ~Recordable() = default;
+
+ /**
+ * Set the timestamp for this log.
+ * @param timestamp the timestamp to set
+ */
+ virtual void SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept = 0;
+
+ /**
+ * Set the severity for this log.
+ * @param severity the severity of the event
+ */
+ virtual void SetSeverity(opentelemetry::logs::Severity severity) noexcept = 0;
+
+ /**
+ * Set body field for this log.
+ * @param message the body to set
+ */
+ virtual void SetBody(nostd::string_view message) noexcept = 0;
+
+ /**
+ * Set Resource of this log
+ * @param Resource the resource to set
+ */
+ virtual void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept = 0;
+
+ /**
+ * Set an attribute of a log.
+ * @param key the name of the attribute
+ * @param value the attribute value
+ */
+ virtual void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept = 0;
+
+ /**
+ * Set the trace id for this log.
+ * @param trace_id the trace id to set
+ */
+ virtual void SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept = 0;
+
+ /**
+ * Set the span id for this log.
+ * @param span_id the span id to set
+ */
+ virtual void SetSpanId(opentelemetry::trace::SpanId span_id) noexcept = 0;
+
+ /**
+ * Inject trace_flags for this log.
+ * @param trace_flags the trace flags to set
+ */
+ virtual void SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept = 0;
+
+ /**
+ * Set instrumentation_library for this log.
+ * @param instrumentation_library the instrumentation library to set
+ */
+ virtual void SetInstrumentationLibrary(
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library) noexcept = 0;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h
new file mode 100644
index 000000000..cc3aec47b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/logs/simple_log_processor.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <atomic>
+# include <mutex>
+
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/logs/exporter.h"
+# include "opentelemetry/sdk/logs/processor.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * The simple log processor passes all log records
+ * in a batch of 1 to the configured
+ * LogExporter.
+ *
+ * All calls to the configured LogExporter are synchronized using a
+ * spin-lock on an atomic_flag.
+ */
+class SimpleLogProcessor : public LogProcessor
+{
+
+public:
+ explicit SimpleLogProcessor(std::unique_ptr<LogExporter> &&exporter);
+ virtual ~SimpleLogProcessor() = default;
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override;
+
+ void OnReceive(std::unique_ptr<Recordable> &&record) noexcept override;
+
+ bool ForceFlush(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+private:
+ // The configured exporter
+ std::unique_ptr<LogExporter> exporter_;
+ // The lock used to ensure the exporter is not called concurrently
+ opentelemetry::common::SpinLockMutex lock_;
+ // The atomic boolean flag to ensure the ShutDown() function is only called once
+ std::atomic_flag shutdown_latch_ = ATOMIC_FLAG_INIT;
+};
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation.h
new file mode 100644
index 000000000..7ec9a6ea2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/metrics/data/metric_data.h"
+# include "opentelemetry/sdk/metrics/data/point_data.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class Aggregation
+{
+public:
+ virtual void Aggregate(long value, const PointAttributes &attributes = {}) noexcept = 0;
+
+ virtual void Aggregate(double value, const PointAttributes &attributes = {}) noexcept = 0;
+
+ /**
+ * Returns the result of the merge of the two aggregations.
+ *
+ * This should always assume that the aggregations do not overlap and merge together for a new
+ * cumulative report.
+ *
+ * @param delta the newly captured (delta) aggregation
+ * @return the result of the merge of the given aggregation.
+ */
+
+ virtual std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept = 0;
+
+ /**
+ * Returns a new delta aggregation by comparing two cumulative measurements.
+ *
+ * @param next the newly captured (cumulative) aggregation.
+ * @return The resulting delta aggregation.
+ */
+ virtual std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept = 0;
+
+ /**
+ * Returns the point data that the aggregation will produce.
+ *
+ * @return PointType
+ */
+
+ virtual PointType ToPoint() const noexcept = 0;
+
+ virtual ~Aggregation() = default;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h
new file mode 100644
index 000000000..887e1beb9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h
@@ -0,0 +1,146 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/drop_aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/sum_aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class DefaultAggregation
+{
+public:
+ static std::unique_ptr<Aggregation> CreateAggregation(
+ const opentelemetry::sdk::metrics::InstrumentDescriptor &instrument_descriptor)
+ {
+ switch (instrument_descriptor.type_)
+ {
+ case InstrumentType::kCounter:
+ case InstrumentType::kUpDownCounter:
+ case InstrumentType::kObservableCounter:
+ case InstrumentType::kObservableUpDownCounter:
+ return (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ ? std::move(std::unique_ptr<Aggregation>(new LongSumAggregation()))
+ : std::move(std::unique_ptr<Aggregation>(new DoubleSumAggregation()));
+ break;
+ case InstrumentType::kHistogram:
+ return (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ ? std::move(std::unique_ptr<Aggregation>(new LongHistogramAggregation()))
+ : std::move(std::unique_ptr<Aggregation>(new DoubleHistogramAggregation()));
+ break;
+ case InstrumentType::kObservableGauge:
+ return (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ ? std::move(std::unique_ptr<Aggregation>(new LongLastValueAggregation()))
+ : std::move(std::unique_ptr<Aggregation>(new DoubleLastValueAggregation()));
+ break;
+ default:
+ return std::move(std::unique_ptr<Aggregation>(new DropAggregation()));
+ };
+ }
+
+ static std::unique_ptr<Aggregation> CreateAggregation(AggregationType aggregation_type,
+ InstrumentDescriptor instrument_descriptor)
+ {
+ switch (aggregation_type)
+ {
+ case AggregationType::kDrop:
+ return std::unique_ptr<Aggregation>(new DropAggregation());
+ break;
+ case AggregationType::kHistogram:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(new LongHistogramAggregation());
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(new DoubleHistogramAggregation());
+ }
+ break;
+ case AggregationType::kLastValue:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation());
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(new DoubleLastValueAggregation());
+ }
+ break;
+ case AggregationType::kSum:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(new LongSumAggregation());
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(new DoubleSumAggregation());
+ }
+ break;
+ default:
+ return DefaultAggregation::CreateAggregation(instrument_descriptor);
+ }
+ }
+
+ static std::unique_ptr<Aggregation> CloneAggregation(AggregationType aggregation_type,
+ InstrumentDescriptor instrument_descriptor,
+ const Aggregation &to_copy)
+ {
+ const PointType point_data = to_copy.ToPoint();
+ switch (aggregation_type)
+ {
+ case AggregationType::kDrop:
+ return std::unique_ptr<Aggregation>(new DropAggregation());
+ case AggregationType::kHistogram:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(
+ new LongHistogramAggregation(nostd::get<HistogramPointData>(point_data)));
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(
+ new DoubleHistogramAggregation(nostd::get<HistogramPointData>(point_data)));
+ }
+ case AggregationType::kLastValue:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(
+ new LongLastValueAggregation(nostd::get<LastValuePointData>(point_data)));
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(
+ new DoubleLastValueAggregation(nostd::get<LastValuePointData>(point_data)));
+ }
+ case AggregationType::kSum:
+ if (instrument_descriptor.value_type_ == InstrumentValueType::kLong)
+ {
+ return std::unique_ptr<Aggregation>(
+ new LongSumAggregation(nostd::get<SumPointData>(point_data)));
+ }
+ else
+ {
+ return std::unique_ptr<Aggregation>(
+ new DoubleSumAggregation(nostd::get<SumPointData>(point_data)));
+ }
+ default:
+ return DefaultAggregation::CreateAggregation(instrument_descriptor);
+ }
+ }
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/drop_aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/drop_aggregation.h
new file mode 100644
index 000000000..6c3d89d24
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/drop_aggregation.h
@@ -0,0 +1,51 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+/**
+ * A null Aggregation which denotes no aggregation should occur.
+ */
+
+class DropAggregation : public Aggregation
+{
+public:
+ DropAggregation() = default;
+
+ DropAggregation(const DropPointData &) {}
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override {}
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override {}
+
+ std::unique_ptr<Aggregation> Merge(const Aggregation &) const noexcept override
+ {
+ return std::unique_ptr<Aggregation>(new DropAggregation());
+ }
+
+ std::unique_ptr<Aggregation> Diff(const Aggregation &) const noexcept override
+ {
+ return std::unique_ptr<Aggregation>(new DropAggregation());
+ }
+
+ PointType ToPoint() const noexcept override
+ {
+ static DropPointData point_data;
+ return point_data;
+ }
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h
new file mode 100644
index 000000000..e2a55fba5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h
@@ -0,0 +1,103 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class LongHistogramAggregation : public Aggregation
+{
+public:
+ LongHistogramAggregation();
+ LongHistogramAggregation(HistogramPointData &&);
+ LongHistogramAggregation(const HistogramPointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override;
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override {}
+
+ /* Returns the result of merge of the existing aggregation with delta aggregation with same
+ * boundaries */
+ std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ /* Returns the new delta aggregation by comparing existing aggregation with next aggregation with
+ * same boundaries. Data points for `next` aggregation (sum , bucket-counts) should be more than
+ * the current aggregation - which is the normal scenario as measurements values are monotonic
+ * increasing.
+ */
+ std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ opentelemetry::common::SpinLockMutex lock_;
+ HistogramPointData point_data_;
+};
+
+class DoubleHistogramAggregation : public Aggregation
+{
+public:
+ DoubleHistogramAggregation();
+ DoubleHistogramAggregation(HistogramPointData &&);
+ DoubleHistogramAggregation(const HistogramPointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override {}
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override;
+
+ /* Returns the result of merge of the existing aggregation with delta aggregation with same
+ * boundaries */
+ std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ /* Returns the new delta aggregation by comparing existing aggregation with next aggregation with
+ * same boundaries. Data points for `next` aggregation (sum , bucket-counts) should be more than
+ * the current aggregation - which is the normal scenario as measurements values are monotonic
+ * increasing.
+ */
+ std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ mutable opentelemetry::common::SpinLockMutex lock_;
+ mutable HistogramPointData point_data_;
+};
+
+template <class T>
+void HistogramMerge(HistogramPointData &current,
+ HistogramPointData &delta,
+ HistogramPointData &merge)
+{
+ for (size_t i = 0; i < current.counts_.size(); i++)
+ {
+ merge.counts_[i] = current.counts_[i] + delta.counts_[i];
+ }
+ merge.boundaries_ = current.boundaries_;
+ merge.sum_ = nostd::get<T>(current.sum_) + nostd::get<T>(delta.sum_);
+ merge.count_ = current.count_ + delta.count_;
+}
+
+template <class T>
+void HistogramDiff(HistogramPointData &current, HistogramPointData &next, HistogramPointData &diff)
+{
+ for (size_t i = 0; i < current.counts_.size(); i++)
+ {
+ diff.counts_[i] = next.counts_[i] - current.counts_[i];
+ }
+ diff.boundaries_ = current.boundaries_;
+ diff.count_ = next.count_ - current.count_;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h
new file mode 100644
index 000000000..3b2c08f8c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h
@@ -0,0 +1,63 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class LongLastValueAggregation : public Aggregation
+{
+public:
+ LongLastValueAggregation();
+ LongLastValueAggregation(LastValuePointData &&);
+ LongLastValueAggregation(const LastValuePointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override;
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override {}
+
+ std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ opentelemetry::common::SpinLockMutex lock_;
+ LastValuePointData point_data_;
+};
+
+class DoubleLastValueAggregation : public Aggregation
+{
+public:
+ DoubleLastValueAggregation();
+ DoubleLastValueAggregation(LastValuePointData &&);
+ DoubleLastValueAggregation(const LastValuePointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override {}
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override;
+
+ virtual std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ virtual std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ mutable opentelemetry::common::SpinLockMutex lock_;
+ mutable LastValuePointData point_data_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/sum_aggregation.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/sum_aggregation.h
new file mode 100644
index 000000000..14f13bd72
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/aggregation/sum_aggregation.h
@@ -0,0 +1,64 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class LongSumAggregation : public Aggregation
+{
+public:
+ LongSumAggregation();
+ LongSumAggregation(SumPointData &&);
+ LongSumAggregation(const SumPointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override;
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override {}
+
+ std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ opentelemetry::common::SpinLockMutex lock_;
+ SumPointData point_data_;
+};
+
+class DoubleSumAggregation : public Aggregation
+{
+public:
+ DoubleSumAggregation();
+ DoubleSumAggregation(SumPointData &&);
+ DoubleSumAggregation(const SumPointData &);
+
+ void Aggregate(long value, const PointAttributes &attributes = {}) noexcept override {}
+
+ void Aggregate(double value, const PointAttributes &attributes = {}) noexcept override;
+
+ std::unique_ptr<Aggregation> Merge(const Aggregation &delta) const noexcept override;
+
+ std::unique_ptr<Aggregation> Diff(const Aggregation &next) const noexcept override;
+
+ PointType ToPoint() const noexcept override;
+
+private:
+ mutable opentelemetry::common::SpinLockMutex lock_;
+ SumPointData point_data_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/async_instruments.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/async_instruments.h
new file mode 100644
index 000000000..8b1f76377
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/async_instruments.h
@@ -0,0 +1,115 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/metrics/async_instruments.h"
+# include "opentelemetry/metrics/observer_result.h"
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+template <class T>
+class Asynchronous
+{
+public:
+ Asynchronous(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : name_(name), callback_(callback), description_(description), unit_(unit)
+ {}
+
+protected:
+ std::string name_;
+ void (*callback_)(opentelemetry::metrics::ObserverResult<T> &);
+ std::string description_;
+ std::string unit_;
+};
+
+class LongObservableCounter : public opentelemetry::metrics::ObservableCounter<long>,
+ public Asynchronous<long>
+{
+public:
+ LongObservableCounter(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+
+ {}
+};
+
+class DoubleObservableCounter : public opentelemetry::metrics::ObservableCounter<double>,
+ public Asynchronous<double>
+{
+public:
+ DoubleObservableCounter(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+
+ {}
+};
+
+class LongObservableGauge : public opentelemetry::metrics::ObservableGauge<long>,
+ public Asynchronous<long>
+{
+public:
+ LongObservableGauge(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+
+ {}
+};
+
+class DoubleObservableGauge : public opentelemetry::metrics::ObservableGauge<double>,
+ public Asynchronous<double>
+{
+public:
+ DoubleObservableGauge(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+
+ {}
+};
+
+class LongObservableUpDownCounter : public opentelemetry::metrics::ObservableUpDownCounter<long>,
+ public Asynchronous<long>
+{
+public:
+ LongObservableUpDownCounter(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+
+ {}
+};
+
+class DoubleObservableUpDownCounter
+ : public opentelemetry::metrics::ObservableUpDownCounter<double>,
+ public Asynchronous<double>
+{
+public:
+ DoubleObservableUpDownCounter(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &),
+ nostd::string_view description = "",
+ nostd::string_view unit = "")
+ : Asynchronous(name, callback, description, unit)
+ {}
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h
new file mode 100644
index 000000000..738d4540f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/metric_data.h
@@ -0,0 +1,42 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/nostd/variant.h"
+# include "opentelemetry/sdk/common/attribute_utils.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/data/point_data.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+using PointAttributes = opentelemetry::sdk::common::OrderedAttributeMap;
+using PointType = opentelemetry::nostd::
+ variant<SumPointData, HistogramPointData, LastValuePointData, DropPointData>;
+
+struct PointDataAttributes
+{
+ PointAttributes attributes;
+ PointType point_data;
+};
+
+class MetricData
+{
+public:
+ InstrumentDescriptor instrument_descriptor;
+ opentelemetry::common::SystemTimestamp start_ts;
+ opentelemetry::common::SystemTimestamp end_ts;
+ std::vector<PointDataAttributes> point_data_attr_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/point_data.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/point_data.h
new file mode 100644
index 000000000..714f96c9a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/data/point_data.h
@@ -0,0 +1,78 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/nostd/variant.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/version.h"
+
+# include <list>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+using ValueType = nostd::variant<long, double>;
+using ListType = nostd::variant<std::list<long>, std::list<double>>;
+
+// TODO: remove ctors and initializers from below classes when GCC<5 stops shipping on Ubuntu
+
+class SumPointData
+{
+public:
+ // TODO: remove ctors and initializers when GCC<5 stops shipping on Ubuntu
+ SumPointData(SumPointData &&) = default;
+ SumPointData(const SumPointData &) = default;
+ SumPointData &operator=(SumPointData &&) = default;
+ SumPointData() = default;
+
+ ValueType value_ = {};
+};
+
+class LastValuePointData
+{
+public:
+ // TODO: remove ctors and initializers when GCC<5 stops shipping on Ubuntu
+ LastValuePointData(LastValuePointData &&) = default;
+ LastValuePointData(const LastValuePointData &) = default;
+ LastValuePointData &operator=(LastValuePointData &&) = default;
+ LastValuePointData() = default;
+
+ ValueType value_ = {};
+ bool is_lastvalue_valid_ = {};
+ opentelemetry::common::SystemTimestamp sample_ts_ = {};
+};
+
+class HistogramPointData
+{
+public:
+ // TODO: remove ctors and initializers when GCC<5 stops shipping on Ubuntu
+ HistogramPointData(HistogramPointData &&) = default;
+ HistogramPointData &operator=(HistogramPointData &&) = default;
+ HistogramPointData(const HistogramPointData &) = default;
+ HistogramPointData() = default;
+
+ ListType boundaries_ = {};
+ ValueType sum_ = {};
+ std::vector<uint64_t> counts_ = {};
+ uint64_t count_ = {};
+};
+
+class DropPointData
+{
+public:
+ // TODO: remove ctors and initializers when GCC<5 stops shipping on Ubuntu
+ DropPointData(DropPointData &&) = default;
+ DropPointData(const DropPointData &) = default;
+ DropPointData() = default;
+ DropPointData &operator=(DropPointData &&) = default;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/always_sample_filter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/always_sample_filter.h
new file mode 100644
index 000000000..5e7f0436e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/always_sample_filter.h
@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/exemplar/filter.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class AlwaysSampleFilter final : public ExemplarFilter
+{
+public:
+ static nostd::shared_ptr<ExemplarFilter> GetAlwaysSampleFilter()
+ {
+ static nostd::shared_ptr<ExemplarFilter> alwaysSampleFilter{new AlwaysSampleFilter{}};
+ return alwaysSampleFilter;
+ }
+
+ bool ShouldSampleMeasurement(long value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ return true;
+ }
+
+ bool ShouldSampleMeasurement(double value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ return true;
+ }
+
+private:
+ explicit AlwaysSampleFilter() = default;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/data.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/data.h
new file mode 100644
index 000000000..14eac6249
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/data.h
@@ -0,0 +1,45 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/context/context.h"
+# include "opentelemetry/sdk/common/attribute_utils.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+using MetricAttributes = opentelemetry::sdk::common::OrderedAttributeMap;
+/**
+ * A sample input measurement.
+ *
+ * Exemplars also hold information about the environment when the measurement was recorded, for
+ * example the span and trace ID of the active span when the exemplar was recorded.
+ */
+class ExemplarData
+{
+public:
+ /**
+ * The set of key/value pairs that were filtered out by the aggregator, but recorded alongside the
+ * original measurement. Only key/value pairs that were filtered out by the aggregator should be
+ * included
+ */
+ MetricAttributes GetFilteredAttributes();
+
+ /** Returns the timestamp in nanos when measurement was collected. */
+ opentelemetry::common::SystemTimestamp GetEpochNanos();
+
+ /**
+ * Returns the SpanContext associated with this exemplar. If the exemplar was not recorded
+ * inside a sampled trace, the Context will be invalid.
+ */
+ opentelemetry::context::Context GetSpanContext();
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/filter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/filter.h
new file mode 100644
index 000000000..4b512e131
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/filter.h
@@ -0,0 +1,39 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/context/context.h"
+# include "opentelemetry/sdk/common/attribute_utils.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+using MetricAttributes = opentelemetry::sdk::common::OrderedAttributeMap;
+
+/**
+ * Exemplar filters are used to pre-filter measurements before attempting to store them in a
+ * reservoir.
+ */
+class ExemplarFilter
+{
+public:
+ // Returns whether or not a reservoir should attempt to filter a measurement.
+ virtual bool ShouldSampleMeasurement(long value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept = 0;
+
+ // Returns whether or not a reservoir should attempt to filter a measurement.
+ virtual bool ShouldSampleMeasurement(double value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept = 0;
+
+ virtual ~ExemplarFilter() = default;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/never_sample_filter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/never_sample_filter.h
new file mode 100644
index 000000000..38f51778c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/never_sample_filter.h
@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/exemplar/filter.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class NeverSampleFilter final : public ExemplarFilter
+{
+public:
+ static nostd::shared_ptr<ExemplarFilter> GetNeverSampleFilter()
+ {
+ nostd::shared_ptr<ExemplarFilter> neverSampleFilter{new NeverSampleFilter{}};
+ return neverSampleFilter;
+ }
+
+ bool ShouldSampleMeasurement(long value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ return false;
+ }
+
+ bool ShouldSampleMeasurement(double value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ return false;
+ }
+
+private:
+ explicit NeverSampleFilter() = default;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h
new file mode 100644
index 000000000..1fe0586d2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <vector>
+# include "opentelemetry/context/context.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/common/attribute_utils.h"
+# include "opentelemetry/sdk/metrics/exemplar/reservoir.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class NoExemplarReservoir final : public ExemplarReservoir
+{
+
+public:
+ static nostd::shared_ptr<ExemplarReservoir> GetNoExemplarReservoir()
+ {
+ return nostd::shared_ptr<ExemplarReservoir>{new NoExemplarReservoir{}};
+ }
+
+ void OfferMeasurement(long value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context,
+ const opentelemetry::common::SystemTimestamp &timestamp) noexcept override
+ {
+ // Stores nothing
+ }
+
+ void OfferMeasurement(double value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context,
+ const opentelemetry::common::SystemTimestamp &timestamp) noexcept override
+ {
+ // Stores nothing.
+ }
+
+ std::vector<ExemplarData> CollectAndReset(
+ const MetricAttributes &pointAttributes) noexcept override
+ {
+ return std::vector<ExemplarData>{};
+ }
+
+private:
+ explicit NoExemplarReservoir() = default;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h
new file mode 100644
index 000000000..25e8421d6
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <vector>
+# include "opentelemetry/sdk/metrics/exemplar/data.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+/**
+ * An interface for an exemplar reservoir of samples.
+ *
+ * <p>This represents a reservoir for a specific "point" of metric data.
+ */
+class ExemplarReservoir
+{
+public:
+ virtual ~ExemplarReservoir() = default;
+
+ /** Offers a long measurement to be sampled. */
+ virtual void OfferMeasurement(
+ long value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context,
+ const opentelemetry::common::SystemTimestamp &timestamp) noexcept = 0;
+
+ /** Offers a double measurement to be sampled. */
+ virtual void OfferMeasurement(
+ double value,
+ const MetricAttributes &attributes,
+ const opentelemetry::context::Context &context,
+ const opentelemetry::common::SystemTimestamp &timestamp) noexcept = 0;
+
+ /**
+ * Builds vector of Exemplars for exporting from the current reservoir.
+ *
+ * <p>Additionally, clears the reservoir for the next sampling period.
+ *
+ * @param pointAttributes the Attributes associated with the metric point.
+ * ExemplarDatas should filter these out of their final data state.
+ * @return A vector of sampled exemplars for this point. Implementers are expected to
+ * filter out pointAttributes from the original recorded attributes.
+ */
+ virtual std::vector<ExemplarData> CollectAndReset(
+ const MetricAttributes &pointAttributes) noexcept = 0;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/metric_producer.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/metric_producer.h
new file mode 100644
index 000000000..d3b38759a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/metric_producer.h
@@ -0,0 +1,57 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/data/metric_data.h"
+# include "opentelemetry/sdk/resource/resource.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+/**
+ * Metric Data to be exported along with resources and
+ * Instrumentation library.
+ */
+struct InstrumentationInfoMetrics
+{
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ *instrumentation_library_;
+ std::vector<MetricData> metric_data_;
+};
+
+struct ResourceMetrics
+{
+ const opentelemetry::sdk::resource::Resource *resource_;
+ std::vector<InstrumentationInfoMetrics> instrumentation_info_metric_data_;
+};
+
+/**
+ * MetricProducer is the interface that is used to make metric data available to the
+ * OpenTelemetry exporters. Implementations should be stateful, in that each call to
+ * `Collect` will return any metric generated since the last call was made.
+ *
+ * <p>Implementations must be thread-safe.
+ */
+
+class MetricProducer
+{
+public:
+ /**
+ * The callback to be called for each metric exporter. This will only be those
+ * metrics that have been produced since the last time this method was called.
+ *
+ * @return a status of completion of method.
+ */
+ virtual bool Collect(
+ nostd::function_ref<bool(ResourceMetrics &metric_data)> callback) noexcept = 0;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h
new file mode 100644
index 000000000..29125a6ea
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h
@@ -0,0 +1,72 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/version.h"
+
+# include <atomic>
+# include <chrono>
+# include <condition_variable>
+# include <thread>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class MetricExporter;
+/**
+ * Struct to hold PeriodicExortingMetricReader options.
+ */
+
+constexpr std::chrono::milliseconds kExportIntervalMillis = std::chrono::milliseconds(60000);
+constexpr std::chrono::milliseconds kExportTimeOutMillis = std::chrono::milliseconds(30000);
+struct PeriodicExportingMetricReaderOptions
+{
+
+ /* The time interval between two consecutive exports. */
+ std::chrono::milliseconds export_interval_millis =
+ std::chrono::milliseconds(kExportIntervalMillis);
+
+ /* how long the export can run before it is cancelled. */
+ std::chrono::milliseconds export_timeout_millis = std::chrono::milliseconds(kExportTimeOutMillis);
+};
+
+class PeriodicExportingMetricReader : public MetricReader
+{
+
+public:
+ PeriodicExportingMetricReader(
+ std::unique_ptr<MetricExporter> exporter,
+ const PeriodicExportingMetricReaderOptions &option,
+ AggregationTemporality aggregation_temporality = AggregationTemporality::kCumulative);
+
+private:
+ bool OnForceFlush(std::chrono::microseconds timeout) noexcept override;
+
+ bool OnShutDown(std::chrono::microseconds timeout) noexcept override;
+
+ void OnInitialized() noexcept override;
+
+ std::unique_ptr<MetricExporter> exporter_;
+ std::chrono::milliseconds export_interval_millis_;
+ std::chrono::milliseconds export_timeout_millis_;
+
+ void DoBackgroundWork();
+
+ /* The background worker thread */
+ std::thread worker_thread_;
+
+ /* Synchronization primitives */
+ std::condition_variable cv_;
+ std::mutex cv_m_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/instruments.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/instruments.h
new file mode 100644
index 000000000..5d8535714
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/instruments.h
@@ -0,0 +1,70 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/common/attribute_utils.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+enum class InstrumentType
+{
+ kCounter,
+ kHistogram,
+ kUpDownCounter,
+ kObservableCounter,
+ kObservableGauge,
+ kObservableUpDownCounter
+};
+
+enum class InstrumentValueType
+{
+ kInt,
+ kLong,
+ kFloat,
+ kDouble
+};
+
+enum class AggregationType
+{
+ kDrop,
+ kHistogram,
+ kLastValue,
+ kSum,
+ kDefault
+};
+
+enum class AggregationTemporality
+{
+ kUnspecified,
+ kDelta,
+ kCumulative
+};
+
+struct InstrumentDescriptor
+{
+ std::string name_;
+ std::string description_;
+ std::string unit_;
+ InstrumentType type_;
+ InstrumentValueType value_type_;
+};
+
+using MetricAttributes = opentelemetry::sdk::common::OrderedAttributeMap;
+
+/*class InstrumentSelector {
+public:
+InstrumentSelector(opentelemetry::nostd::string_view name,
+opentelemetry::sdk::metrics::InstrumentType type): name_(name.data()), type_(type) {} InstrumentType
+GetType(){return type_;} std::string GetNameFilter() { return name_;}
+
+private:
+std::string name_;
+InstrumentType type_;
+};*/
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter.h
new file mode 100644
index 000000000..44e54adf1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter.h
@@ -0,0 +1,156 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <chrono>
+# include "opentelemetry/metrics/meter.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/metrics/state/async_metric_storage.h"
+
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class MetricStorage;
+class WritableMetricStorage;
+
+class Meter final : public opentelemetry::metrics::Meter
+{
+public:
+ /** Construct a new Meter with the given pipeline. */
+ explicit Meter(std::shared_ptr<sdk::metrics::MeterContext> meter_context,
+ std::unique_ptr<opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary>
+ instrumentation_library =
+ opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create(
+ "")) noexcept;
+
+ nostd::shared_ptr<opentelemetry::metrics::Counter<long>> CreateLongCounter(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Counter<double>> CreateDoubleCounter(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ void CreateLongObservableCounter(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &,
+ void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ void CreateDoubleObservableCounter(
+ nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &, void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Histogram<long>> CreateLongHistogram(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ nostd::shared_ptr<opentelemetry::metrics::Histogram<double>> CreateDoubleHistogram(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ void CreateLongObservableGauge(nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &,
+ void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ void CreateDoubleObservableGauge(
+ nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &, void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<long>> CreateLongUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<double>> CreateDoubleUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description = "",
+ nostd::string_view unit = "") noexcept override;
+
+ void CreateLongObservableUpDownCounter(
+ nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<long> &, void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ void CreateDoubleObservableUpDownCounter(
+ nostd::string_view name,
+ void (*callback)(opentelemetry::metrics::ObserverResult<double> &, void *),
+ nostd::string_view description = "",
+ nostd::string_view unit = "",
+ void *state = nullptr) noexcept override;
+
+ /** Returns the associated instruementation library */
+ const sdk::instrumentationlibrary::InstrumentationLibrary *GetInstrumentationLibrary()
+ const noexcept;
+
+ /** collect metrics across all the instruments configured for the meter **/
+ std::vector<MetricData> Collect(CollectorHandle *collector,
+ opentelemetry::common::SystemTimestamp collect_ts) noexcept;
+
+private:
+ // order of declaration is important here - instrumentation library should destroy after
+ // meter-context.
+ std::unique_ptr<sdk::instrumentationlibrary::InstrumentationLibrary> instrumentation_library_;
+ std::shared_ptr<sdk::metrics::MeterContext> meter_context_;
+ // Mapping between instrument-name and Aggregation Storage.
+ std::unordered_map<std::string, std::shared_ptr<MetricStorage>> storage_registry_;
+
+ std::unique_ptr<WritableMetricStorage> RegisterMetricStorage(
+ InstrumentDescriptor &instrument_descriptor);
+
+ template <class T>
+ void RegisterAsyncMetricStorage(InstrumentDescriptor &instrument_descriptor,
+ void (*callback)(opentelemetry::metrics::ObserverResult<T> &,
+ void *),
+ void *state = nullptr)
+ {
+ auto view_registry = meter_context_->GetViewRegistry();
+ auto success = view_registry->FindViews(
+ instrument_descriptor, *instrumentation_library_,
+ [this, &instrument_descriptor, callback, state](const View &view) {
+ auto view_instr_desc = instrument_descriptor;
+ if (!view.GetName().empty())
+ {
+ view_instr_desc.name_ = view.GetName();
+ }
+ if (!view.GetDescription().empty())
+ {
+ view_instr_desc.description_ = view.GetDescription();
+ }
+ auto storage = std::shared_ptr<AsyncMetricStorage<T>>(
+ new AsyncMetricStorage<T>(view_instr_desc, view.GetAggregationType(), callback,
+ &view.GetAttributesProcessor(), state));
+ storage_registry_[instrument_descriptor.name_] = storage;
+ return true;
+ });
+ }
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_context.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_context.h
new file mode 100644
index 000000000..e35700175
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_context.h
@@ -0,0 +1,133 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+# include "opentelemetry/sdk/metrics/view/instrument_selector.h"
+# include "opentelemetry/sdk/metrics/view/meter_selector.h"
+# include "opentelemetry/sdk/metrics/view/view_registry.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+# include <chrono>
+# include <memory>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+// forward declaration
+class Meter;
+class MetricReader;
+
+/**
+ * A class which stores the MeterProvider context.
+
+ */
+class MeterContext : public std::enable_shared_from_this<MeterContext>
+{
+public:
+ /**
+ * Initialize a new meter provider
+ * @param readers The readers to be configured with meter context.
+ * @param views The views to be configured with meter context.
+ * @param resource The resource for this meter context.
+ */
+ MeterContext(
+ std::unique_ptr<ViewRegistry> views = std::unique_ptr<ViewRegistry>(new ViewRegistry()),
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({})) noexcept;
+
+ /**
+ * Obtain the resource associated with this meter context.
+ * @return The resource for this meter context
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Obtain the View Registry configured
+ * @return The reference to view registry
+ */
+ ViewRegistry *GetViewRegistry() const noexcept;
+
+ /**
+ * Obtain the configured meters.
+ *
+ */
+ nostd::span<std::shared_ptr<Meter>> GetMeters() noexcept;
+
+ /**
+ * Obtain the configured collectors.
+ *
+ */
+ nostd::span<std::shared_ptr<CollectorHandle>> GetCollectors() noexcept;
+
+ /**
+ * GET SDK Start time
+ *
+ */
+ opentelemetry::common::SystemTimestamp GetSDKStartTime() noexcept;
+
+ /**
+ * Attaches a metric reader to list of configured readers for this Meter context.
+ * @param reader The metric reader for this meter context. This
+ * must not be a nullptr.
+ *
+ * Note: This reader may not receive any in-flight meter data, but will get newly created meter
+ * data. Note: This method is not thread safe, and should ideally be called from main thread.
+ */
+ void AddMetricReader(std::unique_ptr<MetricReader> reader) noexcept;
+
+ /**
+ * Attaches a View to list of configured Views for this Meter context.
+ * @param view The Views for this meter context. This
+ * must not be a nullptr.
+ *
+ * Note: This view may not receive any in-flight meter data, but will get newly created meter
+ * data. Note: This method is not thread safe, and should ideally be called from main thread.
+ */
+ void AddView(std::unique_ptr<InstrumentSelector> instrument_selector,
+ std::unique_ptr<MeterSelector> meter_selector,
+ std::unique_ptr<View> view) noexcept;
+
+ /**
+ * Adds a meter to the list of configured meters.
+ * Note: This method is INTERNAL to sdk not thread safe.
+ *
+ * @param meter
+ */
+ void AddMeter(std::shared_ptr<Meter> meter);
+
+ /**
+ * Force all active Collectors to flush any buffered meter data
+ * within the given timeout.
+ */
+
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+ /**
+ * Shutdown the Collectors associated with this meter provider.
+ */
+ bool Shutdown() noexcept;
+
+private:
+ opentelemetry::sdk::resource::Resource resource_;
+ std::vector<std::shared_ptr<CollectorHandle>> collectors_;
+ std::unique_ptr<ViewRegistry> views_;
+ opentelemetry::common::SystemTimestamp sdk_start_ts_;
+ std::vector<std::shared_ptr<Meter>> meters_;
+
+ std::atomic_flag shutdown_latch_ = ATOMIC_FLAG_INIT;
+ opentelemetry::common::SpinLockMutex forceflush_lock_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_provider.h
new file mode 100644
index 000000000..685f43e74
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/meter_provider.h
@@ -0,0 +1,95 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <memory>
+# include <mutex>
+# include <vector>
+# include "opentelemetry/metrics/meter.h"
+# include "opentelemetry/metrics/meter_provider.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/metrics/meter.h"
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/resource/resource.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+// forward declaration
+class MetricCollector;
+class MetricReader;
+
+class MeterProvider final : public opentelemetry::metrics::MeterProvider
+{
+public:
+ /**
+ * Initialize a new meter provider
+ * @param views The views for this meter provider
+ * @param resource The resources for this meter provider.
+ */
+ MeterProvider(
+ std::unique_ptr<ViewRegistry> views = std::unique_ptr<ViewRegistry>(new ViewRegistry()),
+ sdk::resource::Resource resource = sdk::resource::Resource::Create({})) noexcept;
+
+ /**
+ * Initialize a new meter provider with a specified context
+ * @param context The shared meter configuration/pipeline for this provider.
+ */
+ explicit MeterProvider(std::shared_ptr<sdk::metrics::MeterContext> context) noexcept;
+
+ nostd::shared_ptr<opentelemetry::metrics::Meter> GetMeter(
+ nostd::string_view name,
+ nostd::string_view version = "",
+ nostd::string_view schema_url = "") noexcept override;
+
+ /**
+ * Obtain the resource associated with this meter provider.
+ * @return The resource for this meter provider.
+ */
+ const sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Attaches a metric reader to list of configured readers for this Meter providers.
+ * @param reader The metric reader for this meter provider. This
+ * must not be a nullptr.
+ *
+ * Note: This reader may not receive any in-flight meter data, but will get newly created meter
+ * data. Note: This method is not thread safe, and should ideally be called from main thread.
+ */
+ void AddMetricReader(std::unique_ptr<MetricReader> reader) noexcept;
+
+ /**
+ * Attaches a View to list of configured Views for this Meter provider.
+ * @param view The Views for this meter provider. This
+ * must not be a nullptr.
+ *
+ * Note: This view may not receive any in-flight meter data, but will get newly created meter
+ * data. Note: This method is not thread safe, and should ideally be called from main thread.
+ */
+ void AddView(std::unique_ptr<InstrumentSelector> instrument_selector,
+ std::unique_ptr<MeterSelector> meter_selector,
+ std::unique_ptr<View> view) noexcept;
+
+ /**
+ * Shutdown the meter provider.
+ */
+ bool Shutdown() noexcept;
+
+ /**
+ * Force flush the meter provider.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+private:
+ std::shared_ptr<sdk::metrics::MeterContext> context_;
+ std::mutex lock_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h
new file mode 100644
index 000000000..3217b83df
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/nostd/span.h"
+# include "opentelemetry/sdk/common/exporter_utils.h"
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+# include "opentelemetry/version.h"
+
+# include <chrono>
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class MetricData;
+/**
+ * MetricExporter defines the interface to be used by metrics libraries to
+ * push metrics data to the OpenTelemetry exporters.
+ */
+class MetricExporter
+{
+public:
+ virtual ~MetricExporter() = default;
+
+ /**
+ * Exports a batch of metrics data. This method must not be called
+ * concurrently for the same exporter instance.
+ * @param data metrics data
+ */
+ virtual opentelemetry::sdk::common::ExportResult Export(const ResourceMetrics &data) noexcept = 0;
+
+ /**
+ * Force flush the exporter.
+ */
+ virtual bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0;
+
+ /**
+ * Shut down the metric exporter.
+ * @param timeout an optional timeout.
+ * @return return the status of the operation.
+ */
+ virtual bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h
new file mode 100644
index 000000000..94924315f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/metric_reader.h
@@ -0,0 +1,72 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# include "opentelemetry/sdk/metrics/data/metric_data.h"
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/version.h"
+
+# include <chrono>
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+/**
+ * MetricReader defines the interface to collect metrics from SDK
+ */
+class MetricReader
+{
+public:
+ MetricReader(
+ AggregationTemporality aggregation_temporality = AggregationTemporality::kCumulative);
+
+ void SetMetricProducer(MetricProducer *metric_producer);
+
+ /**
+ * Collect the metrics from SDK.
+ * @return return the status of the operation.
+ */
+ bool Collect(nostd::function_ref<bool(ResourceMetrics &metric_data)> callback) noexcept;
+
+ AggregationTemporality GetAggregationTemporality() const noexcept;
+
+ /**
+ * Shutdown the meter reader.
+ */
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept;
+
+ /**
+ * Force flush the metric read by the reader.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept;
+
+ virtual ~MetricReader() = default;
+
+private:
+ virtual bool OnForceFlush(std::chrono::microseconds timeout) noexcept = 0;
+
+ virtual bool OnShutDown(std::chrono::microseconds timeout) noexcept = 0;
+
+ virtual void OnInitialized() noexcept {}
+
+protected:
+ bool IsShutdown() const noexcept;
+
+private:
+ MetricProducer *metric_producer_;
+ AggregationTemporality aggregation_temporality_;
+ mutable opentelemetry::common::SpinLockMutex lock_;
+ bool shutdown_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/observer_result.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/observer_result.h
new file mode 100644
index 000000000..ca7227bc5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/observer_result.h
@@ -0,0 +1,48 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/key_value_iterable.h"
+# include "opentelemetry/metrics/observer_result.h"
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+# include <map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+template <class T>
+class ObserverResult final : public opentelemetry::metrics::ObserverResult<T>
+{
+public:
+ ObserverResult(const AttributesProcessor *attributes_processor)
+ : attributes_processor_(attributes_processor)
+ {}
+
+ void Observe(T value) noexcept override { data_.insert({{}, value}); }
+
+ void Observe(T value, const opentelemetry::common::KeyValueIterable &attributes) noexcept override
+ {
+ auto attr = attributes_processor_->process(attributes);
+ data_.insert({attr, value});
+ }
+
+ const std::unordered_map<MetricAttributes, T, AttributeHashGenerator> &GetMeasurements()
+ {
+ return data_;
+ }
+
+private:
+ std::unordered_map<MetricAttributes, T, AttributeHashGenerator> data_;
+
+ const AttributesProcessor *attributes_processor_;
+};
+} // namespace metrics
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h
new file mode 100644
index 000000000..e5dcbc273
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h
@@ -0,0 +1,95 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/common/attributemap_hash.h"
+# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/observer_result.h"
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+# include "opentelemetry/sdk/metrics/state/metric_storage.h"
+# include "opentelemetry/sdk/metrics/state/temporal_metric_storage.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+template <class T>
+class AsyncMetricStorage : public MetricStorage
+{
+public:
+ AsyncMetricStorage(InstrumentDescriptor instrument_descriptor,
+ const AggregationType aggregation_type,
+ void (*measurement_callback)(opentelemetry::metrics::ObserverResult<T> &,
+ void *),
+ const AttributesProcessor *attributes_processor,
+ void *state = nullptr)
+ : instrument_descriptor_(instrument_descriptor),
+ aggregation_type_{aggregation_type},
+ measurement_collection_callback_{measurement_callback},
+ attributes_processor_{attributes_processor},
+ state_{state},
+ cumulative_hash_map_(new AttributesHashMap()),
+ temporal_metric_storage_(instrument_descriptor)
+ {}
+
+ bool Collect(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ nostd::function_ref<bool(MetricData)> metric_collection_callback) noexcept override
+ {
+ opentelemetry::sdk::metrics::ObserverResult<T> ob_res(attributes_processor_);
+
+ // read the measurement using configured callback
+ measurement_collection_callback_(ob_res, state_);
+ std::shared_ptr<AttributesHashMap> delta_hash_map(new AttributesHashMap());
+ // process the read measurements - aggregate and store in hashmap
+ for (auto &measurement : ob_res.GetMeasurements())
+ {
+ auto aggr = DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_);
+ aggr->Aggregate(measurement.second);
+ auto prev = cumulative_hash_map_->Get(measurement.first);
+ if (prev)
+ {
+ auto delta = prev->Diff(*aggr);
+ cumulative_hash_map_->Set(measurement.first,
+ DefaultAggregation::CloneAggregation(
+ aggregation_type_, instrument_descriptor_, *delta));
+ delta_hash_map->Set(measurement.first, std::move(delta));
+ }
+ else
+ {
+ cumulative_hash_map_->Set(
+ measurement.first,
+ DefaultAggregation::CloneAggregation(aggregation_type_, instrument_descriptor_, *aggr));
+ delta_hash_map->Set(measurement.first, std::move(aggr));
+ }
+ }
+
+ return temporal_metric_storage_.buildMetrics(collector, collectors, sdk_start_ts, collection_ts,
+ std::move(delta_hash_map),
+ metric_collection_callback);
+ }
+
+private:
+ InstrumentDescriptor instrument_descriptor_;
+ AggregationType aggregation_type_;
+ void (*measurement_collection_callback_)(opentelemetry::metrics::ObserverResult<T> &, void *);
+ const AttributesProcessor *attributes_processor_;
+ void *state_;
+ std::unique_ptr<AttributesHashMap> cumulative_hash_map_;
+ TemporalMetricStorage temporal_metric_storage_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h
new file mode 100644
index 000000000..50d40e0ae
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h
@@ -0,0 +1,124 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/spin_lock_mutex.h"
+# include "opentelemetry/nostd/function_ref.h"
+# include "opentelemetry/sdk/common/attribute_utils.h"
+# include "opentelemetry/sdk/common/attributemap_hash.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/version.h"
+
+# include <functional>
+# include <memory>
+# include <mutex>
+# include <unordered_map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+using opentelemetry::sdk::common::OrderedAttributeMap;
+
+class AttributeHashGenerator
+{
+public:
+ size_t operator()(const MetricAttributes &attributes) const
+ {
+ return opentelemetry::sdk::common::GetHashForAttributeMap(attributes);
+ }
+};
+
+class AttributesHashMap
+{
+public:
+ Aggregation *Get(const MetricAttributes &attributes) const
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ auto it = hash_map_.find(attributes);
+ if (it != hash_map_.end())
+ {
+ return it->second.get();
+ }
+ return nullptr;
+ }
+
+ /**
+ * @return check if key is present in hash
+ *
+ */
+ bool Has(const MetricAttributes &attributes) const
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ return (hash_map_.find(attributes) == hash_map_.end()) ? false : true;
+ }
+
+ /**
+ * @return the pointer to value for given key if present.
+ * If not present, it uses the provided callback to generate
+ * value and store in the hash
+ */
+ Aggregation *GetOrSetDefault(const MetricAttributes &attributes,
+ std::function<std::unique_ptr<Aggregation>()> aggregation_callback)
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+
+ auto it = hash_map_.find(attributes);
+ if (it != hash_map_.end())
+ {
+ return it->second.get();
+ }
+
+ hash_map_[attributes] = std::move(aggregation_callback());
+ return hash_map_[attributes].get();
+ }
+
+ /**
+ * Set the value for given key, overwriting the value if already present
+ */
+ void Set(const MetricAttributes &attributes, std::unique_ptr<Aggregation> value)
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ hash_map_[attributes] = std::move(value);
+ }
+
+ /**
+ * Iterate the hash to yield key and value stored in hash.
+ */
+ bool GetAllEnteries(
+ nostd::function_ref<bool(const MetricAttributes &, Aggregation &)> callback) const
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ for (auto &kv : hash_map_)
+ {
+ if (!callback(kv.first, *(kv.second.get())))
+ {
+ return false; // callback is not prepared to consume data
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the size of hash.
+ */
+ size_t Size()
+ {
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ return hash_map_.size();
+ }
+
+private:
+ std::unordered_map<MetricAttributes, std::unique_ptr<Aggregation>, AttributeHashGenerator>
+ hash_map_;
+
+ mutable opentelemetry::common::SpinLockMutex lock_;
+};
+} // namespace metrics
+
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h
new file mode 100644
index 000000000..20372f520
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_collector.h
@@ -0,0 +1,57 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/data/metric_data.h"
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class MetricReader;
+class MeterContext;
+
+class CollectorHandle
+{
+public:
+ virtual AggregationTemporality GetAggregationTemporality() noexcept = 0;
+};
+
+/**
+ * An internal opaque interface that the MetricReader receives as
+ * MetricProducer. It acts as the storage key to the internal metric stream
+ * state for each MetricReader.
+ */
+
+class MetricCollector : public MetricProducer, public CollectorHandle
+{
+public:
+ MetricCollector(std::shared_ptr<MeterContext> &&context,
+ std::unique_ptr<MetricReader> metric_reader);
+
+ AggregationTemporality GetAggregationTemporality() noexcept override;
+
+ /**
+ * The callback to be called for each metric exporter. This will only be those
+ * metrics that have been produced since the last time this method was called.
+ *
+ * @return a status of completion of method.
+ */
+ bool Collect(nostd::function_ref<bool(ResourceMetrics &metric_data)> callback) noexcept override;
+
+ bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept;
+
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept;
+
+private:
+ std::shared_ptr<MeterContext> meter_context_;
+ std::shared_ptr<MetricReader> metric_reader_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_storage.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_storage.h
new file mode 100644
index 000000000..e0ba55cbf
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/metric_storage.h
@@ -0,0 +1,86 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/context/context.h"
+# include "opentelemetry/sdk/metrics/data/metric_data.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+/* Represent the storage from which to collect the metrics */
+class CollectorHandle;
+
+class MetricStorage
+{
+public:
+ /* collect the metrics from this storage */
+ virtual bool Collect(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ nostd::function_ref<bool(MetricData)> callback) noexcept = 0;
+};
+
+class WritableMetricStorage
+{
+public:
+ virtual void RecordLong(long value, const opentelemetry::context::Context &context) noexcept = 0;
+
+ virtual void RecordLong(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept = 0;
+
+ virtual void RecordDouble(double value,
+ const opentelemetry::context::Context &context) noexcept = 0;
+
+ virtual void RecordDouble(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept = 0;
+
+ virtual ~WritableMetricStorage() = default;
+};
+
+class NoopMetricStorage : public MetricStorage
+{
+public:
+ bool Collect(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ nostd::function_ref<bool(MetricData)> callback) noexcept override
+ {
+ MetricData metric_data;
+ return callback(std::move(metric_data));
+ }
+};
+
+class NoopWritableMetricStorage : public WritableMetricStorage
+{
+public:
+ void RecordLong(long value, const opentelemetry::context::Context &context) noexcept = 0;
+
+ void RecordLong(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {}
+
+ void RecordDouble(double value, const opentelemetry::context::Context &context) noexcept override
+ {}
+
+ void RecordDouble(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {}
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/multi_metric_storage.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/multi_metric_storage.h
new file mode 100644
index 000000000..ceeafa040
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/multi_metric_storage.h
@@ -0,0 +1,68 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/state/metric_storage.h"
+
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+class MultiMetricStorage : public WritableMetricStorage
+{
+public:
+ void AddStorage(std::shared_ptr<WritableMetricStorage> storage) { storages_.push_back(storage); }
+
+ virtual void RecordLong(long value,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ for (auto &s : storages_)
+ {
+ s->RecordLong(value, context);
+ }
+ }
+
+ virtual void RecordLong(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ for (auto &s : storages_)
+ {
+ s->RecordLong(value, attributes, context);
+ }
+ }
+
+ virtual void RecordDouble(double value,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ for (auto &s : storages_)
+ {
+ s->RecordDouble(value, context);
+ }
+ }
+
+ virtual void RecordDouble(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ for (auto &s : storages_)
+ {
+ s->RecordDouble(value, attributes, context);
+ }
+ }
+
+private:
+ std::vector<std::shared_ptr<WritableMetricStorage>> storages_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h
new file mode 100644
index 000000000..278f7dbe3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h
@@ -0,0 +1,119 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/sdk/common/attributemap_hash.h"
+# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
+# include "opentelemetry/sdk/metrics/exemplar/reservoir.h"
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+# include "opentelemetry/sdk/metrics/state/metric_storage.h"
+
+# include "opentelemetry/sdk/metrics/state/temporal_metric_storage.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+# include <list>
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class SyncMetricStorage : public MetricStorage, public WritableMetricStorage
+{
+
+public:
+ SyncMetricStorage(InstrumentDescriptor instrument_descriptor,
+ const AggregationType aggregation_type,
+ const AttributesProcessor *attributes_processor,
+ nostd::shared_ptr<ExemplarReservoir> &&exemplar_reservoir)
+ : instrument_descriptor_(instrument_descriptor),
+ aggregation_type_{aggregation_type},
+ attributes_hashmap_(new AttributesHashMap()),
+ attributes_processor_{attributes_processor},
+ exemplar_reservoir_(exemplar_reservoir),
+ temporal_metric_storage_(instrument_descriptor)
+
+ {
+ create_default_aggregation_ = [&]() -> std::unique_ptr<Aggregation> {
+ return std::move(
+ DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_));
+ };
+ }
+
+ void RecordLong(long value, const opentelemetry::context::Context &context) noexcept override
+ {
+ if (instrument_descriptor_.value_type_ != InstrumentValueType::kLong)
+ {
+ return;
+ }
+ exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now());
+ attributes_hashmap_->GetOrSetDefault({}, create_default_aggregation_)->Aggregate(value);
+ }
+
+ void RecordLong(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ if (instrument_descriptor_.value_type_ != InstrumentValueType::kLong)
+ {
+ return;
+ }
+
+ exemplar_reservoir_->OfferMeasurement(value, attributes, context,
+ std::chrono::system_clock::now());
+ auto attr = attributes_processor_->process(attributes);
+ attributes_hashmap_->GetOrSetDefault(attr, create_default_aggregation_)->Aggregate(value);
+ }
+
+ void RecordDouble(double value, const opentelemetry::context::Context &context) noexcept override
+ {
+ if (instrument_descriptor_.value_type_ != InstrumentValueType::kDouble)
+ {
+ return;
+ }
+ exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now());
+ attributes_hashmap_->GetOrSetDefault({}, create_default_aggregation_)->Aggregate(value);
+ }
+
+ void RecordDouble(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ exemplar_reservoir_->OfferMeasurement(value, attributes, context,
+ std::chrono::system_clock::now());
+ if (instrument_descriptor_.value_type_ != InstrumentValueType::kDouble)
+ {
+ return;
+ }
+ exemplar_reservoir_->OfferMeasurement(value, attributes, context,
+ std::chrono::system_clock::now());
+ auto attr = attributes_processor_->process(attributes);
+ attributes_hashmap_->GetOrSetDefault(attr, create_default_aggregation_)->Aggregate(value);
+ }
+
+ bool Collect(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ nostd::function_ref<bool(MetricData)> callback) noexcept override;
+
+private:
+ InstrumentDescriptor instrument_descriptor_;
+ AggregationType aggregation_type_;
+
+ // hashmap to maintain the metrics for delta collection (i.e, collection since last Collect call)
+ std::unique_ptr<AttributesHashMap> attributes_hashmap_;
+ const AttributesProcessor *attributes_processor_;
+ std::function<std::unique_ptr<Aggregation>()> create_default_aggregation_;
+ nostd::shared_ptr<ExemplarReservoir> exemplar_reservoir_;
+ TemporalMetricStorage temporal_metric_storage_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h
new file mode 100644
index 000000000..16659c14f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h
@@ -0,0 +1,50 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+struct LastReportedMetrics
+{
+ std::unique_ptr<AttributesHashMap> attributes_map;
+ opentelemetry::common::SystemTimestamp collection_ts;
+};
+
+class TemporalMetricStorage
+{
+public:
+ TemporalMetricStorage(InstrumentDescriptor instrument_descriptor);
+
+ bool buildMetrics(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ std::shared_ptr<AttributesHashMap> delta_metrics,
+ nostd::function_ref<bool(MetricData)> callback) noexcept;
+
+private:
+ InstrumentDescriptor instrument_descriptor_;
+
+ // unreported metrics stash for all the collectors
+ std::unordered_map<CollectorHandle *, std::list<std::shared_ptr<AttributesHashMap>>>
+ unreported_metrics_;
+ // last reported metrics stash for all the collectors.
+ std::unordered_map<CollectorHandle *, LastReportedMetrics> last_reported_metrics_;
+
+ // Lock while building metrics
+ mutable opentelemetry::common::SpinLockMutex lock_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h
new file mode 100644
index 000000000..f4c9bae32
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h
@@ -0,0 +1,127 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/common/key_value_iterable.h"
+# include "opentelemetry/metrics/sync_instruments.h"
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+// forward declaration
+class WritableMetricStorage;
+
+class Synchronous
+{
+public:
+ Synchronous(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : instrument_descriptor_(instrument_descriptor), storage_(std::move(storage))
+ {}
+
+protected:
+ InstrumentDescriptor instrument_descriptor_;
+ std::unique_ptr<WritableMetricStorage> storage_;
+};
+
+class LongCounter : public Synchronous, public opentelemetry::metrics::Counter<long>
+{
+public:
+ LongCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Add(long value, const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
+ void Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Add(long value) noexcept override;
+ void Add(long value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+class DoubleCounter : public Synchronous, public opentelemetry::metrics::Counter<double>
+{
+
+public:
+ DoubleCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
+ void Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Add(double value) noexcept override;
+ void Add(double value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+class LongUpDownCounter : public Synchronous, public opentelemetry::metrics::UpDownCounter<long>
+{
+public:
+ LongUpDownCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Add(long value, const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
+ void Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Add(long value) noexcept override;
+ void Add(long value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+class DoubleUpDownCounter : public Synchronous, public opentelemetry::metrics::UpDownCounter<double>
+{
+public:
+ DoubleUpDownCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
+ void Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Add(double value) noexcept override;
+ void Add(double value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+class LongHistogram : public Synchronous, public opentelemetry::metrics::Histogram<long>
+{
+public:
+ LongHistogram(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Record(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Record(long value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+class DoubleHistogram : public Synchronous, public opentelemetry::metrics::Histogram<double>
+{
+public:
+ DoubleHistogram(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage);
+
+ void Record(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override;
+
+ void Record(double value, const opentelemetry::context::Context &context) noexcept override;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h
new file mode 100644
index 000000000..d82607357
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h
@@ -0,0 +1,81 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/common/attribute_utils.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+using MetricAttributes = opentelemetry::sdk::common::OrderedAttributeMap;
+
+/**
+ * The AttributesProcessor is responsible for customizing which
+ * attribute(s) are to be reported as metrics dimension(s).
+ */
+
+class AttributesProcessor
+{
+public:
+ // Process the metric instrument attributes.
+ // @returns The processed attributes
+ virtual MetricAttributes process(
+ const opentelemetry::common::KeyValueIterable &attributes) const noexcept = 0;
+
+ virtual ~AttributesProcessor() = default;
+};
+
+/**
+ * DefaultAttributesProcessor returns copy of input instrument attributes without
+ * any modification.
+ */
+
+class DefaultAttributesProcessor : public AttributesProcessor
+{
+ MetricAttributes process(
+ const opentelemetry::common::KeyValueIterable &attributes) const noexcept override
+ {
+ MetricAttributes result(attributes);
+ return result;
+ }
+};
+
+/**
+ * FilteringAttributesProcessor filters by allowed attribute names and drops any names
+ * that are not in the allow list.
+ */
+
+class FilteringAttributesProcessor : public AttributesProcessor
+{
+public:
+ FilteringAttributesProcessor(
+ const std::unordered_map<std::string, bool> allowed_attribute_keys = {})
+ : allowed_attribute_keys_(std::move(allowed_attribute_keys))
+ {}
+
+ MetricAttributes process(
+ const opentelemetry::common::KeyValueIterable &attributes) const noexcept override
+ {
+ MetricAttributes result;
+ attributes.ForEachKeyValue(
+ [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept {
+ if (allowed_attribute_keys_.find(key.data()) != allowed_attribute_keys_.end())
+ {
+ result.SetAttribute(key, value);
+ return true;
+ }
+ return true;
+ });
+ return result;
+ }
+
+private:
+ std::unordered_map<std::string, bool> allowed_attribute_keys_;
+};
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/instrument_selector.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/instrument_selector.h
new file mode 100644
index 000000000..e79a292c0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/instrument_selector.h
@@ -0,0 +1,36 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/view/predicate_factory.h"
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class InstrumentSelector
+{
+public:
+ InstrumentSelector(opentelemetry::sdk::metrics::InstrumentType instrument_type,
+ opentelemetry::nostd::string_view name)
+ : name_filter_{std::move(PredicateFactory::GetPredicate(name, PredicateType::kPattern))},
+ instrument_type_{instrument_type}
+ {}
+
+ // Returns name filter predicate. This shouldn't be deleted
+ const opentelemetry::sdk::metrics::Predicate *const GetNameFilter() { return name_filter_.get(); }
+
+ // Returns instrument filter.
+ InstrumentType GetInstrumentType() { return instrument_type_; }
+
+private:
+ std::unique_ptr<opentelemetry::sdk::metrics::Predicate> name_filter_;
+ opentelemetry::sdk::metrics::InstrumentType instrument_type_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/meter_selector.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/meter_selector.h
new file mode 100644
index 000000000..d0bc07ccb
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/meter_selector.h
@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/metrics/view/predicate_factory.h"
+#ifndef ENABLE_METRICS_PREVIEW
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class MeterSelector
+{
+public:
+ MeterSelector(opentelemetry::nostd::string_view name,
+ opentelemetry::nostd::string_view version,
+ opentelemetry::nostd::string_view schema)
+ : name_filter_{std::move(PredicateFactory::GetPredicate(name, PredicateType::kExact))},
+ version_filter_{std::move(PredicateFactory::GetPredicate(version, PredicateType::kExact))},
+ schema_filter_{std::move(PredicateFactory::GetPredicate(schema, PredicateType::kExact))}
+ {}
+
+ // Returns name filter predicate. This shouldn't be deleted
+ const opentelemetry::sdk::metrics::Predicate *const GetNameFilter() { return name_filter_.get(); }
+
+ // Returns version filter predicate. This shouldn't be deleted
+ const opentelemetry::sdk::metrics::Predicate *const GetVersionFilter()
+ {
+ return version_filter_.get();
+ }
+
+ // Returns schema filter predicate. This shouldn't be deleted
+ const opentelemetry::sdk::metrics::Predicate *const GetSchemaFilter()
+ {
+ return schema_filter_.get();
+ }
+
+private:
+ std::unique_ptr<opentelemetry::sdk::metrics::Predicate> name_filter_;
+ std::unique_ptr<opentelemetry::sdk::metrics::Predicate> version_filter_;
+ std::unique_ptr<opentelemetry::sdk::metrics::Predicate> schema_filter_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate.h
new file mode 100644
index 000000000..72de2979a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate.h
@@ -0,0 +1,82 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <vector>
+# if (__GNUC__ == 4 && (__GNUC_MINOR__ == 8 || __GNUC_MINOR__ == 9))
+# define HAVE_WORKING_REGEX 0
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# else
+# include <regex>
+# define HAVE_WORKING_REGEX 1
+# endif
+
+# include "opentelemetry/nostd/string_view.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class Predicate
+{
+public:
+ virtual ~Predicate() = default;
+ virtual bool Match(opentelemetry::nostd::string_view string) const noexcept = 0;
+};
+
+class PatternPredicate : public Predicate
+{
+public:
+ PatternPredicate(opentelemetry::nostd::string_view pattern) : reg_key_{pattern.data()} {}
+ bool Match(opentelemetry::nostd::string_view str) const noexcept override
+ {
+# if HAVE_WORKING_REGEX
+ return std::regex_match(str.data(), reg_key_);
+# else
+ // TBD - Support regex match for GCC4.8
+ OTEL_INTERNAL_LOG_ERROR(
+ "PatternPredicate::Match - failed. std::regex not fully supported for this compiler.");
+ return false; // not supported
+# endif
+ }
+
+private:
+# if HAVE_WORKING_REGEX
+ std::regex reg_key_;
+# else
+ std::string reg_key_;
+# endif
+};
+
+class ExactPredicate : public Predicate
+{
+public:
+ ExactPredicate(opentelemetry::nostd::string_view pattern) : pattern_{pattern} {}
+ bool Match(opentelemetry::nostd::string_view str) const noexcept override
+ {
+ if (pattern_ == str)
+ {
+ return true;
+ }
+ return false;
+ }
+
+private:
+ std::string pattern_;
+};
+
+class MatchEverythingPattern : public Predicate
+{
+ bool Match(opentelemetry::nostd::string_view str) const noexcept override { return true; }
+};
+
+class MatchNothingPattern : public Predicate
+{
+ bool Match(opentelemetry::nostd::string_view str) const noexcept override { return false; }
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate_factory.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate_factory.h
new file mode 100644
index 000000000..466fa76d5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/predicate_factory.h
@@ -0,0 +1,45 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/metrics/view/predicate.h"
+#ifndef ENABLE_METRICS_PREVIEW
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+enum class PredicateType : uint8_t
+{
+ kPattern,
+ kExact
+};
+
+class PredicateFactory
+{
+public:
+ static std::unique_ptr<Predicate> GetPredicate(opentelemetry::nostd::string_view pattern,
+ PredicateType type)
+ {
+ if ((type == PredicateType::kPattern && pattern == "*") ||
+ (type == PredicateType::kExact && pattern == ""))
+ {
+ return std::move(std::unique_ptr<Predicate>(new MatchEverythingPattern()));
+ }
+ if (type == PredicateType::kPattern)
+ {
+ return std::move(std::unique_ptr<Predicate>(new PatternPredicate(pattern)));
+ }
+ if (type == PredicateType::kExact)
+ {
+ return std::move(std::unique_ptr<Predicate>(new ExactPredicate(pattern)));
+ }
+ return std::move(std::unique_ptr<Predicate>(new MatchNothingPattern()));
+ }
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view.h
new file mode 100644
index 000000000..3cd9f850e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view.h
@@ -0,0 +1,57 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+/**
+ * View defines the interface to allow SDK user to
+ * customize the metrics before exported.
+ */
+
+class View
+{
+public:
+ View(const std::string &name,
+ const std::string &description = "",
+ AggregationType aggregation_type = AggregationType::kDefault,
+ std::unique_ptr<opentelemetry::sdk::metrics::AttributesProcessor> attributes_processor =
+ std::unique_ptr<opentelemetry::sdk::metrics::AttributesProcessor>(
+ new opentelemetry::sdk::metrics::DefaultAttributesProcessor()))
+ : name_(name),
+ description_(description),
+ aggregation_type_{aggregation_type},
+ attributes_processor_{std::move(attributes_processor)}
+ {}
+
+ virtual std::string GetName() const noexcept { return name_; }
+
+ virtual std::string GetDescription() const noexcept { return description_; }
+
+ virtual AggregationType GetAggregationType() const noexcept { return aggregation_type_; }
+
+ virtual const opentelemetry::sdk::metrics::AttributesProcessor &GetAttributesProcessor()
+ const noexcept
+ {
+ return *attributes_processor_.get();
+ }
+
+private:
+ std::string name_;
+ std::string description_;
+ AggregationType aggregation_type_;
+ std::unique_ptr<opentelemetry::sdk::metrics::AttributesProcessor> attributes_processor_;
+};
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h
new file mode 100644
index 000000000..795049dd9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h
@@ -0,0 +1,102 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#ifndef ENABLE_METRICS_PREVIEW
+# include <unordered_map>
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/view/instrument_selector.h"
+# include "opentelemetry/sdk/metrics/view/meter_selector.h"
+# include "opentelemetry/sdk/metrics/view/view.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+struct RegisteredView
+{
+ RegisteredView(
+ std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> instrument_selector,
+ std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> meter_selector,
+ std::unique_ptr<opentelemetry::sdk::metrics::View> view)
+ : instrument_selector_{std::move(instrument_selector)},
+ meter_selector_{std::move(meter_selector)},
+ view_{std::move(view)}
+ {}
+ std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> instrument_selector_;
+ std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> meter_selector_;
+ std::unique_ptr<opentelemetry::sdk::metrics::View> view_;
+};
+
+class ViewRegistry
+{
+public:
+ void AddView(std::unique_ptr<opentelemetry::sdk::metrics::InstrumentSelector> instrument_selector,
+ std::unique_ptr<opentelemetry::sdk::metrics::MeterSelector> meter_selector,
+ std::unique_ptr<opentelemetry::sdk::metrics::View> view)
+ {
+ // TBD - thread-safe ?
+
+ auto registered_view = std::unique_ptr<RegisteredView>(new RegisteredView{
+ std::move(instrument_selector), std::move(meter_selector), std::move(view)});
+ registered_views_.push_back(std::move(registered_view));
+ }
+
+ bool FindViews(const opentelemetry::sdk::metrics::InstrumentDescriptor &instrument_descriptor,
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library,
+ nostd::function_ref<bool(const View &)> callback) const
+ {
+ bool found = false;
+ for (auto const &registered_view : registered_views_)
+ {
+ if (MatchMeter(registered_view->meter_selector_.get(), instrumentation_library) &&
+ MatchInstrument(registered_view->instrument_selector_.get(), instrument_descriptor))
+ {
+ found = true;
+ if (!callback(*(registered_view->view_.get())))
+ {
+ return false;
+ }
+ }
+ }
+ // return default view if none found;
+ if (!found)
+ {
+ static View view("otel-default-view");
+ if (!callback(view))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ~ViewRegistry() = default;
+
+private:
+ std::vector<std::unique_ptr<RegisteredView>> registered_views_;
+ static bool MatchMeter(opentelemetry::sdk::metrics::MeterSelector *selector,
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library)
+ {
+ return selector->GetNameFilter()->Match(instrumentation_library.GetName()) &&
+ (instrumentation_library.GetVersion().size() == 0 ||
+ selector->GetVersionFilter()->Match(instrumentation_library.GetVersion())) &&
+ (instrumentation_library.GetSchemaURL().size() == 0 ||
+ selector->GetSchemaFilter()->Match(instrumentation_library.GetSchemaURL()));
+ }
+
+ static bool MatchInstrument(
+ opentelemetry::sdk::metrics::InstrumentSelector *selector,
+ const opentelemetry::sdk::metrics::InstrumentDescriptor &instrument_descriptor)
+ {
+ return selector->GetNameFilter()->Match(instrument_descriptor.name_) &&
+ (selector->GetInstrumentType() == instrument_descriptor.type_);
+ }
+};
+}; // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/experimental_semantic_conventions.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/experimental_semantic_conventions.h
new file mode 100644
index 000000000..d9dc3630f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/experimental_semantic_conventions.h
@@ -0,0 +1,141 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+// NOTE:
+// This implementation is based on the experimental specs for resource semantic convention as
+// defined here:
+// https://github.com/open-telemetry/opentelemetry-specification/tree/v1.0.0/specification/resource/semantic_conventions
+// and MAY will change in future.
+
+#pragma once
+
+#include <type_traits>
+#include <unordered_map>
+
+#include "opentelemetry/common/string_util.h"
+#include "opentelemetry/version.h"
+
+#define OTEL_GET_RESOURCE_ATTR(name) \
+ opentelemetry::sdk::resource::attr(OTEL_CPP_CONST_HASHCODE(name))
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace resource
+{
+
+static const std::unordered_map<uint32_t, const char *> attribute_ids = {
+ {OTEL_CPP_CONST_HASHCODE(AttrServiceName), "service.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrServiceNamespace), "service.namespace"},
+ {OTEL_CPP_CONST_HASHCODE(AttrServiceInstance), "service.instance.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrServiceVersion), "service.version"},
+
+ // telemetry attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrTelemetrySdkName), "telemetry.sdk.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrTelemetrySdkLanguage), "telemetry.sdk.language"},
+ {OTEL_CPP_CONST_HASHCODE(AttrTelemetrySdkVersion), "telemetry.sdk.version"},
+ {OTEL_CPP_CONST_HASHCODE(AttrTelemetryAutoVersion), "telemetry.auto.version"},
+
+ // compute unit: container attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrContainerName), "container.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrContainerId), "container.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrContainerRuntime), "container.runtime"},
+ {OTEL_CPP_CONST_HASHCODE(AttrContainerImageName), "container.image.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrContainerImageTag), "container.image.tag"},
+
+ // compute unit: faas attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrFaasName), "faas.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrFaasId), "faas.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrFaasVersion), "faas.version"},
+ {OTEL_CPP_CONST_HASHCODE(AttrFaasInstance), "faas.instance"},
+ {OTEL_CPP_CONST_HASHCODE(AttrFaasMaxMemory), "faas.max_memory"},
+
+ // compute unit : process attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessId), "process.pid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessExecutableName), "process.executable.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessExecutablePath), "process.executable.path"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessCommand), "process.command"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessCommandLine), "process.command_line"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessCommandArgs), "process.command_args"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessOwner), "process.owner"},
+
+ // compute : process runtimes
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessRuntimeName), "process.runtime.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessRuntimeVersion), "process.runtime.version"},
+ {OTEL_CPP_CONST_HASHCODE(AttrProcessRuntimeDescription), "process.runtime.description"},
+
+ // compute unit : WebEngine
+ {OTEL_CPP_CONST_HASHCODE(AttrWebEngineName), "webengine.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrWebEngineVersion), "webengine.version"},
+ {OTEL_CPP_CONST_HASHCODE(AttrWebEngineDescription), "webengine.description"},
+
+ // compute instance : host
+ {OTEL_CPP_CONST_HASHCODE(AttrHostId), "host.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostName), "host.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostType), "host.type"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostArch), "host.arch"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostImageName), "host.image.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostImageId), "host.image.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrHostImageVersion), "host.image.version"},
+
+ // env os attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrOsType), "os.type"},
+ {OTEL_CPP_CONST_HASHCODE(AttrOsDescription), "os.description"},
+ {OTEL_CPP_CONST_HASHCODE(AttrOsName), "os.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrOsVersion), "os.version"},
+
+ // env device attributes
+ {OTEL_CPP_CONST_HASHCODE(AttrDeviceId), "device.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrDeviceModelIdentifier), "device.model.identifier"},
+ {OTEL_CPP_CONST_HASHCODE(AttrDeviceModelName), "device.model.name"},
+
+ // env cloud
+ {OTEL_CPP_CONST_HASHCODE(AttrCloudProvider), "cloud.provider"},
+ {OTEL_CPP_CONST_HASHCODE(AttrCloudAccountId), "cloud.account.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrCloudRegion), "cloud.region"},
+ {OTEL_CPP_CONST_HASHCODE(AttrCloudAvailabilityZone), "cloud.availability_zone"},
+ {OTEL_CPP_CONST_HASHCODE(AttrCloudPlatform), "cloud.platform"},
+
+ // env deployment
+ {OTEL_CPP_CONST_HASHCODE(AttrDeploymentEnvironment), "deployment.environment"},
+
+ // env kubernetes
+ // - cluster
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sClusterName), "k8s.cluster.name"},
+ // - node
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sNodeName), "k8s.node.name"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sNodeUid), "k8s.node.uid"},
+ // - namespace
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sNamespaceName), "k8s.namespace.name"},
+ // - pod
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sPodUid), "k8s.pod.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sPodName), "k8s.pod.name"},
+ // - container
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sContainerName), "k8s.container.name"},
+ // - replicaset
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sReplicaSetUid), "k8s.replicaset.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sReplicaSetName), "k8s.replicaset.name"},
+ // - deployment
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sDeploymentUid), "k8s.deployment.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sDeploymentName), "k8s.deployment.name"},
+ // - stateful-set
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sStatefulSetUid), "k8s.statefulset.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sStatefulSetName), "k8s.statefulset.name"},
+ // - daemon set
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sDaemonSetUid), "k8s.daemonset.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sDaemonSetName), "k8s.daemonset.name"},
+ // - job
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sJobUid), "k8s.job.uid"},
+ {OTEL_CPP_CONST_HASHCODE(AttrK8sJobName), "k8s.job.name"},
+ // - cronjob
+ {OTEL_CPP_CONST_HASHCODE(AttrCronjobUid), "k8s.cronjob.id"},
+ {OTEL_CPP_CONST_HASHCODE(AttrCronjobName), "k8s.cronjob.name"}};
+
+// function to generate hash code for semantic conventions attributes.
+inline const char *attr(uint32_t attr)
+{
+ return (attribute_ids.find(attr) != attribute_ids.end()) ? attribute_ids.at(attr) : "";
+}
+} // namespace resource
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource.h
new file mode 100644
index 000000000..120e871ab
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource.h
@@ -0,0 +1,86 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/common/attribute_value.h"
+#include "opentelemetry/common/key_value_iterable_view.h"
+
+#include "opentelemetry/sdk/common/attribute_utils.h"
+#include "opentelemetry/sdk/resource/resource_detector.h"
+#include "opentelemetry/sdk/version/version.h"
+#include "opentelemetry/version.h"
+
+#include <memory>
+#include <sstream>
+#include <unordered_map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace resource
+{
+
+using ResourceAttributes = opentelemetry::sdk::common::AttributeMap;
+
+class Resource
+{
+public:
+ Resource(const Resource &) = default;
+
+ const ResourceAttributes &GetAttributes() const noexcept;
+ const std::string &GetSchemaURL() const noexcept;
+
+ /**
+ * Returns a new, merged {@link Resource} by merging the current Resource
+ * with the other Resource. In case of a collision, current Resource takes
+ * precedence.
+ *
+ * @param other the Resource that will be merged with this.
+ * @returns the newly merged Resource.
+ */
+
+ Resource Merge(const Resource &other) noexcept;
+
+ /**
+ * Returns a newly created Resource with the specified attributes.
+ * It adds (merge) SDK attributes and OTEL attributes before returning.
+ * @param attributes for this resource
+ * @returns the newly created Resource.
+ */
+
+ static Resource Create(const ResourceAttributes &attributes,
+ const std::string &schema_url = std::string{});
+
+ /**
+ * Returns an Empty resource.
+ */
+
+ static Resource &GetEmpty();
+
+ /**
+ * Returns a Resource that indentifies the SDK in use.
+ */
+
+ static Resource &GetDefault();
+
+protected:
+ /**
+ * The constructor is protected and only for use internally by the class and
+ * inside ResourceDetector class.
+ * Users should use the Create factory method to obtain a Resource
+ * instance.
+ */
+ Resource(const ResourceAttributes &attributes = ResourceAttributes(),
+ const std::string &schema_url = std::string{}) noexcept;
+
+private:
+ ResourceAttributes attributes_;
+ std::string schema_url_;
+
+ friend class OTELResourceDetector;
+};
+
+} // namespace resource
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource_detector.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource_detector.h
new file mode 100644
index 000000000..5f9d904af
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/resource/resource_detector.h
@@ -0,0 +1,38 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/nostd/unique_ptr.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace resource
+{
+
+class Resource;
+
+/**
+ * Interface for a Resource Detector
+ */
+class ResourceDetector
+{
+public:
+ virtual Resource Detect() = 0;
+};
+
+/**
+ * OTelResourceDetector to detect the presence of and create a Resource
+ * from the OTEL_RESOURCE_ATTRIBUTES environment variable.
+ */
+class OTELResourceDetector : public ResourceDetector
+{
+public:
+ Resource Detect() noexcept override;
+};
+
+} // namespace resource
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h
new file mode 100644
index 000000000..d25ff2d95
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h
@@ -0,0 +1,158 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/common/circular_buffer.h"
+#include "opentelemetry/sdk/trace/exporter.h"
+#include "opentelemetry/sdk/trace/processor.h"
+
+#include <atomic>
+#include <condition_variable>
+#include <thread>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+
+namespace trace
+{
+
+/**
+ * Struct to hold batch SpanProcessor options.
+ */
+struct BatchSpanProcessorOptions
+{
+ /**
+ * The maximum buffer/queue size. After the size is reached, spans are
+ * dropped.
+ */
+ size_t max_queue_size = 2048;
+
+ /* The time interval between two consecutive exports. */
+ std::chrono::milliseconds schedule_delay_millis = std::chrono::milliseconds(5000);
+
+ /**
+ * The maximum batch size of every export. It must be smaller or
+ * equal to max_queue_size.
+ */
+ size_t max_export_batch_size = 512;
+};
+
+/**
+ * This is an implementation of the SpanProcessor which creates batches of finished spans and passes
+ * the export-friendly span data representations to the configured SpanExporter.
+ */
+class BatchSpanProcessor : public SpanProcessor
+{
+public:
+ /**
+ * Creates a batch span processor by configuring the specified exporter and other parameters
+ * as per the official, language-agnostic opentelemetry specs.
+ *
+ * @param exporter - The backend exporter to pass the ended spans to.
+ * @param options - The batch SpanProcessor options.
+ */
+ BatchSpanProcessor(std::unique_ptr<SpanExporter> &&exporter,
+ const BatchSpanProcessorOptions &options);
+
+ /**
+ * Requests a Recordable(Span) from the configured exporter.
+ *
+ * @return A recordable generated by the backend exporter
+ */
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override;
+
+ /**
+ * Called when a span is started.
+ *
+ * NOTE: This method is a no-op.
+ *
+ * @param span - The span that just started
+ * @param parent_context - The parent context of the span that just started
+ */
+ void OnStart(Recordable &span,
+ const opentelemetry::trace::SpanContext &parent_context) noexcept override;
+
+ /**
+ * Called when a span ends.
+ *
+ * @param span - A recordable for a span that just ended
+ */
+ void OnEnd(std::unique_ptr<Recordable> &&span) noexcept override;
+
+ /**
+ * Export all ended spans that have not been exported yet.
+ *
+ * NOTE: Timeout functionality not supported yet.
+ */
+ bool ForceFlush(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ /**
+ * Shuts down the processor and does any cleanup required. Completely drains the buffer/queue of
+ * all its ended spans and passes them to the exporter. Any subsequent calls to OnStart, OnEnd,
+ * ForceFlush or Shutdown will return immediately without doing anything.
+ *
+ * NOTE: Timeout functionality not supported yet.
+ */
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override;
+
+ /**
+ * Class destructor which invokes the Shutdown() method. The Shutdown() method is supposed to be
+ * invoked when the Tracer is shutdown (as per other languages), but the C++ Tracer only takes
+ * shared ownership of the processor, and thus doesn't call Shutdown (as the processor might be
+ * shared with other Tracers).
+ */
+ ~BatchSpanProcessor();
+
+private:
+ /**
+ * The background routine performed by the worker thread.
+ */
+ void DoBackgroundWork();
+
+ /**
+ * Exports all ended spans to the configured exporter.
+ *
+ * @param was_force_flush_called - A flag to check if the current export is the result
+ * of a call to ForceFlush method. If true, then we have to
+ * notify the main thread to wake it up in the ForceFlush
+ * method.
+ */
+ void Export(const bool was_for_flush_called);
+
+ /**
+ * Called when Shutdown() is invoked. Completely drains the queue of all its ended spans and
+ * passes them to the exporter.
+ */
+ void DrainQueue();
+
+ /* The configured backend exporter */
+ std::unique_ptr<SpanExporter> exporter_;
+
+ /* Configurable parameters as per the official specs */
+ const size_t max_queue_size_;
+ const std::chrono::milliseconds schedule_delay_millis_;
+ const size_t max_export_batch_size_;
+
+ /* Synchronization primitives */
+ std::condition_variable cv_, force_flush_cv_;
+ std::mutex cv_m_, force_flush_cv_m_, shutdown_m_;
+
+ /* The buffer/queue to which the ended spans are added */
+ common::CircularBuffer<Recordable> buffer_;
+
+ /* Important boolean flags to handle the workflow of the processor */
+ std::atomic<bool> is_shutdown_{false};
+ std::atomic<bool> is_force_flush_{false};
+ std::atomic<bool> is_force_flush_notified_{false};
+
+ /* The background worker thread */
+ std::thread worker_thread_;
+};
+
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/exporter.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/exporter.h
new file mode 100644
index 000000000..5826b5f45
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/exporter.h
@@ -0,0 +1,55 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <memory>
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/sdk/common/exporter_utils.h"
+#include "opentelemetry/sdk/trace/recordable.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * SpanExporter defines the interface that protocol-specific span exporters must
+ * implement.
+ */
+class SpanExporter
+{
+public:
+ virtual ~SpanExporter() = default;
+
+ /**
+ * Create a span recordable. This object will be used to record span data and
+ * will subsequently be passed to SpanExporter::Export. Vendors can implement
+ * custom recordables or use the default SpanData recordable provided by the
+ * SDK.
+ * @return a newly initialized Recordable object
+ *
+ * Note: This method must be callable from multiple threads.
+ */
+ virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0;
+
+ /**
+ * Exports a batch of span recordables. This method must not be called
+ * concurrently for the same exporter instance.
+ * @param spans a span of unique pointers to span recordables
+ */
+ virtual sdk::common::ExportResult Export(
+ const nostd::span<std::unique_ptr<opentelemetry::sdk::trace::Recordable>>
+ &spans) noexcept = 0;
+
+ /**
+ * Shut down the exporter.
+ * @param timeout an optional timeout.
+ * @return return the status of the operation.
+ */
+ virtual bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept = 0;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/id_generator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/id_generator.h
new file mode 100644
index 000000000..da17effae
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/id_generator.h
@@ -0,0 +1,31 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include "opentelemetry/trace/span_id.h"
+#include "opentelemetry/trace/trace_id.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+/** IdGenerator provides an interface for generating Trace Id and Span Id */
+class IdGenerator
+{
+
+public:
+ virtual ~IdGenerator() = default;
+
+ /** Returns a SpanId represented by opaque 128-bit trace identifier */
+ virtual opentelemetry::trace::SpanId GenerateSpanId() noexcept = 0;
+
+ /** Returns a TraceId represented by opaque 64-bit trace identifier */
+ virtual opentelemetry::trace::TraceId GenerateTraceId() noexcept = 0;
+};
+} // namespace trace
+
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_recordable.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_recordable.h
new file mode 100644
index 000000000..be97dddc9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_recordable.h
@@ -0,0 +1,161 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/common/timestamp.h"
+#include "opentelemetry/sdk/trace/processor.h"
+#include "opentelemetry/sdk/trace/recordable.h"
+#include "opentelemetry/version.h"
+
+#include <map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+namespace
+{
+std::size_t MakeKey(const SpanProcessor &processor)
+{
+ return reinterpret_cast<std::size_t>(&processor);
+}
+
+} // namespace
+
+class MultiRecordable : public Recordable
+{
+public:
+ void AddRecordable(const SpanProcessor &processor,
+ std::unique_ptr<Recordable> recordable) noexcept
+ {
+ recordables_[MakeKey(processor)] = std::move(recordable);
+ }
+
+ const std::unique_ptr<Recordable> &GetRecordable(const SpanProcessor &processor) const noexcept
+ {
+ // TODO - return nullptr ref on failed lookup?
+ auto i = recordables_.find(MakeKey(processor));
+ if (i != recordables_.end())
+ {
+ return i->second;
+ }
+ static std::unique_ptr<Recordable> empty(nullptr);
+ return empty;
+ }
+
+ std::unique_ptr<Recordable> ReleaseRecordable(const SpanProcessor &processor) noexcept
+ {
+ auto i = recordables_.find(MakeKey(processor));
+ if (i != recordables_.end())
+ {
+ std::unique_ptr<Recordable> result(i->second.release());
+ recordables_.erase(MakeKey(processor));
+ return result;
+ }
+ return std::unique_ptr<Recordable>(nullptr);
+ }
+
+ void SetIdentity(const opentelemetry::trace::SpanContext &span_context,
+ opentelemetry::trace::SpanId parent_span_id) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetIdentity(span_context, parent_span_id);
+ }
+ }
+
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetAttribute(key, value);
+ }
+ }
+
+ void AddEvent(nostd::string_view name,
+ opentelemetry::common::SystemTimestamp timestamp,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override
+ {
+
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->AddEvent(name, timestamp, attributes);
+ }
+ }
+
+ void AddLink(const opentelemetry::trace::SpanContext &span_context,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->AddLink(span_context, attributes);
+ }
+ }
+
+ void SetStatus(opentelemetry::trace::StatusCode code,
+ nostd::string_view description) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetStatus(code, description);
+ }
+ }
+
+ void SetName(nostd::string_view name) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetName(name);
+ }
+ }
+
+ void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetSpanKind(span_kind);
+ }
+ }
+
+ void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetResource(resource);
+ }
+ }
+
+ void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetStartTime(start_time);
+ }
+ }
+
+ void SetDuration(std::chrono::nanoseconds duration) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetDuration(duration);
+ }
+ }
+
+ void SetInstrumentationLibrary(
+ const InstrumentationLibrary &instrumentation_library) noexcept override
+ {
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetInstrumentationLibrary(instrumentation_library);
+ }
+ }
+
+private:
+ std::map<std::size_t, std::unique_ptr<Recordable>> recordables_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h
new file mode 100644
index 000000000..8463ad520
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/multi_span_processor.h
@@ -0,0 +1,187 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include "opentelemetry/sdk/trace/multi_recordable.h"
+#include "opentelemetry/sdk/trace/processor.h"
+
+#include <iostream>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+/** Instantiation options. */
+struct MultiSpanProcessorOptions
+{};
+
+/**
+ * Span processor allow hooks for span start and end method invocations.
+ *
+ * Built-in span processors are responsible for batching and conversion of
+ * spans to exportable representation and passing batches to exporters.
+ */
+class MultiSpanProcessor : public SpanProcessor
+{
+public:
+ MultiSpanProcessor(std::vector<std::unique_ptr<SpanProcessor>> &&processors)
+ : head_(nullptr), tail_(nullptr), count_(0)
+ {
+ for (auto &processor : processors)
+ {
+ AddProcessor(std::move(processor));
+ }
+ }
+
+ void AddProcessor(std::unique_ptr<SpanProcessor> &&processor)
+ {
+ // Add preocessor to end of the list.
+ if (processor)
+ {
+ ProcessorNode *pNode = new ProcessorNode(std::move(processor), tail_);
+ if (count_ > 0)
+ {
+ tail_->next_ = pNode;
+ tail_ = pNode;
+ }
+ else
+ {
+ head_ = tail_ = pNode;
+ }
+ count_++;
+ }
+ }
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override
+ {
+ auto recordable = std::unique_ptr<Recordable>(new MultiRecordable);
+ auto multi_recordable = static_cast<MultiRecordable *>(recordable.get());
+ ProcessorNode *node = head_;
+ while (node != nullptr)
+ {
+ auto processor = node->value_.get();
+ multi_recordable->AddRecordable(*processor, processor->MakeRecordable());
+ node = node->next_;
+ }
+ return recordable;
+ }
+
+ virtual void OnStart(Recordable &span,
+ const opentelemetry::trace::SpanContext &parent_context) noexcept override
+ {
+ auto multi_recordable = static_cast<MultiRecordable *>(&span);
+ ProcessorNode *node = head_;
+ while (node != nullptr)
+ {
+ auto processor = node->value_.get();
+ auto &recordable = multi_recordable->GetRecordable(*processor);
+ if (recordable != nullptr)
+ {
+ processor->OnStart(*recordable, parent_context);
+ }
+ node = node->next_;
+ }
+ }
+
+ virtual void OnEnd(std::unique_ptr<Recordable> &&span) noexcept override
+ {
+ auto multi_recordable = static_cast<MultiRecordable *>(span.release());
+ ProcessorNode *node = head_;
+ while (node != nullptr)
+ {
+ auto processor = node->value_.get();
+ auto recordable = multi_recordable->ReleaseRecordable(*processor);
+ if (recordable != nullptr)
+ {
+ processor->OnEnd(std::move(recordable));
+ }
+ node = node->next_;
+ }
+ delete multi_recordable;
+ }
+
+ bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ bool result = true;
+ ProcessorNode *node = head_;
+ while (node != nullptr)
+ {
+ auto processor = node->value_.get();
+ result |= processor->ForceFlush(timeout);
+ node = node->next_;
+ }
+ return result;
+ }
+
+ bool Shutdown(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ bool result = true;
+ ProcessorNode *node = head_;
+ while (node != nullptr)
+ {
+ auto processor = node->value_.get();
+ result |= processor->Shutdown(timeout);
+ node = node->next_;
+ }
+ return result;
+ }
+
+ ~MultiSpanProcessor()
+ {
+ Shutdown();
+ Cleanup();
+ }
+
+private:
+ struct ProcessorNode
+ {
+ std::unique_ptr<SpanProcessor> value_;
+ ProcessorNode *next_, *prev_;
+ ProcessorNode(std::unique_ptr<SpanProcessor> &&value,
+ ProcessorNode *prev = nullptr,
+ ProcessorNode *next = nullptr)
+ : value_(std::move(value)), next_(next), prev_(prev)
+ {}
+ };
+
+ void Cleanup()
+ {
+ if (count_)
+ {
+ ProcessorNode *node = tail_;
+ while (node != nullptr)
+ {
+ if (node->next_ != nullptr)
+ {
+ delete node->next_;
+ node->next_ = nullptr;
+ }
+ if (node->prev_ != nullptr)
+ {
+ node = node->prev_;
+ }
+ else
+ {
+ delete node;
+ node = nullptr;
+ }
+ }
+ head_ = tail_ = nullptr;
+ count_ = 0;
+ }
+ }
+
+ ProcessorNode *head_, *tail_;
+ size_t count_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/processor.h
new file mode 100644
index 000000000..17ac0e59a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/processor.h
@@ -0,0 +1,70 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <chrono>
+#include <memory>
+#include "opentelemetry/sdk/trace/recordable.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * Span processor allow hooks for span start and end method invocations.
+ *
+ * Built-in span processors are responsible for batching and conversion of
+ * spans to exportable representation and passing batches to exporters.
+ */
+class SpanProcessor
+{
+public:
+ virtual ~SpanProcessor() = default;
+
+ /**
+ * Create a span recordable. This requests a new span recordable from the
+ * associated exporter.
+ * @return a newly initialized recordable
+ *
+ * Note: This method must be callable from multiple threads.
+ */
+ virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0;
+
+ /**
+ * OnStart is called when a span is started.
+ * @param span a recordable for a span that was just started
+ * @param parent_context The parent context of the span that just started
+ */
+ virtual void OnStart(Recordable &span,
+ const opentelemetry::trace::SpanContext &parent_context) noexcept = 0;
+
+ /**
+ * OnEnd is called when a span is ended.
+ * @param span a recordable for a span that was ended
+ */
+ virtual void OnEnd(std::unique_ptr<Recordable> &&span) noexcept = 0;
+
+ /**
+ * Export all ended spans that have not yet been exported.
+ * @param timeout an optional timeout, the default timeout of 0 means that no
+ * timeout is applied.
+ */
+ virtual bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0;
+
+ /**
+ * Shut down the processor and do any cleanup required. Ended spans are
+ * exported before shutdown. After the call to Shutdown, subsequent calls to
+ * OnStart, OnEnd, ForceFlush or Shutdown will return immediately without
+ * doing anything.
+ * @param timeout an optional timeout, the default timeout of 0 means that no
+ * timeout is applied.
+ */
+ virtual bool Shutdown(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/random_id_generator.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/random_id_generator.h
new file mode 100644
index 000000000..908f1b850
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/random_id_generator.h
@@ -0,0 +1,24 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include "opentelemetry/sdk/trace/id_generator.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+class RandomIdGenerator : public IdGenerator
+{
+public:
+ opentelemetry::trace::SpanId GenerateSpanId() noexcept override;
+
+ opentelemetry::trace::TraceId GenerateTraceId() noexcept override;
+};
+
+} // namespace trace
+
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/recordable.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/recordable.h
new file mode 100644
index 000000000..b92a3ff06
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/recordable.h
@@ -0,0 +1,152 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/common/attribute_value.h"
+#include "opentelemetry/common/key_value_iterable.h"
+#include "opentelemetry/common/timestamp.h"
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/common/empty_attributes.h"
+#include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/trace/canonical_code.h"
+#include "opentelemetry/trace/span.h"
+#include "opentelemetry/trace/span_context.h"
+#include "opentelemetry/trace/span_id.h"
+#include "opentelemetry/trace/trace_id.h"
+#include "opentelemetry/version.h"
+
+#include <map>
+
+// TODO: Create generic short pattern for opentelemetry::common and opentelemetry::trace
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+using namespace opentelemetry::sdk::instrumentationlibrary;
+
+/**
+ * Maintains a representation of a span in a format that can be processed by a recorder.
+ *
+ * This class is thread-compatible.
+ */
+class Recordable
+{
+public:
+ virtual ~Recordable() = default;
+
+ /**
+ * Set the span context and parent span id
+ * @param span_context the span context to set
+ * @param parent_span_id the parent span id to set
+ */
+ virtual void SetIdentity(const opentelemetry::trace::SpanContext &span_context,
+ opentelemetry::trace::SpanId parent_span_id) noexcept = 0;
+
+ /**
+ * Set an attribute of a span.
+ * @param name the name of the attribute
+ * @param value the attribute value
+ */
+ virtual void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept = 0;
+
+ /**
+ * Add an event to a span.
+ * @param name the name of the event
+ * @param timestamp the timestamp of the event
+ * @param attributes the attributes associated with the event
+ */
+ virtual void AddEvent(nostd::string_view name,
+ opentelemetry::common::SystemTimestamp timestamp,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept = 0;
+
+ /**
+ * Add an event to a span with default timestamp and attributes.
+ * @param name the name of the event
+ */
+ void AddEvent(nostd::string_view name)
+ {
+ AddEvent(name, opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()),
+ opentelemetry::sdk::GetEmptyAttributes());
+ }
+
+ /**
+ * Add an event to a span with default (empty) attributes.
+ * @param name the name of the event
+ * @param timestamp the timestamp of the event
+ */
+ void AddEvent(nostd::string_view name, opentelemetry::common::SystemTimestamp timestamp)
+ {
+ AddEvent(name, timestamp, opentelemetry::sdk::GetEmptyAttributes());
+ }
+
+ /**
+ * Add a link to a span.
+ * @param span_context the span context of the linked span
+ * @param attributes the attributes associated with the link
+ */
+ virtual void AddLink(const opentelemetry::trace::SpanContext &span_context,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept = 0;
+
+ /**
+ * Add a link to a span with default (empty) attributes.
+ * @param span_context the span context of the linked span
+ */
+ void AddLink(opentelemetry::trace::SpanContext span_context)
+ {
+ AddLink(span_context, opentelemetry::sdk::GetEmptyAttributes());
+ }
+
+ /**
+ * Set the status of the span.
+ * @param code the status code
+ * @param description a description of the status
+ */
+ virtual void SetStatus(opentelemetry::trace::StatusCode code,
+ nostd::string_view description) noexcept = 0;
+
+ /**
+ * Set the name of the span.
+ * @param name the name to set
+ */
+ virtual void SetName(nostd::string_view name) noexcept = 0;
+
+ /**
+ * Set the spankind of the span.
+ * @param span_kind the spankind to set
+ */
+ virtual void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept = 0;
+
+ /**
+ * Set Resource of the span
+ * @param Resource the resource to set
+ */
+ virtual void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept = 0;
+
+ /**
+ * Set the start time of the span.
+ * @param start_time the start time to set
+ */
+ virtual void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept = 0;
+
+ /**
+ * Set the duration of the span.
+ * @param duration the duration to set
+ */
+ virtual void SetDuration(std::chrono::nanoseconds duration) noexcept = 0;
+
+ /**
+ * Set the instrumentation library of the span.
+ * @param instrumentation_library the instrumentation library to set
+ */
+ virtual void SetInstrumentationLibrary(
+ const InstrumentationLibrary &instrumentation_library) noexcept = 0;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/sampler.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/sampler.h
new file mode 100644
index 000000000..452ba924b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/sampler.h
@@ -0,0 +1,91 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/common/attribute_value.h"
+#include "opentelemetry/trace/span.h"
+#include "opentelemetry/trace/span_context.h"
+#include "opentelemetry/trace/span_context_kv_iterable.h"
+#include "opentelemetry/trace/trace_id.h"
+#include "opentelemetry/trace/trace_state.h"
+#include "opentelemetry/version.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * A sampling Decision for a Span to be created.
+ */
+enum class Decision
+{
+ // IsRecording() == false, span will not be recorded and all events and attributes will be
+ // dropped.
+ DROP,
+ // IsRecording() == true, but Sampled flag MUST NOT be set.
+ RECORD_ONLY,
+ // IsRecording() == true AND Sampled flag` MUST be set.
+ RECORD_AND_SAMPLE
+};
+
+/**
+ * The output of ShouldSample.
+ * It contains a sampling Decision and a set of Span Attributes.
+ */
+struct SamplingResult
+{
+ Decision decision;
+ // A set of span Attributes that will also be added to the Span. Can be nullptr.
+ std::unique_ptr<const std::map<std::string, opentelemetry::common::AttributeValue>> attributes;
+ // The tracestate used by the span.
+ nostd::shared_ptr<opentelemetry::trace::TraceState> trace_state;
+};
+
+/**
+ * The Sampler interface allows users to create custom samplers which will return a
+ * SamplingResult based on information that is typically available just before the Span was created.
+ */
+class Sampler
+{
+public:
+ virtual ~Sampler() = default;
+ /**
+ * Called during Span creation to make a sampling decision.
+ *
+ * @param parent_context a const reference to the SpanContext of a parent Span.
+ * An invalid SpanContext if this is a root span.
+ * @param trace_id the TraceId for the new Span. This will be identical to that in
+ * the parentContext, unless this is a root span.
+ * @param name the name of the new Span.
+ * @param spanKind the opentelemetry::trace::SpanKind of the Span.
+ * @param attributes list of AttributeValue with their keys.
+ * @param links Collection of links that will be associated with the Span to be created.
+ * @return sampling result whether span should be sampled or not.
+ * @since 0.1.0
+ */
+
+ virtual SamplingResult ShouldSample(
+ const opentelemetry::trace::SpanContext &parent_context,
+ opentelemetry::trace::TraceId trace_id,
+ nostd::string_view name,
+ opentelemetry::trace::SpanKind span_kind,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::trace::SpanContextKeyValueIterable &links) noexcept = 0;
+
+ /**
+ * Returns the sampler name or short description with the configuration.
+ * This may be displayed on debug pages or in the logs.
+ *
+ * @return the description of this Sampler.
+ */
+ virtual nostd::string_view GetDescription() const noexcept = 0;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h
new file mode 100644
index 000000000..2392b9b2f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h
@@ -0,0 +1,48 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/trace/sampler.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * The always off sampler always returns DROP, effectively disabling
+ * tracing functionality.
+ */
+class AlwaysOffSampler : public Sampler
+{
+public:
+ /**
+ * @return Returns DROP always
+ */
+ SamplingResult ShouldSample(
+ const opentelemetry::trace::SpanContext &parent_context,
+ opentelemetry::trace::TraceId /*trace_id*/,
+ nostd::string_view /*name*/,
+ opentelemetry::trace::SpanKind /*span_kind*/,
+ const opentelemetry::common::KeyValueIterable & /*attributes*/,
+ const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override
+ {
+ if (!parent_context.IsValid())
+ {
+ return {Decision::DROP, nullptr, opentelemetry::trace::TraceState::GetDefault()};
+ }
+ else
+ {
+ return {Decision::DROP, nullptr, parent_context.trace_state()};
+ }
+ }
+
+ /**
+ * @return Description MUST be AlwaysOffSampler
+ */
+ nostd::string_view GetDescription() const noexcept override { return "AlwaysOffSampler"; }
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h
new file mode 100644
index 000000000..6c8583599
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h
@@ -0,0 +1,47 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/trace/sampler.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * The always on sampler is a default sampler which always return Decision::RECORD_AND_SAMPLE
+ */
+class AlwaysOnSampler : public Sampler
+{
+public:
+ /**
+ * @return Always return Decision RECORD_AND_SAMPLE
+ */
+ inline SamplingResult ShouldSample(
+ const opentelemetry::trace::SpanContext &parent_context,
+ opentelemetry::trace::TraceId /*trace_id*/,
+ nostd::string_view /*name*/,
+ opentelemetry::trace::SpanKind /*span_kind*/,
+ const opentelemetry::common::KeyValueIterable & /*attributes*/,
+ const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override
+ {
+ if (!parent_context.IsValid())
+ {
+ return {Decision::RECORD_AND_SAMPLE, nullptr, opentelemetry::trace::TraceState::GetDefault()};
+ }
+ else
+ {
+ return {Decision::RECORD_AND_SAMPLE, nullptr, parent_context.trace_state()};
+ }
+ }
+
+ /**
+ * @return Description MUST be AlwaysOnSampler
+ */
+ inline nostd::string_view GetDescription() const noexcept override { return "AlwaysOnSampler"; }
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/parent.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/parent.h
new file mode 100644
index 000000000..c76a6c2a5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/parent.h
@@ -0,0 +1,45 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
+#include "opentelemetry/sdk/trace/sampler.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * The ParentBased sampler is a composite sampler. ParentBased(delegateSampler) either respects
+ * the parent span's sampling decision or delegates to delegateSampler for root spans.
+ */
+class ParentBasedSampler : public Sampler
+{
+public:
+ explicit ParentBasedSampler(std::shared_ptr<Sampler> delegate_sampler) noexcept;
+ /** The decision either respects the parent span's sampling decision or delegates to
+ * delegateSampler for root spans
+ * @return Returns DROP always
+ */
+ SamplingResult ShouldSample(
+ const opentelemetry::trace::SpanContext &parent_context,
+ opentelemetry::trace::TraceId trace_id,
+ nostd::string_view name,
+ opentelemetry::trace::SpanKind span_kind,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::trace::SpanContextKeyValueIterable &links) noexcept override;
+
+ /**
+ * @return Description MUST be ParentBased{delegate_sampler_.getDescription()}
+ */
+ nostd::string_view GetDescription() const noexcept override;
+
+private:
+ const std::shared_ptr<Sampler> delegate_sampler_;
+ const std::string description_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/trace_id_ratio.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/trace_id_ratio.h
new file mode 100644
index 000000000..407b480d6
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/samplers/trace_id_ratio.h
@@ -0,0 +1,53 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/trace/sampler.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * The TraceIdRatioBased sampler computes and returns a decision based on the
+ * provided trace_id and the configured ratio.
+ */
+class TraceIdRatioBasedSampler : public Sampler
+{
+public:
+ /**
+ * @param ratio a required value, 1.0 >= ratio >= 0.0. If the given trace_id
+ * falls into a given ratio of all possible trace_id values, ShouldSample will
+ * return RECORD_AND_SAMPLE.
+ * @throws invalid_argument if ratio is out of bounds [0.0, 1.0]
+ */
+ explicit TraceIdRatioBasedSampler(double ratio);
+
+ /**
+ * @return Returns either RECORD_AND_SAMPLE or DROP based on current
+ * sampler configuration and provided trace_id and ratio. trace_id
+ * is used as a pseudorandom value in conjunction with the predefined
+ * ratio to determine whether this trace should be sampled
+ */
+ SamplingResult ShouldSample(
+ const opentelemetry::trace::SpanContext & /*parent_context*/,
+ opentelemetry::trace::TraceId trace_id,
+ nostd::string_view /*name*/,
+ opentelemetry::trace::SpanKind /*span_kind*/,
+ const opentelemetry::common::KeyValueIterable & /*attributes*/,
+ const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override;
+
+ /**
+ * @return Description MUST be TraceIdRatioBasedSampler{0.000100}
+ */
+ nostd::string_view GetDescription() const noexcept override;
+
+private:
+ std::string description_;
+ const uint64_t threshold_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/simple_processor.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/simple_processor.h
new file mode 100644
index 000000000..accc68596
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/simple_processor.h
@@ -0,0 +1,84 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include <mutex>
+
+#include "opentelemetry/common/spin_lock_mutex.h"
+#include "opentelemetry/sdk/trace/exporter.h"
+#include "opentelemetry/sdk/trace/processor.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * The simple span processor passes finished recordables to the configured
+ * SpanExporter, as soon as they are finished.
+ *
+ * OnEnd and ForceFlush are no-ops.
+ *
+ * All calls to the configured SpanExporter are synchronized using a
+ * spin-lock on an atomic_flag.
+ */
+class SimpleSpanProcessor : public SpanProcessor
+{
+public:
+ /**
+ * Initialize a simple span processor.
+ * @param exporter the exporter used by the span processor
+ */
+ explicit SimpleSpanProcessor(std::unique_ptr<SpanExporter> &&exporter) noexcept
+ : exporter_(std::move(exporter))
+ {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override
+ {
+ return exporter_->MakeRecordable();
+ }
+
+ void OnStart(Recordable &span,
+ const opentelemetry::trace::SpanContext &parent_context) noexcept override
+ {}
+
+ void OnEnd(std::unique_ptr<Recordable> &&span) noexcept override
+ {
+ nostd::span<std::unique_ptr<Recordable>> batch(&span, 1);
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ if (exporter_->Export(batch) == sdk::common::ExportResult::kFailure)
+ {
+ /* Once it is defined how the SDK does logging, an error should be
+ * logged in this case. */
+ }
+ }
+
+ bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ return true;
+ }
+
+ bool Shutdown(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ // We only call shutdown ONCE.
+ if (exporter_ != nullptr && !shutdown_latch_.test_and_set(std::memory_order_acquire))
+ {
+ return exporter_->Shutdown(timeout);
+ }
+ return true;
+ }
+
+ ~SimpleSpanProcessor() { Shutdown(); }
+
+private:
+ std::unique_ptr<SpanExporter> exporter_;
+ opentelemetry::common::SpinLockMutex lock_;
+ std::atomic_flag shutdown_latch_ = ATOMIC_FLAG_INIT;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/span_data.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/span_data.h
new file mode 100644
index 000000000..0fb09f328
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/span_data.h
@@ -0,0 +1,304 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <chrono>
+#include <unordered_map>
+#include <vector>
+#include "opentelemetry/common/attribute_value.h"
+#include "opentelemetry/common/timestamp.h"
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/common/attribute_utils.h"
+#include "opentelemetry/sdk/trace/recordable.h"
+#include "opentelemetry/trace/canonical_code.h"
+#include "opentelemetry/trace/span.h"
+#include "opentelemetry/trace/span_id.h"
+#include "opentelemetry/trace/trace_id.h"
+
+#include <string>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+/**
+ * Class for storing events in SpanData.
+ */
+class SpanDataEvent
+{
+public:
+ SpanDataEvent(std::string name,
+ opentelemetry::common::SystemTimestamp timestamp,
+ const opentelemetry::common::KeyValueIterable &attributes)
+ : name_(name), timestamp_(timestamp), attribute_map_(attributes)
+ {}
+
+ /**
+ * Get the name for this event
+ * @return the name for this event
+ */
+ std::string GetName() const noexcept { return name_; }
+
+ /**
+ * Get the timestamp for this event
+ * @return the timestamp for this event
+ */
+ opentelemetry::common::SystemTimestamp GetTimestamp() const noexcept { return timestamp_; }
+
+ /**
+ * Get the attributes for this event
+ * @return the attributes for this event
+ */
+ const std::unordered_map<std::string, common::OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return attribute_map_.GetAttributes();
+ }
+
+private:
+ std::string name_;
+ opentelemetry::common::SystemTimestamp timestamp_;
+ common::AttributeMap attribute_map_;
+};
+
+/**
+ * Class for storing links in SpanData.
+ */
+class SpanDataLink
+{
+public:
+ SpanDataLink(opentelemetry::trace::SpanContext span_context,
+ const opentelemetry::common::KeyValueIterable &attributes)
+ : span_context_(span_context), attribute_map_(attributes)
+ {}
+
+ /**
+ * Get the attributes for this link
+ * @return the attributes for this link
+ */
+ const std::unordered_map<std::string, common::OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return attribute_map_.GetAttributes();
+ }
+
+ /**
+ * Get the span context for this link
+ * @return the span context for this link
+ */
+ const opentelemetry::trace::SpanContext &GetSpanContext() const noexcept { return span_context_; }
+
+private:
+ opentelemetry::trace::SpanContext span_context_;
+ common::AttributeMap attribute_map_;
+};
+
+/**
+ * SpanData is a representation of all data collected by a span.
+ */
+class SpanData final : public Recordable
+{
+public:
+ SpanData() : resource_{nullptr}, instrumentation_library_{nullptr} {}
+ /**
+ * Get the trace id for this span
+ * @return the trace id for this span
+ */
+ opentelemetry::trace::TraceId GetTraceId() const noexcept { return span_context_.trace_id(); }
+
+ /**
+ * Get the span id for this span
+ * @return the span id for this span
+ */
+ opentelemetry::trace::SpanId GetSpanId() const noexcept { return span_context_.span_id(); }
+
+ /**
+ * Get the span context for this span
+ * @return the span context for this span
+ */
+ const opentelemetry::trace::SpanContext &GetSpanContext() const noexcept { return span_context_; }
+
+ /**
+ * Get the parent span id for this span
+ * @return the span id for this span's parent
+ */
+ opentelemetry::trace::SpanId GetParentSpanId() const noexcept { return parent_span_id_; }
+
+ /**
+ * Get the name for this span
+ * @return the name for this span
+ */
+ opentelemetry::nostd::string_view GetName() const noexcept { return name_; }
+
+ /**
+ * Get the kind of this span
+ * @return the kind of this span
+ */
+ opentelemetry::trace::SpanKind GetSpanKind() const noexcept { return span_kind_; }
+
+ /**
+ * Get the status for this span
+ * @return the status for this span
+ */
+ opentelemetry::trace::StatusCode GetStatus() const noexcept { return status_code_; }
+
+ /**
+ * Get the status description for this span
+ * @return the description of the the status of this span
+ */
+ opentelemetry::nostd::string_view GetDescription() const noexcept { return status_desc_; }
+
+ /**
+ * Get the attributes associated with the resource
+ * @returns the attributes associated with the resource configured for TracerProvider
+ */
+
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept
+ {
+ if (resource_ == nullptr)
+ {
+ // this shouldn't happen as TraceProvider provides default resources
+ static opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::GetEmpty();
+ return resource;
+ }
+ return *resource_;
+ }
+
+ /**
+ * Get the attributes associated with the resource
+ * @returns the attributes associated with the resource configured for TracerProvider
+ */
+
+ const opentelemetry::sdk::trace::InstrumentationLibrary &GetInstrumentationLibrary()
+ const noexcept
+ {
+ if (instrumentation_library_ == nullptr)
+ {
+ // this shouldn't happen as Tracer ensures there is valid default instrumentation library.
+ static std::unique_ptr<opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary>
+ instrumentation_library =
+ opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create(
+ "unknown_service");
+ return *instrumentation_library;
+ }
+ return *instrumentation_library_;
+ }
+
+ /**
+ * Get the start time for this span
+ * @return the start time for this span
+ */
+ opentelemetry::common::SystemTimestamp GetStartTime() const noexcept { return start_time_; }
+
+ /**
+ * Get the duration for this span
+ * @return the duration for this span
+ */
+ std::chrono::nanoseconds GetDuration() const noexcept { return duration_; }
+
+ /**
+ * Get the attributes for this span
+ * @return the attributes for this span
+ */
+ const std::unordered_map<std::string, common::OwnedAttributeValue> &GetAttributes() const noexcept
+ {
+ return attribute_map_.GetAttributes();
+ }
+
+ /**
+ * Get the events associated with this span
+ * @return the events associated with this span
+ */
+ const std::vector<SpanDataEvent> &GetEvents() const noexcept { return events_; }
+
+ /**
+ * Get the links associated with this span
+ * @return the links associated with this span
+ */
+ const std::vector<SpanDataLink> &GetLinks() const noexcept { return links_; }
+
+ void SetIdentity(const opentelemetry::trace::SpanContext &span_context,
+ opentelemetry::trace::SpanId parent_span_id) noexcept override
+ {
+ span_context_ = span_context;
+ parent_span_id_ = parent_span_id;
+ }
+
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept override
+ {
+ attribute_map_.SetAttribute(key, value);
+ }
+
+ void AddEvent(nostd::string_view name,
+ opentelemetry::common::SystemTimestamp timestamp =
+ opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()),
+ const opentelemetry::common::KeyValueIterable &attributes =
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>>(
+ {})) noexcept override
+ {
+ SpanDataEvent event(std::string(name), timestamp, attributes);
+ events_.push_back(event);
+ }
+
+ void AddLink(const opentelemetry::trace::SpanContext &span_context,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override
+ {
+ SpanDataLink link(span_context, attributes);
+ links_.push_back(link);
+ }
+
+ void SetStatus(opentelemetry::trace::StatusCode code,
+ nostd::string_view description) noexcept override
+ {
+ status_code_ = code;
+ status_desc_ = std::string(description);
+ }
+
+ void SetName(nostd::string_view name) noexcept override
+ {
+ name_ = std::string(name.data(), name.length());
+ }
+
+ void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override
+ {
+ span_kind_ = span_kind;
+ }
+
+ void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override
+ {
+ resource_ = &resource;
+ }
+
+ void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override
+ {
+ start_time_ = start_time;
+ }
+
+ void SetDuration(std::chrono::nanoseconds duration) noexcept override { duration_ = duration; }
+
+ void SetInstrumentationLibrary(
+ const InstrumentationLibrary &instrumentation_library) noexcept override
+ {
+ instrumentation_library_ = &instrumentation_library;
+ }
+
+private:
+ opentelemetry::trace::SpanContext span_context_{false, false};
+ opentelemetry::trace::SpanId parent_span_id_;
+ opentelemetry::common::SystemTimestamp start_time_;
+ std::chrono::nanoseconds duration_{0};
+ std::string name_;
+ opentelemetry::trace::StatusCode status_code_{opentelemetry::trace::StatusCode::kUnset};
+ std::string status_desc_;
+ common::AttributeMap attribute_map_;
+ std::vector<SpanDataEvent> events_;
+ std::vector<SpanDataLink> links_;
+ opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal};
+ const opentelemetry::sdk::resource::Resource *resource_;
+ const InstrumentationLibrary *instrumentation_library_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer.h
new file mode 100644
index 000000000..fd9f2c8e8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer.h
@@ -0,0 +1,70 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
+#include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/processor.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/tracer_context.h"
+#include "opentelemetry/trace/noop.h"
+#include "opentelemetry/trace/tracer.h"
+#include "opentelemetry/version.h"
+
+#include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+using namespace opentelemetry::sdk::instrumentationlibrary;
+
+class Tracer final : public trace_api::Tracer, public std::enable_shared_from_this<Tracer>
+{
+public:
+ /** Construct a new Tracer with the given context pipeline. */
+ explicit Tracer(std::shared_ptr<sdk::trace::TracerContext> context,
+ std::unique_ptr<InstrumentationLibrary> instrumentation_library =
+ InstrumentationLibrary::Create("")) noexcept;
+
+ nostd::shared_ptr<trace_api::Span> StartSpan(
+ nostd::string_view name,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const trace_api::SpanContextKeyValueIterable &links,
+ const trace_api::StartSpanOptions &options = {}) noexcept override;
+
+ void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override;
+
+ void CloseWithMicroseconds(uint64_t timeout) noexcept override;
+
+ /** Returns the configured span processor. */
+ SpanProcessor &GetProcessor() noexcept { return context_->GetProcessor(); }
+
+ /** Returns the configured Id generator */
+ IdGenerator &GetIdGenerator() const noexcept { return context_->GetIdGenerator(); }
+
+ /** Returns the associated instruementation library */
+ const InstrumentationLibrary &GetInstrumentationLibrary() const noexcept
+ {
+ return *instrumentation_library_;
+ }
+
+ /** Returns the currently configured resource **/
+ const opentelemetry::sdk::resource::Resource &GetResource() { return context_->GetResource(); }
+
+ // Note: Test only
+ Sampler &GetSampler() { return context_->GetSampler(); }
+
+private:
+ // order of declaration is important here - instrumentation library should destroy after
+ // tracer-context.
+ std::shared_ptr<InstrumentationLibrary> instrumentation_library_;
+ std::shared_ptr<sdk::trace::TracerContext> context_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_context.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_context.h
new file mode 100644
index 000000000..572f60caf
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_context.h
@@ -0,0 +1,100 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/sdk/common/atomic_unique_ptr.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/processor.h"
+#include "opentelemetry/sdk/trace/random_id_generator.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+/**
+ * A class which stores the TracerProvider context.
+ *
+ * This class meets the following design criteria:
+ * - A shared reference between TracerProvider and Tracers instantiated.
+ * - A thread-safe class that allows updating/altering processor/exporter pipelines
+ * and sampling config.
+ * - The owner/destroyer of Processors/Exporters. These will remain active until
+ * this class is destroyed. I.e. Sampling, Exporting, flushing, Custom Iterator etc. are all ok
+ * if this object is alive, and they will work together. If this object is destroyed, then no shared
+ * references to Processor, Exporter, Recordable, Custom Iterator etc. should exist, and all
+ * associated pipelines will have been flushed.
+ */
+class TracerContext
+{
+public:
+ explicit TracerContext(
+ std::vector<std::unique_ptr<SpanProcessor>> &&processor,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({}),
+ std::unique_ptr<Sampler> sampler = std::unique_ptr<AlwaysOnSampler>(new AlwaysOnSampler),
+ std::unique_ptr<IdGenerator> id_generator =
+ std::unique_ptr<IdGenerator>(new RandomIdGenerator())) noexcept;
+
+ /**
+ * Attaches a span processor to list of configured processors to this tracer context.
+ * Processor once attached can't be removed.
+ * @param processor The new span processor for this tracer. This must not be
+ * a nullptr. Ownership is given to the `TracerContext`.
+ *
+ * Note: This method is not thread safe.
+ */
+ void AddProcessor(std::unique_ptr<SpanProcessor> processor) noexcept;
+
+ /**
+ * Obtain the sampler associated with this tracer.
+ * @return The sampler for this tracer.
+ */
+ Sampler &GetSampler() const noexcept;
+
+ /**
+ * Obtain the configured (composite) processor.
+ *
+ * Note: When more than one processor is active, this will
+ * return an "aggregate" processor
+ */
+ SpanProcessor &GetProcessor() const noexcept;
+
+ /**
+ * Obtain the resource associated with this tracer context.
+ * @return The resource for this tracer context.
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Obtain the Id Generator associated with this tracer context.
+ * @return The ID Generator for this tracer context.
+ */
+ opentelemetry::sdk::trace::IdGenerator &GetIdGenerator() const noexcept;
+
+ /**
+ * Force all active SpanProcessors to flush any buffered spans
+ * within the given timeout.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+ /**
+ * Shutdown the span processor associated with this tracer provider.
+ */
+ bool Shutdown() noexcept;
+
+private:
+ // order of declaration is important here - resource object should be destroyed after processor.
+ opentelemetry::sdk::resource::Resource resource_;
+ std::unique_ptr<Sampler> sampler_;
+ std::unique_ptr<IdGenerator> id_generator_;
+ std::unique_ptr<SpanProcessor> processor_;
+};
+
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_provider.h
new file mode 100644
index 000000000..aa0f69a2b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/trace/tracer_provider.h
@@ -0,0 +1,103 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include "opentelemetry/nostd/shared_ptr.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/processor.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/tracer.h"
+#include "opentelemetry/sdk/trace/tracer_context.h"
+#include "opentelemetry/trace/tracer_provider.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+class TracerProvider final : public opentelemetry::trace::TracerProvider
+{
+public:
+ /**
+ * Initialize a new tracer provider with a specified sampler
+ * @param processor The span processor for this tracer provider. This must
+ * not be a nullptr.
+ * @param resource The resources for this tracer provider.
+ * @param sampler The sampler for this tracer provider. This must
+ * not be a nullptr.
+ * @param id_generator The custom id generator for this tracer provider. This must
+ * not be a nullptr
+ */
+ explicit TracerProvider(
+ std::unique_ptr<SpanProcessor> processor,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({}),
+ std::unique_ptr<Sampler> sampler = std::unique_ptr<AlwaysOnSampler>(new AlwaysOnSampler),
+ std::unique_ptr<opentelemetry::sdk::trace::IdGenerator> id_generator =
+ std::unique_ptr<opentelemetry::sdk::trace::IdGenerator>(
+ new RandomIdGenerator())) noexcept;
+
+ explicit TracerProvider(
+ std::vector<std::unique_ptr<SpanProcessor>> &&processors,
+ opentelemetry::sdk::resource::Resource resource =
+ opentelemetry::sdk::resource::Resource::Create({}),
+ std::unique_ptr<Sampler> sampler = std::unique_ptr<AlwaysOnSampler>(new AlwaysOnSampler),
+ std::unique_ptr<opentelemetry::sdk::trace::IdGenerator> id_generator =
+ std::unique_ptr<opentelemetry::sdk::trace::IdGenerator>(
+ new RandomIdGenerator())) noexcept;
+
+ /**
+ * Initialize a new tracer provider with a specified context
+ * @param context The shared tracer configuration/pipeline for this provider.
+ */
+ explicit TracerProvider(std::shared_ptr<sdk::trace::TracerContext> context) noexcept;
+
+ ~TracerProvider();
+
+ opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> GetTracer(
+ nostd::string_view library_name,
+ nostd::string_view library_version = "",
+ nostd::string_view schema_url = "") noexcept override;
+
+ /**
+ * Attaches a span processor to list of configured processors for this tracer provider.
+ * @param processor The new span processor for this tracer provider. This
+ * must not be a nullptr.
+ *
+ * Note: This process may not receive any in-flight spans, but will get newly created spans.
+ * Note: This method is not thread safe, and should ideally be called from main thread.
+ */
+ void AddProcessor(std::unique_ptr<SpanProcessor> processor) noexcept;
+
+ /**
+ * Obtain the resource associated with this tracer provider.
+ * @return The resource for this tracer provider.
+ */
+ const opentelemetry::sdk::resource::Resource &GetResource() const noexcept;
+
+ /**
+ * Shutdown the span processor associated with this tracer provider.
+ */
+ bool Shutdown() noexcept;
+
+ /**
+ * Force flush the span processor associated with this tracer provider.
+ */
+ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept;
+
+private:
+ // order of declaration is important here - tracers should destroy only after context.
+ std::vector<std::shared_ptr<opentelemetry::sdk::trace::Tracer>> tracers_;
+ std::shared_ptr<sdk::trace::TracerContext> context_;
+ std::mutex lock_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/version/version.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/version/version.h
new file mode 100644
index 000000000..65c3c826c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk/version/version.h
@@ -0,0 +1,30 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/detail/preprocessor.h"
+
+#define OPENTELEMETRY_SDK_VERSION "1.4.0"
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace version
+{
+extern const int MAJOR_VERSION;
+extern const int MINOR_VERSION;
+extern const int PATCH_VERSION;
+extern const char *PRE_RELEASE;
+extern const char *BUILD_METADATA;
+extern const int COUNT_NEW_COMMITS;
+extern const char *BRANCH;
+extern const char *COMMIT_HASH;
+extern const char *FULL_VERSION;
+extern const char *FULL_VERSION_WITH_BRANCH_COMMITHASH;
+extern const char *BUILD_DATE;
+} // namespace version
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk_config.h b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk_config.h
new file mode 100644
index 000000000..8ac72a10d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/include/opentelemetry/sdk_config.h
@@ -0,0 +1,7 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/config.h"
+#include "opentelemetry/sdk/common/global_log_handler.h" \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/CMakeLists.txt
new file mode 100644
index 000000000..aab294b6d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_subdirectory(common)
+add_subdirectory(trace)
+if(WITH_METRICS_PREVIEW)
+ add_subdirectory(_metrics)
+else()
+ add_subdirectory(metrics)
+endif()
+if(WITH_LOGS_PREVIEW)
+ add_subdirectory(logs)
+endif()
+add_subdirectory(version)
+add_subdirectory(resource)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/BUILD
new file mode 100644
index 000000000..4b528dda7
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/BUILD
@@ -0,0 +1,26 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "metrics_deprecated",
+ srcs = glob(["**/*.cc"]),
+ hdrs = glob(["**/*.h"]),
+ include_prefix = "src/_metrics",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/CMakeLists.txt
new file mode 100644
index 000000000..c1717ce89
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_library(opentelemetry_metrics_deprecated meter_provider.cc meter.cc
+ ungrouped_processor.cc)
+
+set_target_properties(opentelemetry_metrics_deprecated
+ PROPERTIES EXPORT_NAME metrics_deprecated)
+
+target_link_libraries(opentelemetry_metrics_deprecated
+ PUBLIC opentelemetry_common)
+
+target_include_directories(
+ opentelemetry_metrics_deprecated
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_metrics_deprecated
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter.cc
new file mode 100644
index 000000000..f48eccfbd
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter.cc
@@ -0,0 +1,782 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/sdk/_metrics/meter.h"
+# include "opentelemetry/common/macros.h"
+
+namespace metrics_api = opentelemetry::metrics;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+nostd::shared_ptr<metrics_api::Counter<short>> Meter::NewShortCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto counter = new Counter<short>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::Counter<short>>(counter);
+ metrics_lock_.lock();
+ short_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::Counter<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::Counter<int>> Meter::NewIntCounter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto counter = new Counter<int>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::Counter<int>>(counter);
+ metrics_lock_.lock();
+ int_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::Counter<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::Counter<float>> Meter::NewFloatCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto counter = new Counter<float>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::Counter<float>>(counter);
+ metrics_lock_.lock();
+ float_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::Counter<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::Counter<double>> Meter::NewDoubleCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto counter = new Counter<double>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::Counter<double>>(counter);
+ metrics_lock_.lock();
+ double_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::Counter<double>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownCounter<short>> Meter::NewShortUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto udcounter = new UpDownCounter<short>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::UpDownCounter<short>>(udcounter);
+ metrics_lock_.lock();
+ short_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownCounter<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownCounter<int>> Meter::NewIntUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto udcounter = new UpDownCounter<int>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::UpDownCounter<int>>(udcounter);
+ metrics_lock_.lock();
+ int_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownCounter<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownCounter<float>> Meter::NewFloatUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto udcounter = new UpDownCounter<float>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::UpDownCounter<float>>(udcounter);
+ metrics_lock_.lock();
+ float_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownCounter<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownCounter<double>> Meter::NewDoubleUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto udcounter = new UpDownCounter<double>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::UpDownCounter<double>>(udcounter);
+ metrics_lock_.lock();
+ double_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownCounter<double>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueRecorder<short>> Meter::NewShortValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto recorder = new ValueRecorder<short>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::ValueRecorder<short>>(recorder);
+ metrics_lock_.lock();
+ short_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueRecorder<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueRecorder<int>> Meter::NewIntValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto recorder = new ValueRecorder<int>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::ValueRecorder<int>>(recorder);
+ metrics_lock_.lock();
+ int_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueRecorder<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueRecorder<float>> Meter::NewFloatValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto recorder = new ValueRecorder<float>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::ValueRecorder<float>>(recorder);
+ metrics_lock_.lock();
+ float_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueRecorder<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueRecorder<double>> Meter::NewDoubleValueRecorder(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled)
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto recorder = new ValueRecorder<double>(name, description, unit, enabled);
+ auto ptr = std::shared_ptr<metrics_api::ValueRecorder<double>>(recorder);
+ metrics_lock_.lock();
+ double_metrics_.insert(std::make_pair(std::string(name), ptr));
+ metrics_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueRecorder<double>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::SumObserver<short>> Meter::NewShortSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<short>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new SumObserver<short>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::SumObserver<short>>(sumobs);
+ observers_lock_.lock();
+ short_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::SumObserver<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::SumObserver<int>> Meter::NewIntSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<int>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new SumObserver<int>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::SumObserver<int>>(sumobs);
+ observers_lock_.lock();
+ int_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::SumObserver<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::SumObserver<float>> Meter::NewFloatSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<float>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new SumObserver<float>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::SumObserver<float>>(sumobs);
+ observers_lock_.lock();
+ float_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::SumObserver<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::SumObserver<double>> Meter::NewDoubleSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<double>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new SumObserver<double>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::SumObserver<double>>(sumobs);
+ observers_lock_.lock();
+ double_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::SumObserver<double>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownSumObserver<short>> Meter::NewShortUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<short>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new UpDownSumObserver<short>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<short>>(sumobs);
+ observers_lock_.lock();
+ short_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownSumObserver<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownSumObserver<int>> Meter::NewIntUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<int>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new UpDownSumObserver<int>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<int>>(sumobs);
+ observers_lock_.lock();
+ int_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownSumObserver<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownSumObserver<float>> Meter::NewFloatUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<float>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new UpDownSumObserver<float>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<float>>(sumobs);
+ observers_lock_.lock();
+ float_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownSumObserver<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::UpDownSumObserver<double>> Meter::NewDoubleUpDownSumObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<double>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new UpDownSumObserver<double>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<double>>(sumobs);
+ observers_lock_.lock();
+ double_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::UpDownSumObserver<double>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueObserver<short>> Meter::NewShortValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<short>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new ValueObserver<short>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::ValueObserver<short>>(sumobs);
+ observers_lock_.lock();
+ short_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueObserver<short>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueObserver<int>> Meter::NewIntValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<int>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new ValueObserver<int>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::ValueObserver<int>>(sumobs);
+ observers_lock_.lock();
+ int_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueObserver<int>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueObserver<float>> Meter::NewFloatValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<float>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new ValueObserver<float>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::ValueObserver<float>>(sumobs);
+ observers_lock_.lock();
+ float_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueObserver<float>>(ptr);
+}
+
+nostd::shared_ptr<metrics_api::ValueObserver<double>> Meter::NewDoubleValueObserver(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit,
+ const bool enabled,
+ void (*callback)(metrics_api::ObserverResult<double>))
+{
+ if (!IsValidName(name) || NameAlreadyUsed(name))
+ {
+# if __EXCEPTIONS
+ throw std::invalid_argument("Invalid Name");
+# else
+ std::terminate();
+# endif
+ }
+ auto sumobs = new ValueObserver<double>(name, description, unit, enabled, callback);
+ auto ptr = std::shared_ptr<metrics_api::ValueObserver<double>>(sumobs);
+ observers_lock_.lock();
+ double_observers_.insert(std::make_pair(std::string(name), ptr));
+ observers_lock_.unlock();
+ return nostd::shared_ptr<metrics_api::ValueObserver<double>>(ptr);
+}
+
+void Meter::RecordShortBatch(const common::KeyValueIterable &labels,
+ nostd::span<metrics_api::SynchronousInstrument<short> *> instruments,
+ nostd::span<const short> values) noexcept
+{
+ for (size_t i = 0; i < instruments.size(); ++i)
+ {
+ instruments[i]->update(values[i], labels);
+ }
+}
+
+void Meter::RecordIntBatch(const common::KeyValueIterable &labels,
+ nostd::span<metrics_api::SynchronousInstrument<int> *> instruments,
+ nostd::span<const int> values) noexcept
+{
+ for (size_t i = 0; i < instruments.size(); ++i)
+ {
+ instruments[i]->update(values[i], labels);
+ }
+}
+
+void Meter::RecordFloatBatch(const common::KeyValueIterable &labels,
+ nostd::span<metrics_api::SynchronousInstrument<float> *> instruments,
+ nostd::span<const float> values) noexcept
+{
+ for (size_t i = 0; i < instruments.size(); ++i)
+ {
+ instruments[i]->update(values[i], labels);
+ }
+}
+
+void Meter::RecordDoubleBatch(const common::KeyValueIterable &labels,
+ nostd::span<metrics_api::SynchronousInstrument<double> *> instruments,
+ nostd::span<const double> values) noexcept
+{
+ for (size_t i = 0; i < instruments.size(); ++i)
+ {
+ instruments[i]->update(values[i], labels);
+ }
+}
+
+std::vector<Record> Meter::Collect() noexcept
+{
+ std::vector<Record> records;
+ CollectMetrics(records);
+ CollectObservers(records);
+ return records;
+}
+
+// Must cast to sdk::SynchronousInstrument to have access to GetRecords() function
+void Meter::CollectMetrics(std::vector<Record> &records)
+{
+ metrics_lock_.lock();
+ for (auto i = short_metrics_.begin(); i != short_metrics_.end();)
+ {
+ CollectSingleSyncInstrument<short>(i, records);
+ if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
+ {
+ i = short_metrics_.erase(i); // Remove instrument that is no longer accessible
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = int_metrics_.begin(); i != int_metrics_.end();)
+ {
+ CollectSingleSyncInstrument<int>(i, records);
+ if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
+ {
+ i = int_metrics_.erase(i); // Remove instrument that is no longer accessible
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = float_metrics_.begin(); i != float_metrics_.end();)
+ {
+ CollectSingleSyncInstrument<float>(i, records);
+ if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
+ {
+ i = float_metrics_.erase(i); // Remove instrument that is no longer accessible
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = double_metrics_.begin(); i != double_metrics_.end();)
+ {
+ CollectSingleSyncInstrument<double>(i, records);
+ if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
+ {
+ i = double_metrics_.erase(i); // Remove instrument that is no longer accessible
+ }
+ else
+ {
+ i++;
+ }
+ }
+ metrics_lock_.unlock();
+}
+
+template <typename T>
+void Meter::CollectSingleSyncInstrument(
+ typename std::map<std::string, std::shared_ptr<metrics_api::SynchronousInstrument<T>>>::iterator
+ i,
+ std::vector<Record> &records)
+{
+ if (!i->second->IsEnabled())
+ {
+ i++;
+ return;
+ }
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto cast_ptr = std::dynamic_pointer_cast<SynchronousInstrument<T>>(i->second);
+# else
+ auto cast_ptr = std::static_pointer_cast<SynchronousInstrument<T>>(i->second);
+# endif
+ std::vector<Record> new_records = cast_ptr->GetRecords();
+ records.insert(records.begin(), new_records.begin(), new_records.end());
+}
+
+void Meter::CollectObservers(std::vector<Record> &records)
+{
+ observers_lock_.lock();
+ for (auto i = short_observers_.begin(); i != short_observers_.end();)
+ {
+ CollectSingleAsyncInstrument<short>(i, records);
+ if (i->second.use_count() == 1)
+ {
+ i = short_observers_.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = int_observers_.begin(); i != int_observers_.end();)
+ {
+ CollectSingleAsyncInstrument<int>(i, records);
+ if (i->second.use_count() == 1)
+ {
+ i = int_observers_.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = float_observers_.begin(); i != float_observers_.end();)
+ {
+ CollectSingleAsyncInstrument<float>(i, records);
+ if (i->second.use_count() == 1)
+ {
+ i = float_observers_.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ for (auto i = double_observers_.begin(); i != double_observers_.end();)
+ {
+ CollectSingleAsyncInstrument<double>(i, records);
+ if (i->second.use_count() == 1)
+ {
+ i = double_observers_.erase(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ observers_lock_.unlock();
+}
+
+template <typename T>
+void Meter::CollectSingleAsyncInstrument(
+ typename std::map<std::string,
+ std::shared_ptr<metrics_api::AsynchronousInstrument<T>>>::iterator i,
+ std::vector<Record> &records)
+{
+ if (!i->second->IsEnabled())
+ {
+ i++;
+ return;
+ }
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto cast_ptr = std::dynamic_pointer_cast<AsynchronousInstrument<T>>(i->second);
+# else
+ auto cast_ptr = std::static_pointer_cast<AsynchronousInstrument<T>>(i->second);
+# endif
+ std::vector<Record> new_records = cast_ptr->GetRecords();
+ records.insert(records.begin(), new_records.begin(), new_records.end());
+}
+
+bool Meter::IsValidName(nostd::string_view name)
+{
+ if (name.empty() || isdigit(name[0]) || isspace(name[0]) || ispunct(name[0]))
+ return false;
+ else
+ {
+ for (size_t i = 0; i < name.size(); ++i)
+ {
+ if (!isalnum(name[i]) && name[i] != '_' && name[i] != '.' && name[i] != '-')
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Meter::NameAlreadyUsed(nostd::string_view name)
+{
+ std::lock_guard<std::mutex> lg_metrics(metrics_lock_);
+ std::lock_guard<std::mutex> lg_obsevers(observers_lock_);
+ if (names_.find(std::string(name)) != names_.end())
+ return true;
+ else
+ {
+ names_.insert(std::string(name));
+ return false;
+ }
+}
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter_provider.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter_provider.cc
new file mode 100644
index 000000000..9a36817a6
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/meter_provider.cc
@@ -0,0 +1,29 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/meter_provider.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+namespace nostd = opentelemetry::nostd;
+namespace metrics_api = opentelemetry::metrics;
+
+MeterProvider::MeterProvider(std::string library_name, std::string library_version) noexcept
+ : meter_(new Meter(library_name, library_version))
+{}
+
+nostd::shared_ptr<metrics_api::Meter> MeterProvider::GetMeter(
+ nostd::string_view library_name,
+ nostd::string_view library_version) noexcept
+{
+ return nostd::shared_ptr<metrics_api::Meter>(meter_);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/ungrouped_processor.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/ungrouped_processor.cc
new file mode 100644
index 000000000..b3d1a94eb
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/_metrics/ungrouped_processor.cc
@@ -0,0 +1,178 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+namespace sdk
+{
+
+namespace metrics
+{
+
+UngroupedMetricsProcessor::UngroupedMetricsProcessor(bool stateful)
+{
+ stateful_ = stateful;
+}
+
+/**
+ * CheckpointSelf will return a vector of records to be exported. This function will go through
+ *aggregators that have been sent through process() and return them as a vector of records.
+ **/
+std::vector<opentelemetry::sdk::metrics::Record>
+UngroupedMetricsProcessor::CheckpointSelf() noexcept
+{
+ std::vector<opentelemetry::sdk::metrics::Record> metric_records;
+
+ for (auto iter : batch_map_)
+ {
+ // Create a record from the held KeyStruct values and add to the Checkpoint
+ KeyStruct key = iter.first;
+ opentelemetry::sdk::metrics::Record r{key.name, key.description, key.labels, iter.second};
+
+ metric_records.push_back(r);
+ }
+
+ return metric_records;
+}
+
+/**
+ * Once Process is called, FinishCollection() should also be called. In the case of a non stateful
+ *processor the map will be reset.
+ **/
+void UngroupedMetricsProcessor::FinishedCollection() noexcept
+{
+ if (!stateful_)
+ {
+ batch_map_ = {};
+ }
+}
+
+void UngroupedMetricsProcessor::process(opentelemetry::sdk::metrics::Record record) noexcept
+{
+ auto aggregator = record.GetAggregator();
+ std::string label = record.GetLabels();
+ std::string name = record.GetName();
+ std::string description = record.GetDescription();
+
+ KeyStruct batch_key = KeyStruct(name, description, label, get_instrument(aggregator));
+
+ /**
+ * If we have already seen this aggregator then we will merge it with the copy that exists in the
+ *batch_map_ The call to merge here combines only identical records (same key)
+ **/
+ if (batch_map_.find(batch_key) != batch_map_.end())
+ {
+ auto batch_value = batch_map_[batch_key];
+
+ if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
+ aggregator))
+ {
+ auto batch_value_reference_short =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(batch_value);
+ auto aggregator_reference_short =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator);
+
+ merge_aggregators<short>(batch_value_reference_short, aggregator_reference_short);
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
+ {
+ auto batch_value_reference_int =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(batch_value);
+ auto aggregator_reference_int =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator);
+
+ merge_aggregators<int>(batch_value_reference_int, aggregator_reference_int);
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
+ {
+ auto batch_value_reference_float =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(batch_value);
+ auto aggregator_reference_float =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator);
+
+ merge_aggregators<float>(batch_value_reference_float, aggregator_reference_float);
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
+ {
+ auto batch_value_reference_double =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(batch_value);
+ auto aggregator_reference_double =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator);
+
+ merge_aggregators<double>(batch_value_reference_double, aggregator_reference_double);
+ }
+ return;
+ }
+ /**
+ * If the processor is stateful and this aggregator has not be seen by the processor yet.
+ * We create a copy of this aggregator, merge it with the aggregator from the given record.
+ * Then set this copied aggregator with the batch_key in the batch_map_
+ **/
+ if (stateful_)
+ {
+ if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
+ aggregator))
+ {
+ auto record_agg_short =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator);
+ auto aggregator_short = aggregator_copy<short>(record_agg_short);
+
+ merge_aggregators<short>(aggregator_short, record_agg_short);
+
+ batch_map_[batch_key] = aggregator_short;
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
+ {
+ auto record_agg_int =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator);
+ auto aggregator_int = aggregator_copy<int>(record_agg_int);
+
+ merge_aggregators<int>(aggregator_int, record_agg_int);
+
+ batch_map_[batch_key] = aggregator_int;
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
+ {
+ auto record_agg_float =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator);
+ auto aggregator_float = aggregator_copy<float>(record_agg_float);
+
+ merge_aggregators<float>(aggregator_float, record_agg_float);
+
+ batch_map_[batch_key] = aggregator_float;
+ }
+ else if (nostd::holds_alternative<
+ std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
+ {
+ auto record_agg_double =
+ nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator);
+ auto aggregator_double = aggregator_copy<double>(record_agg_double);
+
+ merge_aggregators<double>(aggregator_double, record_agg_double);
+
+ batch_map_[batch_key] = aggregator_double;
+ }
+ }
+ else
+ {
+ /**
+ * If the processor is not stateful, we don't need to create a copy of the aggregator, since the
+ *map will be reset from FinishedCollection().
+ **/
+ batch_map_[batch_key] = aggregator;
+ }
+}
+
+} // namespace metrics
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/BUILD
new file mode 100644
index 000000000..b8369fc6f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/BUILD
@@ -0,0 +1,44 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "random",
+ srcs = [
+ "core.cc",
+ "random.cc",
+ ],
+ hdrs = [
+ "fast_random_number_generator.h",
+ "random.h",
+ ],
+ include_prefix = "src/common",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "//sdk/src/common/platform:fork",
+ ],
+)
+
+cc_library(
+ name = "global_log_handler",
+ srcs = [
+ "global_log_handler.cc",
+ ],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/CMakeLists.txt
new file mode 100644
index 000000000..d8674353b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(COMMON_SRCS random.cc core.cc global_log_handler.cc)
+if(WIN32)
+ list(APPEND COMMON_SRCS platform/fork_windows.cc)
+else()
+ list(APPEND COMMON_SRCS platform/fork_unix.cc)
+endif()
+
+add_library(opentelemetry_common ${COMMON_SRCS})
+
+set_target_properties(opentelemetry_common PROPERTIES EXPORT_NAME common)
+
+target_link_libraries(
+ opentelemetry_common PUBLIC opentelemetry_api opentelemetry_sdk
+ Threads::Threads)
+
+install(
+ TARGETS opentelemetry_common
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/core.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/core.cc
new file mode 100644
index 000000000..16012e765
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/core.cc
@@ -0,0 +1,8 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+// clang-format off
+// version.h should be included before nostd/variant.h.
+#include "opentelemetry/version.h"
+#include "opentelemetry/nostd/variant.h"
+// clang-format on
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/fast_random_number_generator.h b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/fast_random_number_generator.h
new file mode 100644
index 000000000..9887f2f3b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/fast_random_number_generator.h
@@ -0,0 +1,82 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <limits>
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * Profiling shows that random number generation can be a significant cost of
+ * span generation. This provides a faster random number generator than
+ * std::mt19937_64; and since we don't care about the other beneficial random
+ * number properties that std:mt19937_64 provides for this application, it's a
+ * entirely appropriate replacement.
+ *
+ * Note for Windows users - please make sure that NOMINMAX is defined, e.g.
+ *
+ * ...
+ * #define NOMINMAX
+ * #include <Windows.h>
+ * ...
+ *
+ * See:
+ * https://stackoverflow.com/questions/13416418/define-nominmax-using-stdmin-max
+ *
+ */
+class FastRandomNumberGenerator
+{
+public:
+ using result_type = uint64_t;
+
+ FastRandomNumberGenerator() noexcept = default;
+
+ template <class SeedSequence>
+ FastRandomNumberGenerator(SeedSequence &seed_sequence) noexcept
+ {
+ seed(seed_sequence);
+ }
+
+ uint64_t operator()() noexcept
+ {
+ // Uses the xorshift128p random number generation algorithm described in
+ // https://en.wikipedia.org/wiki/Xorshift
+ auto &state_a = state_[0];
+ auto &state_b = state_[1];
+ auto t = state_a;
+ auto s = state_b;
+ state_a = s;
+ t ^= t << 23; // a
+ t ^= t >> 17; // b
+ t ^= s ^ (s >> 26); // c
+ state_b = t;
+ return t + s;
+ }
+
+ // RandomNumberGenerator concept functions required from standard library.
+ // See http://www.cplusplus.com/reference/random/mt19937/
+ template <class SeedSequence>
+ void seed(SeedSequence &seed_sequence) noexcept
+ {
+ seed_sequence.generate(reinterpret_cast<uint32_t *>(state_.data()),
+ reinterpret_cast<uint32_t *>(state_.data() + state_.size()));
+ }
+
+ static constexpr uint64_t min() noexcept { return 0; }
+
+ static constexpr uint64_t max() noexcept { return std::numeric_limits<uint64_t>::max(); }
+
+private:
+ std::array<uint64_t, 2> state_{};
+};
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/global_log_handler.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/global_log_handler.cc
new file mode 100644
index 000000000..c86b652c7
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/global_log_handler.cc
@@ -0,0 +1,57 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/global_log_handler.h"
+
+#include <cstring>
+#include <random>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+namespace internal_log
+{
+
+LogHandler::~LogHandler() {}
+
+void DefaultLogHandler::Handle(LogLevel level,
+ const char *file,
+ int line,
+ const char *msg,
+ const sdk::common::AttributeMap &attributes) noexcept
+{
+ std::stringstream output_s;
+ output_s << "[" << LevelToString(level) << "] ";
+ if (file != nullptr)
+ {
+ output_s << "File: " << file << ":" << line;
+ }
+ if (msg != nullptr)
+ {
+ output_s << msg;
+ }
+ output_s << std::endl;
+ // TBD - print attributes
+ std::cout << output_s.str(); // thread safe.
+}
+
+void NoopLogHandler::Handle(LogLevel,
+ const char *,
+ int,
+ const char *,
+ const sdk::common::AttributeMap &) noexcept
+{}
+
+std::pair<nostd::shared_ptr<LogHandler>, LogLevel> &GlobalLogHandler::GetHandlerAndLevel() noexcept
+{
+ static std::pair<nostd::shared_ptr<LogHandler>, LogLevel> handler_and_level{
+ nostd::shared_ptr<LogHandler>(new DefaultLogHandler), LogLevel::Warning};
+ return handler_and_level;
+}
+
+} // namespace internal_log
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/BUILD
new file mode 100644
index 000000000..c96a1417a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/BUILD
@@ -0,0 +1,34 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "fork",
+ srcs = select({
+ "//bazel:windows": ["fork_windows.cc"],
+ "//conditions:default": ["fork_unix.cc"],
+ }),
+ hdrs = [
+ "fork.h",
+ ],
+ include_prefix = "src/common/platform",
+ linkopts = select({
+ "//bazel:windows": [],
+ "//conditions:default": ["-pthread"],
+ }),
+ deps = [
+ "//api",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork.h b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork.h
new file mode 100644
index 000000000..b1a0e9d77
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork.h
@@ -0,0 +1,24 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+namespace platform
+{
+/**
+ * Portable wrapper for pthread_atfork.
+ * See
+ * https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html
+ */
+int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept;
+} // namespace platform
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_unix.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_unix.cc
new file mode 100644
index 000000000..cfbd8ab77
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_unix.cc
@@ -0,0 +1,22 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/platform/fork.h"
+
+#include <pthread.h>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+namespace platform
+{
+int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept
+{
+ return ::pthread_atfork(prepare, parent, child);
+}
+} // namespace platform
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_windows.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_windows.cc
new file mode 100644
index 000000000..9d9f2bf79
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/platform/fork_windows.cc
@@ -0,0 +1,23 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/platform/fork.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+namespace platform
+{
+int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept
+{
+ (void)prepare;
+ (void)parent;
+ (void)child;
+ return 0;
+}
+} // namespace platform
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.cc
new file mode 100644
index 000000000..77b88cfa2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.cc
@@ -0,0 +1,80 @@
+
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/random.h"
+#include "src/common/platform/fork.h"
+
+#include <cstring>
+#include <random>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+// Wraps a thread_local random number generator, but adds a fork handler so that
+// the generator will be correctly seeded after forking.
+//
+// See https://stackoverflow.com/q/51882689/4447365 and
+// https://github.com/opentracing-contrib/nginx-opentracing/issues/52
+namespace
+{
+class TlsRandomNumberGenerator
+{
+public:
+ TlsRandomNumberGenerator() noexcept
+ {
+ Seed();
+ platform::AtFork(nullptr, nullptr, OnFork);
+ }
+
+ static FastRandomNumberGenerator &engine() noexcept { return engine_; }
+
+private:
+ static thread_local FastRandomNumberGenerator engine_;
+
+ static void OnFork() noexcept { Seed(); }
+
+ static void Seed() noexcept
+ {
+ std::random_device random_device;
+ std::seed_seq seed_seq{random_device(), random_device(), random_device(), random_device()};
+ engine_.seed(seed_seq);
+ }
+};
+
+thread_local FastRandomNumberGenerator TlsRandomNumberGenerator::engine_{};
+} // namespace
+
+FastRandomNumberGenerator &Random::GetRandomNumberGenerator() noexcept
+{
+ static thread_local TlsRandomNumberGenerator random_number_generator{};
+ return TlsRandomNumberGenerator::engine();
+}
+
+uint64_t Random::GenerateRandom64() noexcept
+{
+ return GetRandomNumberGenerator()();
+}
+
+void Random::GenerateRandomBuffer(opentelemetry::nostd::span<uint8_t> buffer) noexcept
+{
+ auto buf_size = buffer.size();
+
+ for (size_t i = 0; i < buf_size; i += sizeof(uint64_t))
+ {
+ uint64_t value = GenerateRandom64();
+ if (i + sizeof(uint64_t) <= buf_size)
+ {
+ memcpy(&buffer[i], &value, sizeof(uint64_t));
+ }
+ else
+ {
+ memcpy(&buffer[i], &value, buf_size - i);
+ }
+ }
+}
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.h b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.h
new file mode 100644
index 000000000..ecd6dabc1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/common/random.h
@@ -0,0 +1,41 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/version.h"
+#include "src/common/fast_random_number_generator.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace common
+{
+/**
+ * Utility methods for creating random data, based on a seeded thread-local
+ * number generator.
+ */
+class Random
+{
+public:
+ /**
+ * @return an unsigned 64 bit random number
+ */
+ static uint64_t GenerateRandom64() noexcept;
+ /**
+ * Fill the passed span with random bytes.
+ *
+ * @param buffer A span of bytes.
+ */
+ static void GenerateRandomBuffer(opentelemetry::nostd::span<uint8_t> buffer) noexcept;
+
+private:
+ /**
+ * @return a seeded thread-local random number generator.
+ */
+ static FastRandomNumberGenerator &GetRandomNumberGenerator() noexcept;
+};
+} // namespace common
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/BUILD
new file mode 100644
index 000000000..53465cb8b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/BUILD
@@ -0,0 +1,28 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "logs",
+ srcs = glob(["**/*.cc"]),
+ hdrs = glob(["**/*.h"]),
+ include_prefix = "src/logs",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "//sdk/src/common:global_log_handler",
+ "//sdk/src/resource",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/CMakeLists.txt
new file mode 100644
index 000000000..20f13324e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_library(
+ opentelemetry_logs
+ logger_provider.cc
+ logger.cc
+ simple_log_processor.cc
+ batch_log_processor.cc
+ logger_context.cc
+ multi_log_processor.cc
+ multi_recordable.cc)
+
+set_target_properties(opentelemetry_logs PROPERTIES EXPORT_NAME logs)
+
+target_link_libraries(opentelemetry_logs PUBLIC opentelemetry_resources
+ opentelemetry_common)
+
+target_include_directories(
+ opentelemetry_logs
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_logs
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/batch_log_processor.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/batch_log_processor.cc
new file mode 100644
index 000000000..9b20705b0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/batch_log_processor.cc
@@ -0,0 +1,208 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+# include "opentelemetry/sdk/logs/batch_log_processor.h"
+
+# include <vector>
+using opentelemetry::sdk::common::AtomicUniquePtr;
+using opentelemetry::sdk::common::CircularBufferRange;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+BatchLogProcessor::BatchLogProcessor(std::unique_ptr<LogExporter> &&exporter,
+ const size_t max_queue_size,
+ const std::chrono::milliseconds scheduled_delay_millis,
+ const size_t max_export_batch_size)
+ : exporter_(std::move(exporter)),
+ max_queue_size_(max_queue_size),
+ scheduled_delay_millis_(scheduled_delay_millis),
+ max_export_batch_size_(max_export_batch_size),
+ buffer_(max_queue_size_),
+ worker_thread_(&BatchLogProcessor::DoBackgroundWork, this)
+{}
+
+std::unique_ptr<Recordable> BatchLogProcessor::MakeRecordable() noexcept
+{
+ return exporter_->MakeRecordable();
+}
+
+void BatchLogProcessor::OnReceive(std::unique_ptr<Recordable> &&record) noexcept
+{
+ if (is_shutdown_.load() == true)
+ {
+ return;
+ }
+
+ if (buffer_.Add(record) == false)
+ {
+ return;
+ }
+
+ // If the queue gets at least half full a preemptive notification is
+ // sent to the worker thread to start a new export cycle.
+ if (buffer_.size() >= max_queue_size_ / 2)
+ {
+ // signal the worker thread
+ cv_.notify_one();
+ }
+}
+
+bool BatchLogProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ if (is_shutdown_.load() == true)
+ {
+ return false;
+ }
+
+ is_force_flush_ = true;
+
+ // Keep attempting to wake up the worker thread
+ while (is_force_flush_.load() == true)
+ {
+ cv_.notify_one();
+ }
+
+ // Now wait for the worker thread to signal back from the Export method
+ std::unique_lock<std::mutex> lk(force_flush_cv_m_);
+ while (is_force_flush_notified_.load() == false)
+ {
+ force_flush_cv_.wait(lk);
+ }
+
+ // Notify the worker thread
+ is_force_flush_notified_ = false;
+
+ return true;
+}
+
+void BatchLogProcessor::DoBackgroundWork()
+{
+ auto timeout = scheduled_delay_millis_;
+
+ while (true)
+ {
+ // Wait for `timeout` milliseconds
+ std::unique_lock<std::mutex> lk(cv_m_);
+ cv_.wait_for(lk, timeout);
+
+ if (is_shutdown_.load() == true)
+ {
+ DrainQueue();
+ return;
+ }
+
+ bool was_force_flush_called = is_force_flush_.load();
+
+ // Check if this export was the result of a force flush.
+ if (was_force_flush_called == true)
+ {
+ // Since this export was the result of a force flush, signal the
+ // main thread that the worker thread has been notified
+ is_force_flush_ = false;
+ }
+ else
+ {
+ // If the buffer was empty during the entire `timeout` time interval,
+ // go back to waiting. If this was a spurious wake-up, we export only if
+ // `buffer_` is not empty. This is acceptable because batching is a best
+ // mechanism effort here.
+ if (buffer_.empty() == true)
+ {
+ continue;
+ }
+ }
+
+ auto start = std::chrono::steady_clock::now();
+ Export(was_force_flush_called);
+ auto end = std::chrono::steady_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+
+ // Subtract the duration of this export call from the next `timeout`.
+ timeout = scheduled_delay_millis_ - duration;
+ }
+}
+
+void BatchLogProcessor::Export(const bool was_force_flush_called)
+{
+ std::vector<std::unique_ptr<Recordable>> records_arr;
+
+ size_t num_records_to_export;
+
+ if (was_force_flush_called == true)
+ {
+ num_records_to_export = buffer_.size();
+ }
+ else
+ {
+ num_records_to_export =
+ buffer_.size() >= max_export_batch_size_ ? max_export_batch_size_ : buffer_.size();
+ }
+
+ buffer_.Consume(num_records_to_export,
+ [&](CircularBufferRange<AtomicUniquePtr<Recordable>> range) noexcept {
+ range.ForEach([&](AtomicUniquePtr<Recordable> &ptr) {
+ std::unique_ptr<Recordable> swap_ptr = std::unique_ptr<Recordable>(nullptr);
+ ptr.Swap(swap_ptr);
+ records_arr.push_back(std::unique_ptr<Recordable>(swap_ptr.release()));
+ return true;
+ });
+ });
+
+ exporter_->Export(
+ nostd::span<std::unique_ptr<Recordable>>(records_arr.data(), records_arr.size()));
+
+ // Notify the main thread in case this export was the result of a force flush.
+ if (was_force_flush_called == true)
+ {
+ is_force_flush_notified_ = true;
+ while (is_force_flush_notified_.load() == true)
+ {
+ force_flush_cv_.notify_one();
+ }
+ }
+}
+
+void BatchLogProcessor::DrainQueue()
+{
+ while (buffer_.empty() == false)
+ {
+ Export(false);
+ }
+}
+
+bool BatchLogProcessor::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ std::lock_guard<std::mutex> shutdown_guard{shutdown_m_};
+ bool already_shutdown = is_shutdown_.exchange(true);
+
+ if (worker_thread_.joinable())
+ {
+ cv_.notify_one();
+ worker_thread_.join();
+ }
+
+ // Should only shutdown exporter ONCE.
+ if (!already_shutdown && exporter_ != nullptr)
+ {
+ return exporter_->Shutdown();
+ }
+
+ return true;
+}
+
+BatchLogProcessor::~BatchLogProcessor()
+{
+ if (is_shutdown_.load() == false)
+ {
+ Shutdown();
+ }
+}
+
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger.cc
new file mode 100644
index 000000000..b8fdb15c3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger.cc
@@ -0,0 +1,126 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+# include "opentelemetry/sdk/logs/logger.h"
+# include "opentelemetry/sdk/logs/log_record.h"
+# include "opentelemetry/sdk_config.h"
+# include "opentelemetry/trace/provider.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+namespace trace_api = opentelemetry::trace;
+namespace nostd = opentelemetry::nostd;
+namespace common = opentelemetry::common;
+
+Logger::Logger(nostd::string_view name,
+ std::shared_ptr<LoggerContext> context,
+ std::unique_ptr<instrumentationlibrary::InstrumentationLibrary>
+ instrumentation_library) noexcept
+ : logger_name_(std::string(name)),
+ instrumentation_library_(std::move(instrumentation_library)),
+ context_(context)
+{}
+
+const nostd::string_view Logger::GetName() noexcept
+{
+ return logger_name_;
+}
+
+/**
+ * Create and populate recordable with the log event's fields passed in.
+ * The timestamp, severity, traceid, spanid, and traceflags, are injected
+ * if the user does not specify them.
+ */
+void Logger::Log(opentelemetry::logs::Severity severity,
+ nostd::string_view body,
+ const common::KeyValueIterable &attributes,
+ trace_api::TraceId trace_id,
+ trace_api::SpanId span_id,
+ trace_api::TraceFlags trace_flags,
+ common::SystemTimestamp timestamp) noexcept
+{
+ // If this logger does not have a processor, no need to create a log record
+ if (!context_)
+ {
+ return;
+ }
+ auto &processor = context_->GetProcessor();
+
+ // TODO: Sampler (should include check for minSeverity)
+
+ auto recordable = processor.MakeRecordable();
+ if (recordable == nullptr)
+ {
+ OTEL_INTERNAL_LOG_ERROR("[LOGGER] Recordable creation failed");
+ return;
+ }
+
+ // Populate recordable fields
+ recordable->SetTimestamp(timestamp);
+ recordable->SetSeverity(severity);
+ recordable->SetBody(body);
+ recordable->SetInstrumentationLibrary(GetInstrumentationLibrary());
+
+ recordable->SetResource(context_->GetResource());
+
+ attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept {
+ recordable->SetAttribute(key, value);
+ return true;
+ });
+
+ // Inject trace_id/span_id/trace_flags if none is set by user
+ auto provider = trace_api::Provider::GetTracerProvider();
+ auto tracer = provider->GetTracer(logger_name_);
+ auto span_context = tracer->GetCurrentSpan()->GetContext();
+
+ // Leave these fields in the recordable empty if neither the passed in values
+ // nor the context values are valid (e.g. the application is not using traces)
+
+ // TraceId
+ if (trace_id.IsValid())
+ {
+ recordable->SetTraceId(trace_id);
+ }
+ else if (span_context.trace_id().IsValid())
+ {
+ recordable->SetTraceId(span_context.trace_id());
+ }
+
+ // SpanId
+ if (span_id.IsValid())
+ {
+ recordable->SetSpanId(span_id);
+ }
+ else if (span_context.span_id().IsValid())
+ {
+ recordable->SetSpanId(span_context.span_id());
+ }
+
+ // TraceFlags
+ if (trace_flags.IsSampled())
+ {
+ recordable->SetTraceFlags(trace_flags);
+ }
+ else if (span_context.trace_flags().IsSampled())
+ {
+ recordable->SetTraceFlags(span_context.trace_flags());
+ }
+
+ // Send the log record to the processor
+ processor.OnReceive(std::move(recordable));
+}
+
+const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary &
+Logger::GetInstrumentationLibrary() const noexcept
+{
+ return *instrumentation_library_;
+}
+
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_context.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_context.cc
new file mode 100644
index 000000000..b0025ff72
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_context.cc
@@ -0,0 +1,54 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/logger_context.h"
+# include "opentelemetry/sdk/logs/multi_log_processor.h"
+
+# include <memory>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+LoggerContext::LoggerContext(std::vector<std::unique_ptr<LogProcessor>> &&processors,
+ opentelemetry::sdk::resource::Resource resource) noexcept
+ : resource_(resource),
+ processor_(std::unique_ptr<LogProcessor>(new MultiLogProcessor(std::move(processors))))
+{}
+
+void LoggerContext::AddProcessor(std::unique_ptr<LogProcessor> processor) noexcept
+{
+ auto multi_processor = static_cast<MultiLogProcessor *>(processor_.get());
+ multi_processor->AddProcessor(std::move(processor));
+}
+
+LogProcessor &LoggerContext::GetProcessor() const noexcept
+{
+ return *processor_;
+}
+
+const opentelemetry::sdk::resource::Resource &LoggerContext::GetResource() const noexcept
+{
+ return resource_;
+}
+
+bool LoggerContext::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return processor_->ForceFlush(timeout);
+}
+
+bool LoggerContext::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ return processor_->ForceFlush(timeout);
+}
+
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_provider.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_provider.cc
new file mode 100644
index 000000000..089b8d0de
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/logger_provider.cc
@@ -0,0 +1,142 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/logger_provider.h"
+
+# include <memory>
+# include <mutex>
+# include <string>
+# include <unordered_map>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+namespace nostd = opentelemetry::nostd;
+namespace logs_api = opentelemetry::logs;
+
+LoggerProvider::LoggerProvider(std::unique_ptr<LogProcessor> &&processor,
+ opentelemetry::sdk::resource::Resource resource) noexcept
+{
+ std::vector<std::unique_ptr<LogProcessor>> processors;
+ processors.emplace_back(std::move(processor));
+ context_ = std::make_shared<sdk::logs::LoggerContext>(std::move(processors), std::move(resource));
+}
+
+LoggerProvider::LoggerProvider(std::vector<std::unique_ptr<LogProcessor>> &&processors,
+ opentelemetry::sdk::resource::Resource resource) noexcept
+ : context_{
+ std::make_shared<sdk::logs::LoggerContext>(std::move(processors), std::move(resource))}
+{}
+
+LoggerProvider::LoggerProvider() noexcept
+ : context_{
+ std::make_shared<sdk::logs::LoggerContext>(std::vector<std::unique_ptr<LogProcessor>>{})}
+{}
+
+LoggerProvider::LoggerProvider(std::shared_ptr<sdk::logs::LoggerContext> context) noexcept
+ : context_{context}
+{}
+
+LoggerProvider::~LoggerProvider()
+{
+ // Logger hold the shared pointer to the context. So we can not use destructor of LoggerContext to
+ // Shutdown and flush all pending recordables when we hasve more than one loggers.These
+ // recordables may use the raw pointer of instrumentation_library_ in Logger
+ if (context_)
+ {
+ context_->Shutdown();
+ }
+}
+
+nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::GetLogger(
+ nostd::string_view logger_name,
+ nostd::string_view options,
+ nostd::string_view library_name,
+ nostd::string_view library_version,
+ nostd::string_view schema_url) noexcept
+{
+ // Ensure only one thread can read/write from the map of loggers
+ std::lock_guard<std::mutex> lock_guard{lock_};
+
+ // If a logger with a name "logger_name" already exists, return it
+ for (auto &logger : loggers_)
+ {
+ auto &logger_lib = logger->GetInstrumentationLibrary();
+ if (logger->GetName() == logger_name &&
+ logger_lib.equal(library_name, library_version, schema_url))
+ {
+ return nostd::shared_ptr<opentelemetry::logs::Logger>{logger};
+ }
+ }
+
+ // Check if creating a new logger would exceed the max number of loggers
+ // TODO: Remove the noexcept from the API's and SDK's GetLogger(~)
+ /*
+ if (loggers_.size() > MAX_LOGGER_COUNT)
+ {
+#if __EXCEPTIONS
+ throw std::length_error("Number of loggers exceeds max count");
+#else
+ std::terminate();
+#endif
+ }
+ */
+
+ // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-instrumentationscope
+ opentelemetry::nostd::unique_ptr<instrumentationlibrary::InstrumentationLibrary> lib;
+ if (library_name.empty())
+ {
+ lib = instrumentationlibrary::InstrumentationLibrary::Create(logger_name, library_version,
+ schema_url);
+ }
+ else
+ {
+ lib = instrumentationlibrary::InstrumentationLibrary::Create(library_name, library_version,
+ schema_url);
+ }
+
+ loggers_.push_back(std::shared_ptr<opentelemetry::sdk::logs::Logger>(
+ new Logger(logger_name, context_, std::move(lib))));
+ return nostd::shared_ptr<opentelemetry::logs::Logger>{loggers_.back()};
+}
+
+nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::GetLogger(
+ nostd::string_view logger_name,
+ nostd::span<nostd::string_view> args,
+ nostd::string_view library_name,
+ nostd::string_view library_version,
+ nostd::string_view schema_url) noexcept
+{
+ return GetLogger(logger_name, "", library_name, library_version, schema_url);
+}
+
+void LoggerProvider::AddProcessor(std::unique_ptr<LogProcessor> processor) noexcept
+{
+ context_->AddProcessor(std::move(processor));
+}
+
+const opentelemetry::sdk::resource::Resource &LoggerProvider::GetResource() const noexcept
+{
+ return context_->GetResource();
+}
+
+bool LoggerProvider::Shutdown() noexcept
+{
+ return context_->Shutdown();
+}
+
+bool LoggerProvider::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return context_->ForceFlush(timeout);
+}
+
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_log_processor.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_log_processor.cc
new file mode 100644
index 000000000..5c7fe400f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_log_processor.cc
@@ -0,0 +1,151 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/multi_log_processor.h"
+
+# include <chrono>
+# include <memory>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+MultiLogProcessor::MultiLogProcessor(std::vector<std::unique_ptr<LogProcessor>> &&processors)
+{
+ for (auto &processor : processors)
+ {
+ AddProcessor(std::move(processor));
+ }
+}
+MultiLogProcessor::~MultiLogProcessor()
+{
+ ForceFlush();
+ Shutdown();
+}
+
+void MultiLogProcessor::AddProcessor(std::unique_ptr<LogProcessor> &&processor)
+{
+ // Add preocessor to end of the list.
+ if (processor)
+ {
+ processors_.emplace_back(std::move(processor));
+ }
+}
+
+std::unique_ptr<Recordable> MultiLogProcessor::MakeRecordable() noexcept
+{
+ auto recordable = std::unique_ptr<Recordable>(new MultiRecordable);
+ auto multi_recordable = static_cast<MultiRecordable *>(recordable.get());
+ for (auto &processor : processors_)
+ {
+ multi_recordable->AddRecordable(*processor, processor->MakeRecordable());
+ }
+ return recordable;
+}
+
+void MultiLogProcessor::OnReceive(std::unique_ptr<Recordable> &&record) noexcept
+{
+ if (!record)
+ {
+ return;
+ }
+ auto multi_recordable = static_cast<MultiRecordable *>(record.get());
+
+ for (auto &processor : processors_)
+ {
+ auto recordable = multi_recordable->ReleaseRecordable(*processor);
+ if (recordable)
+ {
+ processor->OnReceive(std::move(recordable));
+ }
+ }
+}
+
+bool MultiLogProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ // Converto nanos to prevent overflow
+ std::chrono::nanoseconds timeout_ns = std::chrono::nanoseconds::max();
+ if (std::chrono::duration_cast<std::chrono::microseconds>(timeout_ns) > timeout)
+ {
+ timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout);
+ }
+ bool result = true;
+ auto start_time = std::chrono::system_clock::now();
+ auto overflow_checker = std::chrono::system_clock::time_point::max();
+ std::chrono::system_clock::time_point expire_time;
+ if (overflow_checker - start_time <= timeout_ns)
+ {
+ expire_time = overflow_checker;
+ }
+ else
+ {
+ expire_time =
+ start_time + std::chrono::duration_cast<std::chrono::system_clock::duration>(timeout_ns);
+ }
+ for (auto &processor : processors_)
+ {
+ if (!processor->ForceFlush(std::chrono::duration_cast<std::chrono::microseconds>(timeout_ns)))
+ {
+ result = false;
+ }
+ start_time = std::chrono::system_clock::now();
+ if (expire_time > start_time)
+ {
+ timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(expire_time - start_time);
+ }
+ else
+ {
+ timeout_ns = std::chrono::nanoseconds::zero();
+ }
+ }
+ return result;
+}
+
+bool MultiLogProcessor::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ // Converto nanos to prevent overflow
+ std::chrono::nanoseconds timeout_ns = std::chrono::nanoseconds::max();
+ if (std::chrono::duration_cast<std::chrono::microseconds>(timeout_ns) > timeout)
+ {
+ timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout);
+ }
+ bool result = true;
+ auto start_time = std::chrono::system_clock::now();
+ auto overflow_checker = std::chrono::system_clock::time_point::max();
+ std::chrono::system_clock::time_point expire_time;
+ if (overflow_checker - start_time <= timeout_ns)
+ {
+ expire_time = overflow_checker;
+ }
+ else
+ {
+ expire_time =
+ start_time + std::chrono::duration_cast<std::chrono::system_clock::duration>(timeout_ns);
+ }
+ for (auto &processor : processors_)
+ {
+ result |=
+ processor->Shutdown(std::chrono::duration_cast<std::chrono::microseconds>(timeout_ns));
+ start_time = std::chrono::system_clock::now();
+ if (expire_time > start_time)
+ {
+ timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(expire_time - start_time);
+ }
+ else
+ {
+ timeout_ns = std::chrono::nanoseconds::zero();
+ }
+ }
+ return result;
+}
+
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_recordable.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_recordable.cc
new file mode 100644
index 000000000..4d615ec73
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/multi_recordable.cc
@@ -0,0 +1,140 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/multi_recordable.h"
+
+# include <cstddef>
+# include <memory>
+# include <unordered_map>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+
+namespace
+{
+std::size_t MakeKey(const opentelemetry::sdk::logs::LogProcessor &processor)
+{
+ return reinterpret_cast<std::size_t>(&processor);
+}
+
+} // namespace
+
+void MultiRecordable::AddRecordable(const LogProcessor &processor,
+ std::unique_ptr<Recordable> recordable) noexcept
+{
+ recordables_[MakeKey(processor)] = std::move(recordable);
+}
+
+const std::unique_ptr<Recordable> &MultiRecordable::GetRecordable(
+ const LogProcessor &processor) const noexcept
+{
+ // TODO - return nullptr ref on failed lookup?
+ auto i = recordables_.find(MakeKey(processor));
+ if (i != recordables_.end())
+ {
+ return i->second;
+ }
+ static std::unique_ptr<Recordable> empty(nullptr);
+ return empty;
+}
+
+std::unique_ptr<Recordable> MultiRecordable::ReleaseRecordable(
+ const LogProcessor &processor) noexcept
+{
+ auto i = recordables_.find(MakeKey(processor));
+ if (i != recordables_.end())
+ {
+ std::unique_ptr<Recordable> result(i->second.release());
+ recordables_.erase(MakeKey(processor));
+ return result;
+ }
+ return std::unique_ptr<Recordable>(nullptr);
+}
+
+void MultiRecordable::SetTimestamp(opentelemetry::common::SystemTimestamp timestamp) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetTimestamp(timestamp);
+ }
+}
+
+void MultiRecordable::SetSeverity(opentelemetry::logs::Severity severity) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetSeverity(severity);
+ }
+}
+
+void MultiRecordable::SetBody(nostd::string_view message) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetBody(message);
+ }
+}
+
+void MultiRecordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetResource(resource);
+ }
+}
+
+void MultiRecordable::SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetAttribute(key, value);
+ }
+}
+
+void MultiRecordable::SetTraceId(opentelemetry::trace::TraceId trace_id) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetTraceId(trace_id);
+ }
+}
+
+void MultiRecordable::SetSpanId(opentelemetry::trace::SpanId span_id) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetSpanId(span_id);
+ }
+}
+
+void MultiRecordable::SetTraceFlags(opentelemetry::trace::TraceFlags trace_flags) noexcept
+{
+ for (auto &recordable : recordables_)
+ {
+ recordable.second->SetTraceFlags(trace_flags);
+ }
+}
+
+void MultiRecordable::SetInstrumentationLibrary(
+ const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary
+ &instrumentation_library) noexcept
+{
+ instrumentation_library_ = &instrumentation_library;
+}
+
+const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary &
+MultiRecordable::GetInstrumentationLibrary() const noexcept
+{
+ return *instrumentation_library_;
+}
+} // namespace logs
+} // namespace sdk
+
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/simple_log_processor.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/simple_log_processor.cc
new file mode 100644
index 000000000..6e2fde9f1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/logs/simple_log_processor.cc
@@ -0,0 +1,64 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+# include "opentelemetry/sdk/logs/simple_log_processor.h"
+
+# include <chrono>
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace logs
+{
+/**
+ * Initialize a simple log processor.
+ * @param exporter the configured exporter where log records are sent
+ */
+SimpleLogProcessor::SimpleLogProcessor(std::unique_ptr<LogExporter> &&exporter)
+ : exporter_(std::move(exporter))
+{}
+
+std::unique_ptr<Recordable> SimpleLogProcessor::MakeRecordable() noexcept
+{
+ return exporter_->MakeRecordable();
+}
+
+/**
+ * Batches the log record it receives in a batch of 1 and immediately sends it
+ * to the configured exporter
+ */
+void SimpleLogProcessor::OnReceive(std::unique_ptr<Recordable> &&record) noexcept
+{
+ nostd::span<std::unique_ptr<Recordable>> batch(&record, 1);
+ // Get lock to ensure Export() is never called concurrently
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+
+ if (exporter_->Export(batch) != sdk::common::ExportResult::kSuccess)
+ {
+ /* Alert user of the failed export */
+ }
+}
+/**
+ * The simple processor does not have any log records to flush so this method is not used
+ */
+bool SimpleLogProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return true;
+}
+
+bool SimpleLogProcessor::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ // Should only shutdown exporter ONCE.
+ if (!shutdown_latch_.test_and_set(std::memory_order_acquire) && exporter_ != nullptr)
+ {
+ return exporter_->Shutdown(timeout);
+ }
+
+ return true;
+}
+} // namespace logs
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/BUILD
new file mode 100644
index 000000000..e75ba6a1a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/BUILD
@@ -0,0 +1,28 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "metrics",
+ srcs = glob(["**/*.cc"]),
+ hdrs = glob(["**/*.h"]),
+ include_prefix = "src/metrics",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "//sdk/src/common:global_log_handler",
+ "//sdk/src/resource",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/CMakeLists.txt
new file mode 100644
index 000000000..77a371a80
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_library(
+ opentelemetry_metrics
+ meter_provider.cc
+ meter.cc
+ meter_context.cc
+ metric_reader.cc
+ export/periodic_exporting_metric_reader.cc
+ state/metric_collector.cc
+ state/sync_metric_storage.cc
+ state/temporal_metric_storage.cc
+ aggregation/histogram_aggregation.cc
+ aggregation/lastvalue_aggregation.cc
+ aggregation/sum_aggregation.cc
+ sync_instruments.cc)
+
+set_target_properties(opentelemetry_metrics PROPERTIES EXPORT_NAME metrics)
+
+target_link_libraries(opentelemetry_metrics PUBLIC opentelemetry_common)
+
+target_include_directories(
+ opentelemetry_metrics
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_metrics
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/histogram_aggregation.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/histogram_aggregation.cc
new file mode 100644
index 000000000..aa2be7471
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/histogram_aggregation.cc
@@ -0,0 +1,142 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
+# include "opentelemetry/version.h"
+
+# include <mutex>
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+LongHistogramAggregation::LongHistogramAggregation()
+{
+ point_data_.boundaries_ = std::list<long>{0l, 5l, 10l, 25l, 50l, 75l, 100l, 250l, 500l, 1000l};
+ point_data_.counts_ =
+ std::vector<uint64_t>(nostd::get<std::list<long>>(point_data_.boundaries_).size() + 1, 0);
+ point_data_.sum_ = 0l;
+ point_data_.count_ = 0;
+}
+
+LongHistogramAggregation::LongHistogramAggregation(HistogramPointData &&data)
+ : point_data_{std::move(data)}
+{}
+
+LongHistogramAggregation::LongHistogramAggregation(const HistogramPointData &data)
+ : point_data_{data}
+{}
+
+void LongHistogramAggregation::Aggregate(long value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.count_ += 1;
+ point_data_.sum_ = nostd::get<long>(point_data_.sum_) + value;
+ size_t index = 0;
+ for (auto it = nostd::get<std::list<long>>(point_data_.boundaries_).begin();
+ it != nostd::get<std::list<long>>(point_data_.boundaries_).end(); ++it)
+ {
+ if (value < *it)
+ {
+ point_data_.counts_[index] += 1;
+ return;
+ }
+ index++;
+ }
+}
+
+std::unique_ptr<Aggregation> LongHistogramAggregation::Merge(
+ const Aggregation &delta) const noexcept
+{
+ auto curr_value = nostd::get<HistogramPointData>(ToPoint());
+ auto delta_value = nostd::get<HistogramPointData>(
+ (static_cast<const LongHistogramAggregation &>(delta).ToPoint()));
+ LongHistogramAggregation *aggr = new LongHistogramAggregation();
+ HistogramMerge<long>(curr_value, delta_value, aggr->point_data_);
+ return std::unique_ptr<Aggregation>(aggr);
+}
+
+std::unique_ptr<Aggregation> LongHistogramAggregation::Diff(const Aggregation &next) const noexcept
+{
+ auto curr_value = nostd::get<HistogramPointData>(ToPoint());
+ auto next_value = nostd::get<HistogramPointData>(
+ (static_cast<const LongHistogramAggregation &>(next).ToPoint()));
+ LongHistogramAggregation *aggr = new LongHistogramAggregation();
+ HistogramDiff<long>(curr_value, next_value, aggr->point_data_);
+ return std::unique_ptr<Aggregation>(aggr);
+}
+
+PointType LongHistogramAggregation::ToPoint() const noexcept
+{
+ return point_data_;
+}
+
+DoubleHistogramAggregation::DoubleHistogramAggregation()
+{
+ point_data_.boundaries_ =
+ std::list<double>{0.0, 5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0, 1000.0};
+ point_data_.counts_ =
+ std::vector<uint64_t>(nostd::get<std::list<double>>(point_data_.boundaries_).size() + 1, 0);
+ point_data_.sum_ = 0.0;
+ point_data_.count_ = 0;
+}
+
+DoubleHistogramAggregation::DoubleHistogramAggregation(HistogramPointData &&data)
+ : point_data_{std::move(data)}
+{}
+
+DoubleHistogramAggregation::DoubleHistogramAggregation(const HistogramPointData &data)
+ : point_data_{data}
+{}
+
+void DoubleHistogramAggregation::Aggregate(double value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.count_ += 1;
+ point_data_.sum_ = nostd::get<double>(point_data_.sum_) + value;
+ size_t index = 0;
+ for (auto it = nostd::get<std::list<double>>(point_data_.boundaries_).begin();
+ it != nostd::get<std::list<double>>(point_data_.boundaries_).end(); ++it)
+ {
+ if (value < *it)
+ {
+ point_data_.counts_[index] += 1;
+ return;
+ }
+ index++;
+ }
+}
+
+std::unique_ptr<Aggregation> DoubleHistogramAggregation::Merge(
+ const Aggregation &delta) const noexcept
+{
+ auto curr_value = nostd::get<HistogramPointData>(ToPoint());
+ auto delta_value = nostd::get<HistogramPointData>(
+ (static_cast<const DoubleHistogramAggregation &>(delta).ToPoint()));
+ DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation();
+ HistogramMerge<double>(curr_value, delta_value, aggr->point_data_);
+ return std::unique_ptr<Aggregation>(aggr);
+}
+
+std::unique_ptr<Aggregation> DoubleHistogramAggregation::Diff(
+ const Aggregation &next) const noexcept
+{
+ auto curr_value = nostd::get<HistogramPointData>(ToPoint());
+ auto next_value = nostd::get<HistogramPointData>(
+ (static_cast<const DoubleHistogramAggregation &>(next).ToPoint()));
+ DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation();
+ HistogramDiff<double>(curr_value, next_value, aggr->point_data_);
+ return std::unique_ptr<Aggregation>(aggr);
+}
+
+PointType DoubleHistogramAggregation::ToPoint() const noexcept
+{
+ return point_data_;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/lastvalue_aggregation.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/lastvalue_aggregation.cc
new file mode 100644
index 000000000..a12500533
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/lastvalue_aggregation.cc
@@ -0,0 +1,134 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h"
+# include "opentelemetry/common/timestamp.h"
+# include "opentelemetry/version.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+LongLastValueAggregation::LongLastValueAggregation()
+{
+ point_data_.is_lastvalue_valid_ = false;
+ point_data_.value_ = 0l;
+}
+
+LongLastValueAggregation::LongLastValueAggregation(LastValuePointData &&data)
+ : point_data_{std::move(data)}
+{}
+
+LongLastValueAggregation::LongLastValueAggregation(const LastValuePointData &data)
+ : point_data_{data}
+{}
+
+void LongLastValueAggregation::Aggregate(long value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.is_lastvalue_valid_ = true;
+ point_data_.value_ = value;
+}
+
+std::unique_ptr<Aggregation> LongLastValueAggregation::Merge(
+ const Aggregation &delta) const noexcept
+{
+ if (nostd::get<LastValuePointData>(ToPoint()).sample_ts_.time_since_epoch() >
+ nostd::get<LastValuePointData>(delta.ToPoint()).sample_ts_.time_since_epoch())
+ {
+ LastValuePointData merge_data = std::move(nostd::get<LastValuePointData>(ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(merge_data)));
+ }
+ else
+ {
+ LastValuePointData merge_data = std::move(nostd::get<LastValuePointData>(delta.ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(merge_data)));
+ }
+}
+
+std::unique_ptr<Aggregation> LongLastValueAggregation::Diff(const Aggregation &next) const noexcept
+{
+ if (nostd::get<LastValuePointData>(ToPoint()).sample_ts_.time_since_epoch() >
+ nostd::get<LastValuePointData>(next.ToPoint()).sample_ts_.time_since_epoch())
+ {
+ LastValuePointData diff_data = std::move(nostd::get<LastValuePointData>(ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(diff_data)));
+ }
+ else
+ {
+ LastValuePointData diff_data = std::move(nostd::get<LastValuePointData>(next.ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(diff_data)));
+ }
+}
+
+PointType LongLastValueAggregation::ToPoint() const noexcept
+{
+ return point_data_;
+}
+
+DoubleLastValueAggregation::DoubleLastValueAggregation()
+{
+ point_data_.is_lastvalue_valid_ = false;
+ point_data_.value_ = 0.0;
+}
+
+DoubleLastValueAggregation::DoubleLastValueAggregation(LastValuePointData &&data)
+ : point_data_{std::move(data)}
+{}
+
+DoubleLastValueAggregation::DoubleLastValueAggregation(const LastValuePointData &data)
+ : point_data_{data}
+{}
+
+void DoubleLastValueAggregation::Aggregate(double value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.is_lastvalue_valid_ = true;
+ point_data_.value_ = value;
+}
+
+std::unique_ptr<Aggregation> DoubleLastValueAggregation::Merge(
+ const Aggregation &delta) const noexcept
+{
+ if (nostd::get<LastValuePointData>(ToPoint()).sample_ts_.time_since_epoch() >
+ nostd::get<LastValuePointData>(delta.ToPoint()).sample_ts_.time_since_epoch())
+ {
+ LastValuePointData merge_data = std::move(nostd::get<LastValuePointData>(ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(merge_data)));
+ }
+ else
+ {
+ LastValuePointData merge_data = std::move(nostd::get<LastValuePointData>(delta.ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(merge_data)));
+ }
+}
+
+std::unique_ptr<Aggregation> DoubleLastValueAggregation::Diff(
+ const Aggregation &next) const noexcept
+{
+ if (nostd::get<LastValuePointData>(ToPoint()).sample_ts_.time_since_epoch() >
+ nostd::get<LastValuePointData>(next.ToPoint()).sample_ts_.time_since_epoch())
+ {
+ LastValuePointData diff_data = std::move(nostd::get<LastValuePointData>(ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(diff_data)));
+ }
+ else
+ {
+ LastValuePointData diff_data = std::move(nostd::get<LastValuePointData>(next.ToPoint()));
+ return std::unique_ptr<Aggregation>(new LongLastValueAggregation(std::move(diff_data)));
+ }
+}
+
+PointType DoubleLastValueAggregation::ToPoint() const noexcept
+{
+ return point_data_;
+}
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/sum_aggregation.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/sum_aggregation.cc
new file mode 100644
index 000000000..5ca786496
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/aggregation/sum_aggregation.cc
@@ -0,0 +1,111 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/aggregation/sum_aggregation.h"
+# include "opentelemetry/sdk/metrics/data/point_data.h"
+# include "opentelemetry/version.h"
+
+# include <iostream>
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+LongSumAggregation::LongSumAggregation()
+{
+ point_data_.value_ = 0l;
+}
+
+LongSumAggregation::LongSumAggregation(SumPointData &&data) : point_data_{std::move(data)} {}
+
+LongSumAggregation::LongSumAggregation(const SumPointData &data) : point_data_{data} {}
+
+void LongSumAggregation::Aggregate(long value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.value_ = nostd::get<long>(point_data_.value_) + value;
+}
+
+std::unique_ptr<Aggregation> LongSumAggregation::Merge(const Aggregation &delta) const noexcept
+{
+ long merge_value =
+ nostd::get<long>(
+ nostd::get<SumPointData>((static_cast<const LongSumAggregation &>(delta).ToPoint()))
+ .value_) +
+ nostd::get<long>(nostd::get<SumPointData>(ToPoint()).value_);
+ std::unique_ptr<Aggregation> aggr(new LongSumAggregation());
+ static_cast<LongSumAggregation *>(aggr.get())->point_data_.value_ = merge_value;
+ return aggr;
+}
+
+std::unique_ptr<Aggregation> LongSumAggregation::Diff(const Aggregation &next) const noexcept
+{
+
+ long diff_value = nostd::get<long>(nostd::get<SumPointData>(
+ (static_cast<const LongSumAggregation &>(next).ToPoint()))
+ .value_) -
+ nostd::get<long>(nostd::get<SumPointData>(ToPoint()).value_);
+ std::unique_ptr<Aggregation> aggr(new LongSumAggregation());
+ static_cast<LongSumAggregation *>(aggr.get())->point_data_.value_ = diff_value;
+ return aggr;
+}
+
+PointType LongSumAggregation::ToPoint() const noexcept
+{
+ return point_data_;
+}
+
+DoubleSumAggregation::DoubleSumAggregation()
+{
+ point_data_.value_ = 0.0;
+}
+
+DoubleSumAggregation::DoubleSumAggregation(SumPointData &&data) : point_data_(std::move(data)) {}
+
+DoubleSumAggregation::DoubleSumAggregation(const SumPointData &data) : point_data_(data) {}
+
+void DoubleSumAggregation::Aggregate(double value, const PointAttributes &attributes) noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ point_data_.value_ = nostd::get<double>(point_data_.value_) + value;
+}
+
+std::unique_ptr<Aggregation> DoubleSumAggregation::Merge(const Aggregation &delta) const noexcept
+{
+ double merge_value =
+ nostd::get<double>(
+ nostd::get<SumPointData>((static_cast<const DoubleSumAggregation &>(delta).ToPoint()))
+ .value_) +
+ nostd::get<double>(nostd::get<SumPointData>(ToPoint()).value_);
+ std::unique_ptr<Aggregation> aggr(new DoubleSumAggregation());
+ static_cast<DoubleSumAggregation *>(aggr.get())->point_data_.value_ = merge_value;
+ return aggr;
+}
+
+std::unique_ptr<Aggregation> DoubleSumAggregation::Diff(const Aggregation &next) const noexcept
+{
+
+ double diff_value =
+ nostd::get<double>(
+ nostd::get<SumPointData>((static_cast<const DoubleSumAggregation &>(next).ToPoint()))
+ .value_) -
+ nostd::get<double>(nostd::get<SumPointData>(ToPoint()).value_);
+ std::unique_ptr<Aggregation> aggr(new DoubleSumAggregation());
+ static_cast<DoubleSumAggregation *>(aggr.get())->point_data_.value_ = diff_value;
+ return aggr;
+}
+
+PointType DoubleSumAggregation::ToPoint() const noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ return point_data_;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/export/periodic_exporting_metric_reader.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/export/periodic_exporting_metric_reader.cc
new file mode 100644
index 000000000..f11f84544
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/export/periodic_exporting_metric_reader.cc
@@ -0,0 +1,101 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h"
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# include "opentelemetry/sdk/metrics/metric_exporter.h"
+
+# include <chrono>
+# include <future>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+PeriodicExportingMetricReader::PeriodicExportingMetricReader(
+ std::unique_ptr<MetricExporter> exporter,
+ const PeriodicExportingMetricReaderOptions &option,
+ AggregationTemporality aggregation_temporality)
+ : MetricReader(aggregation_temporality),
+ exporter_{std::move(exporter)},
+ export_interval_millis_{option.export_interval_millis},
+ export_timeout_millis_{option.export_timeout_millis}
+{
+ if (export_interval_millis_ <= export_timeout_millis_)
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "[Periodic Exporting Metric Reader] Invalid configuration: "
+ "export_interval_millis_ should be less than export_timeout_millis_, using default values");
+ export_interval_millis_ = kExportIntervalMillis;
+ export_timeout_millis_ = kExportTimeOutMillis;
+ }
+}
+
+void PeriodicExportingMetricReader::OnInitialized() noexcept
+{
+ worker_thread_ = std::thread(&PeriodicExportingMetricReader::DoBackgroundWork, this);
+}
+
+void PeriodicExportingMetricReader::DoBackgroundWork()
+{
+ std::unique_lock<std::mutex> lk(cv_m_);
+ do
+ {
+ if (IsShutdown())
+ {
+ break;
+ }
+ std::atomic<bool> cancel_export_for_timeout{false};
+ auto start = std::chrono::steady_clock::now();
+ auto future_receive = std::async(std::launch::async, [this, &cancel_export_for_timeout] {
+ Collect([this, &cancel_export_for_timeout](ResourceMetrics &metric_data) {
+ if (cancel_export_for_timeout)
+ {
+ OTEL_INTERNAL_LOG_ERROR(
+ "[Periodic Exporting Metric Reader] Collect took longer configured time: "
+ << export_timeout_millis_.count() << " ms, and timed out");
+ return false;
+ }
+ this->exporter_->Export(metric_data);
+ return true;
+ });
+ });
+ std::future_status status;
+ do
+ {
+ status = future_receive.wait_for(std::chrono::milliseconds(export_timeout_millis_));
+ if (status == std::future_status::timeout)
+ {
+ cancel_export_for_timeout = true;
+ break;
+ }
+ } while (status != std::future_status::ready);
+ auto end = std::chrono::steady_clock::now();
+ auto export_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+ auto remaining_wait_interval_ms = export_interval_millis_ - export_time_ms;
+ cv_.wait_for(lk, remaining_wait_interval_ms);
+ } while (true);
+}
+
+bool PeriodicExportingMetricReader::OnForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return exporter_->ForceFlush(timeout);
+}
+
+bool PeriodicExportingMetricReader::OnShutDown(std::chrono::microseconds timeout) noexcept
+{
+ if (worker_thread_.joinable())
+ {
+ cv_.notify_one();
+ worker_thread_.join();
+ }
+ return exporter_->Shutdown(timeout);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter.cc
new file mode 100644
index 000000000..600bae986
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter.cc
@@ -0,0 +1,259 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/meter.h"
+# include "opentelemetry/metrics/noop.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/metrics/async_instruments.h"
+# include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h"
+# include "opentelemetry/sdk/metrics/state/multi_metric_storage.h"
+# include "opentelemetry/sdk/metrics/state/sync_metric_storage.h"
+# include "opentelemetry/sdk/metrics/sync_instruments.h"
+# include "opentelemetry/sdk_config.h"
+
+# include "opentelemetry/version.h"
+
+# include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+namespace metrics = opentelemetry::metrics;
+namespace nostd = opentelemetry::nostd;
+
+Meter::Meter(std::shared_ptr<MeterContext> meter_context,
+ std::unique_ptr<sdk::instrumentationlibrary::InstrumentationLibrary>
+ instrumentation_library) noexcept
+ : instrumentation_library_{std::move(instrumentation_library)}, meter_context_{meter_context}
+{}
+
+nostd::shared_ptr<metrics::Counter<long>> Meter::CreateLongCounter(nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kCounter, InstrumentValueType::kLong};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::Counter<long>>(
+ new LongCounter(instrument_descriptor, std::move(storage)));
+}
+
+nostd::shared_ptr<metrics::Counter<double>> Meter::CreateDoubleCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kCounter,
+ InstrumentValueType::kDouble};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::Counter<double>>{
+ new DoubleCounter(instrument_descriptor, std::move(storage))};
+}
+
+void Meter::CreateLongObservableCounter(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<long> &, void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableCounter,
+ InstrumentValueType::kLong};
+ RegisterAsyncMetricStorage<long>(instrument_descriptor, callback, state);
+}
+
+void Meter::CreateDoubleObservableCounter(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<double> &,
+ void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableCounter,
+ InstrumentValueType::kDouble};
+ RegisterAsyncMetricStorage<double>(instrument_descriptor, callback, state);
+}
+
+nostd::shared_ptr<metrics::Histogram<long>> Meter::CreateLongHistogram(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kHistogram,
+ InstrumentValueType::kLong};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::Histogram<long>>{
+ new LongHistogram(instrument_descriptor, std::move(storage))};
+}
+
+nostd::shared_ptr<metrics::Histogram<double>> Meter::CreateDoubleHistogram(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kHistogram,
+ InstrumentValueType::kDouble};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::Histogram<double>>{
+ new DoubleHistogram(instrument_descriptor, std::move(storage))};
+}
+
+void Meter::CreateLongObservableGauge(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<long> &, void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableGauge,
+ InstrumentValueType::kLong};
+ RegisterAsyncMetricStorage<long>(instrument_descriptor, callback, state);
+}
+
+void Meter::CreateDoubleObservableGauge(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<double> &, void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableGauge,
+ InstrumentValueType::kDouble};
+ RegisterAsyncMetricStorage<double>(instrument_descriptor, callback, state);
+}
+
+nostd::shared_ptr<metrics::UpDownCounter<long>> Meter::CreateLongUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kUpDownCounter,
+ InstrumentValueType::kLong};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::UpDownCounter<long>>{
+ new LongUpDownCounter(instrument_descriptor, std::move(storage))};
+}
+
+nostd::shared_ptr<metrics::UpDownCounter<double>> Meter::CreateDoubleUpDownCounter(
+ nostd::string_view name,
+ nostd::string_view description,
+ nostd::string_view unit) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kUpDownCounter,
+ InstrumentValueType::kDouble};
+ auto storage = RegisterMetricStorage(instrument_descriptor);
+ return nostd::shared_ptr<metrics::UpDownCounter<double>>{
+ new DoubleUpDownCounter(instrument_descriptor, std::move(storage))};
+}
+
+void Meter::CreateLongObservableUpDownCounter(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<long> &,
+ void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableUpDownCounter,
+ InstrumentValueType::kLong};
+ RegisterAsyncMetricStorage<long>(instrument_descriptor, callback, state);
+}
+
+void Meter::CreateDoubleObservableUpDownCounter(nostd::string_view name,
+ void (*callback)(metrics::ObserverResult<double> &,
+ void *),
+ nostd::string_view description,
+ nostd::string_view unit,
+ void *state) noexcept
+{
+ InstrumentDescriptor instrument_descriptor = {
+ std::string{name.data(), name.size()}, std::string{description.data(), description.size()},
+ std::string{unit.data(), unit.size()}, InstrumentType::kObservableUpDownCounter,
+ InstrumentValueType::kDouble};
+ RegisterAsyncMetricStorage<double>(instrument_descriptor, callback, state);
+}
+
+const sdk::instrumentationlibrary::InstrumentationLibrary *Meter::GetInstrumentationLibrary()
+ const noexcept
+{
+ return instrumentation_library_.get();
+}
+
+std::unique_ptr<WritableMetricStorage> Meter::RegisterMetricStorage(
+ InstrumentDescriptor &instrument_descriptor)
+{
+ auto view_registry = meter_context_->GetViewRegistry();
+ std::unique_ptr<WritableMetricStorage> storages(new MultiMetricStorage());
+
+ auto success = view_registry->FindViews(
+ instrument_descriptor, *instrumentation_library_,
+ [this, &instrument_descriptor, &storages](const View &view) {
+ auto view_instr_desc = instrument_descriptor;
+ if (!view.GetName().empty())
+ {
+ view_instr_desc.name_ = view.GetName();
+ }
+ if (!view.GetDescription().empty())
+ {
+ view_instr_desc.description_ = view.GetDescription();
+ }
+ auto storage = std::shared_ptr<SyncMetricStorage>(new SyncMetricStorage(
+ view_instr_desc, view.GetAggregationType(), &view.GetAttributesProcessor(),
+ NoExemplarReservoir::GetNoExemplarReservoir()));
+ storage_registry_[instrument_descriptor.name_] = storage;
+ auto multi_storage = static_cast<MultiMetricStorage *>(storages.get());
+ multi_storage->AddStorage(storage);
+ return true;
+ });
+
+ if (!success)
+ {
+ OTEL_INTERNAL_LOG_ERROR(
+ "[Meter::RegisterMetricStorage] - Error during finding matching views."
+ << "Some of the matching view configurations mayn't be used for metric collection");
+ }
+ return storages;
+}
+
+/** collect metrics across all the meters **/
+std::vector<MetricData> Meter::Collect(CollectorHandle *collector,
+ opentelemetry::common::SystemTimestamp collect_ts) noexcept
+{
+ std::vector<MetricData> metric_data_list;
+ for (auto &metric_storage : storage_registry_)
+ {
+ metric_storage.second->Collect(collector, meter_context_->GetCollectors(),
+ meter_context_->GetSDKStartTime(), collect_ts,
+ [&metric_data_list](MetricData metric_data) {
+ metric_data_list.push_back(metric_data);
+ return true;
+ });
+ }
+ return metric_data_list;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_context.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_context.cc
new file mode 100644
index 000000000..73721e324
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_context.cc
@@ -0,0 +1,108 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/sdk_config.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+MeterContext::MeterContext(std::unique_ptr<ViewRegistry> views,
+ opentelemetry::sdk::resource::Resource resource) noexcept
+ : resource_{resource}, views_(std::move(views)), sdk_start_ts_{std::chrono::system_clock::now()}
+{}
+
+const resource::Resource &MeterContext::GetResource() const noexcept
+{
+ return resource_;
+}
+
+ViewRegistry *MeterContext::GetViewRegistry() const noexcept
+{
+ return views_.get();
+}
+
+nostd::span<std::shared_ptr<Meter>> MeterContext::GetMeters() noexcept
+{
+ return nostd::span<std::shared_ptr<Meter>>{meters_};
+}
+
+nostd::span<std::shared_ptr<CollectorHandle>> MeterContext::GetCollectors() noexcept
+{
+ return nostd::span<std::shared_ptr<CollectorHandle>>(collectors_);
+}
+
+opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept
+{
+ return sdk_start_ts_;
+}
+
+void MeterContext::AddMetricReader(std::unique_ptr<MetricReader> reader) noexcept
+{
+ auto collector =
+ std::shared_ptr<MetricCollector>{new MetricCollector(shared_from_this(), std::move(reader))};
+ collectors_.push_back(collector);
+}
+
+void MeterContext::AddView(std::unique_ptr<InstrumentSelector> instrument_selector,
+ std::unique_ptr<MeterSelector> meter_selector,
+ std::unique_ptr<View> view) noexcept
+{
+ views_->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view));
+}
+
+void MeterContext::AddMeter(std::shared_ptr<Meter> meter)
+{
+ meters_.push_back(meter);
+}
+
+bool MeterContext::Shutdown() noexcept
+{
+ bool result = true;
+ if (!shutdown_latch_.test_and_set(std::memory_order_acquire))
+ {
+
+ for (auto &collector : collectors_)
+ {
+ bool status = std::static_pointer_cast<MetricCollector>(collector)->Shutdown();
+ result = result && status;
+ }
+ if (!result)
+ {
+ OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Unable to shutdown all metric readers");
+ }
+ }
+ return result;
+}
+
+bool MeterContext::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ // TODO - Implement timeout logic.
+ bool result = true;
+ if (!shutdown_latch_.test_and_set(std::memory_order_acquire))
+ {
+
+ for (auto &collector : collectors_)
+ {
+ bool status = std::static_pointer_cast<MetricCollector>(collector)->ForceFlush(timeout);
+ result = result && status;
+ }
+ if (!result)
+ {
+ OTEL_INTERNAL_LOG_WARN("[MeterContext::ForceFlush] Unable to ForceFlush all metric readers");
+ }
+ }
+ return result;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_provider.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_provider.cc
new file mode 100644
index 000000000..788811cd6
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/meter_provider.cc
@@ -0,0 +1,94 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/meter_provider.h"
+# include "opentelemetry/metrics/meter.h"
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# include "opentelemetry/sdk_config.h"
+# include "opentelemetry/version.h"
+
+# include <vector>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+namespace resource = opentelemetry::sdk::resource;
+namespace metrics_api = opentelemetry::metrics;
+
+MeterProvider::MeterProvider(std::shared_ptr<MeterContext> context) noexcept : context_{context} {}
+
+MeterProvider::MeterProvider(std::unique_ptr<ViewRegistry> views,
+ sdk::resource::Resource resource) noexcept
+ : context_(std::make_shared<MeterContext>(std::move(views), resource))
+{}
+
+nostd::shared_ptr<metrics_api::Meter> MeterProvider::GetMeter(
+ nostd::string_view name,
+ nostd::string_view version,
+ nostd::string_view schema_url) noexcept
+{
+ if (name.data() == nullptr || name == "")
+ {
+ OTEL_INTERNAL_LOG_WARN("[MeterProvider::GetMeter] Library name is empty.");
+ name = "";
+ }
+
+ const std::lock_guard<std::mutex> guard(lock_);
+
+ for (auto &meter : context_->GetMeters())
+ {
+ auto meter_lib = meter->GetInstrumentationLibrary();
+ if (meter_lib->equal(name, version, schema_url))
+ {
+ return nostd::shared_ptr<metrics_api::Meter>{meter};
+ }
+ }
+ auto lib = instrumentationlibrary::InstrumentationLibrary::Create(name, version, schema_url);
+ auto meter = std::shared_ptr<Meter>(new Meter(context_, std::move(lib)));
+ context_->AddMeter(meter);
+ return nostd::shared_ptr<metrics_api::Meter>{meter};
+}
+
+const resource::Resource &MeterProvider::GetResource() const noexcept
+{
+ return context_->GetResource();
+}
+
+void MeterProvider::AddMetricReader(std::unique_ptr<MetricReader> reader) noexcept
+{
+ return context_->AddMetricReader(std::move(reader));
+}
+
+void MeterProvider::AddView(std::unique_ptr<InstrumentSelector> instrument_selector,
+ std::unique_ptr<MeterSelector> meter_selector,
+ std::unique_ptr<View> view) noexcept
+{
+ return context_->AddView(std::move(instrument_selector), std::move(meter_selector),
+ std::move(view));
+}
+
+/**
+ * Shutdown the meter provider.
+ */
+bool MeterProvider::Shutdown() noexcept
+{
+ return context_->Shutdown();
+}
+
+/**
+ * Force flush the meter provider.
+ */
+bool MeterProvider::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return context_->ForceFlush(timeout);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/metric_reader.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/metric_reader.cc
new file mode 100644
index 000000000..c8d6de896
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/metric_reader.cc
@@ -0,0 +1,94 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+
+# include <mutex>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+MetricReader::MetricReader(AggregationTemporality aggregation_temporality)
+ : aggregation_temporality_(aggregation_temporality), shutdown_(false), metric_producer_(nullptr)
+{}
+
+void MetricReader::SetMetricProducer(MetricProducer *metric_producer)
+{
+ metric_producer_ = metric_producer;
+ OnInitialized();
+}
+
+AggregationTemporality MetricReader::GetAggregationTemporality() const noexcept
+{
+ return aggregation_temporality_;
+}
+
+bool MetricReader::Collect(
+ nostd::function_ref<bool(ResourceMetrics &metric_data)> callback) noexcept
+{
+ if (!metric_producer_)
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "MetricReader::Collect Cannot invoke Collect(). No MetricProducer registered for "
+ "collection!")
+ }
+ if (IsShutdown())
+ {
+ OTEL_INTERNAL_LOG_WARN("MetricReader::Collect Cannot invoke Collect(). Shutdown in progress!");
+ }
+
+ return metric_producer_->Collect(callback);
+}
+
+bool MetricReader::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ bool status = true;
+ if (IsShutdown())
+ {
+ OTEL_INTERNAL_LOG_WARN("MetricReader::Shutdown - Cannot invoke shutdown twice!");
+ }
+
+ {
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ shutdown_ = true;
+ }
+
+ if (!OnShutDown(timeout))
+ {
+ status = false;
+ OTEL_INTERNAL_LOG_WARN("MetricReader::OnShutDown Shutdown failed. Will not be tried again!");
+ }
+ return status;
+}
+
+/** Flush metric read by this reader **/
+bool MetricReader::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ bool status = true;
+ if (shutdown_)
+ {
+ OTEL_INTERNAL_LOG_WARN("MetricReader::Shutdown Cannot invoke Force flush on shutdown reader!");
+ }
+ if (!OnForceFlush(timeout))
+ {
+ status = false;
+ OTEL_INTERNAL_LOG_ERROR("MetricReader::OnForceFlush failed!");
+ }
+ return status;
+}
+
+bool MetricReader::IsShutdown() const noexcept
+{
+ const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);
+ return shutdown_;
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/metric_collector.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/metric_collector.cc
new file mode 100644
index 000000000..6cae7bf12
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/metric_collector.cc
@@ -0,0 +1,62 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+# include "opentelemetry/sdk/common/global_log_handler.h"
+# include "opentelemetry/sdk/metrics/meter.h"
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/sdk_config.h"
+# include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+MetricCollector::MetricCollector(
+ std::shared_ptr<opentelemetry::sdk::metrics::MeterContext> &&context,
+ std::unique_ptr<MetricReader> metric_reader)
+ : meter_context_{std::move(context)}, metric_reader_{std::move(metric_reader)}
+{
+ metric_reader_->SetMetricProducer(this);
+}
+
+AggregationTemporality MetricCollector::GetAggregationTemporality() noexcept
+{
+ return metric_reader_->GetAggregationTemporality();
+}
+
+bool MetricCollector::Collect(
+ nostd::function_ref<bool(ResourceMetrics &metric_data)> callback) noexcept
+{
+ ResourceMetrics resource_metrics;
+ for (auto &meter : meter_context_->GetMeters())
+ {
+ auto collection_ts = std::chrono::system_clock::now();
+ InstrumentationInfoMetrics instrumentation_info_metrics;
+ instrumentation_info_metrics.metric_data_ = meter->Collect(this, collection_ts);
+ instrumentation_info_metrics.instrumentation_library_ = meter->GetInstrumentationLibrary();
+ resource_metrics.instrumentation_info_metric_data_.push_back(instrumentation_info_metrics);
+ }
+ resource_metrics.resource_ = &meter_context_->GetResource();
+ callback(resource_metrics);
+ return true;
+}
+
+bool MetricCollector::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return metric_reader_->ForceFlush(timeout);
+}
+
+bool MetricCollector::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ return metric_reader_->Shutdown(timeout);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/sync_metric_storage.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/sync_metric_storage.cc
new file mode 100644
index 000000000..8c79f9d7c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/sync_metric_storage.cc
@@ -0,0 +1,36 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/sdk/metrics/state/sync_metric_storage.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+bool SyncMetricStorage::Collect(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ nostd::function_ref<bool(MetricData)> callback) noexcept
+{
+ opentelemetry::common::SystemTimestamp last_collection_ts = sdk_start_ts;
+ auto aggregation_temporarily = collector->GetAggregationTemporality();
+
+ // Add the current delta metrics to `unreported metrics stash` for all the collectors,
+ // this will also empty the delta metrics hashmap, and make it available for
+ // recordings
+ std::shared_ptr<AttributesHashMap> delta_metrics = std::move(attributes_hashmap_);
+ attributes_hashmap_.reset(new AttributesHashMap);
+
+ return temporal_metric_storage_.buildMetrics(collector, collectors, sdk_start_ts, collection_ts,
+ std::move(delta_metrics), callback);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/temporal_metric_storage.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/temporal_metric_storage.cc
new file mode 100644
index 000000000..55e93e3d4
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/state/temporal_metric_storage.cc
@@ -0,0 +1,131 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/sdk/metrics/state/temporal_metric_storage.h"
+# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+TemporalMetricStorage::TemporalMetricStorage(InstrumentDescriptor instrument_descriptor)
+ : instrument_descriptor_(instrument_descriptor)
+{}
+
+bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector,
+ nostd::span<std::shared_ptr<CollectorHandle>> collectors,
+ opentelemetry::common::SystemTimestamp sdk_start_ts,
+ opentelemetry::common::SystemTimestamp collection_ts,
+ std::shared_ptr<AttributesHashMap> delta_metrics,
+ nostd::function_ref<bool(MetricData)> callback) noexcept
+{
+ std::lock_guard<opentelemetry::common::SpinLockMutex> guard(lock_);
+ opentelemetry::common::SystemTimestamp last_collection_ts = sdk_start_ts;
+ auto aggregation_temporarily = collector->GetAggregationTemporality();
+ for (auto &col : collectors)
+ {
+ unreported_metrics_[col.get()].push_back(delta_metrics);
+ }
+
+ // Get the unreported metrics for the `collector` from `unreported metrics stash`
+ // since last collection, this will also cleanup the unreported metrics for `collector`
+ // from the stash.
+ auto present = unreported_metrics_.find(collector);
+ if (present == unreported_metrics_.end())
+ {
+ // no unreported metrics for the collector, return.
+ return true;
+ }
+ auto unreported_list = std::move(present->second);
+ // Iterate over the unreporter metrics for `collector` and store result in `merged_metrics`
+ std::unique_ptr<AttributesHashMap> merged_metrics(new AttributesHashMap);
+ for (auto &agg_hashmap : unreported_list)
+ {
+ agg_hashmap->GetAllEnteries(
+ [&merged_metrics, this](const MetricAttributes &attributes, Aggregation &aggregation) {
+ auto agg = merged_metrics->Get(attributes);
+ if (agg)
+ {
+ merged_metrics->Set(attributes, agg->Merge(aggregation));
+ }
+ else
+ {
+ merged_metrics->Set(
+ attributes,
+ DefaultAggregation::CreateAggregation(instrument_descriptor_)->Merge(aggregation));
+ merged_metrics->GetAllEnteries(
+ [](const MetricAttributes &attr, Aggregation &aggr) { return true; });
+ }
+ return true;
+ });
+ }
+ // Get the last reported metrics for the `collector` from `last reported metrics` stash
+ // - If the aggregation_temporarily for the collector is cumulative
+ // - Merge the last reported metrics with unreported metrics (which is in merged_metrics),
+ // Final result of merge would be in merged_metrics.
+ // - Move the final merge to the `last reported metrics` stash.
+ // - If the aggregation_temporarily is delta
+ // - Store the unreported metrics for `collector` (which is in merged_mtrics) to
+ // `last reported metrics` stash.
+
+ auto reported = last_reported_metrics_.find(collector);
+ if (reported != last_reported_metrics_.end())
+ {
+ last_collection_ts = last_reported_metrics_[collector].collection_ts;
+ auto last_aggr_hashmap = std::move(last_reported_metrics_[collector].attributes_map);
+ if (aggregation_temporarily == AggregationTemporality::kCumulative)
+ {
+ // merge current delta to previous cumulative
+ last_aggr_hashmap->GetAllEnteries(
+ [&merged_metrics, this](const MetricAttributes &attributes, Aggregation &aggregation) {
+ auto agg = merged_metrics->Get(attributes);
+ if (agg)
+ {
+ merged_metrics->Set(attributes, agg->Merge(aggregation));
+ }
+ else
+ {
+ merged_metrics->Set(attributes,
+ DefaultAggregation::CreateAggregation(instrument_descriptor_));
+ }
+ return true;
+ });
+ }
+ last_reported_metrics_[collector] =
+ LastReportedMetrics{std::move(merged_metrics), collection_ts};
+ }
+ else
+ {
+ merged_metrics->GetAllEnteries(
+ [](const MetricAttributes &attr, Aggregation &aggr) { return true; });
+ last_reported_metrics_.insert(
+ std::make_pair(collector, LastReportedMetrics{std::move(merged_metrics), collection_ts}));
+ }
+
+ // Generate the MetricData from the final merged_metrics, and invoke callback over it.
+
+ AttributesHashMap *result_to_export = (last_reported_metrics_[collector]).attributes_map.get();
+ MetricData metric_data;
+ metric_data.instrument_descriptor = instrument_descriptor_;
+ metric_data.start_ts = last_collection_ts;
+ metric_data.end_ts = collection_ts;
+ result_to_export->GetAllEnteries(
+ [&metric_data](const MetricAttributes &attributes, Aggregation &aggregation) {
+ PointDataAttributes point_data_attr;
+ point_data_attr.point_data = aggregation.ToPoint();
+ point_data_attr.attributes = attributes;
+ metric_data.point_data_attr_.push_back(point_data_attr);
+ return true;
+ });
+ return callback(metric_data);
+}
+
+} // namespace metrics
+
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/sync_instruments.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/sync_instruments.cc
new file mode 100644
index 000000000..7cf9034cd
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/metrics/sync_instruments.cc
@@ -0,0 +1,202 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/sync_instruments.h"
+# include "opentelemetry/sdk/metrics/state/metric_storage.h"
+# include "opentelemetry/sdk_config.h"
+
+# include <cmath>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+LongCounter::LongCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void LongCounter::Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordLong(value, attributes, context);
+}
+
+void LongCounter::Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordLong(value, attributes, context);
+}
+
+void LongCounter::Add(long value) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordLong(value, context);
+}
+
+void LongCounter::Add(long value, const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordLong(value, context);
+}
+
+DoubleCounter::DoubleCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void DoubleCounter::Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordDouble(value, attributes, context);
+}
+
+void DoubleCounter::Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordDouble(value, attributes, context);
+}
+
+void DoubleCounter::Add(double value) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordDouble(value, context);
+}
+
+void DoubleCounter::Add(double value, const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordDouble(value, context);
+}
+
+LongUpDownCounter::LongUpDownCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void LongUpDownCounter::Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordLong(value, attributes, context);
+}
+
+void LongUpDownCounter::Add(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordLong(value, attributes, context);
+}
+
+void LongUpDownCounter::Add(long value) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordLong(value, context);
+}
+
+void LongUpDownCounter::Add(long value, const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordLong(value, context);
+}
+
+DoubleUpDownCounter::DoubleUpDownCounter(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void DoubleUpDownCounter::Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordDouble(value, attributes, context);
+}
+
+void DoubleUpDownCounter::Add(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordDouble(value, attributes, context);
+}
+
+void DoubleUpDownCounter::Add(double value) noexcept
+{
+ auto context = opentelemetry::context::Context{};
+ return storage_->RecordDouble(value, context);
+}
+
+void DoubleUpDownCounter::Add(double value, const opentelemetry::context::Context &context) noexcept
+{
+ return storage_->RecordDouble(value, context);
+}
+
+LongHistogram::LongHistogram(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void LongHistogram::Record(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ if (value < 0)
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "[LongHistogram::Record(value, attributes)] negative value provided to histogram Name:"
+ << instrument_descriptor_.name_ << " Value:" << value);
+ return;
+ }
+ return storage_->RecordLong(value, attributes, context);
+}
+
+void LongHistogram::Record(long value, const opentelemetry::context::Context &context) noexcept
+{
+ if (value < 0)
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "[LongHistogram::Record(value)] negative value provided to histogram Name:"
+ << instrument_descriptor_.name_ << " Value:" << value);
+ return;
+ }
+ return storage_->RecordLong(value, context);
+}
+
+DoubleHistogram::DoubleHistogram(InstrumentDescriptor instrument_descriptor,
+ std::unique_ptr<WritableMetricStorage> storage)
+ : Synchronous(instrument_descriptor, std::move(storage))
+{}
+
+void DoubleHistogram::Record(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept
+{
+ if (value < 0 || std::isnan(value) || std::isinf(value))
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "[DoubleHistogram::Record(value, attributes)] negative/nan/infinite value provided to "
+ "histogram Name:"
+ << instrument_descriptor_.name_);
+ return;
+ }
+ return storage_->RecordDouble(value, attributes, context);
+}
+
+void DoubleHistogram::Record(double value, const opentelemetry::context::Context &context) noexcept
+{
+ if (value < 0 || std::isnan(value) || std::isinf(value))
+ {
+ OTEL_INTERNAL_LOG_WARN(
+ "[DoubleHistogram::Record(value)] negative/nan/infinite value provided to histogram Name:"
+ << instrument_descriptor_.name_);
+ return;
+ }
+ return storage_->RecordDouble(value, context);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/BUILD
new file mode 100644
index 000000000..e42948b7e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/BUILD
@@ -0,0 +1,26 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "resource",
+ srcs = glob(["**/*.cc"]),
+ hdrs = glob(["**/*.h"]),
+ include_prefix = "src/resource",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/CMakeLists.txt
new file mode 100644
index 000000000..f8e8267dc
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_library(opentelemetry_resources resource.cc resource_detector.cc)
+
+set_target_properties(opentelemetry_resources PROPERTIES EXPORT_NAME resources)
+
+target_link_libraries(opentelemetry_resources opentelemetry_common)
+
+target_include_directories(
+ opentelemetry_resources
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_resources
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource.cc
new file mode 100644
index 000000000..ae71aefeb
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource.cc
@@ -0,0 +1,82 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/sdk/resource/experimental_semantic_conventions.h"
+#include "opentelemetry/sdk/resource/resource_detector.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace resource
+{
+
+const std::string kTelemetrySdkLanguage = "telemetry.sdk.language";
+const std::string kTelemetrySdkName = "telemetry.sdk.name";
+const std::string kTelemetrySdkVersion = "telemetry.sdk.version";
+const std::string kServiceName = "service.name";
+const std::string kProcessExecutableName = "process.executable.name";
+
+Resource::Resource(const ResourceAttributes &attributes, const std::string &schema_url) noexcept
+ : attributes_(attributes), schema_url_(schema_url)
+{}
+
+Resource Resource::Merge(const Resource &other) noexcept
+{
+ ResourceAttributes merged_resource_attributes(other.attributes_);
+ merged_resource_attributes.insert(attributes_.begin(), attributes_.end());
+ return Resource(merged_resource_attributes, other.schema_url_);
+}
+
+Resource Resource::Create(const ResourceAttributes &attributes, const std::string &schema_url)
+{
+ static auto otel_resource = OTELResourceDetector().Detect();
+ auto resource =
+ Resource::GetDefault().Merge(otel_resource).Merge(Resource{attributes, schema_url});
+
+ if (resource.attributes_.find(OTEL_GET_RESOURCE_ATTR(AttrServiceName)) ==
+ resource.attributes_.end())
+ {
+ std::string default_service_name = "unknown_service";
+ auto it_process_executable_name =
+ resource.attributes_.find(OTEL_GET_RESOURCE_ATTR(AttrProcessExecutableName));
+ if (it_process_executable_name != resource.attributes_.end())
+ {
+ default_service_name += ":" + nostd::get<std::string>(it_process_executable_name->second);
+ }
+ resource.attributes_[OTEL_GET_RESOURCE_ATTR(AttrServiceName)] = default_service_name;
+ }
+ return resource;
+}
+
+Resource &Resource::GetEmpty()
+{
+ static Resource empty_resource;
+ return empty_resource;
+}
+
+Resource &Resource::GetDefault()
+{
+ static Resource default_resource(
+ {{OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkLanguage), "cpp"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkName), "opentelemetry"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkVersion), OPENTELEMETRY_SDK_VERSION}},
+ std::string{});
+ return default_resource;
+}
+
+const ResourceAttributes &Resource::GetAttributes() const noexcept
+{
+ return attributes_;
+}
+
+const std::string &Resource::GetSchemaURL() const noexcept
+{
+ return schema_url_;
+}
+
+} // namespace resource
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource_detector.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource_detector.cc
new file mode 100644
index 000000000..c60056539
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/resource/resource_detector.cc
@@ -0,0 +1,39 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/resource/resource_detector.h"
+#include "opentelemetry/sdk/common/env_variables.h"
+#include "opentelemetry/sdk/resource/resource.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace resource
+{
+
+const char *OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES";
+
+Resource OTELResourceDetector::Detect() noexcept
+{
+ auto attributes_str =
+ opentelemetry::sdk::common::GetEnvironmentVariable(OTEL_RESOURCE_ATTRIBUTES);
+ if (attributes_str.size() == 0)
+ {
+ return Resource();
+ }
+ ResourceAttributes attributes;
+ std::istringstream iss(attributes_str);
+ std::string token;
+ while (std::getline(iss, token, ','))
+ {
+ size_t pos = token.find('=');
+ std::string key = token.substr(0, pos);
+ std::string value = token.substr(pos + 1);
+ attributes[key] = value;
+ }
+ return Resource(attributes);
+}
+
+} // namespace resource
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/BUILD
new file mode 100644
index 000000000..362680b74
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/BUILD
@@ -0,0 +1,29 @@
+# Copyright 2020, OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "trace",
+ srcs = glob(["**/*.cc"]),
+ hdrs = glob(["**/*.h"]),
+ include_prefix = "src/trace",
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "//sdk/src/common:global_log_handler",
+ "//sdk/src/common:random",
+ "//sdk/src/resource",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/CMakeLists.txt
new file mode 100644
index 000000000..ddef00fb4
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_library(
+ opentelemetry_trace
+ tracer_context.cc
+ tracer_provider.cc
+ tracer.cc
+ span.cc
+ batch_span_processor.cc
+ samplers/parent.cc
+ samplers/trace_id_ratio.cc
+ random_id_generator.cc)
+
+set_target_properties(opentelemetry_trace PROPERTIES EXPORT_NAME trace)
+
+target_link_libraries(opentelemetry_trace PUBLIC opentelemetry_common
+ opentelemetry_resources)
+
+target_include_directories(
+ opentelemetry_trace
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_trace
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/batch_span_processor.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/batch_span_processor.cc
new file mode 100644
index 000000000..0ab042b9a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/batch_span_processor.cc
@@ -0,0 +1,211 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/batch_span_processor.h"
+
+#include <vector>
+using opentelemetry::sdk::common::AtomicUniquePtr;
+using opentelemetry::sdk::common::CircularBuffer;
+using opentelemetry::sdk::common::CircularBufferRange;
+using opentelemetry::trace::SpanContext;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+BatchSpanProcessor::BatchSpanProcessor(std::unique_ptr<SpanExporter> &&exporter,
+ const BatchSpanProcessorOptions &options)
+ : exporter_(std::move(exporter)),
+ max_queue_size_(options.max_queue_size),
+ schedule_delay_millis_(options.schedule_delay_millis),
+ max_export_batch_size_(options.max_export_batch_size),
+ buffer_(max_queue_size_),
+ worker_thread_(&BatchSpanProcessor::DoBackgroundWork, this)
+{}
+
+std::unique_ptr<Recordable> BatchSpanProcessor::MakeRecordable() noexcept
+{
+ return exporter_->MakeRecordable();
+}
+
+void BatchSpanProcessor::OnStart(Recordable &, const SpanContext &) noexcept
+{
+ // no-op
+}
+
+void BatchSpanProcessor::OnEnd(std::unique_ptr<Recordable> &&span) noexcept
+{
+ if (is_shutdown_.load() == true)
+ {
+ return;
+ }
+
+ if (buffer_.Add(span) == false)
+ {
+ return;
+ }
+
+ // If the queue gets at least half full a preemptive notification is
+ // sent to the worker thread to start a new export cycle.
+ if (buffer_.size() >= max_queue_size_ / 2)
+ {
+ // signal the worker thread
+ cv_.notify_one();
+ }
+}
+
+bool BatchSpanProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ if (is_shutdown_.load() == true)
+ {
+ return false;
+ }
+
+ is_force_flush_ = true;
+
+ // Keep attempting to wake up the worker thread
+ while (is_force_flush_.load() == true)
+ {
+ cv_.notify_one();
+ }
+
+ // Now wait for the worker thread to signal back from the Export method
+ std::unique_lock<std::mutex> lk(force_flush_cv_m_);
+ while (is_force_flush_notified_.load() == false)
+ {
+ force_flush_cv_.wait(lk);
+ }
+
+ // Notify the worker thread
+ is_force_flush_notified_ = false;
+
+ return true;
+}
+
+void BatchSpanProcessor::DoBackgroundWork()
+{
+ auto timeout = schedule_delay_millis_;
+
+ while (true)
+ {
+ // Wait for `timeout` milliseconds
+ std::unique_lock<std::mutex> lk(cv_m_);
+ cv_.wait_for(lk, timeout);
+
+ if (is_shutdown_.load() == true)
+ {
+ DrainQueue();
+ return;
+ }
+
+ bool was_force_flush_called = is_force_flush_.load();
+
+ // Check if this export was the result of a force flush.
+ if (was_force_flush_called == true)
+ {
+ // Since this export was the result of a force flush, signal the
+ // main thread that the worker thread has been notified
+ is_force_flush_ = false;
+ }
+ else
+ {
+ // If the buffer was empty during the entire `timeout` time interval,
+ // go back to waiting. If this was a spurious wake-up, we export only if
+ // `buffer_` is not empty. This is acceptable because batching is a best
+ // mechanism effort here.
+ if (buffer_.empty() == true)
+ {
+ timeout = schedule_delay_millis_;
+ continue;
+ }
+ }
+
+ auto start = std::chrono::steady_clock::now();
+ Export(was_force_flush_called);
+ auto end = std::chrono::steady_clock::now();
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+
+ // Subtract the duration of this export call from the next `timeout`.
+ timeout = schedule_delay_millis_ - duration;
+ }
+}
+
+void BatchSpanProcessor::Export(const bool was_force_flush_called)
+{
+ std::vector<std::unique_ptr<Recordable>> spans_arr;
+
+ size_t num_spans_to_export;
+
+ if (was_force_flush_called == true)
+ {
+ num_spans_to_export = buffer_.size();
+ }
+ else
+ {
+ num_spans_to_export =
+ buffer_.size() >= max_export_batch_size_ ? max_export_batch_size_ : buffer_.size();
+ }
+
+ buffer_.Consume(num_spans_to_export,
+ [&](CircularBufferRange<AtomicUniquePtr<Recordable>> range) noexcept {
+ range.ForEach([&](AtomicUniquePtr<Recordable> &ptr) {
+ std::unique_ptr<Recordable> swap_ptr = std::unique_ptr<Recordable>(nullptr);
+ ptr.Swap(swap_ptr);
+ spans_arr.push_back(std::unique_ptr<Recordable>(swap_ptr.release()));
+ return true;
+ });
+ });
+
+ exporter_->Export(nostd::span<std::unique_ptr<Recordable>>(spans_arr.data(), spans_arr.size()));
+
+ // Notify the main thread in case this export was the result of a force flush.
+ if (was_force_flush_called == true)
+ {
+ is_force_flush_notified_ = true;
+ while (is_force_flush_notified_.load() == true)
+ {
+ force_flush_cv_.notify_one();
+ }
+ }
+}
+
+void BatchSpanProcessor::DrainQueue()
+{
+ while (buffer_.empty() == false)
+ {
+ Export(false);
+ }
+}
+
+bool BatchSpanProcessor::Shutdown(std::chrono::microseconds timeout) noexcept
+{
+ std::lock_guard<std::mutex> shutdown_guard{shutdown_m_};
+ bool already_shutdown = is_shutdown_.exchange(true);
+
+ if (worker_thread_.joinable())
+ {
+ cv_.notify_one();
+ worker_thread_.join();
+ }
+
+ // Should only shutdown exporter ONCE.
+ if (!already_shutdown && exporter_ != nullptr)
+ {
+ return exporter_->Shutdown();
+ }
+
+ return true;
+}
+
+BatchSpanProcessor::~BatchSpanProcessor()
+{
+ if (is_shutdown_.load() == false)
+ {
+ Shutdown();
+ }
+}
+
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/random_id_generator.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/random_id_generator.cc
new file mode 100644
index 000000000..e2fa5b098
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/random_id_generator.cc
@@ -0,0 +1,30 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/random_id_generator.h"
+#include "opentelemetry/version.h"
+#include "src/common/random.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+namespace trace_api = opentelemetry::trace;
+
+trace_api::SpanId RandomIdGenerator::GenerateSpanId() noexcept
+{
+ uint8_t span_id_buf[trace_api::SpanId::kSize];
+ sdk::common::Random::GenerateRandomBuffer(span_id_buf);
+ return trace_api::SpanId(span_id_buf);
+}
+
+trace_api::TraceId RandomIdGenerator::GenerateTraceId() noexcept
+{
+ uint8_t trace_id_buf[trace_api::TraceId::kSize];
+ sdk::common::Random::GenerateRandomBuffer(trace_id_buf);
+ return trace_api::TraceId(trace_id_buf);
+}
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/parent.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/parent.cc
new file mode 100644
index 000000000..3aa6b4a45
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/parent.cc
@@ -0,0 +1,48 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/samplers/parent.h"
+
+namespace trace_api = opentelemetry::trace;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+ParentBasedSampler::ParentBasedSampler(std::shared_ptr<Sampler> delegate_sampler) noexcept
+ : delegate_sampler_(delegate_sampler),
+ description_("ParentBased{" + std::string{delegate_sampler->GetDescription()} + "}")
+{}
+
+SamplingResult ParentBasedSampler::ShouldSample(
+ const trace_api::SpanContext &parent_context,
+ trace_api::TraceId trace_id,
+ nostd::string_view name,
+ trace_api::SpanKind span_kind,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const trace_api::SpanContextKeyValueIterable &links) noexcept
+{
+ if (!parent_context.IsValid())
+ {
+ // If no parent (root span) exists returns the result of the delegateSampler
+ return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes,
+ links);
+ }
+
+ // If parent exists:
+ if (parent_context.IsSampled())
+ {
+ return {Decision::RECORD_AND_SAMPLE, nullptr, parent_context.trace_state()};
+ }
+
+ return {Decision::DROP, nullptr, parent_context.trace_state()};
+}
+
+nostd::string_view ParentBasedSampler::GetDescription() const noexcept
+{
+ return description_;
+}
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/trace_id_ratio.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/trace_id_ratio.cc
new file mode 100644
index 000000000..7c154346d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/samplers/trace_id_ratio.cc
@@ -0,0 +1,111 @@
+// Copyright 2020, Open Telemetry Authors
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "opentelemetry/sdk/trace/samplers/trace_id_ratio.h"
+
+#include <cmath>
+#include <cstdint>
+#include <stdexcept>
+
+namespace trace_api = opentelemetry::trace;
+
+namespace
+{
+/**
+ * Converts a ratio in [0, 1] to a threshold in [0, UINT64_MAX]
+ *
+ * @param ratio a required value top be converted to uint64_t. is
+ * bounded by 1 >= ratio >= 0.
+ * @return Returns threshold value computed after converting ratio to
+ * uint64_t datatype
+ */
+uint64_t CalculateThreshold(double ratio) noexcept
+{
+ if (ratio <= 0.0)
+ return 0;
+ if (ratio >= 1.0)
+ return UINT64_MAX;
+
+ // We can't directly return ratio * UINT64_MAX.
+ //
+ // UINT64_MAX is (2^64)-1, but as a double rounds up to 2^64.
+ // For probabilities >= 1-(2^-54), the product wraps to zero!
+ // Instead, calculate the high and low 32 bits separately.
+ const double product = UINT32_MAX * ratio;
+ double hi_bits, lo_bits = ldexp(modf(product, &hi_bits), 32) + product;
+ return (static_cast<uint64_t>(hi_bits) << 32) + static_cast<uint64_t>(lo_bits);
+}
+
+/**
+ * @param trace_id a required value to be converted to uint64_t. trace_id must
+ * at least 8 bytes long
+ * @return Returns threshold value computed after converting trace_id to
+ * uint64_t datatype
+ */
+uint64_t CalculateThresholdFromBuffer(const trace_api::TraceId &trace_id) noexcept
+{
+ // We only use the first 8 bytes of TraceId.
+ static_assert(trace_api::TraceId::kSize >= 8, "TraceID must be at least 8 bytes long.");
+
+ uint64_t res = 0;
+ std::memcpy(&res, &trace_id, 8);
+
+ double ratio = (double)res / UINT64_MAX;
+
+ return CalculateThreshold(ratio);
+}
+} // namespace
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+TraceIdRatioBasedSampler::TraceIdRatioBasedSampler(double ratio)
+ : threshold_(CalculateThreshold(ratio))
+{
+ if (ratio > 1.0)
+ ratio = 1.0;
+ if (ratio < 0.0)
+ ratio = 0.0;
+ description_ = "TraceIdRatioBasedSampler{" + std::to_string(ratio) + "}";
+}
+
+SamplingResult TraceIdRatioBasedSampler::ShouldSample(
+ const trace_api::SpanContext & /*parent_context*/,
+ trace_api::TraceId trace_id,
+ nostd::string_view /*name*/,
+ trace_api::SpanKind /*span_kind*/,
+ const opentelemetry::common::KeyValueIterable & /*attributes*/,
+ const trace_api::SpanContextKeyValueIterable & /*links*/) noexcept
+{
+ if (threshold_ == 0)
+ return {Decision::DROP, nullptr};
+
+ if (CalculateThresholdFromBuffer(trace_id) <= threshold_)
+ {
+ return {Decision::RECORD_AND_SAMPLE, nullptr};
+ }
+
+ return {Decision::DROP, nullptr};
+}
+
+nostd::string_view TraceIdRatioBasedSampler::GetDescription() const noexcept
+{
+ return description_;
+}
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.cc
new file mode 100644
index 000000000..13ea99126
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.cc
@@ -0,0 +1,187 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/trace/span.h"
+#include "src/common/random.h"
+
+#include "opentelemetry/context/runtime_context.h"
+#include "opentelemetry/trace/trace_flags.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+using opentelemetry::common::SteadyTimestamp;
+using opentelemetry::common::SystemTimestamp;
+namespace common = opentelemetry::common;
+
+namespace
+{
+SystemTimestamp NowOr(const SystemTimestamp &system)
+{
+ if (system == SystemTimestamp())
+ {
+ return SystemTimestamp(std::chrono::system_clock::now());
+ }
+ else
+ {
+ return system;
+ }
+}
+
+SteadyTimestamp NowOr(const SteadyTimestamp &steady)
+{
+ if (steady == SteadyTimestamp())
+ {
+ return SteadyTimestamp(std::chrono::steady_clock::now());
+ }
+ else
+ {
+ return steady;
+ }
+}
+} // namespace
+
+Span::Span(std::shared_ptr<Tracer> &&tracer,
+ nostd::string_view name,
+ const common::KeyValueIterable &attributes,
+ const trace_api::SpanContextKeyValueIterable &links,
+ const trace_api::StartSpanOptions &options,
+ const trace_api::SpanContext &parent_span_context,
+ std::unique_ptr<trace_api::SpanContext> span_context) noexcept
+ : tracer_{std::move(tracer)},
+ recordable_{tracer_->GetProcessor().MakeRecordable()},
+ start_steady_time{options.start_steady_time},
+ span_context_(std::move(span_context)),
+ has_ended_{false}
+{
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->SetName(name);
+ recordable_->SetInstrumentationLibrary(tracer_->GetInstrumentationLibrary());
+ recordable_->SetIdentity(*span_context_, parent_span_context.IsValid()
+ ? parent_span_context.span_id()
+ : trace_api::SpanId());
+
+ attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept {
+ recordable_->SetAttribute(key, value);
+ return true;
+ });
+
+ links.ForEachKeyValue([&](opentelemetry::trace::SpanContext span_context,
+ const common::KeyValueIterable &attributes) {
+ recordable_->AddLink(span_context, attributes);
+ return true;
+ });
+
+ recordable_->SetSpanKind(options.kind);
+ recordable_->SetStartTime(NowOr(options.start_system_time));
+ start_steady_time = NowOr(options.start_steady_time);
+ recordable_->SetResource(tracer_->GetResource());
+ tracer_->GetProcessor().OnStart(*recordable_, parent_span_context);
+}
+
+Span::~Span()
+{
+ End();
+}
+
+void Span::SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+
+ recordable_->SetAttribute(key, value);
+}
+
+void Span::AddEvent(nostd::string_view name) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->AddEvent(name);
+}
+
+void Span::AddEvent(nostd::string_view name, SystemTimestamp timestamp) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->AddEvent(name, timestamp);
+}
+
+void Span::AddEvent(nostd::string_view name,
+ SystemTimestamp timestamp,
+ const common::KeyValueIterable &attributes) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->AddEvent(name, timestamp, attributes);
+}
+
+void Span::SetStatus(opentelemetry::trace::StatusCode code, nostd::string_view description) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->SetStatus(code, description);
+}
+
+void Span::UpdateName(nostd::string_view name) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+ recordable_->SetName(name);
+}
+
+void Span::End(const trace_api::EndSpanOptions &options) noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+
+ if (has_ended_ == true)
+ {
+ return;
+ }
+ has_ended_ = true;
+
+ if (recordable_ == nullptr)
+ {
+ return;
+ }
+
+ auto end_steady_time = NowOr(options.end_steady_time);
+ recordable_->SetDuration(std::chrono::steady_clock::time_point(end_steady_time) -
+ std::chrono::steady_clock::time_point(start_steady_time));
+
+ tracer_->GetProcessor().OnEnd(std::move(recordable_));
+ recordable_.reset();
+}
+
+bool Span::IsRecording() const noexcept
+{
+ std::lock_guard<std::mutex> lock_guard{mu_};
+ return recordable_ != nullptr;
+}
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.h b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.h
new file mode 100644
index 000000000..f507afbef
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/span.h
@@ -0,0 +1,66 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <mutex>
+
+#include "opentelemetry/sdk/trace/tracer.h"
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+class Span final : public opentelemetry::trace::Span
+{
+public:
+ Span(std::shared_ptr<Tracer> &&tracer,
+ nostd::string_view name,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::trace::SpanContextKeyValueIterable &links,
+ const opentelemetry::trace::StartSpanOptions &options,
+ const opentelemetry::trace::SpanContext &parent_span_context,
+ std::unique_ptr<opentelemetry::trace::SpanContext> span_context) noexcept;
+
+ ~Span() override;
+
+ // trace::Span
+ void SetAttribute(nostd::string_view key,
+ const opentelemetry::common::AttributeValue &value) noexcept override;
+
+ void AddEvent(nostd::string_view name) noexcept override;
+
+ void AddEvent(nostd::string_view name,
+ opentelemetry::common::SystemTimestamp timestamp) noexcept override;
+
+ void AddEvent(nostd::string_view name,
+ opentelemetry::common::SystemTimestamp timestamp,
+ const opentelemetry::common::KeyValueIterable &attributes) noexcept override;
+
+ void SetStatus(opentelemetry::trace::StatusCode code,
+ nostd::string_view description) noexcept override;
+
+ void UpdateName(nostd::string_view name) noexcept override;
+
+ void End(const opentelemetry::trace::EndSpanOptions &options = {}) noexcept override;
+
+ bool IsRecording() const noexcept override;
+
+ opentelemetry::trace::SpanContext GetContext() const noexcept override
+ {
+ return *span_context_.get();
+ }
+
+private:
+ std::shared_ptr<Tracer> tracer_;
+ mutable std::mutex mu_;
+ std::unique_ptr<Recordable> recordable_;
+ opentelemetry::common::SteadyTimestamp start_steady_time;
+ std::unique_ptr<opentelemetry::trace::SpanContext> span_context_;
+ bool has_ended_;
+};
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer.cc
new file mode 100644
index 000000000..be5e5f7d9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer.cc
@@ -0,0 +1,116 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/tracer.h"
+#include "opentelemetry/context/runtime_context.h"
+#include "opentelemetry/nostd/shared_ptr.h"
+#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
+#include "opentelemetry/trace/context.h"
+#include "opentelemetry/version.h"
+#include "src/trace/span.h"
+
+#include <memory>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+
+Tracer::Tracer(std::shared_ptr<sdk::trace::TracerContext> context,
+ std::unique_ptr<InstrumentationLibrary> instrumentation_library) noexcept
+ : instrumentation_library_{std::move(instrumentation_library)}, context_{context}
+{}
+
+nostd::shared_ptr<trace_api::Span> Tracer::StartSpan(
+ nostd::string_view name,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const trace_api::SpanContextKeyValueIterable &links,
+ const trace_api::StartSpanOptions &options) noexcept
+{
+ trace_api::SpanContext parent_context = GetCurrentSpan()->GetContext();
+ if (nostd::holds_alternative<trace_api::SpanContext>(options.parent))
+ {
+ auto span_context = nostd::get<trace_api::SpanContext>(options.parent);
+ if (span_context.IsValid())
+ {
+ parent_context = span_context;
+ }
+ }
+ else if (nostd::holds_alternative<context::Context>(options.parent))
+ {
+ auto context = nostd::get<context::Context>(options.parent);
+ // fetch span context from parent span stored in the context
+ auto span_context = opentelemetry::trace::GetSpan(context)->GetContext();
+ if (span_context.IsValid())
+ {
+ parent_context = span_context;
+ }
+ }
+
+ trace_api::TraceId trace_id;
+ trace_api::SpanId span_id = GetIdGenerator().GenerateSpanId();
+ bool is_parent_span_valid = false;
+
+ if (parent_context.IsValid())
+ {
+ trace_id = parent_context.trace_id();
+ is_parent_span_valid = true;
+ }
+ else
+ {
+ trace_id = GetIdGenerator().GenerateTraceId();
+ }
+
+ auto sampling_result = context_->GetSampler().ShouldSample(parent_context, trace_id, name,
+ options.kind, attributes, links);
+ auto trace_flags = sampling_result.decision == Decision::DROP
+ ? trace_api::TraceFlags{}
+ : trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled};
+
+ auto span_context = std::unique_ptr<trace_api::SpanContext>(new trace_api::SpanContext(
+ trace_id, span_id, trace_flags, false,
+ sampling_result.trace_state ? sampling_result.trace_state
+ : is_parent_span_valid ? parent_context.trace_state()
+ : trace_api::TraceState::GetDefault()));
+
+ if (sampling_result.decision == Decision::DROP)
+ {
+ // create no-op span with valid span-context.
+
+ auto noop_span = nostd::shared_ptr<trace_api::Span>{
+ new (std::nothrow) trace_api::NoopSpan(this->shared_from_this(), std::move(span_context))};
+ return noop_span;
+ }
+ else
+ {
+
+ auto span = nostd::shared_ptr<trace_api::Span>{
+ new (std::nothrow) Span{this->shared_from_this(), name, attributes, links, options,
+ parent_context, std::move(span_context)}};
+
+ // if the attributes is not nullptr, add attributes to the span.
+ if (sampling_result.attributes)
+ {
+ for (auto &kv : *sampling_result.attributes)
+ {
+ span->SetAttribute(kv.first, kv.second);
+ }
+ }
+
+ return span;
+ }
+}
+
+void Tracer::ForceFlushWithMicroseconds(uint64_t timeout) noexcept
+{
+ (void)timeout;
+}
+
+void Tracer::CloseWithMicroseconds(uint64_t timeout) noexcept
+{
+ (void)timeout;
+}
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_context.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_context.cc
new file mode 100644
index 000000000..d20421802
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_context.cc
@@ -0,0 +1,63 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/tracer_context.h"
+#include "opentelemetry/sdk/trace/multi_span_processor.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+namespace resource = opentelemetry::sdk::resource;
+
+TracerContext::TracerContext(std::vector<std::unique_ptr<SpanProcessor>> &&processors,
+ resource::Resource resource,
+ std::unique_ptr<Sampler> sampler,
+ std::unique_ptr<IdGenerator> id_generator) noexcept
+ : resource_(resource),
+ sampler_(std::move(sampler)),
+ id_generator_(std::move(id_generator)),
+ processor_(std::unique_ptr<SpanProcessor>(new MultiSpanProcessor(std::move(processors))))
+{}
+
+Sampler &TracerContext::GetSampler() const noexcept
+{
+ return *sampler_;
+}
+
+const resource::Resource &TracerContext::GetResource() const noexcept
+{
+ return resource_;
+}
+
+opentelemetry::sdk::trace::IdGenerator &TracerContext::GetIdGenerator() const noexcept
+{
+ return *id_generator_;
+}
+
+void TracerContext::AddProcessor(std::unique_ptr<SpanProcessor> processor) noexcept
+{
+
+ auto multi_processor = static_cast<MultiSpanProcessor *>(processor_.get());
+ multi_processor->AddProcessor(std::move(processor));
+}
+
+SpanProcessor &TracerContext::GetProcessor() const noexcept
+{
+ return *processor_;
+}
+
+bool TracerContext::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return processor_->ForceFlush(timeout);
+}
+
+bool TracerContext::Shutdown() noexcept
+{
+ return processor_->Shutdown();
+}
+
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_provider.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_provider.cc
new file mode 100644
index 000000000..64997d7d0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/trace/tracer_provider.cc
@@ -0,0 +1,104 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/tracer_provider.h"
+#include "opentelemetry/sdk_config.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace trace
+{
+namespace resource = opentelemetry::sdk::resource;
+namespace trace_api = opentelemetry::trace;
+
+TracerProvider::TracerProvider(std::shared_ptr<sdk::trace::TracerContext> context) noexcept
+ : context_{context}
+{}
+
+TracerProvider::TracerProvider(std::unique_ptr<SpanProcessor> processor,
+ resource::Resource resource,
+ std::unique_ptr<Sampler> sampler,
+ std::unique_ptr<IdGenerator> id_generator) noexcept
+{
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+ context_ = std::make_shared<TracerContext>(std::move(processors), resource, std::move(sampler),
+ std::move(id_generator));
+}
+
+TracerProvider::TracerProvider(std::vector<std::unique_ptr<SpanProcessor>> &&processors,
+ resource::Resource resource,
+ std::unique_ptr<Sampler> sampler,
+ std::unique_ptr<IdGenerator> id_generator) noexcept
+{
+ context_ = std::make_shared<TracerContext>(std::move(processors), resource, std::move(sampler),
+ std::move(id_generator));
+}
+
+TracerProvider::~TracerProvider()
+{
+ // Tracer hold the shared pointer to the context. So we can not use destructor of TracerContext to
+ // Shutdown and flush all pending recordables when we have more than one tracers.These recordables
+ // may use the raw pointer of instrumentation_library_ in Tracer
+ if (context_)
+ {
+ context_->Shutdown();
+ }
+}
+
+nostd::shared_ptr<trace_api::Tracer> TracerProvider::GetTracer(
+ nostd::string_view library_name,
+ nostd::string_view library_version,
+ nostd::string_view schema_url) noexcept
+{
+ if (library_name.data() == nullptr)
+ {
+ OTEL_INTERNAL_LOG_ERROR("[TracerProvider::GetTracer] Library name is null.");
+ library_name = "";
+ }
+ else if (library_name == "")
+ {
+ OTEL_INTERNAL_LOG_ERROR("[TracerProvider::GetTracer] Library name is empty.");
+ }
+
+ const std::lock_guard<std::mutex> guard(lock_);
+
+ for (auto &tracer : tracers_)
+ {
+ auto &tracer_lib = tracer->GetInstrumentationLibrary();
+ if (tracer_lib.equal(library_name, library_version, schema_url))
+ {
+ return nostd::shared_ptr<trace_api::Tracer>{tracer};
+ }
+ }
+
+ auto lib = InstrumentationLibrary::Create(library_name, library_version, schema_url);
+ tracers_.push_back(std::shared_ptr<opentelemetry::sdk::trace::Tracer>(
+ new sdk::trace::Tracer(context_, std::move(lib))));
+ return nostd::shared_ptr<trace_api::Tracer>{tracers_.back()};
+}
+
+void TracerProvider::AddProcessor(std::unique_ptr<SpanProcessor> processor) noexcept
+{
+ context_->AddProcessor(std::move(processor));
+}
+
+const resource::Resource &TracerProvider::GetResource() const noexcept
+{
+ return context_->GetResource();
+}
+
+bool TracerProvider::Shutdown() noexcept
+{
+ return context_->Shutdown();
+}
+
+bool TracerProvider::ForceFlush(std::chrono::microseconds timeout) noexcept
+{
+ return context_->ForceFlush(timeout);
+}
+
+} // namespace trace
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/version/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/src/version/CMakeLists.txt
new file mode 100644
index 000000000..59231070b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/version/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_library(opentelemetry_version version.cc)
+
+set_target_properties(opentelemetry_version PROPERTIES EXPORT_NAME version)
+
+target_link_libraries(opentelemetry_version PUBLIC opentelemetry_api
+ opentelemetry_sdk)
+
+target_include_directories(
+ opentelemetry_version
+ PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
+
+install(
+ TARGETS opentelemetry_version
+ EXPORT "${PROJECT_NAME}-target"
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/src/version/version.cc b/src/jaegertracing/opentelemetry-cpp/sdk/src/version/version.cc
new file mode 100644
index 000000000..9303a305a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/src/version/version.cc
@@ -0,0 +1,24 @@
+// Please DONOT touch this file.
+// Any changes done here would be overwritten during release/build.
+
+#include "opentelemetry/sdk/version/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace version
+{
+const int MAJOR_VERSION = 1;
+const int MINOR_VERSION = 4;
+const int PATCH_VERSION = 0;
+const char *PRE_RELEASE = "";
+const char *BUILD_METADATA = "";
+const int COUNT_NEW_COMMITS = 0;
+const char *BRANCH = "";
+const char *COMMIT_HASH = "";
+const char *SHORT_VERSION = "";
+const char *FULL_VERSION = "";
+const char *BUILD_DATE = "";
+} // namespace version
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/CMakeLists.txt
new file mode 100644
index 000000000..dc8cc2b22
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_subdirectory(common)
+add_subdirectory(trace)
+if(WITH_METRICS_PREVIEW)
+ add_subdirectory(_metrics)
+else()
+ add_subdirectory(metrics)
+endif()
+if(WITH_LOGS_PREVIEW)
+ add_subdirectory(logs)
+endif()
+add_subdirectory(resource)
+add_subdirectory(instrumentationlibrary)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/BUILD
new file mode 100644
index 000000000..44835d102
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/BUILD
@@ -0,0 +1,165 @@
+cc_test(
+ name = "controller_test",
+ srcs = [
+ "controller_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//exporters/ostream:ostream_metrics_exporter_deprecated",
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "gauge_aggregator_test",
+ srcs = [
+ "gauge_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "min_max_sum_count_aggregator_test",
+ srcs = [
+ "min_max_sum_count_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "meter_provider_sdk_test",
+ srcs = [
+ "meter_provider_sdk_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "meter_test",
+ srcs = [
+ "meter_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "counter_aggregator_test",
+ srcs = [
+ "counter_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "exact_aggregator_test",
+ srcs = [
+ "exact_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "histogram_aggregator_test",
+ srcs = [
+ "histogram_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "metric_instrument_test",
+ srcs = [
+ "metric_instrument_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "sketch_aggregator_test",
+ srcs = [
+ "sketch_aggregator_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "ungrouped_processor_test",
+ srcs = [
+ "ungrouped_processor_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/_metrics:metrics_deprecated",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/CMakeLists.txt
new file mode 100644
index 000000000..5d950ffb3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/CMakeLists.txt
@@ -0,0 +1,21 @@
+foreach(
+ testname
+ meter_provider_sdk_test
+ gauge_aggregator_test
+ min_max_sum_count_aggregator_test
+ exact_aggregator_test
+ counter_aggregator_test
+ histogram_aggregator_test
+ ungrouped_processor_test
+ meter_test
+ metric_instrument_test
+ controller_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(
+ ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
+ opentelemetry_metrics_deprecated)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX metrics.
+ TEST_LIST ${testname})
+endforeach()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/controller_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/controller_test.cc
new file mode 100644
index 000000000..aa92c8d04
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/controller_test.cc
@@ -0,0 +1,56 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/controller.h"
+# include "opentelemetry/sdk/_metrics/meter.h"
+# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
+
+# include <gtest/gtest.h>
+# include <numeric>
+# include <thread>
+// #include <chrono>
+
+namespace metrics_api = opentelemetry::metrics;
+using namespace opentelemetry::sdk::common;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+class DummyExporter : public MetricsExporter
+{
+ ExportResult Export(const std::vector<Record> &records) noexcept
+ {
+ return ExportResult::kSuccess;
+ }
+};
+
+TEST(Controller, Constructor)
+{
+
+ std::shared_ptr<metrics_api::Meter> meter =
+ std::shared_ptr<metrics_api::Meter>(new Meter("Test"));
+ PushController alpha(meter, std::unique_ptr<MetricsExporter>(new DummyExporter),
+ std::shared_ptr<MetricsProcessor>(
+ new opentelemetry::sdk::metrics::UngroupedMetricsProcessor(false)),
+ .05);
+
+ auto instr = meter->NewIntCounter("test", "none", "none", true);
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels};
+
+ alpha.start();
+
+ for (int i = 0; i < 20; i++)
+ {
+ instr->add(i, labelkv);
+ }
+ alpha.stop();
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/counter_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/counter_aggregator_test.cc
new file mode 100644
index 000000000..7ef452e77
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/counter_aggregator_test.cc
@@ -0,0 +1,120 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+
+# include <gtest/gtest.h>
+# include <numeric>
+# include <thread>
+
+namespace metrics_api = opentelemetry::metrics;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+TEST(CounterAggregator, NoUpdates)
+{
+ CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
+
+ EXPECT_EQ(alpha.get_checkpoint().size(), 1);
+ EXPECT_EQ(alpha.get_checkpoint()[0], 0);
+
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint().size(), 1);
+ EXPECT_EQ(alpha.get_checkpoint()[0], 0);
+}
+
+TEST(CounterAggregator, Update)
+{
+ CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
+ CounterAggregator<int> beta(metrics_api::InstrumentKind::Counter);
+
+ for (int i = 0; i < 123456; i++)
+ {
+ alpha.update(1);
+ }
+
+ int sum = 0;
+ for (int i = 0; i < 100; i++)
+ {
+ int tmp = std::rand() % 128;
+ beta.update(tmp);
+ sum += tmp;
+ }
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], 0); // checkpoint shouldn't change even with updates
+ EXPECT_EQ(beta.get_checkpoint()[0], 0);
+
+ alpha.checkpoint();
+ beta.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], 123456);
+ EXPECT_EQ(beta.get_checkpoint()[0], sum);
+
+ alpha.update(15);
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint()[0], 15); // reset to 0 after first checkpoint call
+}
+
+// callback update function used to test concurrent calls
+void incrementingCallback(Aggregator<int> &agg)
+{
+ for (int i = 0; i < 2000000; i++)
+ {
+ agg.update(1);
+ }
+}
+
+TEST(CounterAggregator, Concurrency)
+{
+ CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
+
+ // spawn new threads that initiate the callback
+ std::thread first(incrementingCallback, std::ref(alpha));
+ std::thread second(incrementingCallback, std::ref(alpha));
+
+ first.join();
+ second.join();
+
+ alpha.checkpoint();
+
+ // race conditions result in values below 2*2000000
+ EXPECT_EQ(alpha.get_checkpoint()[0], 2 * 2000000);
+}
+
+TEST(CounterAggregator, Merge)
+{
+ CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
+ CounterAggregator<int> beta(metrics_api::InstrumentKind::Counter);
+
+ alpha.merge(beta);
+
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint()[0], 0); // merge with no updates
+
+ for (int i = 0; i < 500; i++)
+ {
+ alpha.update(1);
+ }
+
+ for (int i = 0; i < 700; i++)
+ {
+ beta.update(1);
+ }
+
+ alpha.merge(beta);
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint()[0], 1200);
+
+ // HistogramAggregator gamma(metrics_api::BoundInstrumentKind::BoundValueRecorder);
+ // ASSERT_THROW(alpha.merge(gamma), AggregatorMismatch);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/exact_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/exact_aggregator_test.cc
new file mode 100644
index 000000000..443cb65ea
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/exact_aggregator_test.cc
@@ -0,0 +1,229 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <gtest/gtest.h>
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include <thread>
+
+# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
+
+using namespace opentelemetry::sdk::metrics;
+namespace metrics_api = opentelemetry::metrics;
+
+TEST(ExactAggregatorOrdered, Update)
+{
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ std::vector<int> correct;
+
+ ASSERT_EQ(agg.get_values(), correct);
+
+ agg.update(1);
+ correct.push_back(1);
+
+ ASSERT_EQ(agg.get_values(), std::vector<int>{1});
+
+ for (int i = 2; i <= 5; ++i)
+ {
+ correct.push_back(i);
+ agg.update(i);
+ }
+ ASSERT_EQ(agg.get_values(), correct);
+}
+
+TEST(ExactAggregatorOrdered, Checkpoint)
+{
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ std::vector<int> correct;
+
+ ASSERT_EQ(agg.get_checkpoint(), correct);
+
+ agg.update(1);
+ correct.push_back(1);
+ agg.checkpoint();
+
+ ASSERT_EQ(agg.get_checkpoint(), correct);
+}
+
+TEST(ExactAggregatorOrdered, Merge)
+{
+ ExactAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ ExactAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
+
+ agg1.update(1);
+ agg2.update(2);
+ agg1.merge(agg2);
+
+ std::vector<int> correct{1, 2};
+
+ ASSERT_EQ(agg1.get_values(), correct);
+}
+
+TEST(ExactAggregatorOrdered, BadMerge)
+{
+ // This verifies that we encounter and error when we try to merge
+ // two aggregators of different numeric types together.
+ ExactAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ ExactAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
+
+ agg1.update(1);
+ agg2.update(2);
+
+ agg1.merge(agg2);
+
+ // Verify that the aggregators did NOT merge
+ std::vector<int> correct{1};
+ ASSERT_EQ(agg1.get_values(), correct);
+}
+
+TEST(ExactAggregatorOrdered, Types)
+{
+ // This test verifies that we do not encounter any errors when
+ // using various numeric types.
+ ExactAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
+ ExactAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
+ ExactAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
+ ExactAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
+
+ for (int i = 1; i <= 5; ++i)
+ {
+ agg_int.update(i);
+ agg_long.update(i);
+ }
+
+ for (float i = 1.0; i <= 5.0; i += 1)
+ {
+ agg_float.update(i);
+ agg_double.update(i);
+ }
+
+ std::vector<int> correct_int{1, 2, 3, 4, 5};
+ std::vector<long> correct_long{1, 2, 3, 4, 5};
+ std::vector<float> correct_float{1.0, 2.0, 3.0, 4.0, 5.0};
+ std::vector<double> correct_double{1.0, 2.0, 3.0, 4.0, 5.0};
+
+ ASSERT_EQ(agg_int.get_values(), correct_int);
+ ASSERT_EQ(agg_long.get_values(), correct_long);
+ ASSERT_EQ(agg_float.get_values(), correct_float);
+ ASSERT_EQ(agg_double.get_values(), correct_double);
+}
+
+TEST(ExactAggregatorQuant, Update)
+{
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
+
+ std::vector<int> correct;
+
+ ASSERT_EQ(agg.get_values(), correct);
+
+ agg.update(1);
+ correct.push_back(1);
+
+ ASSERT_EQ(agg.get_values(), std::vector<int>{1});
+
+ for (int i = 2; i <= 5; ++i)
+ {
+ correct.push_back(i);
+ agg.update(i);
+ }
+ ASSERT_EQ(agg.get_values(), correct);
+}
+
+TEST(ExactAggregatorQuant, Checkpoint)
+{
+ // This test verifies that the aggregator updates correctly when
+ // quantile estimation is turned on.
+
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
+
+ std::vector<int> correct;
+
+ ASSERT_EQ(agg.get_checkpoint(), correct);
+
+ agg.update(1);
+ agg.update(0);
+ agg.update(-1);
+
+ // The vector MUST be sorted when checkpointed
+ correct.push_back(-1);
+ correct.push_back(0);
+ correct.push_back(1);
+ agg.checkpoint();
+
+ ASSERT_EQ(agg.get_checkpoint(), correct);
+}
+
+TEST(ExactAggregatorQuant, Quantile)
+{
+ // This test verifies that the quantile estimation function returns
+ // the correct values.
+
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
+
+ std::vector<int> tmp{3, 9, 42, 57, 163, 210, 272, 300};
+ for (int i : tmp)
+ {
+ agg.update(i);
+ }
+ agg.checkpoint();
+ ASSERT_EQ(agg.get_quantiles(.25), 42);
+ ASSERT_EQ(agg.get_quantiles(0.5), 163);
+ ASSERT_EQ(agg.get_quantiles(0.75), 272);
+}
+
+TEST(ExactAggregatorInOrder, Quantile)
+{
+ // This test verifies that if the user has an exact aggregator in "in-order" mode
+ // an exception will be thrown if they call the quantile() function.
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ std::vector<int> tmp{3, 9, 42, 57, 163, 210, 272, 300};
+ for (int i : tmp)
+ {
+ agg.update(i);
+ }
+ agg.checkpoint();
+# if __EXCEPTIONS
+ ASSERT_THROW(agg.get_quantiles(0.5), std::domain_error);
+# else
+# endif
+}
+
+void callback(ExactAggregator<int> &agg)
+{
+ for (int i = 1; i <= 10000; ++i)
+ {
+ agg.update(i);
+ }
+}
+
+TEST(ExactAggregatorQuant, Concurrency)
+{
+ // This test checks that the aggregator updates appropriately
+ // when called in a multi-threaded context.
+ ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
+
+ std::thread first(&callback, std::ref(agg));
+ std::thread second(&callback, std::ref(agg));
+
+ first.join();
+ second.join();
+
+ std::vector<int> correct;
+ for (int i = 1; i <= 10000; ++i)
+ {
+ correct.push_back(i);
+ correct.push_back(i);
+ }
+ agg.checkpoint();
+
+ ASSERT_EQ(agg.get_checkpoint(), correct);
+}
+#else
+TEST(ExactAggregatorQuant, DummyTest)
+{
+ // empty
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/gauge_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/gauge_aggregator_test.cc
new file mode 100644
index 000000000..9565e0629
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/gauge_aggregator_test.cc
@@ -0,0 +1,133 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include <thread>
+
+# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
+
+using namespace opentelemetry::sdk::metrics;
+namespace metrics_api = opentelemetry::metrics;
+
+TEST(GaugeAggregator, Update)
+{
+ // This tests that the aggregator updates the maintained value correctly
+ // after a call to the update() function.
+ auto agg = new GaugeAggregator<int>(metrics_api::InstrumentKind::Counter);
+
+ // Verify default value
+ ASSERT_EQ(agg->get_values()[0], 0);
+
+ // Verify that the value updates correctly
+ agg->update(1);
+ ASSERT_EQ(agg->get_values()[0], 1);
+
+ // Verify that the value continually updates correctly
+ for (int i = 0; i < 10; ++i)
+ {
+ agg->update(i);
+ }
+ ASSERT_EQ(agg->get_values()[0], 9);
+ delete agg;
+}
+
+TEST(GaugeAggregator, Checkpoint)
+{
+ // This tests that the aggregator correctly updates the
+ // checkpoint_ value after a call to update() followed
+ // by a call to checkpoint().
+ GaugeAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ // Verify default checkpoint, before updates
+ ASSERT_EQ(agg.get_checkpoint()[0], 0);
+
+ agg.update(10);
+ agg.checkpoint();
+
+ // Verify that the new checkpoint contains the update value
+ ASSERT_EQ(agg.get_checkpoint()[0], 10);
+}
+
+TEST(GaugeAggregator, Merge)
+{
+ // This tests that the values_ vector is updated correctly after
+ // two aggregators are merged together.
+ GaugeAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ GaugeAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
+
+ agg1.update(1);
+ agg2.update(2);
+
+ agg1.merge(agg2);
+
+ // Verify that the aggregators merged and the value was updated correctly
+ ASSERT_EQ(agg1.get_values()[0], 2);
+}
+
+TEST(GaugeAggregator, BadMerge)
+{
+ // This verifies that we encounter and error when we try to merge
+ // two aggregators of different numeric types together.
+ GaugeAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ GaugeAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
+
+ agg1.update(1);
+ agg2.update(2);
+ agg1.merge(agg2);
+
+ // Verify that the aggregators did NOT merge
+ std::vector<int> correct{1};
+ ASSERT_EQ(agg1.get_values(), correct);
+}
+
+TEST(GaugeAggregator, Types)
+{
+ // This test verifies that we do not encounter any errors when
+ // using various numeric types.
+ GaugeAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
+ GaugeAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
+ GaugeAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
+ GaugeAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ agg_int.update(i);
+ agg_long.update(i);
+ }
+
+ for (float i = 1.0; i <= 10.0; i += 1)
+ {
+ agg_float.update(i);
+ agg_double.update(i);
+ }
+
+ ASSERT_EQ(agg_int.get_values()[0], 10);
+ ASSERT_EQ(agg_long.get_values()[0], 10);
+ ASSERT_EQ(agg_float.get_values()[0], 10.0);
+ ASSERT_EQ(agg_double.get_values()[0], 10.0);
+}
+
+static void callback(GaugeAggregator<int> &agg)
+{
+ for (int i = 1; i <= 10000; ++i)
+ {
+ agg.update(i);
+ }
+}
+
+TEST(GaugeAggregator, Concurrency)
+{
+ // This test checks that the aggregator updates appropriately
+ // when called in a multi-threaded context.
+ GaugeAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ std::thread first(&callback, std::ref(agg));
+ std::thread second(&callback, std::ref(agg));
+
+ first.join();
+ second.join();
+
+ ASSERT_EQ(agg.get_values()[0], 10000);
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/histogram_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/histogram_aggregator_test.cc
new file mode 100644
index 000000000..daf920aa7
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/histogram_aggregator_test.cc
@@ -0,0 +1,173 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
+
+# include <gtest/gtest.h>
+# include <iostream>
+# include <numeric>
+# include <thread>
+
+// #include <chrono>
+
+namespace metrics_api = opentelemetry::metrics;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+// Test updating with a uniform set of updates
+TEST(Histogram, Uniform)
+{
+ std::vector<double> boundaries{10, 20, 30, 40, 50};
+ HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
+
+ EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Histogram);
+
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint().size(), 2);
+ EXPECT_EQ(alpha.get_counts().size(), 6);
+
+ for (int i = 0; i < 60; i++)
+ {
+ alpha.update(i);
+ }
+
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], 1770);
+ EXPECT_EQ(alpha.get_checkpoint()[1], 60);
+
+ std::vector<int> correct = {10, 10, 10, 10, 10, 10};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+// Test updating with a normal distribution
+TEST(Histogram, Normal)
+{
+ std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
+ HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
+
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0));
+ EXPECT_EQ(alpha.get_checkpoint()[1], vals.size());
+
+ std::vector<int> correct = {1, 2, 3, 4, 3, 2, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+TEST(Histogram, Merge)
+{
+ std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
+ HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
+ HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
+
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+
+ std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
+ for (int i : otherVals)
+ {
+ beta.update(i);
+ }
+
+ alpha.merge(beta);
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
+ std::accumulate(otherVals.begin(), otherVals.end(), 0));
+ EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
+
+ std::vector<int> correct = {5, 2, 3, 4, 3, 4, 5};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+// Update callback used to validate multi-threaded performance
+void histogramUpdateCallback(Aggregator<int> &agg, std::vector<int> vals)
+{
+ for (int i : vals)
+ {
+ agg.update(i);
+ }
+}
+
+int randVal()
+{
+ return rand() % 15;
+}
+
+TEST(Histogram, Concurrency)
+{
+ std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
+ HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
+
+ std::vector<int> vals1(1000);
+ std::generate(vals1.begin(), vals1.end(), randVal);
+
+ std::vector<int> vals2(1000);
+ std::generate(vals2.begin(), vals2.end(), randVal);
+
+ std::thread first(histogramUpdateCallback, std::ref(alpha), vals1);
+ std::thread second(histogramUpdateCallback, std::ref(alpha), vals2);
+
+ first.join();
+ second.join();
+
+ HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
+
+ // Timing harness to compare linear and binary insertion
+ // auto start = std::chrono::system_clock::now();
+ for (int i : vals1)
+ {
+ beta.update(i);
+ }
+ for (int i : vals2)
+ {
+ beta.update(i);
+ }
+ // auto end = std::chrono::system_clock::now();
+ // auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
+ // std::cout <<"Update time: " <<elapsed.count() <<std::endl;
+
+ alpha.checkpoint();
+ beta.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint(), beta.get_checkpoint());
+ EXPECT_EQ(alpha.get_counts(), beta.get_counts());
+}
+
+# if __EXCEPTIONS
+
+TEST(Histogram, Errors)
+{
+ std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
+ std::vector<double> boundaries2{1, 4, 6, 8, 10, 12};
+ std::vector<double> unsortedBoundaries{10, 12, 4, 6, 8};
+ EXPECT_ANY_THROW(
+ HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, unsortedBoundaries));
+
+ HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
+ HistogramAggregator<int> gamma(metrics_api::InstrumentKind::Counter, boundaries2);
+
+ EXPECT_ANY_THROW(beta.merge(gamma));
+}
+
+# endif
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_provider_sdk_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_provider_sdk_test.cc
new file mode 100644
index 000000000..2181bb62a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_provider_sdk_test.cc
@@ -0,0 +1,26 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+
+# include "opentelemetry/sdk/_metrics/meter.h"
+# include "opentelemetry/sdk/_metrics/meter_provider.h"
+
+using namespace opentelemetry::sdk::metrics;
+
+TEST(MeterProvider, GetMeter)
+{
+ MeterProvider tf;
+ auto t1 = tf.GetMeter("test");
+ auto t2 = tf.GetMeter("test");
+ auto t3 = tf.GetMeter("different", "1.0.0");
+ ASSERT_NE(nullptr, t1);
+ ASSERT_NE(nullptr, t2);
+ ASSERT_NE(nullptr, t3);
+
+ // Should return the same instance each time.
+ ASSERT_EQ(t1, t2);
+ ASSERT_EQ(t1, t3);
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_test.cc
new file mode 100644
index 000000000..73ff1f9bd
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/meter_test.cc
@@ -0,0 +1,297 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include <future>
+
+# include "opentelemetry/sdk/_metrics/meter.h"
+
+using namespace opentelemetry::sdk::metrics;
+namespace metrics_api = opentelemetry::metrics;
+namespace common = opentelemetry::common;
+namespace nostd = opentelemetry::nostd;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+TEST(Meter, CreateSyncInstruments)
+{
+ // Test that there are no errors creating synchronous instruments.
+ Meter m("Test");
+
+ m.NewShortCounter("Test-short-counter", "For testing", "Unitless", true);
+ m.NewIntCounter("Test-int-counter", "For testing", "Unitless", true);
+ m.NewFloatCounter("Test-float-counter", "For testing", "Unitless", true);
+ m.NewDoubleCounter("Test-double-counter", "For testing", "Unitless", true);
+
+ m.NewShortUpDownCounter("Test-short-ud-counter", "For testing", "Unitless", true);
+ m.NewIntUpDownCounter("Test-int-ud-counter", "For testing", "Unitless", true);
+ m.NewFloatUpDownCounter("Test-float-ud-counter", "For testing", "Unitless", true);
+ m.NewDoubleUpDownCounter("Test-double-ud-counter", "For testing", "Unitless", true);
+
+ m.NewShortValueRecorder("Test-short-recorder", "For testing", "Unitless", true);
+ m.NewIntValueRecorder("Test-int-recorder", "For testing", "Unitless", true);
+ m.NewFloatValueRecorder("Test-float-recorder", "For testing", "Unitless", true);
+ m.NewDoubleValueRecorder("Test-double-recorder", "For testing", "Unitless", true);
+}
+
+// Dummy functions for asynchronous instrument constructors
+void ShortCallback(metrics_api::ObserverResult<short>) {}
+void IntCallback(metrics_api::ObserverResult<int>) {}
+void FloatCallback(metrics_api::ObserverResult<float>) {}
+void DoubleCallback(metrics_api::ObserverResult<double>) {}
+
+TEST(Meter, CreateAsyncInstruments)
+{
+ // Test that there are no errors when creating asynchronous instruments.
+ Meter m("Test");
+
+ m.NewShortSumObserver("Test-short-sum-obs", "For testing", "Unitless", true, &ShortCallback);
+ m.NewIntSumObserver("Test-int-sum-obs", "For testing", "Unitless", true, &IntCallback);
+ m.NewFloatSumObserver("Test-float-sum-obs", "For testing", "Unitless", true, &FloatCallback);
+ m.NewDoubleSumObserver("Test-double-sum-obs", "For testing", "Unitless", true, &DoubleCallback);
+
+ m.NewShortUpDownSumObserver("Test-short-ud-sum-obs", "For testing", "Unitless", true,
+ &ShortCallback);
+ m.NewIntUpDownSumObserver("Test-int-ud-sum-obs", "For testing", "Unitless", true, &IntCallback);
+ m.NewFloatUpDownSumObserver("Test-float-ud-sum-obs", "For testing", "Unitless", true,
+ &FloatCallback);
+ m.NewDoubleUpDownSumObserver("Test-double-ud-sum-obs", "For testing", "Unitless", true,
+ &DoubleCallback);
+
+ m.NewShortValueObserver("Test-short-val-obs", "For testing", "Unitless", true, &ShortCallback);
+ m.NewIntValueObserver("Test-int-val-obs", "For testing", "Unitless", true, &IntCallback);
+ m.NewFloatValueObserver("Test-float-val-obs", "For testing", "Unitless", true, &FloatCallback);
+ m.NewDoubleValueObserver("Test-double-val-obs", "For testing", "Unitless", true, &DoubleCallback);
+}
+
+TEST(Meter, CollectSyncInstruments)
+{
+ // Verify that the records returned on a call to Collect() are correct for synchronous
+ // instruments.
+ Meter m("Test");
+
+ ASSERT_EQ(m.Collect().size(), 0);
+
+ auto counter = m.NewShortCounter("Test-counter", "For testing", "Unitless", true);
+
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ counter->add(1, labelkv);
+
+ std::vector<Record> res = m.Collect();
+ auto agg_var = res[0].GetAggregator();
+ auto agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 1);
+
+ // Now call add() and Collect() again to ensure that the value in the underlying
+ // aggregator was reset to the default.
+
+ counter->add(10, labelkv);
+
+ res = m.Collect();
+ agg_var = res[0].GetAggregator();
+ agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 10);
+}
+
+TEST(Meter, CollectDeletedSync)
+{
+ // Verify that calling Collect() after creating a synchronous instrument and destroying
+ // the return pointer does not result in a segfault.
+
+ Meter m("Test");
+
+ ASSERT_EQ(m.Collect().size(), 0);
+
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ {
+ auto counter = m.NewShortCounter("Test-counter", "For testing", "Unitless", true);
+ counter->add(1, labelkv);
+ } // counter shared_ptr deleted here
+
+ std::vector<Record> res = m.Collect();
+ auto agg_var = res[0].GetAggregator();
+ auto agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 1);
+}
+
+// Dummy function for asynchronous instrument constructors.
+void Callback(metrics_api::ObserverResult<short> result)
+{
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ result.observe(1, labelkv);
+}
+
+TEST(Meter, CollectAsyncInstruments)
+{
+ // Verify that the records returned on a call to Collect() are correct for asynchronous
+ // instruments.
+ Meter m("Test");
+
+ ASSERT_EQ(m.Collect().size(), 0);
+
+ auto sumobs =
+ m.NewShortSumObserver("Test-counter", "For testing", "Unitless", true, &ShortCallback);
+
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ sumobs->observe(1, labelkv);
+
+ std::vector<Record> res = m.Collect();
+ auto agg_var = res[0].GetAggregator();
+ auto agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 1);
+
+ // Now call observe() and Collect() again to ensure that the value in the underlying
+ // aggregator was reset to the default.
+
+ sumobs->observe(10, labelkv);
+
+ res = m.Collect();
+ agg_var = res[0].GetAggregator();
+ agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 10);
+}
+
+TEST(Meter, CollectDeletedAsync)
+{
+ // Verify that calling Collect() after creating an asynchronous instrument and destroying
+ // the return pointer does not result in a segfault.
+
+ Meter m("Test");
+
+ ASSERT_EQ(m.Collect().size(), 0);
+
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ {
+ auto sumobs = m.NewShortSumObserver("Test-counter", "For testing", "Unitless", true, &Callback);
+ sumobs->observe(1, labelkv);
+ } // sumobs shared_ptr deleted here
+
+ std::vector<Record> res = m.Collect();
+ auto agg_var = res[0].GetAggregator();
+ auto agg = nostd::get<0>(agg_var);
+
+ ASSERT_EQ(agg->get_checkpoint()[0], 1);
+}
+
+TEST(Meter, RecordBatch)
+{
+ // This tests that RecordBatch appropriately updates the aggregators of the instruments
+ // passed to the function. Short, int, float, and double data types are tested.
+ Meter m("Test");
+
+ auto scounter = m.NewShortCounter("Test-scounter", "For testing", "Unitless", true);
+ auto icounter = m.NewIntCounter("Test-icounter", "For testing", "Unitless", true);
+ auto fcounter = m.NewFloatCounter("Test-fcounter", "For testing", "Unitless", true);
+ auto dcounter = m.NewDoubleCounter("Test-dcounter", "For testing", "Unitless", true);
+
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ metrics_api::SynchronousInstrument<short> *sinstr_arr[] = {scounter.get()};
+ short svalues_arr[] = {1};
+
+ nostd::span<metrics_api::SynchronousInstrument<short> *> sinstrs{sinstr_arr};
+ nostd::span<const short, 1> svalues{svalues_arr};
+
+ m.RecordShortBatch(labelkv, sinstrs, svalues);
+ std::vector<Record> res = m.Collect();
+ auto short_agg_var = res[0].GetAggregator();
+ auto short_agg = nostd::get<0>(short_agg_var);
+ ASSERT_EQ(short_agg->get_checkpoint()[0], 1);
+
+ metrics_api::SynchronousInstrument<int> *iinstr_arr[] = {icounter.get()};
+ int ivalues_arr[] = {1};
+
+ nostd::span<metrics_api::SynchronousInstrument<int> *> iinstrs{iinstr_arr};
+ nostd::span<const int, 1> ivalues{ivalues_arr};
+
+ m.RecordIntBatch(labelkv, iinstrs, ivalues);
+ res = m.Collect();
+ auto int_agg_var = res[0].GetAggregator();
+ auto int_agg = nostd::get<1>(int_agg_var);
+ ASSERT_EQ(int_agg->get_checkpoint()[0], 1);
+
+ metrics_api::SynchronousInstrument<float> *finstr_arr[] = {fcounter.get()};
+ float fvalues_arr[] = {1.0};
+
+ nostd::span<metrics_api::SynchronousInstrument<float> *> finstrs{finstr_arr};
+ nostd::span<const float, 1> fvalues{fvalues_arr};
+
+ m.RecordFloatBatch(labelkv, finstrs, fvalues);
+ res = m.Collect();
+ auto float_agg_var = res[0].GetAggregator();
+ auto float_agg = nostd::get<2>(float_agg_var);
+ ASSERT_EQ(float_agg->get_checkpoint()[0], 1.0);
+
+ metrics_api::SynchronousInstrument<double> *dinstr_arr[] = {dcounter.get()};
+ double dvalues_arr[] = {1.0};
+
+ nostd::span<metrics_api::SynchronousInstrument<double> *> dinstrs{dinstr_arr};
+ nostd::span<const double, 1> dvalues{dvalues_arr};
+
+ m.RecordDoubleBatch(labelkv, dinstrs, dvalues);
+ res = m.Collect();
+ auto double_agg_var = res[0].GetAggregator();
+ auto double_agg = nostd::get<3>(double_agg_var);
+ ASSERT_EQ(double_agg->get_checkpoint()[0], 1.0);
+}
+
+TEST(Meter, DisableCollectSync)
+{
+ Meter m("Test");
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto c = m.NewShortCounter("c", "", "", false);
+ c->add(1, labelkv);
+ ASSERT_EQ(m.Collect().size(), 0);
+}
+
+TEST(Meter, DisableCollectAsync)
+{
+ Meter m("Test");
+ std::map<std::string, std::string> labels = {{"Key", "Value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto c = m.NewShortValueObserver("c", "", "", false, &ShortCallback);
+ c->observe(1, labelkv);
+ ASSERT_EQ(m.Collect().size(), 0);
+}
+
+TEST(MeterStringUtil, IsValid)
+{
+# if __EXCEPTIONS
+ Meter m("Test");
+ ASSERT_ANY_THROW(m.NewShortCounter("", "Empty name is invalid", " ", true));
+ ASSERT_ANY_THROW(m.NewShortCounter("1a", "Can't begin with a number", " ", true));
+ ASSERT_ANY_THROW(m.NewShortCounter(".a", "Can't begin with punctuation", " ", true));
+ ASSERT_ANY_THROW(m.NewShortCounter(" a", "Can't begin with space", " ", true));
+ ASSERT_ANY_THROW(m.NewShortCounter(
+ "te^ s=%t", "Only alphanumeric ., -, and _ characters are allowed", " ", true));
+# endif
+}
+
+TEST(MeterStringUtil, AlreadyExists)
+{
+# if __EXCEPTIONS
+ Meter m("Test");
+
+ m.NewShortCounter("a", "First instance of instrument named 'a'", "", true);
+ ASSERT_ANY_THROW(m.NewShortCounter("a", "Second (illegal) instrument named 'a'", "", true));
+ ASSERT_ANY_THROW(m.NewShortSumObserver("a", "Still illegal even though it is not a short counter",
+ "", true, &ShortCallback));
+# endif
+}
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/metric_instrument_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/metric_instrument_test.cc
new file mode 100644
index 000000000..28df53fc3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/metric_instrument_test.cc
@@ -0,0 +1,487 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+
+# include <gtest/gtest.h>
+# include <cstring>
+# include <iostream>
+# include <map>
+# include <memory>
+# include <string>
+# include <thread>
+
+# include "opentelemetry/common/macros.h"
+# include "opentelemetry/sdk/_metrics/async_instruments.h"
+# include "opentelemetry/sdk/_metrics/sync_instruments.h"
+
+namespace metrics_api = opentelemetry::metrics;
+
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+# define METRICS_TEST_TYPE_CAST(TO, FROM) dynamic_cast<TO>(FROM)
+# else
+# define METRICS_TEST_TYPE_CAST(TO, FROM) static_cast<TO>(FROM)
+# endif
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+void ObserverConstructorCallback(metrics_api::ObserverResult<int> result)
+{
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ result.observe(1, labelkv);
+}
+
+TEST(ApiSdkConversion, async)
+{
+ nostd::shared_ptr<metrics_api::AsynchronousInstrument<int>> alpha =
+ nostd::shared_ptr<metrics_api::AsynchronousInstrument<int>>(
+ new ValueObserver<int>("ankit", "none", "unitles", true, &ObserverConstructorCallback));
+
+ std::map<std::string, std::string> labels = {{"key587", "value264"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ alpha->observe(123456, labelkv);
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(AsynchronousInstrument<int> *, alpha.get())
+ ->GetRecords()[0]
+ .GetLabels(),
+ "{key587:value264}");
+
+ alpha->observe(123456, labelkv);
+ AggregatorVariant canCollect = METRICS_TEST_TYPE_CAST(AsynchronousInstrument<int> *, alpha.get())
+ ->GetRecords()[0]
+ .GetAggregator();
+ EXPECT_EQ(nostd::holds_alternative<std::shared_ptr<Aggregator<short>>>(canCollect), false);
+ EXPECT_EQ(nostd::holds_alternative<std::shared_ptr<Aggregator<int>>>(canCollect), true);
+ EXPECT_EQ(nostd::get<std::shared_ptr<Aggregator<int>>>(canCollect)->get_checkpoint()[0], 123456);
+}
+
+TEST(IntValueObserver, InstrumentFunctions)
+{
+ ValueObserver<int> alpha("enabled", "no description", "unitless", true,
+ &ObserverConstructorCallback);
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ EXPECT_EQ(alpha.GetName(), "enabled");
+ EXPECT_EQ(alpha.GetDescription(), "no description");
+ EXPECT_EQ(alpha.GetUnits(), "unitless");
+ EXPECT_EQ(alpha.IsEnabled(), true);
+ EXPECT_EQ(alpha.GetKind(), metrics_api::InstrumentKind::ValueObserver);
+
+ alpha.run();
+ EXPECT_EQ(alpha.boundAggregators_[KvToString(labelkv)]->get_values()[0], 1); // min
+}
+
+void ObserverCallback(std::shared_ptr<ValueObserver<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->observe(i, labels);
+ }
+}
+
+void NegObserverCallback(std::shared_ptr<ValueObserver<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->observe(-i, labels);
+ }
+}
+
+TEST(IntValueObserver, StressObserve)
+{
+ std::shared_ptr<ValueObserver<int>> alpha(new ValueObserver<int>(
+ "enabled", "no description", "unitless", true, &ObserverConstructorCallback));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(ObserverCallback, alpha, 25,
+ labelkv); // spawn new threads that call the callback
+ std::thread second(ObserverCallback, alpha, 25, labelkv);
+ std::thread third(ObserverCallback, alpha, 25, labelkv1);
+ std::thread fourth(NegObserverCallback, alpha, 25, labelkv1); // negative values
+
+ first.join();
+ second.join();
+ third.join();
+ fourth.join();
+
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 0); // min
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[1], 24); // max
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[2], 600); // sum
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[3], 50); // count
+
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], -24); // min
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[1], 24); // max
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[2], 0); // sum
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[3], 50); // count
+}
+
+void SumObserverCallback(std::shared_ptr<SumObserver<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->observe(1, labels);
+ }
+}
+
+TEST(IntSumObserver, StressObserve)
+{
+ std::shared_ptr<SumObserver<int>> alpha(
+ new SumObserver<int>("test", "none", "unitless", true, &ObserverConstructorCallback));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(SumObserverCallback, alpha, 100000, labelkv);
+ std::thread second(SumObserverCallback, alpha, 100000, labelkv);
+ std::thread third(SumObserverCallback, alpha, 300000, labelkv1);
+
+ first.join();
+ second.join();
+ third.join();
+
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 200000);
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], 300000);
+}
+
+void UpDownSumObserverCallback(std::shared_ptr<UpDownSumObserver<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->observe(1, labels);
+ }
+}
+
+void NegUpDownSumObserverCallback(std::shared_ptr<UpDownSumObserver<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->observe(-1, labels);
+ }
+}
+
+TEST(IntUpDownObserver, StressAdd)
+{
+ std::shared_ptr<UpDownSumObserver<int>> alpha(
+ new UpDownSumObserver<int>("test", "none", "unitless", true, &ObserverConstructorCallback));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(UpDownSumObserverCallback, alpha, 12340,
+ labelkv); // spawn new threads that call the callback
+ std::thread second(UpDownSumObserverCallback, alpha, 12340, labelkv);
+ std::thread third(UpDownSumObserverCallback, alpha, 56780, labelkv1);
+ std::thread fourth(NegUpDownSumObserverCallback, alpha, 12340, labelkv1); // negative values
+
+ first.join();
+ second.join();
+ third.join();
+ fourth.join();
+
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 12340 * 2);
+ EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], 56780 - 12340);
+}
+
+TEST(Counter, InstrumentFunctions)
+{
+ Counter<int> alpha("enabled", "no description", "unitless", true);
+ Counter<double> beta("not enabled", "some description", "units", false);
+
+ EXPECT_EQ(static_cast<std::string>(alpha.GetName()), "enabled");
+ EXPECT_EQ(static_cast<std::string>(alpha.GetDescription()), "no description");
+ EXPECT_EQ(static_cast<std::string>(alpha.GetUnits()), "unitless");
+ EXPECT_EQ(alpha.IsEnabled(), true);
+
+ EXPECT_EQ(static_cast<std::string>(beta.GetName()), "not enabled");
+ EXPECT_EQ(static_cast<std::string>(beta.GetDescription()), "some description");
+ EXPECT_EQ(static_cast<std::string>(beta.GetUnits()), "units");
+ EXPECT_EQ(beta.IsEnabled(), false);
+}
+
+TEST(Counter, Binding)
+{
+ Counter<int> alpha("test", "none", "unitless", true);
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ std::map<std::string, std::string> labels2 = {{"key2", "value2"}, {"key3", "value3"}};
+ std::map<std::string, std::string> labels3 = {{"key3", "value3"}, {"key2", "value2"}};
+
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+ auto labelkv2 = common::KeyValueIterableView<decltype(labels2)>{labels2};
+ auto labelkv3 = common::KeyValueIterableView<decltype(labels3)>{labels3};
+
+ auto beta = alpha.bindCounter(labelkv);
+ auto gamma = alpha.bindCounter(labelkv1);
+ auto delta = alpha.bindCounter(labelkv1);
+ auto epsilon = alpha.bindCounter(labelkv1);
+ auto zeta = alpha.bindCounter(labelkv2);
+ auto eta = alpha.bindCounter(labelkv3);
+
+ EXPECT_EQ(beta->get_ref(), 1);
+ EXPECT_EQ(gamma->get_ref(), 3);
+ EXPECT_EQ(eta->get_ref(), 2);
+
+ delta->unbind();
+ gamma->unbind();
+ epsilon->unbind();
+
+ EXPECT_EQ(alpha.boundInstruments_[KvToString(labelkv1)]->get_ref(), 0);
+ EXPECT_EQ(alpha.boundInstruments_.size(), 3);
+}
+
+TEST(Counter, getAggsandnewupdate)
+{
+ Counter<int> alpha("test", "none", "unitless", true);
+
+ std::map<std::string, std::string> labels = {{"key3", "value3"}, {"key2", "value2"}};
+
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto beta = alpha.bindCounter(labelkv);
+ beta->add(1);
+ beta->unbind();
+
+ EXPECT_EQ(alpha.boundInstruments_[KvToString(labelkv)]->get_ref(), 0);
+ EXPECT_EQ(alpha.boundInstruments_.size(), 1);
+
+ auto theta = alpha.GetRecords();
+ EXPECT_EQ(theta.size(), 1);
+ EXPECT_EQ(theta[0].GetName(), "test");
+ EXPECT_EQ(theta[0].GetDescription(), "none");
+ EXPECT_EQ(theta[0].GetLabels(), "{key2:value2,key3:value3}");
+}
+
+void CounterCallback(std::shared_ptr<Counter<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->add(1, labels);
+ }
+}
+
+TEST(Counter, StressAdd)
+{
+ std::shared_ptr<Counter<int>> alpha(new Counter<int>("test", "none", "unitless", true));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(CounterCallback, alpha, 1000, labelkv);
+ std::thread second(CounterCallback, alpha, 1000, labelkv);
+ std::thread third(CounterCallback, alpha, 3000, labelkv1);
+
+ first.join();
+ second.join();
+ third.join();
+
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundCounter<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ 2000);
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundCounter<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ 3000);
+}
+
+void UpDownCounterCallback(std::shared_ptr<UpDownCounter<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->add(1, labels);
+ }
+}
+
+void NegUpDownCounterCallback(std::shared_ptr<UpDownCounter<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->add(-1, labels);
+ }
+}
+
+TEST(IntUpDownCounter, StressAdd)
+{
+ std::shared_ptr<UpDownCounter<int>> alpha(
+ new UpDownCounter<int>("test", "none", "unitless", true));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(UpDownCounterCallback, alpha, 12340,
+ labelkv); // spawn new threads that call the callback
+ std::thread second(UpDownCounterCallback, alpha, 12340, labelkv);
+ std::thread third(UpDownCounterCallback, alpha, 56780, labelkv1);
+ std::thread fourth(NegUpDownCounterCallback, alpha, 12340, labelkv1); // negative values
+
+ first.join();
+ second.join();
+ third.join();
+ fourth.join();
+
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundUpDownCounter<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ 12340 * 2);
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundUpDownCounter<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ 56780 - 12340);
+}
+
+void RecorderCallback(std::shared_ptr<ValueRecorder<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->record(i, labels);
+ }
+}
+
+void NegRecorderCallback(std::shared_ptr<ValueRecorder<int>> in,
+ int freq,
+ const common::KeyValueIterable &labels)
+{
+ for (int i = 0; i < freq; i++)
+ {
+ in->record(-i, labels);
+ }
+}
+
+TEST(IntValueRecorder, StressRecord)
+{
+ std::shared_ptr<ValueRecorder<int>> alpha(
+ new ValueRecorder<int>("test", "none", "unitless", true));
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+ std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+ auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
+
+ std::thread first(RecorderCallback, alpha, 25,
+ labelkv); // spawn new threads that call the callback
+ std::thread second(RecorderCallback, alpha, 50, labelkv);
+ std::thread third(RecorderCallback, alpha, 25, labelkv1);
+ std::thread fourth(NegRecorderCallback, alpha, 100, labelkv1); // negative values
+
+ first.join();
+ second.join();
+ third.join();
+ fourth.join();
+
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ 0); // min
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[1],
+ 49); // max
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[2],
+ 1525); // sum
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv)].get())
+ ->GetAggregator()
+ ->get_values()[3],
+ 75); // count
+
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[0],
+ -99); // min
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[1],
+ 24); // max
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[2],
+ -4650); // sum
+ EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
+ alpha->boundInstruments_[KvToString(labelkv1)].get())
+ ->GetAggregator()
+ ->get_values()[3],
+ 125); // count
+}
+
+TEST(Instruments, NoUpdateNoRecord)
+{
+ // This test verifies that instruments that have received no updates
+ // in the last collection period are not made into records for export.
+
+ Counter<int> alpha("alpha", "no description", "unitless", true);
+
+ std::map<std::string, std::string> labels = {{"key", "value"}};
+
+ auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
+
+ EXPECT_EQ(alpha.GetRecords().size(), 0);
+ alpha.add(1, labelkv);
+ EXPECT_EQ(alpha.GetRecords().size(), 1);
+
+ UpDownCounter<int> beta("beta", "no description", "unitless", true);
+
+ EXPECT_EQ(beta.GetRecords().size(), 0);
+ beta.add(1, labelkv);
+ EXPECT_EQ(beta.GetRecords().size(), 1);
+
+ ValueRecorder<int> gamma("gamma", "no description", "unitless", true);
+
+ EXPECT_EQ(gamma.GetRecords().size(), 0);
+ gamma.record(1, labelkv);
+ EXPECT_EQ(gamma.GetRecords().size(), 1);
+}
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/min_max_sum_count_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/min_max_sum_count_aggregator_test.cc
new file mode 100644
index 000000000..3b657d955
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/min_max_sum_count_aggregator_test.cc
@@ -0,0 +1,209 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include <thread>
+
+# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
+
+using namespace opentelemetry::sdk::metrics;
+namespace metrics_api = opentelemetry::metrics;
+
+TEST(MinMaxSumCountAggregator, Update)
+{
+ // This tests that the aggregator updates the maintained value correctly
+ // after a call to the update() function.
+ MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+ auto value_set = agg.get_values();
+ ASSERT_EQ(value_set[0], 0);
+ ASSERT_EQ(value_set[1], 0);
+ ASSERT_EQ(value_set[2], 0);
+ ASSERT_EQ(value_set[3], 0);
+
+ // 1 + 2 + 3 + ... + 10 = 55
+ for (int i = 1; i <= 10; ++i)
+ {
+ agg.update(i);
+ }
+
+ value_set = agg.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[1], 10); // max
+ ASSERT_EQ(value_set[2], 55); // sum
+ ASSERT_EQ(value_set[3], 10); // count
+}
+
+TEST(MinMaxSumCountAggregator, FirstUpdate)
+{
+ // This tests that the aggregator appropriately maintains the min and
+ // max values after a single update call.
+ MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+ agg.update(1);
+ auto value_set = agg.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[1], 1); // max
+ ASSERT_EQ(value_set[2], 1); // sum
+ ASSERT_EQ(value_set[3], 1); // count
+}
+
+TEST(MinMaxSumCountAggregator, Checkpoint)
+{
+ // This test verifies that the default checkpoint is set correctly
+ // and that the checkpoint values update correctly after a call
+ // to the checkpoint() function.
+ MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ // Verify that the default checkpoint is set correctly.
+ auto checkpoint_set = agg.get_checkpoint();
+ ASSERT_EQ(checkpoint_set[0], 0); // min
+ ASSERT_EQ(checkpoint_set[1], 0); // max
+ ASSERT_EQ(checkpoint_set[2], 0); // sum
+ ASSERT_EQ(checkpoint_set[3], 0); // count
+
+ // 1 + 2 + 3 + ... + 10 = 55
+ for (int i = 1; i <= 10; ++i)
+ {
+ agg.update(i);
+ }
+
+ agg.checkpoint();
+
+ // Verify that the checkpoint values were updated.
+ checkpoint_set = agg.get_checkpoint();
+ ASSERT_EQ(checkpoint_set[0], 1); // min
+ ASSERT_EQ(checkpoint_set[1], 10); // max
+ ASSERT_EQ(checkpoint_set[2], 55); // sum
+ ASSERT_EQ(checkpoint_set[3], 10); // count
+
+ // Verify that the current values were reset to the default state.
+ auto value_set = agg.get_values();
+ ASSERT_EQ(value_set[0], 0); // min
+ ASSERT_EQ(value_set[1], 0); // max
+ ASSERT_EQ(value_set[2], 0); // sum
+ ASSERT_EQ(value_set[3], 0); // count
+}
+
+TEST(MinMaxSumCountAggregator, Merge)
+{
+ // This tests that the values_ vector is updated correctly after
+ // two aggregators are merged together.
+ MinMaxSumCountAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ MinMaxSumCountAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
+
+ // 1 + 2 + 3 + ... + 10 = 55
+ for (int i = 1; i <= 10; ++i)
+ {
+ agg1.update(i);
+ }
+
+ // 1 + 2 + 3 + ... + 20 = 210
+ for (int i = 1; i <= 20; ++i)
+ {
+ agg2.update(i);
+ }
+
+ agg1.merge(agg2);
+
+ // Verify that the current values were changed by the merge.
+ auto value_set = agg1.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[1], 20); // max
+ ASSERT_EQ(value_set[2], 265); // sum
+ ASSERT_EQ(value_set[3], 30); // count
+}
+
+TEST(MinMaxSumCountAggregator, BadMerge)
+{
+ // This verifies that we encounter and error when we try to merge
+ // two aggregators of different numeric types together.
+ MinMaxSumCountAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
+ MinMaxSumCountAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
+
+ agg1.update(1);
+ agg2.update(2);
+
+ agg1.merge(agg2);
+
+ // Verify that the values did NOT merge
+ auto value_set = agg1.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[0], 1); // max
+ ASSERT_EQ(value_set[0], 1); // sum
+ ASSERT_EQ(value_set[0], 1); // count
+}
+
+TEST(MinMaxSumCountAggregator, Types)
+{
+ // This test verifies that we do not encounter any errors when
+ // using various numeric types.
+ MinMaxSumCountAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
+ MinMaxSumCountAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
+ MinMaxSumCountAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
+ MinMaxSumCountAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ agg_int.update(i);
+ agg_long.update(i);
+ }
+
+ for (float i = 1.0; i <= 10.0; i += 1)
+ {
+ agg_float.update(i);
+ agg_double.update(i);
+ }
+
+ auto value_set = agg_int.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[1], 10); // max
+ ASSERT_EQ(value_set[2], 55); // sum
+ ASSERT_EQ(value_set[3], 10); // count
+
+ auto value_set2 = agg_long.get_values();
+ ASSERT_EQ(value_set[0], 1); // min
+ ASSERT_EQ(value_set[1], 10); // max
+ ASSERT_EQ(value_set[2], 55); // sum
+ ASSERT_EQ(value_set[3], 10); // count
+
+ auto value_set3 = agg_float.get_values();
+ ASSERT_EQ(value_set[0], 1.0); // min
+ ASSERT_EQ(value_set[1], 10.0); // max
+ ASSERT_EQ(value_set[2], 55.0); // sum
+ ASSERT_EQ(value_set[3], 10); // count
+
+ auto value_set4 = agg_double.get_values();
+ ASSERT_EQ(value_set[0], 1.0); // min
+ ASSERT_EQ(value_set[1], 10.0); // max
+ ASSERT_EQ(value_set[2], 55.0); // sum
+ ASSERT_EQ(value_set[3], 10); // count
+}
+
+static void callback(MinMaxSumCountAggregator<int> &agg)
+{
+ // 1 + 2 + ... + 10000 = 50005000
+ for (int i = 1; i <= 10000; ++i)
+ {
+ agg.update(i);
+ }
+}
+
+TEST(MinMaxSumCountAggregator, Concurrency)
+{
+ // This test checks that the aggregator updates appropriately
+ // when called in a multi-threaded context.
+ MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
+
+ std::thread first(&callback, std::ref(agg));
+ std::thread second(&callback, std::ref(agg));
+
+ first.join();
+ second.join();
+
+ auto value_set = agg.get_values();
+ ASSERT_EQ(value_set[0], 1);
+ ASSERT_EQ(value_set[1], 10000);
+ ASSERT_EQ(value_set[2], 2 * 50005000);
+ ASSERT_EQ(value_set[3], 2 * 10000);
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/sketch_aggregator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/sketch_aggregator_test.cc
new file mode 100644
index 000000000..6dc2fbef3
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/sketch_aggregator_test.cc
@@ -0,0 +1,254 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
+
+# include <gtest/gtest.h>
+# include <iostream>
+# include <numeric>
+# include <thread>
+
+namespace metrics_api = opentelemetry::metrics;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace sdk
+{
+namespace metrics
+{
+
+// Test updating with a uniform set of updates
+TEST(Sketch, UniformValues)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .000005);
+
+ EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Sketch);
+
+ alpha.checkpoint();
+ EXPECT_EQ(alpha.get_checkpoint().size(), 2);
+ EXPECT_EQ(alpha.get_boundaries().size(), 0);
+ EXPECT_EQ(alpha.get_counts().size(), 0);
+
+ for (int i = 0; i < 60; i++)
+ {
+ alpha.update(i);
+ }
+
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_boundaries().size(), 60);
+ EXPECT_EQ(alpha.get_counts().size(), 60);
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], 1770);
+ EXPECT_EQ(alpha.get_checkpoint()[1], 60);
+}
+
+// Test updating with a normal distribution
+TEST(Sketch, NormalValues)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005);
+
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0));
+ EXPECT_EQ(alpha.get_checkpoint()[1], vals.size());
+
+ std::vector<int> correct = {1, 2, 3, 4, 3, 2, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+
+ std::vector<double> captured_bounds = alpha.get_boundaries();
+ for (size_t i = 0; i < captured_bounds.size(); i++)
+ {
+ captured_bounds[i] = round(captured_bounds[i]);
+ }
+
+ // It is not guaranteed that bounds are correct once the bucket sizes pass 1000
+ std::vector<double> correct_bounds = {1, 3, 5, 7, 9, 11, 13};
+ EXPECT_EQ(captured_bounds, correct_bounds);
+}
+
+int randVal()
+{
+ return rand() % 100000;
+}
+
+/** Note that in this case, "Large" refers to a number of distinct values which exceed the maximum
+ * number of allowed buckets.
+ */
+TEST(Sketch, QuantileSmall)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .00005);
+
+ std::vector<int> vals1(2048);
+ std::generate(vals1.begin(), vals1.end(), randVal);
+
+ std::vector<int> vals2(2048);
+ std::generate(vals1.begin(), vals1.end(), randVal);
+
+ for (int i : vals1)
+ {
+ alpha.update(i);
+ }
+ alpha.checkpoint();
+ std::sort(vals1.begin(), vals1.end());
+
+ EXPECT_TRUE(abs(alpha.get_quantiles(.25) - vals1[2048 * .25 - 1]) <= 10);
+ EXPECT_TRUE(abs(alpha.get_quantiles(.50) - vals1[2048 * .50 - 1]) <= 10);
+ EXPECT_TRUE(abs(alpha.get_quantiles(.75) - vals1[2048 * .75 - 1]) <= 10);
+}
+
+TEST(Sketch, UpdateQuantileLarge)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+
+ // This addition should trigger the "1" and "3" buckets to merge
+ alpha.update(15);
+ alpha.checkpoint();
+
+ std::vector<int> correct = {3, 3, 4, 3, 2, 1, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+ alpha.update(15);
+ alpha.update(17);
+ alpha.checkpoint();
+
+ correct = {6, 4, 3, 2, 1, 1, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+TEST(Sketch, MergeSmall)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005);
+ SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005);
+
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+
+ std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
+ for (int i : otherVals)
+ {
+ beta.update(i);
+ }
+
+ alpha.merge(beta);
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
+ std::accumulate(otherVals.begin(), otherVals.end(), 0));
+ EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
+
+ std::vector<int> correct = {5, 2, 3, 4, 3, 4, 4, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+TEST(Sketch, MergeLarge)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
+ SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
+
+ std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+ for (int i : vals)
+ {
+ alpha.update(i);
+ }
+
+ std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
+ for (int i : otherVals)
+ {
+ beta.update(i);
+ }
+
+ alpha.merge(beta);
+ alpha.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
+ std::accumulate(otherVals.begin(), otherVals.end(), 0));
+ EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
+
+ std::vector<int> correct = {7, 3, 4, 3, 4, 4, 1};
+ EXPECT_EQ(alpha.get_counts(), correct);
+}
+
+// Update callback used to validate multi-threaded performance
+void sketchUpdateCallback(Aggregator<int> &agg, std::vector<int> vals)
+{
+ for (int i : vals)
+ {
+ agg.update(i);
+ }
+}
+
+TEST(Sketch, Concurrency)
+{
+ SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 20);
+
+ std::vector<int> vals1(1000);
+ std::generate(vals1.begin(), vals1.end(), randVal);
+
+ std::vector<int> vals2(1000);
+ std::generate(vals2.begin(), vals2.end(), randVal);
+
+ std::thread first(sketchUpdateCallback, std::ref(alpha), vals1);
+ std::thread second(sketchUpdateCallback, std::ref(alpha), vals2);
+
+ first.join();
+ second.join();
+
+ SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005, 20);
+
+ for (int i : vals1)
+ {
+ beta.update(i);
+ }
+ for (int i : vals2)
+ {
+ beta.update(i);
+ }
+
+ alpha.checkpoint();
+ beta.checkpoint();
+
+ EXPECT_EQ(alpha.get_checkpoint(), beta.get_checkpoint());
+ EXPECT_EQ(alpha.get_counts(), beta.get_counts());
+ EXPECT_EQ(alpha.get_boundaries(), beta.get_boundaries());
+}
+
+# if __EXCEPTIONS
+
+TEST(Sketch, Errors)
+{
+
+ SketchAggregator<int> tol1(metrics_api::InstrumentKind::ValueRecorder, .000005);
+ SketchAggregator<int> tol2(metrics_api::InstrumentKind::ValueRecorder, .005);
+ SketchAggregator<int> sz1(metrics_api::InstrumentKind::ValueRecorder, .000005, 2938);
+ SketchAggregator<int> sz2(metrics_api::InstrumentKind::ValueRecorder, .000005);
+
+ EXPECT_ANY_THROW(tol1.merge(tol2));
+ EXPECT_ANY_THROW(sz1.merge(sz2));
+ EXPECT_ANY_THROW(tol1.get_quantiles(-.000001));
+ EXPECT_ANY_THROW(tol1.get_quantiles(1.000001));
+}
+
+# endif
+
+} // namespace metrics
+} // namespace sdk
+OPENTELEMETRY_END_NAMESPACE
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/ungrouped_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/ungrouped_processor_test.cc
new file mode 100644
index 000000000..934bfe23e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/_metrics/ungrouped_processor_test.cc
@@ -0,0 +1,601 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
+# include <gtest/gtest.h>
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+
+namespace metric_sdk = opentelemetry::sdk::metrics;
+namespace metrics_api = opentelemetry::metrics;
+namespace nostd = opentelemetry::nostd;
+
+/* Test that CheckpointSelf() will return the amount of unique records in it, then
+ call FinishedCollection and see the map reset */
+TEST(UngroupedMetricsProcessor, UngroupedProcessorFinishedCollectionStateless)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(false));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5.5);
+ aggregator->checkpoint();
+
+ aggregator2->update(500.4);
+ aggregator2->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+ // Must have different (name, description, label, instrument) to map to
+ metric_sdk::Record r2("name2", "description2", "labels2", aggregator2);
+
+ processor->process(r);
+ processor->process(r2);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint.size(), 2);
+
+ processor->FinishedCollection();
+
+ checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint.size(), 0);
+}
+
+/* Test that CheckpointSelf() will return the amount of unique records in it, then
+ call FinishedCollection and see the map stay the same */
+TEST(UngroupedMetricsProcessor, UngroupedProcessorFinishedCollectionStateful)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5.5);
+ aggregator->checkpoint();
+
+ aggregator2->update(500.4);
+ aggregator2->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+ // Must have different (name, description, label, instrument) to map to
+ metric_sdk::Record r2("name2", "description2", "labels2", aggregator2);
+
+ processor->process(r);
+ processor->process(r2);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint.size(), 2);
+
+ processor->FinishedCollection();
+
+ ASSERT_EQ(checkpoint.size(), 2);
+}
+
+// Test to make sure we keep information from record(short) that goes through process()
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessShort)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(false));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
+ new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(4);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator()),
+ aggregator);
+}
+
+// Test to make sure we keep information from record(int) that goes through process()
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessInt)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(false));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator()),
+ aggregator);
+}
+
+// Test to make sure we keep information from record(float) that goes through process()
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessFloat)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(false));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
+ new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(8.5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator()),
+ aggregator);
+}
+
+// Test to make sure we keep information from record(double) that goes through process()
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessDouble)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(false));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5.5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator()),
+ aggregator);
+}
+
+/**
+ * The following tests are for the Stateful version of the processor. These tests will make sure
+ * that when we send the same aggreagtor twice through process(), that the values will be merged.
+ * We can easily recreate this expected value by making a test aggregator that is updated through
+ * both process functions but only checkpointed at the end.
+ */
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulShort)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
+ new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<short>>(
+ new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5);
+ aggregator_test->update(5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(4);
+ aggregator_test->update(4);
+ aggregator->checkpoint();
+ aggregator_test->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint()[0],
+ aggregator_test->get_checkpoint()[0]);
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulInt)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5);
+ aggregator_test->update(5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(4);
+ aggregator_test->update(4);
+ aggregator->checkpoint();
+ aggregator_test->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint()[0],
+ aggregator_test->get_checkpoint()[0]);
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulFloat)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
+ new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<float>>(
+ new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5);
+ aggregator_test->update(5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(4);
+ aggregator_test->update(4);
+ aggregator->checkpoint();
+ aggregator_test->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint()[0],
+ aggregator_test->get_checkpoint()[0]);
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulDouble)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(5.5);
+ aggregator_test->update(5.5);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(4.4);
+ aggregator_test->update(4.4);
+ aggregator->checkpoint();
+ aggregator_test->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint()[0],
+ aggregator_test->get_checkpoint()[0]);
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulMinMaxSumCount)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::MinMaxSumCountAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::MinMaxSumCountAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(1.1);
+ aggregator->update(2.2);
+ aggregator2->update(1.1);
+ aggregator2->update(2.2);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(5.5);
+ aggregator2->update(5.5);
+ aggregator->checkpoint();
+ aggregator2->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator2->get_checkpoint());
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulGauge)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::GaugeAggregator<double>(metrics_api::InstrumentKind::Counter));
+
+ aggregator->update(1.1);
+ aggregator->update(2.2);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(5.4);
+ aggregator->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulExact)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::ExactAggregator<double>(metrics_api::InstrumentKind::Counter, false));
+
+ auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
+ new metric_sdk::ExactAggregator<double>(metrics_api::InstrumentKind::Counter, false));
+
+ aggregator->update(1.1);
+ aggregator->update(2.2);
+ aggregator2->update(1.1);
+ aggregator2->update(2.2);
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator->get_checkpoint());
+
+ aggregator->update(5.4);
+ aggregator2->update(5.4);
+ aggregator->checkpoint();
+ aggregator2->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(
+ nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator2->get_checkpoint());
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulHistogram)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ std::vector<double> boundaries{10, 20, 30, 40, 50};
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::HistogramAggregator<int>(metrics_api::InstrumentKind::Counter, boundaries));
+
+ auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::HistogramAggregator<int>(metrics_api::InstrumentKind::Counter, boundaries));
+
+ for (int i = 0; i < 60; i++)
+ {
+ aggregator->update(i);
+ aggregator2->update(i);
+ }
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_boundaries(),
+ aggregator->get_boundaries());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_counts(),
+ aggregator->get_counts());
+
+ for (int i = 0; i < 60; i++)
+ {
+ aggregator->update(i);
+ aggregator2->update(i);
+ }
+ aggregator->checkpoint();
+ aggregator2->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+
+ ASSERT_EQ(checkpoint2.size(), 1);
+ ASSERT_EQ(checkpoint2[0].GetName(), "name");
+ ASSERT_EQ(checkpoint2[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint2[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_boundaries(),
+ aggregator->get_boundaries());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_counts(),
+ aggregator2->get_counts());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_checkpoint(),
+ aggregator2->get_checkpoint());
+}
+
+TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulSketch)
+{
+ auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
+ new metric_sdk::UngroupedMetricsProcessor(true));
+
+ auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .00005));
+
+ auto test_aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+ new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .00005));
+
+ for (int i = 0; i < 60; i++)
+ {
+ aggregator->update(i);
+ test_aggregator->update(i);
+ }
+ aggregator->checkpoint();
+
+ metric_sdk::Record r("name", "description", "labels", aggregator);
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint[0].GetName(), "name");
+ ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_boundaries(),
+ aggregator->get_boundaries());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
+ ->get_counts(),
+ aggregator->get_counts());
+
+ for (int i = 0; i < 60; i++)
+ {
+ aggregator->update(i);
+ test_aggregator->update(i);
+ }
+ aggregator->checkpoint();
+ test_aggregator->checkpoint();
+
+ processor->process(r);
+
+ std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
+ ASSERT_EQ(checkpoint2[0].GetName(), "name");
+ ASSERT_EQ(checkpoint2[0].GetLabels(), "labels");
+ ASSERT_EQ(checkpoint2[0].GetDescription(), "description");
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_boundaries(),
+ test_aggregator->get_boundaries());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_counts(),
+ test_aggregator->get_counts());
+ ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
+ ->get_checkpoint(),
+ test_aggregator->get_checkpoint());
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD
new file mode 100644
index 000000000..91d56996f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/BUILD
@@ -0,0 +1,153 @@
+load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
+
+cc_test(
+ name = "random_test",
+ srcs = [
+ "random_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//sdk/src/common:random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "fast_random_number_generator_test",
+ srcs = [
+ "fast_random_number_generator_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//sdk/src/common:random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "random_benchmark",
+ srcs = ["random_benchmark.cc"],
+ tags = ["test"],
+ deps = ["//sdk/src/common:random"],
+)
+
+cc_test(
+ name = "atomic_unique_ptr_test",
+ srcs = [
+ "atomic_unique_ptr_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "circular_buffer_range_test",
+ srcs = [
+ "circular_buffer_range_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "random_fork_test",
+ srcs = [
+ "random_fork_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//sdk/src/common:random",
+ ],
+)
+
+cc_library(
+ name = "baseline_circular_buffer",
+ hdrs = [
+ "baseline_circular_buffer.h",
+ ],
+ include_prefix = "test/common",
+ deps = [
+ "//api",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "circular_buffer_benchmark",
+ srcs = ["circular_buffer_benchmark.cc"],
+ tags = ["test"],
+ deps = [
+ ":baseline_circular_buffer",
+ "//sdk:headers",
+ ],
+)
+
+cc_test(
+ name = "empty_attributes_test",
+ srcs = [
+ "empty_attributes_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "attribute_utils_test",
+ srcs = [
+ "attribute_utils_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "global_log_handle_test",
+ srcs = [
+ "global_log_handle_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "//sdk/src/common:global_log_handler",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "attributemap_hash_test",
+ srcs = [
+ "attributemap_hash_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "attributemap_hash_benchmark",
+ srcs = ["attributemap_hash_benchmark.cc"],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt
new file mode 100644
index 000000000..0fefc86b1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/CMakeLists.txt
@@ -0,0 +1,37 @@
+foreach(
+ testname
+ random_test
+ fast_random_number_generator_test
+ atomic_unique_ptr_test
+ circular_buffer_range_test
+ circular_buffer_test
+ attribute_utils_test
+ attributemap_hash_test
+ global_log_handle_test)
+
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(
+ ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
+ opentelemetry_common opentelemetry_trace)
+
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX trace.
+ TEST_LIST ${testname})
+endforeach()
+
+add_executable(random_fork_test random_fork_test.cc)
+target_link_libraries(random_fork_test opentelemetry_common)
+add_test(random_fork_test random_fork_test)
+
+add_executable(random_benchmark random_benchmark.cc)
+target_link_libraries(random_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common)
+
+add_executable(circular_buffer_benchmark circular_buffer_benchmark.cc)
+target_link_libraries(circular_buffer_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api)
+
+add_executable(attributemap_hash_benchmark attributemap_hash_benchmark.cc)
+target_link_libraries(attributemap_hash_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc
new file mode 100644
index 000000000..aa6d88a00
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/atomic_unique_ptr_test.cc
@@ -0,0 +1,42 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/atomic_unique_ptr.h"
+
+#include <gtest/gtest.h>
+using opentelemetry::sdk::common::AtomicUniquePtr;
+
+TEST(AtomicUniquePtrTest, SwapIfNullWithNull)
+{
+ AtomicUniquePtr<int> ptr;
+ EXPECT_TRUE(ptr.IsNull());
+
+ std::unique_ptr<int> x{new int{33}};
+ EXPECT_TRUE(ptr.SwapIfNull(x));
+ EXPECT_EQ(x, nullptr);
+}
+
+TEST(AtomicUniquePtrTest, SwapIfNullWithNonNull)
+{
+ AtomicUniquePtr<int> ptr;
+ ptr.Reset(new int{11});
+ std::unique_ptr<int> x{new int{33}};
+ EXPECT_TRUE(!ptr.SwapIfNull(x));
+ EXPECT_NE(x, nullptr);
+ EXPECT_EQ(*x, 33);
+ EXPECT_EQ(*ptr, 11);
+}
+
+TEST(AtomicUniquePtrTest, Swap)
+{
+ AtomicUniquePtr<int> ptr;
+ EXPECT_TRUE(ptr.IsNull());
+
+ ptr.Reset(new int{11});
+ std::unique_ptr<int> x{new int{33}};
+ ptr.Swap(x);
+ EXPECT_FALSE(ptr.IsNull());
+ EXPECT_NE(x, nullptr);
+ EXPECT_EQ(*x, 11);
+ EXPECT_EQ(*ptr, 33);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc
new file mode 100644
index 000000000..b7ef17244
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attribute_utils_test.cc
@@ -0,0 +1,53 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/attribute_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(AttributeMapTest, DefaultConstruction)
+{
+
+ opentelemetry::sdk::common::AttributeMap attribute_map;
+ EXPECT_EQ(attribute_map.GetAttributes().size(), 0);
+}
+
+TEST(OrderedAttributeMapTest, DefaultConstruction)
+{
+ opentelemetry::sdk::common::OrderedAttributeMap attribute_map;
+ EXPECT_EQ(attribute_map.GetAttributes().size(), 0);
+}
+
+TEST(AttributeMapTest, AttributesConstruction)
+{
+ const int kNumAttributes = 3;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"};
+ int values[kNumAttributes] = {15, 24, 37};
+ std::map<std::string, int> attributes = {
+ {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}};
+
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes);
+ opentelemetry::sdk::common::AttributeMap attribute_map(iterable);
+
+ for (int i = 0; i < kNumAttributes; i++)
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<int>(attribute_map.GetAttributes().at(keys[i])), values[i]);
+ }
+}
+
+TEST(OrderedAttributeMapTest, AttributesConstruction)
+{
+ const int kNumAttributes = 3;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"};
+ int values[kNumAttributes] = {15, 24, 37};
+ std::map<std::string, int> attributes = {
+ {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}};
+
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes);
+ opentelemetry::sdk::common::OrderedAttributeMap attribute_map(iterable);
+
+ for (int i = 0; i < kNumAttributes; i++)
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<int>(attribute_map.GetAttributes().at(keys[i])), values[i]);
+ }
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc
new file mode 100644
index 000000000..811ecb23d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_benchmark.cc
@@ -0,0 +1,22 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <benchmark/benchmark.h>
+#include "opentelemetry/sdk/common/attributemap_hash.h"
+
+using namespace opentelemetry::sdk::common;
+namespace
+{
+void BM_AttributeMapHash(benchmark::State &state)
+{
+ OrderedAttributeMap map1 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"},
+ {"k5", true}, {"k6", 12}, {"k7", 12.209}};
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(GetHashForAttributeMap(map1));
+ }
+}
+BENCHMARK(BM_AttributeMapHash);
+
+} // namespace
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc
new file mode 100644
index 000000000..7d2748670
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/attributemap_hash_test.cc
@@ -0,0 +1,32 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/attributemap_hash.h"
+#include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::common;
+TEST(AttributeMapHashTest, BasicTests)
+{
+ {
+ OrderedAttributeMap map1 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}};
+ OrderedAttributeMap map2 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"}};
+ OrderedAttributeMap map3 = {{"k3", "v3"}, {"k1", "v1"}, {"k2", "v2"}};
+
+ EXPECT_TRUE(GetHashForAttributeMap(map1) != 0);
+ EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map1));
+ EXPECT_TRUE(GetHashForAttributeMap(map1) != GetHashForAttributeMap(map2));
+ EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map3));
+ }
+
+ {
+ OrderedAttributeMap map1 = {{"k1", 10}, {"k2", true}, {"k3", 12.22}};
+ OrderedAttributeMap map2 = {{"k3", 12.22}, {"k1", 10}, {"k2", true}};
+ EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map2));
+ EXPECT_TRUE(GetHashForAttributeMap(map1) != 0);
+ }
+
+ {
+ OrderedAttributeMap map1 = {};
+ EXPECT_TRUE(GetHashForAttributeMap(map1) == 0);
+ }
+} \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h
new file mode 100644
index 000000000..398a4d038
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/baseline_circular_buffer.h
@@ -0,0 +1,88 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include "opentelemetry/version.h"
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+namespace testing
+{
+/**
+ * A locking circular buffer.
+ *
+ * Used as a baseline in benchmarking.
+ */
+template <class T>
+class BaselineCircularBuffer
+{
+public:
+ explicit BaselineCircularBuffer(size_t max_size) : data_{max_size} {}
+
+ /**
+ * Add an element to the circular buffer.
+ * @param element the element to add
+ * @return true if the element was added successfully
+ */
+ bool Add(std::unique_ptr<T> &element) noexcept { return this->Add(std::move(element)); }
+
+ bool Add(std::unique_ptr<T> &&element) noexcept
+ {
+ std::lock_guard<std::mutex> lock_guard{mutex_};
+ if (tail_ + data_.size() == head_)
+ {
+ return false;
+ }
+ data_[head_ % data_.size()] = std::move(element);
+ head_ += 1;
+ return true;
+ }
+
+ /**
+ * Consume elements in the circular buffer.
+ * @param f the callback to call for each element
+ */
+ template <class F>
+ void Consume(F f) noexcept
+ {
+ std::lock_guard<std::mutex> lock_guard{mutex_};
+ if (head_ == tail_)
+ {
+ return;
+ }
+ auto tail_index = tail_ % data_.size();
+ auto head_index = head_ % data_.size();
+ if (tail_index < head_index)
+ {
+ for (auto i = tail_index; i < head_index; ++i)
+ {
+ f(std::move(data_[i]));
+ }
+ }
+ else
+ {
+ for (auto i = tail_index; i < data_.size(); ++i)
+ {
+ f(std::move(data_[i]));
+ }
+ for (auto i = 0ull; i < head_index; ++i)
+ {
+ f(std::move(data_[i]));
+ }
+ }
+ tail_ = head_;
+ }
+
+private:
+ std::mutex mutex_;
+ uint64_t head_{0};
+ uint64_t tail_{0};
+ std::vector<std::unique_ptr<T>> data_;
+};
+} // namespace testing
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc
new file mode 100644
index 000000000..1f2b9b42c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_benchmark.cc
@@ -0,0 +1,133 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "benchmark/benchmark.h"
+
+#include <atomic>
+#include <cstdint>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <thread>
+#include <vector>
+
+#include "opentelemetry/sdk/common/circular_buffer.h"
+#include "test/common/baseline_circular_buffer.h"
+using opentelemetry::sdk::common::AtomicUniquePtr;
+using opentelemetry::sdk::common::CircularBuffer;
+using opentelemetry::sdk::common::CircularBufferRange;
+using opentelemetry::testing::BaselineCircularBuffer;
+
+const int N = 10000;
+
+static uint64_t ConsumeBufferNumbers(BaselineCircularBuffer<uint64_t> &buffer) noexcept
+{
+ uint64_t result = 0;
+ buffer.Consume([&](std::unique_ptr<uint64_t> &&x) {
+ result += *x;
+ x.reset();
+ });
+ return result;
+}
+
+static uint64_t ConsumeBufferNumbers(CircularBuffer<uint64_t> &buffer) noexcept
+{
+ uint64_t result = 0;
+ buffer.Consume(buffer.size(),
+ [&](CircularBufferRange<AtomicUniquePtr<uint64_t>> &range) noexcept {
+ range.ForEach([&](AtomicUniquePtr<uint64_t> &ptr) noexcept {
+ result += *ptr;
+ ptr.Reset();
+ return true;
+ });
+ });
+ return result;
+}
+
+template <class Buffer>
+static void GenerateNumbersForThread(Buffer &buffer, int n, std::atomic<uint64_t> &sum) noexcept
+{
+ thread_local std::mt19937_64 random_number_generator{std::random_device{}()};
+ for (int i = 0; i < n; ++i)
+ {
+ auto x = random_number_generator();
+ std::unique_ptr<uint64_t> element{new uint64_t{x}};
+ if (buffer.Add(element))
+ {
+ sum += x;
+ }
+ }
+}
+
+template <class Buffer>
+static uint64_t GenerateNumbers(Buffer &buffer, int num_threads, int n) noexcept
+{
+ std::atomic<uint64_t> sum{0};
+ std::vector<std::thread> threads(num_threads);
+ for (auto &thread : threads)
+ {
+ thread = std::thread{GenerateNumbersForThread<Buffer>, std::ref(buffer), n, std::ref(sum)};
+ }
+ for (auto &thread : threads)
+ {
+ thread.join();
+ }
+ return sum;
+}
+
+template <class Buffer>
+static void ConsumeNumbers(Buffer &buffer, uint64_t &sum, std::atomic<bool> &finished) noexcept
+{
+ while (!finished)
+ {
+ sum += ConsumeBufferNumbers(buffer);
+ }
+ sum += ConsumeBufferNumbers(buffer);
+}
+
+template <class Buffer>
+static void RunSimulation(Buffer &buffer, int num_threads, int n) noexcept
+{
+ std::atomic<bool> finished{false};
+ uint64_t consumer_sum{0};
+ std::thread consumer_thread{ConsumeNumbers<Buffer>, std::ref(buffer), std::ref(consumer_sum),
+ std::ref(finished)};
+ uint64_t producer_sum = GenerateNumbers(buffer, num_threads, n);
+ finished = true;
+ consumer_thread.join();
+ if (consumer_sum != producer_sum)
+ {
+ std::cerr << "Sumulation failed: consumer_sum != producer_sum\n";
+ std::terminate();
+ }
+}
+
+static void BM_BaselineBuffer(benchmark::State &state)
+{
+ const size_t max_elements = 500;
+ const int num_threads = static_cast<int>(state.range(0));
+ const int n = static_cast<int>(N / num_threads);
+ BaselineCircularBuffer<uint64_t> buffer{max_elements};
+ for (auto _ : state)
+ {
+ RunSimulation(buffer, num_threads, n);
+ }
+}
+
+BENCHMARK(BM_BaselineBuffer)->Arg(1)->Arg(2)->Arg(4);
+
+static void BM_LockFreeBuffer(benchmark::State &state)
+{
+ const size_t max_elements = 500;
+ const int num_threads = static_cast<int>(state.range(0));
+ const int n = static_cast<int>(N / num_threads);
+ CircularBuffer<uint64_t> buffer{max_elements};
+ for (auto _ : state)
+ {
+ RunSimulation(buffer, num_threads, n);
+ }
+}
+
+BENCHMARK(BM_LockFreeBuffer)->Arg(1)->Arg(2)->Arg(4);
+
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc
new file mode 100644
index 000000000..585270468
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_range_test.cc
@@ -0,0 +1,59 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/circular_buffer_range.h"
+
+#include <iterator>
+
+#include <gtest/gtest.h>
+using opentelemetry::sdk::common::CircularBufferRange;
+
+TEST(CircularBufferRangeTest, ForEach)
+{
+ int array1[] = {1, 2, 3, 4};
+ int array2[] = {5, 6, 7};
+ CircularBufferRange<int> range{array1, array2};
+
+ int x = 0;
+ range.ForEach([&](int y) {
+ EXPECT_EQ(++x, y);
+ return true;
+ });
+ EXPECT_EQ(x, 7);
+}
+
+TEST(CircularBufferRangeTest, ForEachWithExit)
+{
+ int array1[] = {1, 2, 3, 4};
+ int array2[] = {5, 6, 7};
+ CircularBufferRange<int> range{array1, array2};
+
+ int x = 0;
+ range.ForEach([&](int y) {
+ EXPECT_EQ(++x, y);
+ return false;
+ });
+ EXPECT_EQ(x, 1);
+
+ x = 0;
+ range.ForEach([&](int y) {
+ EXPECT_EQ(++x, y);
+ return y != 5;
+ });
+ EXPECT_EQ(x, 5);
+}
+
+TEST(CircularBufferRangeTest, Conversion)
+{
+ int array1[] = {1, 2, 3, 4};
+ int array2[] = {5, 6, 7};
+ CircularBufferRange<int> range{array1, array2};
+
+ CircularBufferRange<const int> range2{range};
+ int x = 0;
+ range2.ForEach([&](int y) {
+ EXPECT_EQ(++x, y);
+ return true;
+ });
+ EXPECT_EQ(x, 7);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc
new file mode 100644
index 000000000..a20c3e42a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/circular_buffer_test.cc
@@ -0,0 +1,161 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/circular_buffer.h"
+
+#include <algorithm>
+#include <cassert>
+#include <random>
+#include <thread>
+
+#include <gtest/gtest.h>
+using opentelemetry::sdk::common::AtomicUniquePtr;
+using opentelemetry::sdk::common::CircularBuffer;
+using opentelemetry::sdk::common::CircularBufferRange;
+
+static thread_local std::mt19937 RandomNumberGenerator{std::random_device{}()};
+
+static void GenerateRandomNumbers(CircularBuffer<uint32_t> &buffer,
+ std::vector<uint32_t> &numbers,
+ int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ auto value = static_cast<uint32_t>(RandomNumberGenerator());
+ std::unique_ptr<uint32_t> x{new uint32_t{value}};
+ if (buffer.Add(x))
+ {
+ numbers.push_back(value);
+ }
+ }
+}
+
+static void RunNumberProducers(CircularBuffer<uint32_t> &buffer,
+ std::vector<uint32_t> &numbers,
+ int num_threads,
+ int n)
+{
+ std::vector<std::vector<uint32_t>> thread_numbers(num_threads);
+ std::vector<std::thread> threads(num_threads);
+ for (int thread_index = 0; thread_index < num_threads; ++thread_index)
+ {
+ threads[thread_index] = std::thread{GenerateRandomNumbers, std::ref(buffer),
+ std::ref(thread_numbers[thread_index]), n};
+ }
+ for (auto &thread : threads)
+ {
+ thread.join();
+ }
+ for (int thread_index = 0; thread_index < num_threads; ++thread_index)
+ {
+ numbers.insert(numbers.end(), thread_numbers[thread_index].begin(),
+ thread_numbers[thread_index].end());
+ }
+}
+
+void RunNumberConsumer(CircularBuffer<uint32_t> &buffer,
+ std::atomic<bool> &exit,
+ std::vector<uint32_t> &numbers)
+{
+ while (true)
+ {
+ if (exit && buffer.Peek().empty())
+ {
+ return;
+ }
+ auto n = std::uniform_int_distribution<size_t>{0, buffer.Peek().size()}(RandomNumberGenerator);
+ buffer.Consume(n, [&](CircularBufferRange<AtomicUniquePtr<uint32_t>> range) noexcept {
+ assert(range.size() == n);
+ range.ForEach([&](AtomicUniquePtr<uint32_t> &ptr) noexcept {
+ assert(!ptr.IsNull());
+ numbers.push_back(*ptr);
+ ptr.Reset();
+ return true;
+ });
+ });
+ }
+}
+
+TEST(CircularBufferTest, Add)
+{
+ CircularBuffer<int> buffer{10};
+
+ std::unique_ptr<int> x{new int{11}};
+ EXPECT_TRUE(buffer.Add(x));
+ EXPECT_EQ(x, nullptr);
+ auto range = buffer.Peek();
+ EXPECT_EQ(range.size(), 1);
+ range.ForEach([](const AtomicUniquePtr<int> &y) {
+ EXPECT_EQ(*y, 11);
+ return true;
+ });
+}
+
+TEST(CircularBufferTest, Clear)
+{
+ CircularBuffer<int> buffer{10};
+
+ std::unique_ptr<int> x{new int{11}};
+ EXPECT_TRUE(buffer.Add(x));
+ EXPECT_EQ(x, nullptr);
+ buffer.Clear();
+ EXPECT_TRUE(buffer.empty());
+}
+
+TEST(CircularBufferTest, AddOnFull)
+{
+ CircularBuffer<int> buffer{10};
+ for (int i = 0; i < static_cast<int>(buffer.max_size()); ++i)
+ {
+ std::unique_ptr<int> x{new int{i}};
+ EXPECT_TRUE(buffer.Add(x));
+ }
+ std::unique_ptr<int> x{new int{33}};
+ EXPECT_FALSE(buffer.Add(x));
+ EXPECT_NE(x, nullptr);
+ EXPECT_EQ(*x, 33);
+}
+
+TEST(CircularBufferTest, Consume)
+{
+ CircularBuffer<int> buffer{10};
+ for (int i = 0; i < static_cast<int>(buffer.max_size()); ++i)
+ {
+ std::unique_ptr<int> x{new int{i}};
+ EXPECT_TRUE(buffer.Add(x));
+ }
+ int count = 0;
+ buffer.Consume(5, [&](CircularBufferRange<AtomicUniquePtr<int>> range) noexcept {
+ range.ForEach([&](AtomicUniquePtr<int> &ptr) {
+ EXPECT_EQ(*ptr, count++);
+ ptr.Reset();
+ return true;
+ });
+ });
+ EXPECT_EQ(count, 5);
+}
+
+TEST(CircularBufferTest, Simulation)
+{
+ const int num_producer_threads = 4;
+ const int n = 25000;
+ for (size_t max_size : {1, 2, 10, 50, 100, 1000})
+ {
+ CircularBuffer<uint32_t> buffer{max_size};
+ std::vector<uint32_t> producer_numbers;
+ std::vector<uint32_t> consumer_numbers;
+ auto producers = std::thread{RunNumberProducers, std::ref(buffer), std::ref(producer_numbers),
+ num_producer_threads, n};
+ std::atomic<bool> exit{false};
+ auto consumer = std::thread{RunNumberConsumer, std::ref(buffer), std::ref(exit),
+ std::ref(consumer_numbers)};
+ producers.join();
+ exit = true;
+ consumer.join();
+ std::sort(producer_numbers.begin(), producer_numbers.end());
+ std::sort(consumer_numbers.begin(), consumer_numbers.end());
+
+ EXPECT_EQ(producer_numbers.size(), consumer_numbers.size());
+ EXPECT_EQ(producer_numbers, consumer_numbers);
+ }
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc
new file mode 100644
index 000000000..f37ea0a5c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/empty_attributes_test.cc
@@ -0,0 +1,19 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/empty_attributes.h"
+
+#include <gtest/gtest.h>
+
+TEST(EmptyAttributesTest, TestSize)
+{
+ EXPECT_EQ(opentelemetry::sdk::GetEmptyAttributes().size(), 0);
+}
+
+// Test that GetEmptyAttributes() always returns the same KeyValueIterableView
+TEST(EmptyAttributesTest, TestMemory)
+{
+ auto attributes1 = opentelemetry::sdk::GetEmptyAttributes();
+ auto attributes2 = opentelemetry::sdk::GetEmptyAttributes();
+ EXPECT_EQ(memcmp(&attributes1, &attributes2, sizeof(attributes1)), 0);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc
new file mode 100644
index 000000000..e9209fdb6
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/fast_random_number_generator_test.cc
@@ -0,0 +1,22 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/random.h"
+
+#include <random>
+
+#include <gtest/gtest.h>
+
+using opentelemetry::sdk::common::FastRandomNumberGenerator;
+
+TEST(FastRandomNumberGeneratorTest, GenerateUniqueNumbers)
+{
+ std::seed_seq seed_sequence{1, 2, 3};
+ FastRandomNumberGenerator random_number_generator;
+ random_number_generator.seed(seed_sequence);
+ std::set<uint64_t> values;
+ for (int i = 0; i < 1000; ++i)
+ {
+ EXPECT_TRUE(values.insert(random_number_generator()).second);
+ }
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc
new file mode 100644
index 000000000..a38bdc872
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/global_log_handle_test.cc
@@ -0,0 +1,67 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/common/global_log_handler.h"
+
+#include <gtest/gtest.h>
+
+#include <cstring>
+
+class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler
+{
+public:
+ void Handle(opentelemetry::sdk::common::internal_log::LogLevel level,
+ const char *,
+ int,
+ const char *msg,
+ const opentelemetry::sdk::common::AttributeMap &) noexcept override
+ {
+ if (level == opentelemetry::sdk::common::internal_log::LogLevel::Debug)
+ {
+ EXPECT_EQ(0, strncmp(msg, "Debug message", 13));
+ }
+ else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Error)
+ {
+ EXPECT_EQ(0, strncmp(msg, "Error message", 13));
+ }
+ else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Info)
+ {
+ EXPECT_EQ(0, strncmp(msg, "Info message", 12));
+ }
+ else if (level == opentelemetry::sdk::common::internal_log::LogLevel::Warning)
+ {
+ EXPECT_EQ(0, strncmp(msg, "Warning message", 15));
+ }
+ ++count;
+ }
+
+ size_t count = 0;
+};
+
+TEST(GlobalLogHandleTest, CustomLogHandler)
+{
+ using opentelemetry::sdk::common::internal_log::LogHandler;
+ auto backup_log_handle =
+ opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogHandler();
+ auto backup_log_level = opentelemetry::sdk::common::internal_log::GlobalLogHandler::GetLogLevel();
+
+ auto custom_log_handler = opentelemetry::nostd::shared_ptr<LogHandler>(new CustomLogHandler{});
+ opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(custom_log_handler);
+ auto before_count = static_cast<CustomLogHandler *>(custom_log_handler.get())->count;
+ opentelemetry::sdk::common::AttributeMap attributes = {
+ {"url", "https://opentelemetry.io/"}, {"content-length", 0}, {"content-type", "text/html"}};
+ OTEL_INTERNAL_LOG_ERROR("Error message");
+ OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes);
+ EXPECT_EQ(before_count + 1, static_cast<CustomLogHandler *>(custom_log_handler.get())->count);
+
+ opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(
+ opentelemetry::sdk::common::internal_log::LogLevel::Debug);
+ OTEL_INTERNAL_LOG_ERROR("Error message");
+ OTEL_INTERNAL_LOG_DEBUG("Debug message. Headers:", attributes);
+ OTEL_INTERNAL_LOG_INFO("Info message");
+ OTEL_INTERNAL_LOG_WARN("Warning message");
+ EXPECT_EQ(before_count + 5, static_cast<CustomLogHandler *>(custom_log_handler.get())->count);
+
+ opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogHandler(backup_log_handle);
+ opentelemetry::sdk::common::internal_log::GlobalLogHandler::SetLogLevel(backup_log_level);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc
new file mode 100644
index 000000000..df2ebf95e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_benchmark.cc
@@ -0,0 +1,35 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/random.h"
+
+#include <cstdint>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+namespace
+{
+using opentelemetry::sdk::common::Random;
+
+void BM_RandomIdGeneration(benchmark::State &state)
+{
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(Random::GenerateRandom64());
+ }
+}
+BENCHMARK(BM_RandomIdGeneration);
+
+void BM_RandomIdStdGeneration(benchmark::State &state)
+{
+ std::mt19937_64 generator{0};
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(generator());
+ }
+}
+BENCHMARK(BM_RandomIdStdGeneration);
+
+} // namespace
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc
new file mode 100644
index 000000000..2db8b9fcd
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_fork_test.cc
@@ -0,0 +1,53 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef __unix__
+// Verifies that IDs don't clash after forking the process.
+//
+// See https://github.com/opentracing-contrib/nginx-opentracing/issues/52
+# include "src/common/random.h"
+
+# include <sys/mman.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+# include <cstdio>
+# include <cstdlib>
+# include <iostream>
+using opentelemetry::sdk::common::Random;
+
+static uint64_t *child_id;
+
+int main()
+{
+ // Set up shared memory to communicate between parent and child processes.
+ //
+ // See https://stackoverflow.com/a/13274800/4447365
+ child_id = static_cast<uint64_t *>(
+ mmap(nullptr, sizeof(*child_id), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+ *child_id = 0;
+ if (fork() == 0)
+ {
+ *child_id = Random::GenerateRandom64();
+ exit(EXIT_SUCCESS);
+ }
+ else
+ {
+ wait(nullptr);
+ auto parent_id = Random::GenerateRandom64();
+ auto child_id_copy = *child_id;
+ munmap(static_cast<void *>(child_id), sizeof(*child_id));
+ if (parent_id == child_id_copy)
+ {
+ std::cerr << "Child and parent ids are the same value " << parent_id << "\n";
+ return -1;
+ }
+ }
+ return 0;
+}
+#else
+int main()
+{
+ return 0;
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc
new file mode 100644
index 000000000..35cfd4a1e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/common/random_test.cc
@@ -0,0 +1,35 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "src/common/random.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include <gtest/gtest.h>
+using opentelemetry::sdk::common::Random;
+
+TEST(RandomTest, GenerateRandom64)
+{
+ EXPECT_NE(Random::GenerateRandom64(), Random::GenerateRandom64());
+}
+
+TEST(RandomTest, GenerateRandomBuffer)
+{
+ uint8_t buf1[8] = {0};
+ uint8_t buf2[8] = {0};
+ Random::GenerateRandomBuffer(buf1);
+ Random::GenerateRandomBuffer(buf2);
+ EXPECT_FALSE(std::equal(std::begin(buf1), std::end(buf1), std::begin(buf2)));
+
+ // Edge cases.
+ for (auto size : {7, 8, 9, 16, 17})
+ {
+ std::vector<uint8_t> buf1(size);
+ std::vector<uint8_t> buf2(size);
+
+ Random::GenerateRandomBuffer(buf1);
+ Random::GenerateRandomBuffer(buf2);
+ EXPECT_FALSE(std::equal(std::begin(buf1), std::end(buf1), std::begin(buf2)));
+ }
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/BUILD
new file mode 100644
index 000000000..38cc25300
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/BUILD
@@ -0,0 +1,14 @@
+load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
+
+cc_test(
+ name = "instrumentationlibrary_test",
+ srcs = [
+ "instrumentationlibrary_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/CMakeLists.txt
new file mode 100644
index 000000000..512266dc8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/CMakeLists.txt
@@ -0,0 +1,11 @@
+include(GoogleTest)
+
+foreach(testname instrumentationlibrary_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX instrumentationlibrary.
+ TEST_LIST ${testname})
+endforeach()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc
new file mode 100644
index 000000000..a410ca99f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc
@@ -0,0 +1,26 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+
+TEST(InstrumentationLibrary, CreateInstrumentationLibrary)
+{
+
+ std::string library_name = "opentelemetry-cpp";
+ std::string library_version = "0.1.0";
+ std::string schema_url = "https://opentelemetry.io/schemas/1.2.0";
+ auto instrumentation_library =
+ InstrumentationLibrary::Create(library_name, library_version, schema_url);
+
+ EXPECT_EQ(instrumentation_library->GetName(), library_name);
+ EXPECT_EQ(instrumentation_library->GetVersion(), library_version);
+ EXPECT_EQ(instrumentation_library->GetSchemaURL(), schema_url);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/BUILD
new file mode 100644
index 000000000..c8f051070
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/BUILD
@@ -0,0 +1,75 @@
+cc_test(
+ name = "logger_provider_sdk_test",
+ srcs = [
+ "logger_provider_sdk_test.cc",
+ ],
+ tags = [
+ "logs",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "//sdk/src/logs",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "logger_sdk_test",
+ srcs = [
+ "logger_sdk_test.cc",
+ ],
+ tags = [
+ "logs",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/logs",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "simple_log_processor_test",
+ srcs = [
+ "simple_log_processor_test.cc",
+ ],
+ tags = [
+ "logs",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/logs",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "log_record_test",
+ srcs = [
+ "log_record_test.cc",
+ ],
+ tags = [
+ "logs",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/logs",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "batch_log_processor_test",
+ srcs = [
+ "batch_log_processor_test.cc",
+ ],
+ tags = [
+ "logs",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/logs",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/CMakeLists.txt
new file mode 100644
index 000000000..84b865d22
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/CMakeLists.txt
@@ -0,0 +1,10 @@
+foreach(testname logger_provider_sdk_test logger_sdk_test log_record_test
+ simple_log_processor_test batch_log_processor_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_logs)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX logs.
+ TEST_LIST ${testname})
+endforeach()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/batch_log_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/batch_log_processor_test.cc
new file mode 100644
index 000000000..63e44676c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/batch_log_processor_test.cc
@@ -0,0 +1,269 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/batch_log_processor.h"
+# include "opentelemetry/sdk/logs/exporter.h"
+# include "opentelemetry/sdk/logs/log_record.h"
+
+# include <gtest/gtest.h>
+# include <chrono>
+# include <thread>
+
+using namespace opentelemetry::sdk::logs;
+using namespace opentelemetry::sdk::common;
+
+/**
+ * A sample log exporter
+ * for testing the batch log processor
+ */
+class MockLogExporter final : public LogExporter
+{
+public:
+ MockLogExporter(std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received,
+ std::shared_ptr<std::atomic<bool>> is_shutdown,
+ std::shared_ptr<std::atomic<bool>> is_export_completed,
+ const std::chrono::milliseconds export_delay = std::chrono::milliseconds(0))
+ : logs_received_(logs_received),
+ is_shutdown_(is_shutdown),
+ is_export_completed_(is_export_completed),
+ export_delay_(export_delay)
+ {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept
+ {
+ return std::unique_ptr<Recordable>(new LogRecord());
+ }
+
+ // Export method stores the logs received into a shared list of record names
+ ExportResult Export(
+ const opentelemetry::nostd::span<std::unique_ptr<Recordable>> &records) noexcept override
+ {
+ *is_export_completed_ = false; // Meant exclusively to test scheduled_delay_millis
+
+ for (auto &record : records)
+ {
+ auto log = std::unique_ptr<LogRecord>(static_cast<LogRecord *>(record.release()));
+ if (log != nullptr)
+ {
+ logs_received_->push_back(std::move(log));
+ }
+ }
+
+ *is_export_completed_ = true;
+ return ExportResult::kSuccess;
+ }
+
+ // toggles the boolean flag marking this exporter as shut down
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override
+ {
+ *is_shutdown_ = true;
+ return true;
+ }
+
+private:
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received_;
+ std::shared_ptr<std::atomic<bool>> is_shutdown_;
+ std::shared_ptr<std::atomic<bool>> is_export_completed_;
+ const std::chrono::milliseconds export_delay_;
+};
+
+/**
+ * A fixture class for testing the BatchLogProcessor class that uses the TestExporter defined above.
+ */
+class BatchLogProcessorTest : public testing::Test // ::testing::Test
+{
+public:
+ // returns a batch log processor that received a batch of log records, a shared pointer to a
+ // is_shutdown flag, and the processor configuration options (default if unspecified)
+ std::shared_ptr<LogProcessor> GetMockProcessor(
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received,
+ std::shared_ptr<std::atomic<bool>> is_shutdown,
+ std::shared_ptr<std::atomic<bool>> is_export_completed =
+ std::shared_ptr<std::atomic<bool>>(new std::atomic<bool>(false)),
+ const std::chrono::milliseconds export_delay = std::chrono::milliseconds(0),
+ const std::chrono::milliseconds scheduled_delay_millis = std::chrono::milliseconds(5000),
+ const size_t max_queue_size = 2048,
+ const size_t max_export_batch_size = 512)
+ {
+ return std::shared_ptr<LogProcessor>(
+ new BatchLogProcessor(std::unique_ptr<LogExporter>(new MockLogExporter(
+ logs_received, is_shutdown, is_export_completed, export_delay)),
+ max_queue_size, scheduled_delay_millis, max_export_batch_size));
+ }
+};
+
+TEST_F(BatchLogProcessorTest, TestShutdown)
+{
+ // initialize a batch log processor with the test exporter
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+
+ auto batch_processor = GetMockProcessor(logs_received, is_shutdown);
+
+ // Create a few test log records and send them to the processor
+ const int num_logs = 3;
+
+ for (int i = 0; i < num_logs; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+
+ // Test that shutting down the processor will first wait for the
+ // current batch of logs to be sent to the log exporter
+ // by checking the number of logs sent and the names of the logs sent
+ EXPECT_EQ(true, batch_processor->Shutdown());
+ // It's safe to shutdown again
+ EXPECT_TRUE(batch_processor->Shutdown());
+
+ EXPECT_EQ(num_logs, logs_received->size());
+
+ // Assume logs are received by exporter in same order as sent by processor
+ for (int i = 0; i < num_logs; ++i)
+ {
+ EXPECT_EQ("Log" + std::to_string(i), logs_received->at(i)->GetBody());
+ }
+
+ // Also check that the processor is shut down at the end
+ EXPECT_TRUE(is_shutdown->load());
+}
+
+TEST_F(BatchLogProcessorTest, TestForceFlush)
+{
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+
+ auto batch_processor = GetMockProcessor(logs_received, is_shutdown);
+ const int num_logs = 2048;
+
+ for (int i = 0; i < num_logs; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_logs, logs_received->size());
+ for (int i = 0; i < num_logs; ++i)
+ {
+ EXPECT_EQ("Log" + std::to_string(i), logs_received->at(i)->GetBody());
+ }
+
+ // Create some more logs to make sure that the processor still works
+ for (int i = 0; i < num_logs; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_logs * 2, logs_received->size());
+ for (int i = 0; i < num_logs * 2; ++i)
+ {
+ EXPECT_EQ("Log" + std::to_string(i % num_logs), logs_received->at(i)->GetBody());
+ }
+}
+
+TEST_F(BatchLogProcessorTest, TestManyLogsLoss)
+{
+ /* Test that when exporting more than max_queue_size logs, some are most likely lost*/
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+
+ const int max_queue_size = 4096;
+
+ auto batch_processor = GetMockProcessor(logs_received, is_shutdown);
+
+ // Create max_queue_size log records
+ for (int i = 0; i < max_queue_size; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ // Log should be exported by now
+ EXPECT_GE(max_queue_size, logs_received->size());
+}
+
+TEST_F(BatchLogProcessorTest, TestManyLogsLossLess)
+{
+ /* Test that no logs are lost when sending max_queue_size logs */
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+ auto batch_processor = GetMockProcessor(logs_received, is_shutdown);
+
+ const int num_logs = 2048;
+
+ for (int i = 0; i < num_logs; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_logs, logs_received->size());
+ for (int i = 0; i < num_logs; ++i)
+ {
+ EXPECT_EQ("Log" + std::to_string(i), logs_received->at(i)->GetBody());
+ }
+}
+
+TEST_F(BatchLogProcessorTest, TestScheduledDelayMillis)
+{
+ /* Test that max_export_batch_size logs are exported every scheduled_delay_millis
+ seconds */
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::atomic<bool>> is_export_completed(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+
+ const std::chrono::milliseconds export_delay(0);
+ const std::chrono::milliseconds scheduled_delay_millis(2000);
+ const size_t max_export_batch_size = 512;
+
+ auto batch_processor = GetMockProcessor(logs_received, is_shutdown, is_export_completed,
+ export_delay, scheduled_delay_millis);
+
+ for (std::size_t i = 0; i < max_export_batch_size; ++i)
+ {
+ auto log = batch_processor->MakeRecordable();
+ log->SetBody("Log" + std::to_string(i));
+ batch_processor->OnReceive(std::move(log));
+ }
+ // Sleep for scheduled_delay_millis milliseconds
+ std::this_thread::sleep_for(scheduled_delay_millis);
+
+ // small delay to give time to export, which is being performed
+ // asynchronously by the worker thread (this thread will not
+ // forcibly join() the main thread unless processor's shutdown() is called).
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ // Logs should be exported by now
+ EXPECT_TRUE(is_export_completed->load());
+ EXPECT_EQ(max_export_batch_size, logs_received->size());
+ for (size_t i = 0; i < max_export_batch_size; ++i)
+ {
+ EXPECT_EQ("Log" + std::to_string(i), logs_received->at(i)->GetBody());
+ }
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/log_record_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/log_record_test.cc
new file mode 100644
index 000000000..89b07473a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/log_record_test.cc
@@ -0,0 +1,66 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/log_record.h"
+# include "opentelemetry/nostd/variant.h"
+# include "opentelemetry/trace/span_id.h"
+# include "opentelemetry/trace/trace_id.h"
+
+# include <gtest/gtest.h>
+
+using opentelemetry::sdk::logs::LogRecord;
+namespace trace_api = opentelemetry::trace;
+namespace logs_api = opentelemetry::logs;
+namespace nostd = opentelemetry::nostd;
+
+// Test what a default LogRecord with no fields set holds
+TEST(LogRecord, GetDefaultValues)
+{
+ trace_api::TraceId zero_trace_id;
+ trace_api::SpanId zero_span_id;
+ trace_api::TraceFlags zero_trace_flags;
+ LogRecord record;
+
+ ASSERT_EQ(record.GetSeverity(), logs_api::Severity::kInvalid);
+ ASSERT_EQ(record.GetBody(), "");
+ ASSERT_NE(record.GetResource().GetAttributes().size(), 0);
+ ASSERT_EQ(record.GetAttributes().size(), 0);
+ ASSERT_EQ(record.GetTraceId(), zero_trace_id);
+ ASSERT_EQ(record.GetSpanId(), zero_span_id);
+ ASSERT_EQ(record.GetTraceFlags(), zero_trace_flags);
+ ASSERT_EQ(record.GetTimestamp().time_since_epoch(), std::chrono::nanoseconds(0));
+}
+
+// Test LogRecord fields are properly set and get
+TEST(LogRecord, SetAndGet)
+{
+ trace_api::TraceId trace_id;
+ trace_api::SpanId span_id;
+ trace_api::TraceFlags trace_flags;
+ opentelemetry::common::SystemTimestamp now(std::chrono::system_clock::now());
+
+ // Set all fields of the LogRecord
+ LogRecord record;
+ auto resource = opentelemetry::sdk::resource::Resource::Create({{"res1", true}});
+ record.SetSeverity(logs_api::Severity::kInvalid);
+ record.SetBody("Message");
+ record.SetResource(resource);
+ record.SetAttribute("attr1", (int64_t)314159);
+ record.SetTraceId(trace_id);
+ record.SetSpanId(span_id);
+ record.SetTraceFlags(trace_flags);
+ record.SetTimestamp(now);
+
+ // Test that all fields match what was set
+ ASSERT_EQ(record.GetSeverity(), logs_api::Severity::kInvalid);
+ ASSERT_EQ(record.GetBody(), "Message");
+ ASSERT_TRUE(nostd::get<bool>(record.GetResource().GetAttributes().at("res1")));
+ ASSERT_EQ(nostd::get<int64_t>(record.GetAttributes().at("attr1")), 314159);
+ ASSERT_EQ(record.GetTraceId(), trace_id);
+ ASSERT_EQ(record.GetSpanId(), span_id);
+ ASSERT_EQ(record.GetTraceFlags(), trace_flags);
+ ASSERT_EQ(record.GetTimestamp().time_since_epoch(), now.time_since_epoch());
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_provider_sdk_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_provider_sdk_test.cc
new file mode 100644
index 000000000..3e5e8dfb2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_provider_sdk_test.cc
@@ -0,0 +1,133 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include <array>
+# include "opentelemetry/logs/provider.h"
+# include "opentelemetry/nostd/shared_ptr.h"
+# include "opentelemetry/nostd/string_view.h"
+# include "opentelemetry/sdk/logs/log_record.h"
+# include "opentelemetry/sdk/logs/logger.h"
+# include "opentelemetry/sdk/logs/logger_provider.h"
+# include "opentelemetry/sdk/logs/simple_log_processor.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::logs;
+namespace logs_api = opentelemetry::logs;
+namespace nostd = opentelemetry::nostd;
+
+TEST(LoggerProviderSDK, PushToAPI)
+{
+ auto lp =
+ nostd::shared_ptr<logs_api::LoggerProvider>(new opentelemetry::sdk::logs::LoggerProvider());
+ logs_api::Provider::SetLoggerProvider(lp);
+
+ // Check that the loggerprovider was correctly pushed into the API
+ ASSERT_EQ(lp, logs_api::Provider::GetLoggerProvider());
+}
+
+TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple)
+{
+ auto lp = std::shared_ptr<logs_api::LoggerProvider>(new LoggerProvider());
+
+ nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"};
+ auto logger1 = lp->GetLogger("logger1", "", "opentelelemtry_library", "", schema_url);
+ auto logger2 = lp->GetLogger("logger2", "", "", "", schema_url);
+
+ // Check that the logger is not nullptr
+ ASSERT_NE(logger1, nullptr);
+ ASSERT_NE(logger2, nullptr);
+
+ auto sdk_logger1 = static_cast<opentelemetry::sdk::logs::Logger *>(logger1.get());
+ auto sdk_logger2 = static_cast<opentelemetry::sdk::logs::Logger *>(logger2.get());
+ ASSERT_EQ(sdk_logger1->GetInstrumentationLibrary().GetName(), "opentelelemtry_library");
+ ASSERT_EQ(sdk_logger1->GetInstrumentationLibrary().GetVersion(), "");
+ ASSERT_EQ(sdk_logger1->GetInstrumentationLibrary().GetSchemaURL(), schema_url);
+
+ ASSERT_EQ(sdk_logger2->GetInstrumentationLibrary().GetName(), "logger2");
+ ASSERT_EQ(sdk_logger2->GetInstrumentationLibrary().GetVersion(), "");
+ ASSERT_EQ(sdk_logger2->GetInstrumentationLibrary().GetSchemaURL(), schema_url);
+
+ // Check that two loggers with different names aren't the same instance
+ ASSERT_NE(logger1, logger2);
+
+ // Check that two loggers with the same name are the same instance
+ auto logger3 = lp->GetLogger("logger1", "", "opentelelemtry_library", "", schema_url);
+ ASSERT_EQ(logger1, logger3);
+ auto sdk_logger3 = static_cast<opentelemetry::sdk::logs::Logger *>(logger3.get());
+ ASSERT_EQ(sdk_logger3->GetInstrumentationLibrary(), sdk_logger1->GetInstrumentationLibrary());
+}
+
+TEST(LoggerProviderSDK, LoggerProviderLoggerArguments)
+{
+ // Currently, arguments are not supported by the loggers.
+ // TODO: Once the logging spec defines what arguments are allowed, add more
+ // detail to this test
+ auto lp = std::shared_ptr<logs_api::LoggerProvider>(new LoggerProvider());
+
+ nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"};
+ auto logger1 = lp->GetLogger("logger1", "", "opentelelemtry_library", "", schema_url);
+
+ // Check GetLogger(logger_name, args)
+ std::array<nostd::string_view, 1> sv{"string"};
+ nostd::span<nostd::string_view> args{sv};
+ auto logger2 = lp->GetLogger("logger2", args, "opentelelemtry_library", "", schema_url);
+ auto sdk_logger1 = static_cast<opentelemetry::sdk::logs::Logger *>(logger1.get());
+ auto sdk_logger2 = static_cast<opentelemetry::sdk::logs::Logger *>(logger2.get());
+ ASSERT_EQ(sdk_logger2->GetInstrumentationLibrary(), sdk_logger1->GetInstrumentationLibrary());
+}
+
+class DummyProcessor : public LogProcessor
+{
+ std::unique_ptr<Recordable> MakeRecordable() noexcept
+ {
+ return std::unique_ptr<Recordable>(new LogRecord);
+ }
+
+ void OnReceive(std::unique_ptr<Recordable> &&record) noexcept {}
+ bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept
+ {
+ return true;
+ }
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept
+ {
+ return true;
+ }
+};
+
+TEST(LoggerProviderSDK, GetResource)
+{
+ // Create a LoggerProvider without a processor
+ auto resource = opentelemetry::sdk::resource::Resource::Create({{"key", "value"}});
+ LoggerProvider lp{nullptr, resource};
+ ASSERT_EQ(nostd::get<std::string>(lp.GetResource().GetAttributes().at("key")), "value");
+}
+
+TEST(LoggerProviderSDK, Shutdown)
+{
+ std::unique_ptr<SimpleLogProcessor> processor(new SimpleLogProcessor(nullptr));
+ std::vector<std::unique_ptr<LogProcessor>> processors;
+ processors.push_back(std::move(processor));
+
+ LoggerProvider lp(std::make_shared<LoggerContext>(std::move(processors)));
+
+ EXPECT_TRUE(lp.Shutdown());
+
+ // It's safe to shutdown again
+ EXPECT_TRUE(lp.Shutdown());
+}
+
+TEST(LoggerProviderSDK, ForceFlush)
+{
+ std::unique_ptr<SimpleLogProcessor> processor(new SimpleLogProcessor(nullptr));
+ std::vector<std::unique_ptr<LogProcessor>> processors;
+ processors.push_back(std::move(processor));
+
+ LoggerProvider lp(std::make_shared<LoggerContext>(std::move(processors)));
+
+ EXPECT_TRUE(lp.ForceFlush());
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_sdk_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_sdk_test.cc
new file mode 100644
index 000000000..3747731f1
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/logger_sdk_test.cc
@@ -0,0 +1,97 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/log_record.h"
+# include "opentelemetry/sdk/logs/logger.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::logs;
+namespace logs_api = opentelemetry::logs;
+
+TEST(LoggerSDK, LogToNullProcessor)
+{
+ // Confirm Logger::Log() does not have undefined behavior
+ // even when there is no processor set
+ // since it calls Processor::OnReceive()
+
+ auto lp = std::shared_ptr<logs_api::LoggerProvider>(new LoggerProvider());
+ const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"};
+ auto logger = lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url);
+
+ auto sdk_logger = static_cast<opentelemetry::sdk::logs::Logger *>(logger.get());
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetName(), "opentelelemtry_library");
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetVersion(), "");
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetSchemaURL(), schema_url);
+ // Log a sample log record to a nullptr processor
+ logger->Debug("Test log");
+}
+
+class MockProcessor final : public LogProcessor
+{
+private:
+ std::shared_ptr<LogRecord> record_received_;
+
+public:
+ // A processor used for testing that keeps a track of the recordable it received
+ explicit MockProcessor(std::shared_ptr<LogRecord> record_received) noexcept
+ : record_received_(record_received)
+ {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept
+ {
+ return std::unique_ptr<Recordable>(new LogRecord);
+ }
+ // OnReceive stores the record it receives into the shared_ptr recordable passed into its
+ // constructor
+ void OnReceive(std::unique_ptr<Recordable> &&record) noexcept
+ {
+ // Cast the recordable received into a concrete LogRecord type
+ auto copy = std::shared_ptr<LogRecord>(static_cast<LogRecord *>(record.release()));
+
+ // Copy over the received log record's severity, name, and body fields over to the recordable
+ // passed in the constructor
+ record_received_->SetSeverity(copy->GetSeverity());
+ record_received_->SetBody(copy->GetBody());
+ }
+ bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept
+ {
+ return true;
+ }
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept
+ {
+ return true;
+ }
+};
+
+TEST(LoggerSDK, LogToAProcessor)
+{
+ // Create an API LoggerProvider and logger
+ auto api_lp = std::shared_ptr<logs_api::LoggerProvider>(new LoggerProvider());
+ const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"};
+ auto logger = api_lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url);
+
+ // Cast the API LoggerProvider to an SDK Logger Provider and assert that it is still the same
+ // LoggerProvider by checking that getting a logger with the same name as the previously defined
+ // logger is the same instance
+ auto lp = static_cast<LoggerProvider *>(api_lp.get());
+ auto logger2 = lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url);
+ ASSERT_EQ(logger, logger2);
+
+ auto sdk_logger = static_cast<opentelemetry::sdk::logs::Logger *>(logger.get());
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetName(), "opentelelemtry_library");
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetVersion(), "");
+ ASSERT_EQ(sdk_logger->GetInstrumentationLibrary().GetSchemaURL(), schema_url);
+ // Set a processor for the LoggerProvider
+ auto shared_recordable = std::shared_ptr<LogRecord>(new LogRecord());
+ lp->AddProcessor(std::unique_ptr<LogProcessor>(new MockProcessor(shared_recordable)));
+
+ // Check that the recordable created by the Log() statement is set properly
+ logger->Log(logs_api::Severity::kWarn, "Log Message");
+
+ ASSERT_EQ(shared_recordable->GetSeverity(), logs_api::Severity::kWarn);
+ ASSERT_EQ(shared_recordable->GetBody(), "Log Message");
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/simple_log_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/simple_log_processor_test.cc
new file mode 100644
index 000000000..32c62a508
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/logs/simple_log_processor_test.cc
@@ -0,0 +1,152 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_LOGS_PREVIEW
+
+# include "opentelemetry/sdk/logs/simple_log_processor.h"
+# include "opentelemetry/nostd/span.h"
+# include "opentelemetry/sdk/logs/exporter.h"
+# include "opentelemetry/sdk/logs/log_record.h"
+
+# include <gtest/gtest.h>
+
+# include <chrono>
+# include <thread>
+
+using namespace opentelemetry::sdk::logs;
+using namespace opentelemetry::sdk::common;
+namespace nostd = opentelemetry::nostd;
+
+/*
+ * A test exporter that can return a vector of all the records it has received,
+ * and keep track of the number of times its Shutdown() function was called.
+ */
+class TestExporter final : public LogExporter
+{
+public:
+ TestExporter(int *shutdown_counter,
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received,
+ size_t *batch_size_received)
+ : shutdown_counter_(shutdown_counter),
+ logs_received_(logs_received),
+ batch_size_received(batch_size_received)
+ {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override
+ {
+ return std::unique_ptr<Recordable>(new LogRecord());
+ }
+
+ // Stores the names of the log records this exporter receives to an internal list
+ ExportResult Export(const nostd::span<std::unique_ptr<Recordable>> &records) noexcept override
+ {
+ *batch_size_received = records.size();
+ for (auto &record : records)
+ {
+ auto log_record = std::unique_ptr<LogRecord>(static_cast<LogRecord *>(record.release()));
+
+ if (log_record != nullptr)
+ {
+ logs_received_->push_back(std::move(log_record));
+ }
+ }
+ return ExportResult::kSuccess;
+ }
+
+ // Increment the shutdown counter everytime this method is called
+ bool Shutdown(std::chrono::microseconds timeout) noexcept override
+ {
+ *shutdown_counter_ += 1;
+ return true;
+ }
+
+private:
+ int *shutdown_counter_;
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received_;
+ size_t *batch_size_received;
+};
+
+// Tests whether the simple processor successfully creates a batch of size 1
+// and whether the contents of the record is sent to the exporter correctly
+TEST(SimpleLogProcessorTest, SendReceivedLogsToExporter)
+{
+ // Create a simple processor with a TestExporter attached
+ std::shared_ptr<std::vector<std::unique_ptr<LogRecord>>> logs_received(
+ new std::vector<std::unique_ptr<LogRecord>>);
+ size_t batch_size_received = 0;
+
+ std::unique_ptr<TestExporter> exporter(
+ new TestExporter(nullptr, logs_received, &batch_size_received));
+
+ SimpleLogProcessor processor(std::move(exporter));
+
+ // Send some log records to the processor (which should then send to the TestExporter)
+ const int num_logs = 5;
+ for (int i = 0; i < num_logs; i++)
+ {
+ auto recordable = processor.MakeRecordable();
+ recordable->SetBody("Log Body");
+ processor.OnReceive(std::move(recordable));
+
+ // Verify that the batch of 1 log record sent by processor matches what exporter received
+ EXPECT_EQ(1, batch_size_received);
+ }
+
+ // Test whether the processor's log sent matches the log record received by the exporter
+ EXPECT_EQ(logs_received->size(), num_logs);
+ for (int i = 0; i < num_logs; i++)
+ {
+ EXPECT_EQ("Log Body", logs_received->at(i)->GetBody());
+ }
+}
+
+// Tests behavior when calling the processor's ShutDown() multiple times
+TEST(SimpleLogProcessorTest, ShutdownCalledOnce)
+{
+ // Create a TestExporter
+ int num_shutdowns = 0;
+
+ std::unique_ptr<TestExporter> exporter(new TestExporter(&num_shutdowns, nullptr, nullptr));
+
+ // Create a processor with the previous test exporter
+ SimpleLogProcessor processor(std::move(exporter));
+
+ // The first time processor shutdown is called
+ EXPECT_EQ(0, num_shutdowns);
+ EXPECT_EQ(true, processor.Shutdown());
+ EXPECT_EQ(1, num_shutdowns);
+
+ EXPECT_EQ(true, processor.Shutdown());
+ // Processor::ShutDown(), even if called more than once, should only shutdown exporter once
+ EXPECT_EQ(1, num_shutdowns);
+}
+
+// A test exporter that always returns failure when shut down
+class FailShutDownExporter final : public LogExporter
+{
+public:
+ FailShutDownExporter() {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override
+ {
+ return std::unique_ptr<Recordable>(new LogRecord());
+ }
+
+ ExportResult Export(const nostd::span<std::unique_ptr<Recordable>> &records) noexcept override
+ {
+ return ExportResult::kSuccess;
+ }
+
+ bool Shutdown(std::chrono::microseconds timeout) noexcept override { return false; }
+};
+
+// Tests for when when processor should fail to shutdown
+TEST(SimpleLogProcessorTest, ShutDownFail)
+{
+ std::unique_ptr<FailShutDownExporter> exporter(new FailShutDownExporter());
+ SimpleLogProcessor processor(std::move(exporter));
+
+ // Expect failure result when exporter fails to shutdown
+ EXPECT_EQ(false, processor.Shutdown());
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/BUILD
new file mode 100644
index 000000000..819a8d225
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/BUILD
@@ -0,0 +1,203 @@
+load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
+
+cc_test(
+ name = "meter_provider_sdk_test",
+ srcs = [
+ "meter_provider_sdk_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "metric_reader_test",
+ srcs = [
+ "metric_reader_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "view_registry_test",
+ srcs = [
+ "view_registry_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "aggregation_test",
+ srcs = [
+ "aggregation_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "sync_metric_storage_test",
+ srcs = [
+ "sync_metric_storage_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "sync_instruments_test",
+ srcs = [
+ "sync_instruments_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "async_metric_storage_test",
+ srcs = [
+ "async_metric_storage_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "observer_result_test",
+ srcs = [
+ "observer_result_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "multi_metric_storage_test",
+ srcs = [
+ "multi_metric_storage_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "attributes_processor_test",
+ srcs = [
+ "attributes_processor_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "attributes_hashmap_test",
+ srcs = [
+ "attributes_hashmap_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "attributes_processor_benchmark",
+ srcs = [
+ "attributes_processor_benchmark.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "attributes_hashmap_benchmark",
+ srcs = [
+ "attributes_hashmap_benchmark.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//sdk/src/metrics",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/CMakeLists.txt
new file mode 100644
index 000000000..faf2f2b49
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/CMakeLists.txt
@@ -0,0 +1,34 @@
+foreach(
+ testname
+ meter_provider_sdk_test
+ view_registry_test
+ aggregation_test
+ attributes_processor_test
+ attributes_hashmap_test
+ sync_metric_storage_test
+ async_metric_storage_test
+ multi_metric_storage_test
+ observer_result_test
+ sync_instruments_test
+ async_instruments_test
+ metric_reader_test
+ periodic_exporting_metric_reader_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(
+ ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
+ opentelemetry_resources opentelemetry_metrics)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX metrics.
+ TEST_LIST ${testname})
+endforeach()
+
+add_executable(attributes_processor_benchmark attributes_processor_benchmark.cc)
+target_link_libraries(attributes_processor_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common)
+
+add_executable(attributes_hashmap_benchmark attributes_hashmap_benchmark.cc)
+target_link_libraries(attributes_hashmap_benchmark benchmark::benchmark
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common)
+
+add_subdirectory(exemplar)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/aggregation_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/aggregation_test.cc
new file mode 100644
index 000000000..f8051776d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/aggregation_test.cc
@@ -0,0 +1,182 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/sum_aggregation.h"
+
+# include "opentelemetry/nostd/variant.h"
+
+using namespace opentelemetry::sdk::metrics;
+namespace nostd = opentelemetry::nostd;
+TEST(Aggregation, LongSumAggregation)
+{
+ LongSumAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<SumPointData>(data));
+ auto sum_data = nostd::get<SumPointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<long>(sum_data.value_));
+ EXPECT_EQ(nostd::get<long>(sum_data.value_), 0l);
+ EXPECT_NO_THROW(aggr.Aggregate(12l, {}));
+ EXPECT_NO_THROW(aggr.Aggregate(0l, {}));
+ sum_data = nostd::get<SumPointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<long>(sum_data.value_), 12l);
+}
+
+TEST(Aggregation, DoubleSumAggregation)
+{
+ DoubleSumAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<SumPointData>(data));
+ auto sum_data = nostd::get<SumPointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<double>(sum_data.value_));
+ EXPECT_EQ(nostd::get<double>(sum_data.value_), 0);
+ EXPECT_NO_THROW(aggr.Aggregate(12.0, {}));
+ EXPECT_NO_THROW(aggr.Aggregate(1.0, {}));
+ sum_data = nostd::get<SumPointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<double>(sum_data.value_), 13.0);
+}
+
+TEST(Aggregation, LongLastValueAggregation)
+{
+ LongLastValueAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<LastValuePointData>(data));
+ auto lastvalue_data = nostd::get<LastValuePointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<long>(lastvalue_data.value_));
+ EXPECT_EQ(lastvalue_data.is_lastvalue_valid_, false);
+ EXPECT_NO_THROW(aggr.Aggregate(12l, {}));
+ EXPECT_NO_THROW(aggr.Aggregate(1l, {}));
+ lastvalue_data = nostd::get<LastValuePointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<long>(lastvalue_data.value_), 1.0);
+}
+
+TEST(Aggregation, DoubleLastValueAggregation)
+{
+ DoubleLastValueAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<LastValuePointData>(data));
+ auto lastvalue_data = nostd::get<LastValuePointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<double>(lastvalue_data.value_));
+ EXPECT_EQ(lastvalue_data.is_lastvalue_valid_, false);
+ EXPECT_NO_THROW(aggr.Aggregate(12.0, {}));
+ EXPECT_NO_THROW(aggr.Aggregate(1.0, {}));
+ lastvalue_data = nostd::get<LastValuePointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<double>(lastvalue_data.value_), 1.0);
+}
+
+TEST(Aggregation, LongHistogramAggregation)
+{
+ LongHistogramAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
+ auto histogram_data = nostd::get<HistogramPointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<long>(histogram_data.sum_));
+ ASSERT_TRUE(nostd::holds_alternative<std::list<long>>(histogram_data.boundaries_));
+ EXPECT_EQ(nostd::get<long>(histogram_data.sum_), 0);
+ EXPECT_EQ(histogram_data.count_, 0);
+ EXPECT_NO_THROW(aggr.Aggregate(12l, {})); // lies in fourth bucket
+ EXPECT_NO_THROW(aggr.Aggregate(100l, {})); // lies in eight bucket
+ histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<long>(histogram_data.sum_), 112);
+ EXPECT_EQ(histogram_data.count_, 2);
+ EXPECT_EQ(histogram_data.counts_[3], 1);
+ EXPECT_EQ(histogram_data.counts_[7], 1);
+ EXPECT_NO_THROW(aggr.Aggregate(13l, {})); // lies in fourth bucket
+ EXPECT_NO_THROW(aggr.Aggregate(252l, {})); // lies in ninth bucket
+ histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
+ EXPECT_EQ(histogram_data.count_, 4);
+ EXPECT_EQ(histogram_data.counts_[3], 2);
+ EXPECT_EQ(histogram_data.counts_[8], 1);
+
+ // Merge
+ LongHistogramAggregation aggr1;
+ aggr1.Aggregate(1l, {});
+ aggr1.Aggregate(11l, {});
+ aggr1.Aggregate(26l, {});
+
+ LongHistogramAggregation aggr2;
+ aggr2.Aggregate(2l, {});
+ aggr2.Aggregate(3l, {});
+ aggr2.Aggregate(13l, {});
+ aggr2.Aggregate(28l, {});
+ aggr2.Aggregate(105l, {});
+
+ auto aggr3 = aggr1.Merge(aggr2);
+ histogram_data = nostd::get<HistogramPointData>(aggr3->ToPoint());
+
+ EXPECT_EQ(histogram_data.count_, 8); // 3 each from aggr1 and aggr2
+ EXPECT_EQ(histogram_data.counts_[1], 3); // 1, 2, 3
+ EXPECT_EQ(histogram_data.counts_[3], 2); // 11, 13
+ EXPECT_EQ(histogram_data.counts_[4], 2); // 25, 28
+ EXPECT_EQ(histogram_data.counts_[7], 1); // 105
+
+ // Diff
+ auto aggr4 = aggr1.Diff(aggr2);
+ histogram_data = nostd::get<HistogramPointData>(aggr4->ToPoint());
+ EXPECT_EQ(histogram_data.count_, 2); // aggr2:5 - aggr1:3
+ EXPECT_EQ(histogram_data.counts_[1], 1); // aggr2(2, 3) - aggr1(1)
+ EXPECT_EQ(histogram_data.counts_[3], 0); // aggr2(13) - aggr1(11)
+ EXPECT_EQ(histogram_data.counts_[4], 0); // aggr2(28) - aggr1(25)
+ EXPECT_EQ(histogram_data.counts_[7], 1); // aggr2(105) - aggr1(0)
+}
+
+TEST(Aggregation, DoubleHistogramAggregation)
+{
+ DoubleHistogramAggregation aggr;
+ auto data = aggr.ToPoint();
+ ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
+ auto histogram_data = nostd::get<HistogramPointData>(data);
+ ASSERT_TRUE(nostd::holds_alternative<double>(histogram_data.sum_));
+ ASSERT_TRUE(nostd::holds_alternative<std::list<double>>(histogram_data.boundaries_));
+ EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 0);
+ EXPECT_EQ(histogram_data.count_, 0);
+ EXPECT_NO_THROW(aggr.Aggregate(12.0, {})); // lies in fourth bucket
+ EXPECT_NO_THROW(aggr.Aggregate(100.0, {})); // lies in eight bucket
+ histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
+ EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 112);
+ EXPECT_EQ(histogram_data.count_, 2);
+ EXPECT_EQ(histogram_data.counts_[3], 1);
+ EXPECT_EQ(histogram_data.counts_[7], 1);
+ EXPECT_NO_THROW(aggr.Aggregate(13.0, {})); // lies in fourth bucket
+ EXPECT_NO_THROW(aggr.Aggregate(252.0, {})); // lies in ninth bucket
+ histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
+ EXPECT_EQ(histogram_data.count_, 4);
+ EXPECT_EQ(histogram_data.counts_[3], 2);
+ EXPECT_EQ(histogram_data.counts_[8], 1);
+ EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 377);
+
+ // Merge
+ DoubleHistogramAggregation aggr1;
+ aggr1.Aggregate(1.0, {});
+ aggr1.Aggregate(11.0, {});
+ aggr1.Aggregate(25.1, {});
+
+ DoubleHistogramAggregation aggr2;
+ aggr2.Aggregate(2.0, {});
+ aggr2.Aggregate(3.0, {});
+ aggr2.Aggregate(13.0, {});
+ aggr2.Aggregate(28.1, {});
+ aggr2.Aggregate(105.0, {});
+
+ auto aggr3 = aggr1.Merge(aggr2);
+ histogram_data = nostd::get<HistogramPointData>(aggr3->ToPoint());
+
+ EXPECT_EQ(histogram_data.count_, 8); // 3 each from aggr1 and aggr2
+ EXPECT_EQ(histogram_data.counts_[1], 3); // 1.0, 2.0, 3.0
+ EXPECT_EQ(histogram_data.counts_[3], 2); // 11.0, 13.0
+ EXPECT_EQ(histogram_data.counts_[4], 2); // 25.1, 28.1
+ EXPECT_EQ(histogram_data.counts_[7], 1); // 105.0
+
+ // Diff
+ auto aggr4 = aggr1.Diff(aggr2);
+ histogram_data = nostd::get<HistogramPointData>(aggr4->ToPoint());
+ EXPECT_EQ(histogram_data.count_, 2); // aggr2:5 - aggr1:3
+ EXPECT_EQ(histogram_data.counts_[1], 1); // aggr2(2.0, 3.0) - aggr1(1.0)
+ EXPECT_EQ(histogram_data.counts_[3], 0); // aggr2(13.0) - aggr1(11.0)
+ EXPECT_EQ(histogram_data.counts_[4], 0); // aggr2(28.1) - aggr1(25.1)
+ EXPECT_EQ(histogram_data.counts_[7], 1); // aggr2(105.0) - aggr1(0)
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_instruments_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_instruments_test.cc
new file mode 100644
index 000000000..ff9504f78
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_instruments_test.cc
@@ -0,0 +1,60 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/async_instruments.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::metrics;
+
+using M = std::map<std::string, std::string>;
+
+void asyc_generate_measurements_long(opentelemetry::metrics::ObserverResult<long> &observer) {}
+
+void asyc_generate_measurements_double(opentelemetry::metrics::ObserverResult<double> &observer) {}
+
+TEST(AsyncInstruments, LongObservableCounter)
+{
+ auto asyc_generate_meas_long = [](opentelemetry::metrics::ObserverResult<long> &observer) {};
+ EXPECT_NO_THROW(
+ LongObservableCounter counter("long_counter", asyc_generate_meas_long, "description", "1"));
+}
+
+TEST(AsyncInstruments, DoubleObservableCounter)
+{
+ auto asyc_generate_meas_double = [](opentelemetry::metrics::ObserverResult<double> &observer) {};
+ EXPECT_NO_THROW(DoubleObservableCounter counter("long_counter", asyc_generate_meas_double,
+ "description", "1"));
+}
+
+TEST(AsyncInstruments, LongObservableGauge)
+{
+ auto asyc_generate_meas_long = [](opentelemetry::metrics::ObserverResult<long> &observer) {};
+ EXPECT_NO_THROW(
+ LongObservableGauge counter("long_counter", asyc_generate_meas_long, "description", "1"));
+}
+
+TEST(AsyncInstruments, DoubleObservableGauge)
+{
+ auto asyc_generate_meas_double = [](opentelemetry::metrics::ObserverResult<double> &observer) {};
+ EXPECT_NO_THROW(
+ DoubleObservableGauge counter("long_counter", asyc_generate_meas_double, "description", "1"));
+}
+
+TEST(AsyncInstruments, LongObservableUpDownCounter)
+{
+ auto asyc_generate_meas_long = [](opentelemetry::metrics::ObserverResult<long> &observer) {};
+ EXPECT_NO_THROW(LongObservableUpDownCounter counter("long_counter", asyc_generate_meas_long,
+ "description", "1"));
+}
+
+TEST(AsyncInstruments, DoubleObservableUpDownCounter)
+{
+ auto asyc_generate_meas_double = [](opentelemetry::metrics::ObserverResult<double> &observer) {};
+ EXPECT_NO_THROW(DoubleObservableUpDownCounter counter("long_counter", asyc_generate_meas_double,
+ "description", "1"));
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_metric_storage_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_metric_storage_test.cc
new file mode 100644
index 000000000..2be5332a8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/async_metric_storage_test.cc
@@ -0,0 +1,132 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/async_metric_storage.h"
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/metrics/metric_exporter.h"
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/sdk/metrics/observer_result.h"
+# include "opentelemetry/sdk/metrics/state/metric_collector.h"
+
+# include <gtest/gtest.h>
+# include <vector>
+
+using namespace opentelemetry::sdk::metrics;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+using namespace opentelemetry::sdk::resource;
+
+using namespace opentelemetry::sdk::metrics;
+using namespace opentelemetry::common;
+using M = std::map<std::string, std::string>;
+
+class MockCollectorHandle : public CollectorHandle
+{
+public:
+ MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {}
+
+ AggregationTemporality GetAggregationTemporality() noexcept override { return temporality; }
+
+private:
+ AggregationTemporality temporality;
+};
+
+class WritableMetricStorageTestFixture : public ::testing::TestWithParam<AggregationTemporality>
+{};
+
+class MeasurementFetcher
+{
+public:
+ static void Fetcher(opentelemetry::metrics::ObserverResult<long> &observer_result,
+ void * /*state*/)
+ {
+ fetch_count++;
+ if (fetch_count == 1)
+ {
+ observer_result.Observe(20l, {{"RequestType", "GET"}});
+ observer_result.Observe(10l, {{"RequestType", "PUT"}});
+ number_of_get += 20l;
+ number_of_put += 10l;
+ }
+ else if (fetch_count == 2)
+ {
+ observer_result.Observe(40l, {{"RequestType", "GET"}});
+ observer_result.Observe(20l, {{"RequestType", "PUT"}});
+ number_of_get += 40l;
+ number_of_put += 20l;
+ }
+ }
+
+ static void init_values()
+ {
+ fetch_count = 0;
+ number_of_get = 0;
+ number_of_put = 0;
+ }
+
+ static size_t fetch_count;
+ static long number_of_get;
+ static long number_of_put;
+ static const size_t number_of_attributes = 2; // GET , PUT
+};
+
+size_t MeasurementFetcher::fetch_count;
+long MeasurementFetcher::number_of_get;
+long MeasurementFetcher::number_of_put;
+const size_t MeasurementFetcher::number_of_attributes;
+
+TEST_P(WritableMetricStorageTestFixture, TestAggregation)
+{
+ MeasurementFetcher::init_values();
+ AggregationTemporality temporality = GetParam();
+
+ InstrumentDescriptor instr_desc = {"name", "desc", "1unit", InstrumentType::kObservableCounter,
+ InstrumentValueType::kLong};
+
+ auto sdk_start_ts = std::chrono::system_clock::now();
+ // Some computation here
+ auto collection_ts = std::chrono::system_clock::now() + std::chrono::seconds(5);
+
+ std::shared_ptr<CollectorHandle> collector(new MockCollectorHandle(temporality));
+ std::vector<std::shared_ptr<CollectorHandle>> collectors;
+ collectors.push_back(collector);
+ size_t count_attributes = 0;
+ long value = 0;
+
+ MeasurementFetcher measurement_fetcher;
+ opentelemetry::sdk::metrics::AsyncMetricStorage<long> storage(instr_desc, AggregationType::kSum,
+ MeasurementFetcher::Fetcher,
+ new DefaultAttributesProcessor());
+
+ storage.Collect(collector.get(), collectors, sdk_start_ts, collection_ts,
+ [&](const MetricData data) {
+ for (auto data_attr : data.point_data_attr_)
+ {
+ auto data = opentelemetry::nostd::get<SumPointData>(data_attr.point_data);
+ if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "GET")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_),
+ MeasurementFetcher::number_of_get);
+ }
+ else if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "PUT")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_),
+ MeasurementFetcher::number_of_put);
+ }
+ count_attributes++;
+ }
+ return true;
+ });
+ EXPECT_EQ(MeasurementFetcher::number_of_attributes, count_attributes);
+}
+
+INSTANTIATE_TEST_SUITE_P(WritableMetricStorageTestLong,
+ WritableMetricStorageTestFixture,
+ ::testing::Values(AggregationTemporality::kCumulative,
+ AggregationTemporality::kDelta));
+
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_benchmark.cc
new file mode 100644
index 000000000..38d515a7e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_benchmark.cc
@@ -0,0 +1,53 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <benchmark/benchmark.h>
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/common/attributemap_hash.h"
+# include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
+# include "opentelemetry/sdk/metrics/aggregation/drop_aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+
+# include <functional>
+# include <vector>
+
+using namespace opentelemetry::sdk::metrics;
+constexpr size_t MAX_THREADS = 500;
+namespace
+{
+
+void BM_AttributseHashMap(benchmark::State &state)
+{
+
+ AttributesHashMap hash_map;
+ std::vector<std::thread> workers;
+ std::vector<MetricAttributes> attributes = {{{"k1", "v1"}, {"k2", "v2"}},
+ {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}}};
+
+ std::function<std::unique_ptr<Aggregation>()> create_default_aggregation =
+ []() -> std::unique_ptr<Aggregation> {
+ return std::unique_ptr<Aggregation>(new DropAggregation);
+ };
+
+ while (state.KeepRunning())
+ {
+ for (size_t i = 0; i < MAX_THREADS; i++)
+ {
+ workers.push_back(std::thread([&]() {
+ hash_map.GetOrSetDefault(attributes[i % 2], create_default_aggregation)->Aggregate(1l);
+ benchmark::DoNotOptimize(hash_map.Has(attributes[i % 2]));
+ }));
+ }
+ }
+
+ for (auto &t : workers)
+ {
+ t.join();
+ }
+}
+
+BENCHMARK(BM_AttributseHashMap);
+} // namespace
+#endif
+BENCHMARK_MAIN(); \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_test.cc
new file mode 100644
index 000000000..610744c8e
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_hashmap_test.cc
@@ -0,0 +1,71 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/attributes_hashmap.h"
+# include <gtest/gtest.h>
+# include "opentelemetry/sdk/metrics/aggregation/drop_aggregation.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+
+# include <functional>
+
+using namespace opentelemetry::sdk::metrics;
+namespace nostd = opentelemetry::nostd;
+
+TEST(AttributesHashMap, BasicTests)
+{
+
+ // Empty map
+ AttributesHashMap hash_map;
+ EXPECT_EQ(hash_map.Size(), 0);
+ MetricAttributes m1 = {{"k1", "v1"}};
+ EXPECT_EQ(hash_map.Get(m1), nullptr);
+ EXPECT_EQ(hash_map.Has(m1), false);
+
+ // Set
+ std::unique_ptr<Aggregation> aggregation1(
+ new DropAggregation()); // = std::unique_ptr<Aggregation>(new DropAggregation);
+ hash_map.Set(m1, std::move(aggregation1));
+ EXPECT_NO_THROW(hash_map.Get(m1)->Aggregate(1l));
+ EXPECT_EQ(hash_map.Size(), 1);
+ EXPECT_EQ(hash_map.Has(m1), true);
+
+ // Set same key again
+ auto aggregation2 = std::unique_ptr<Aggregation>(new DropAggregation());
+ hash_map.Set(m1, std::move(aggregation2));
+ EXPECT_NO_THROW(hash_map.Get(m1)->Aggregate(1l));
+ EXPECT_EQ(hash_map.Size(), 1);
+ EXPECT_EQ(hash_map.Has(m1), true);
+
+ // Set more enteria
+ auto aggregation3 = std::unique_ptr<Aggregation>(new DropAggregation());
+ MetricAttributes m3 = {{"k1", "v1"}, {"k2", "v2"}};
+ hash_map.Set(m3, std::move(aggregation3));
+ EXPECT_EQ(hash_map.Has(m1), true);
+ EXPECT_EQ(hash_map.Has(m3), true);
+ EXPECT_NO_THROW(hash_map.Get(m3)->Aggregate(1l));
+ EXPECT_EQ(hash_map.Size(), 2);
+
+ // GetOrSetDefault
+ std::function<std::unique_ptr<Aggregation>()> create_default_aggregation =
+ []() -> std::unique_ptr<Aggregation> {
+ return std::unique_ptr<Aggregation>(new DropAggregation);
+ };
+ MetricAttributes m4 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}};
+ EXPECT_NO_THROW(hash_map.GetOrSetDefault(m4, create_default_aggregation)->Aggregate(1l));
+ EXPECT_EQ(hash_map.Size(), 3);
+
+ // Set attributes with different order - shouldn't create a new entry.
+ MetricAttributes m5 = {{"k2", "v2"}, {"k1", "v1"}};
+ EXPECT_EQ(hash_map.Has(m5), true);
+
+ // GetAllEnteries
+ size_t count = 0;
+ hash_map.GetAllEnteries([&count](const MetricAttributes &attributes, Aggregation &aggregation) {
+ count++;
+ return true;
+ });
+ EXPECT_EQ(count, hash_map.Size());
+}
+
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_benchmark.cc
new file mode 100644
index 000000000..d558a668f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_benchmark.cc
@@ -0,0 +1,27 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <benchmark/benchmark.h>
+#ifndef ENABLE_METRICS_PREVIEW
+# include <map>
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+using namespace opentelemetry::sdk::metrics;
+namespace
+{
+void BM_AttributseProcessorFilter(benchmark::State &state)
+{
+ std::map<std::string, int> attributes = {
+ {"att1", 10}, {"attr1", 20}, {"attr3", 30}, {"attr4", 40}};
+ FilteringAttributesProcessor attributes_processor(
+ {{"attr2", true}, {"attr4", true}, {"attr6", true}});
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes);
+ while (state.KeepRunning())
+ {
+ auto filtered_attributes = attributes_processor.process(iterable);
+ }
+}
+
+BENCHMARK(BM_AttributseProcessorFilter);
+} // namespace
+#endif
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_test.cc
new file mode 100644
index 000000000..d496cc7b0
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/attributes_processor_test.cc
@@ -0,0 +1,49 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::metrics;
+using namespace opentelemetry::common;
+using namespace opentelemetry::sdk::common;
+
+TEST(AttributesProcessor, FilteringAttributesProcessor)
+{
+ const int kNumFilterAttributes = 3;
+ std::unordered_map<std::string, bool> filter = {
+ {"attr2", true}, {"attr4", true}, {"attr6", true}};
+ const int kNumAttributes = 6;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3", "attr4", "attr5", "attr6"};
+ int values[kNumAttributes] = {10, 20, 30, 40, 50, 60};
+ std::map<std::string, int> attributes = {{keys[0], values[0]}, {keys[1], values[1]},
+ {keys[2], values[2]}, {keys[3], values[3]},
+ {keys[4], values[4]}, {keys[5], values[5]}};
+ FilteringAttributesProcessor attributes_processor(filter);
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes);
+ auto filtered_attributes = attributes_processor.process(iterable);
+ for (auto &e : filtered_attributes)
+ {
+ EXPECT_FALSE(filter.find(e.first) == filter.end());
+ }
+ EXPECT_EQ(filter.size(), kNumFilterAttributes);
+}
+
+TEST(AttributesProcessor, FilteringAllAttributesProcessor)
+{
+ const int kNumFilterAttributes = 0;
+ std::unordered_map<std::string, bool> filter = {};
+ const int kNumAttributes = 6;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3", "attr4", "attr5", "attr6"};
+ int values[kNumAttributes] = {10, 20, 30, 40, 50, 60};
+ std::map<std::string, int> attributes = {{keys[0], values[0]}, {keys[1], values[1]},
+ {keys[2], values[2]}, {keys[3], values[3]},
+ {keys[4], values[4]}, {keys[5], values[5]}};
+ FilteringAttributesProcessor attributes_processor(filter);
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>> iterable(attributes);
+ auto filtered_attributes = attributes_processor.process(iterable);
+ EXPECT_EQ(filter.size(), kNumFilterAttributes);
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/BUILD
new file mode 100644
index 000000000..6481f679d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/BUILD
@@ -0,0 +1,47 @@
+cc_test(
+ name = "no_exemplar_reservoir_test",
+ srcs = [
+ "no_exemplar_reservoir_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "never_sample_filter_test",
+ srcs = [
+ "never_sample_filter_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "always_sample_filter_test",
+ srcs = [
+ "always_sample_filter_test.cc",
+ ],
+ tags = [
+ "metrics",
+ "test",
+ ],
+ deps = [
+ "//api",
+ "//sdk:headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/CMakeLists.txt
new file mode 100644
index 000000000..303294761
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/CMakeLists.txt
@@ -0,0 +1,10 @@
+foreach(testname no_exemplar_reservoir_test never_sample_filter_test
+ always_sample_filter_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX metrics.
+ TEST_LIST ${testname})
+endforeach()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/always_sample_filter_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/always_sample_filter_test.cc
new file mode 100644
index 000000000..cf4e44995
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/always_sample_filter_test.cc
@@ -0,0 +1,19 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/exemplar/always_sample_filter.h"
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::metrics;
+
+TEST(AlwaysSampleFilter, SampleMeasurement)
+{
+ auto filter = opentelemetry::sdk::metrics::AlwaysSampleFilter::GetAlwaysSampleFilter();
+ ASSERT_TRUE(
+ filter->ShouldSampleMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{}));
+ ASSERT_TRUE(
+ filter->ShouldSampleMeasurement(1l, MetricAttributes{}, opentelemetry::context::Context{}));
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/never_sample_filter_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/never_sample_filter_test.cc
new file mode 100644
index 000000000..930c57220
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/never_sample_filter_test.cc
@@ -0,0 +1,20 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/context/context.h"
+#ifndef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include "opentelemetry/sdk/metrics/exemplar/never_sample_filter.h"
+
+using namespace opentelemetry::sdk::metrics;
+
+TEST(NeverSampleFilter, SampleMeasurement)
+{
+ auto filter = opentelemetry::sdk::metrics::NeverSampleFilter::GetNeverSampleFilter();
+ ASSERT_FALSE(
+ filter->ShouldSampleMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{}));
+ ASSERT_FALSE(
+ filter->ShouldSampleMeasurement(1l, MetricAttributes{}, opentelemetry::context::Context{}));
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc
new file mode 100644
index 000000000..3e16940ff
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc
@@ -0,0 +1,22 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h"
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::metrics;
+
+TEST(NoExemplarReservoir, OfferMeasurement)
+{
+ auto reservoir = opentelemetry::sdk::metrics::NoExemplarReservoir::GetNoExemplarReservoir();
+ EXPECT_NO_THROW(reservoir->OfferMeasurement(1.0, MetricAttributes{},
+ opentelemetry::context::Context{},
+ std::chrono::system_clock::now()));
+ EXPECT_NO_THROW(reservoir->OfferMeasurement(
+ 1l, MetricAttributes{}, opentelemetry::context::Context{}, std::chrono::system_clock::now()));
+ auto exemplar_data = reservoir->CollectAndReset(MetricAttributes{});
+ ASSERT_TRUE(exemplar_data.empty());
+}
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/meter_provider_sdk_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/meter_provider_sdk_test.cc
new file mode 100644
index 000000000..b0fabe50b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/meter_provider_sdk_test.cc
@@ -0,0 +1,91 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include <gtest/gtest.h>
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+# include "opentelemetry/sdk/metrics/meter.h"
+# include "opentelemetry/sdk/metrics/meter_provider.h"
+# include "opentelemetry/sdk/metrics/metric_exporter.h"
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include "opentelemetry/sdk/metrics/view/instrument_selector.h"
+# include "opentelemetry/sdk/metrics/view/meter_selector.h"
+
+using namespace opentelemetry::sdk::metrics;
+
+class MockMetricExporter : public MetricExporter
+{
+
+public:
+ MockMetricExporter() = default;
+ opentelemetry::sdk::common::ExportResult Export(const ResourceMetrics &records) noexcept override
+ {
+ return opentelemetry::sdk::common::ExportResult::kSuccess;
+ }
+
+ bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ return true;
+ }
+
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override
+ {
+ return true;
+ }
+};
+
+class MockMetricReader : public MetricReader
+{
+public:
+ MockMetricReader(std::unique_ptr<MetricExporter> exporter) : exporter_(std::move(exporter)) {}
+ virtual bool OnForceFlush(std::chrono::microseconds timeout) noexcept override { return true; }
+ virtual bool OnShutDown(std::chrono::microseconds timeout) noexcept override { return true; }
+ virtual void OnInitialized() noexcept override {}
+
+private:
+ std::unique_ptr<MetricExporter> exporter_;
+};
+
+TEST(MeterProvider, GetMeter)
+{
+
+ MeterProvider mp1;
+ // std::unique_ptr<View> view{std::unique_ptr<View>()};
+ // MeterProvider mp1(std::move(exporters), std::move(readers), std::move(views);
+ auto m1 = mp1.GetMeter("test");
+ auto m2 = mp1.GetMeter("test");
+ auto m3 = mp1.GetMeter("different", "1.0.0");
+ auto m4 = mp1.GetMeter("");
+ auto m5 = mp1.GetMeter(opentelemetry::nostd::string_view{});
+ auto m6 = mp1.GetMeter("different", "1.0.0", "https://opentelemetry.io/schemas/1.2.0");
+ ASSERT_NE(nullptr, m1);
+ ASSERT_NE(nullptr, m2);
+ ASSERT_NE(nullptr, m3);
+ ASSERT_NE(nullptr, m6);
+
+ // Should return the same instance each time.
+ ASSERT_EQ(m1, m2);
+ ASSERT_NE(m1, m3);
+ ASSERT_EQ(m4, m5);
+ ASSERT_NE(m3, m6);
+
+ // Should be an sdk::trace::Tracer with the processor attached.
+# ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto sdkMeter1 = dynamic_cast<Meter *>(m1.get());
+# else
+ auto sdkMeter1 = static_cast<Meter *>(m1.get());
+# endif
+ ASSERT_NE(nullptr, sdkMeter1);
+ std::unique_ptr<MockMetricExporter> exporter(new MockMetricExporter());
+ std::unique_ptr<MetricReader> reader{new MockMetricReader(std::move(exporter))};
+ ASSERT_NO_THROW(mp1.AddMetricReader(std::move(reader)));
+
+ std::unique_ptr<View> view{std::unique_ptr<View>()};
+ std::unique_ptr<InstrumentSelector> instrument_selector{
+ new InstrumentSelector(InstrumentType::kCounter, "instru1")};
+ std::unique_ptr<MeterSelector> meter_selector{new MeterSelector("name1", "version1", "schema1")};
+ ASSERT_NO_THROW(
+ mp1.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)));
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/metric_reader_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/metric_reader_test.cc
new file mode 100644
index 000000000..c9c30853d
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/metric_reader_test.cc
@@ -0,0 +1,39 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/metric_reader.h"
+# include <gtest/gtest.h>
+# include "opentelemetry/sdk/metrics/meter_context.h"
+# include "opentelemetry/sdk/metrics/metric_exporter.h"
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+using namespace opentelemetry::sdk::metrics;
+
+class MockMetricReader : public MetricReader
+{
+public:
+ MockMetricReader(AggregationTemporality aggr_temporality) : MetricReader(aggr_temporality) {}
+
+ virtual bool OnForceFlush(std::chrono::microseconds timeout) noexcept override { return true; }
+ virtual bool OnShutDown(std::chrono::microseconds timeout) noexcept override { return true; }
+ virtual void OnInitialized() noexcept override {}
+};
+
+TEST(MetricReaderTest, BasicTests)
+{
+ AggregationTemporality aggr_temporality = AggregationTemporality::kDelta;
+ std::unique_ptr<MetricReader> metric_reader1(new MockMetricReader(aggr_temporality));
+ EXPECT_EQ(metric_reader1->GetAggregationTemporality(), aggr_temporality);
+
+ std::shared_ptr<MeterContext> meter_context1(new MeterContext());
+ EXPECT_NO_THROW(meter_context1->AddMetricReader(std::move(metric_reader1)));
+
+ std::unique_ptr<MetricReader> metric_reader2(new MockMetricReader(aggr_temporality));
+ std::shared_ptr<MeterContext> meter_context2(new MeterContext());
+ MetricProducer *metric_producer =
+ new MetricCollector(std::move(meter_context2), std::move(metric_reader2));
+ EXPECT_NO_THROW(metric_producer->Collect([](ResourceMetrics &metric_data) { return true; }));
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/multi_metric_storage_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/multi_metric_storage_test.cc
new file mode 100644
index 000000000..d88946485
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/multi_metric_storage_test.cc
@@ -0,0 +1,62 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/multi_metric_storage.h"
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+using namespace opentelemetry::sdk::metrics;
+
+class TestMetricStorage : public WritableMetricStorage
+{
+public:
+ void RecordLong(long value, const opentelemetry::context::Context &context) noexcept override
+ {
+ num_calls_long++;
+ }
+
+ void RecordLong(long value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ num_calls_long++;
+ }
+
+ void RecordDouble(double value, const opentelemetry::context::Context &context) noexcept override
+ {
+ num_calls_double++;
+ }
+
+ void RecordDouble(double value,
+ const opentelemetry::common::KeyValueIterable &attributes,
+ const opentelemetry::context::Context &context) noexcept override
+ {
+ num_calls_double++;
+ }
+
+ size_t num_calls_long;
+ size_t num_calls_double;
+};
+
+TEST(MultiMetricStorageTest, BasicTests)
+{
+ std::shared_ptr<opentelemetry::sdk::metrics::WritableMetricStorage> storage(
+ new TestMetricStorage());
+ MultiMetricStorage storages{};
+ storages.AddStorage(storage);
+ EXPECT_NO_THROW(storages.RecordLong(10l, opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(storages.RecordLong(20l, opentelemetry::context::Context{}));
+
+ EXPECT_NO_THROW(storages.RecordDouble(10.0, opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(storages.RecordLong(30l, opentelemetry::context::Context{}));
+
+ EXPECT_EQ(static_cast<TestMetricStorage *>(storage.get())->num_calls_long, 3);
+ EXPECT_EQ(static_cast<TestMetricStorage *>(storage.get())->num_calls_double, 1);
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/observer_result_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/observer_result_test.cc
new file mode 100644
index 000000000..a4cc28ae5
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/observer_result_test.cc
@@ -0,0 +1,38 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/observer_result.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::metrics;
+TEST(ObserverResult, BasicTests)
+{
+ const AttributesProcessor *attributes_processor = new DefaultAttributesProcessor();
+
+ ObserverResult<long> observer_result(attributes_processor);
+
+ observer_result.Observe(10l);
+ observer_result.Observe(20l);
+ EXPECT_EQ(observer_result.GetMeasurements().size(), 1);
+
+ std::map<std::string, int64_t> m1 = {{"k2", 12}};
+ observer_result.Observe(
+ 30l, opentelemetry::common::KeyValueIterableView<std::map<std::string, int64_t>>(m1));
+ EXPECT_EQ(observer_result.GetMeasurements().size(), 2);
+
+ observer_result.Observe(
+ 40l, opentelemetry::common::KeyValueIterableView<std::map<std::string, int64_t>>(m1));
+ EXPECT_EQ(observer_result.GetMeasurements().size(), 2);
+
+ std::map<std::string, int64_t> m2 = {{"k2", 12}, {"k4", 12}};
+ observer_result.Observe(
+ 40l, opentelemetry::common::KeyValueIterableView<std::map<std::string, int64_t>>(m2));
+ EXPECT_EQ(observer_result.GetMeasurements().size(), 3);
+
+ delete attributes_processor;
+}
+
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/periodic_exporting_metric_reader_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/periodic_exporting_metric_reader_test.cc
new file mode 100644
index 000000000..5219f3110
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/periodic_exporting_metric_reader_test.cc
@@ -0,0 +1,81 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+
+# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h"
+# include "opentelemetry/sdk/metrics/export/metric_producer.h"
+# include "opentelemetry/sdk/metrics/metric_exporter.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+using namespace opentelemetry::sdk::metrics;
+
+class MockPushMetricExporter : public MetricExporter
+{
+public:
+ opentelemetry::sdk::common::ExportResult Export(const ResourceMetrics &record) noexcept override
+ {
+ records_.push_back(record);
+ return opentelemetry::sdk::common::ExportResult::kSuccess;
+ }
+
+ bool ForceFlush(
+ std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override
+ {
+ return false;
+ }
+
+ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override
+ {
+ return true;
+ }
+
+ size_t GetDataCount() { return records_.size(); }
+
+private:
+ std::vector<ResourceMetrics> records_;
+};
+
+class MockMetricProducer : public MetricProducer
+{
+public:
+ MockMetricProducer(std::chrono::microseconds sleep_ms = std::chrono::microseconds::zero())
+ : sleep_ms_{sleep_ms}, data_sent_size_(0)
+ {}
+
+ bool Collect(nostd::function_ref<bool(ResourceMetrics &)> callback) noexcept override
+ {
+ std::this_thread::sleep_for(sleep_ms_);
+ data_sent_size_++;
+ ResourceMetrics data;
+ callback(data);
+ return true;
+ }
+
+ size_t GetDataCount() { return data_sent_size_; }
+
+private:
+ std::chrono::microseconds sleep_ms_;
+ size_t data_sent_size_;
+};
+
+TEST(PeriodicExporingMetricReader, BasicTests)
+{
+ std::unique_ptr<MetricExporter> exporter(new MockPushMetricExporter());
+ PeriodicExportingMetricReaderOptions options;
+ options.export_timeout_millis = std::chrono::milliseconds(200);
+ options.export_interval_millis = std::chrono::milliseconds(500);
+ auto exporter_ptr = exporter.get();
+ PeriodicExportingMetricReader reader(std::move(exporter), options);
+ MockMetricProducer producer;
+ reader.SetMetricProducer(&producer);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2000));
+ reader.Shutdown();
+ EXPECT_EQ(static_cast<MockPushMetricExporter *>(exporter_ptr)->GetDataCount(),
+ static_cast<MockMetricProducer *>(&producer)->GetDataCount());
+}
+
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_instruments_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_instruments_test.cc
new file mode 100644
index 000000000..1a590d8d2
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_instruments_test.cc
@@ -0,0 +1,138 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/sync_instruments.h"
+# include "opentelemetry/context/context.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h"
+# include "opentelemetry/sdk/metrics/state/multi_metric_storage.h"
+
+# include <gtest/gtest.h>
+# include <cmath>
+# include <limits>
+
+using namespace opentelemetry;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+using namespace opentelemetry::sdk::metrics;
+
+auto instrumentation_library = InstrumentationLibrary::Create("opentelemetry-cpp", "0.1.0");
+
+using M = std::map<std::string, std::string>;
+
+TEST(SyncInstruments, LongCounter)
+{
+ InstrumentDescriptor instrument_descriptor = {
+ "long_counter", "description", "1", InstrumentType::kCounter, InstrumentValueType::kLong};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ LongCounter counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Add(10l));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::context::Context{}));
+
+ EXPECT_NO_THROW(counter.Add(
+ 10l, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}})));
+ EXPECT_NO_THROW(counter.Add(
+ 10l, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::common::KeyValueIterableView<M>({})));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+}
+
+TEST(SyncInstruments, DoubleCounter)
+{
+ InstrumentDescriptor instrument_descriptor = {
+ "double_counter", "description", "1", InstrumentType::kCounter, InstrumentValueType::kDouble};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ DoubleCounter counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Add(10.10));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::context::Context{}));
+
+ EXPECT_NO_THROW(counter.Add(
+ 10.10, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}})));
+ EXPECT_NO_THROW(counter.Add(
+ 10.10, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::common::KeyValueIterableView<M>({})));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+}
+
+TEST(SyncInstruments, LongUpDownCounter)
+{
+ InstrumentDescriptor instrument_descriptor = {"long_updowncounter", "description", "1",
+ InstrumentType::kUpDownCounter,
+ InstrumentValueType::kLong};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ LongUpDownCounter counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Add(10l));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::context::Context{}));
+
+ EXPECT_NO_THROW(counter.Add(
+ 10l, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}})));
+ EXPECT_NO_THROW(counter.Add(
+ 10l, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::common::KeyValueIterableView<M>({})));
+ EXPECT_NO_THROW(counter.Add(10l, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+}
+
+TEST(SyncInstruments, DoubleUpDownCounter)
+{
+ InstrumentDescriptor instrument_descriptor = {"double_updowncounter", "description", "1",
+ InstrumentType::kUpDownCounter,
+ InstrumentValueType::kDouble};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ DoubleUpDownCounter counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Add(10.10));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::context::Context{}));
+
+ EXPECT_NO_THROW(counter.Add(
+ 10.10, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Add(
+ 10.10, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}})));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Add(10.10, opentelemetry::common::KeyValueIterableView<M>({})));
+}
+
+TEST(SyncInstruments, LongHistogram)
+{
+ InstrumentDescriptor instrument_descriptor = {
+ "long_histogram", "description", "1", InstrumentType::kHistogram, InstrumentValueType::kLong};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ LongHistogram counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Record(10l, opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Record(-10l, opentelemetry::context::Context{})); // This is ignored
+
+ EXPECT_NO_THROW(counter.Record(
+ 10l, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Record(10l, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+}
+
+TEST(SyncInstruments, DoubleHistogram)
+{
+ InstrumentDescriptor instrument_descriptor = {"double_histogram", "description", "1",
+ InstrumentType::kHistogram,
+ InstrumentValueType::kDouble};
+ std::unique_ptr<WritableMetricStorage> metric_storage(new MultiMetricStorage());
+ DoubleHistogram counter(instrument_descriptor, std::move(metric_storage));
+ EXPECT_NO_THROW(counter.Record(10.10, opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Record(-10.10, opentelemetry::context::Context{})); // This is ignored.
+ EXPECT_NO_THROW(counter.Record(std::numeric_limits<double>::quiet_NaN(),
+ opentelemetry::context::Context{})); // This is ignored too
+ EXPECT_NO_THROW(counter.Record(std::numeric_limits<double>::infinity(),
+ opentelemetry::context::Context{})); // This is ignored too
+
+ EXPECT_NO_THROW(counter.Record(
+ 10.10, opentelemetry::common::KeyValueIterableView<M>({{"abc", "123"}, {"xyz", "456"}}),
+ opentelemetry::context::Context{}));
+ EXPECT_NO_THROW(counter.Record(10.10, opentelemetry::common::KeyValueIterableView<M>({}),
+ opentelemetry::context::Context{}));
+}
+
+#endif \ No newline at end of file
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_metric_storage_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_metric_storage_test.cc
new file mode 100644
index 000000000..7dfc4f947
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/sync_metric_storage_test.cc
@@ -0,0 +1,246 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/state/sync_metric_storage.h"
+# include "opentelemetry/common/key_value_iterable_view.h"
+# include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/view/attributes_processor.h"
+
+# include <gtest/gtest.h>
+# include <map>
+
+using namespace opentelemetry::sdk::metrics;
+using namespace opentelemetry::common;
+using M = std::map<std::string, std::string>;
+
+class MockCollectorHandle : public CollectorHandle
+{
+public:
+ MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {}
+
+ AggregationTemporality GetAggregationTemporality() noexcept override { return temporality; }
+
+private:
+ AggregationTemporality temporality;
+};
+
+class WritableMetricStorageTestFixture : public ::testing::TestWithParam<AggregationTemporality>
+{};
+
+TEST_P(WritableMetricStorageTestFixture, LongSumAggregation)
+{
+ AggregationTemporality temporality = GetParam();
+ auto sdk_start_ts = std::chrono::system_clock::now();
+ long expected_total_get_requests = 0;
+ long expected_total_put_requests = 0;
+ InstrumentDescriptor instr_desc = {"name", "desc", "1unit", InstrumentType::kCounter,
+ InstrumentValueType::kLong};
+ std::map<std::string, std::string> attributes_get = {{"RequestType", "GET"}};
+ std::map<std::string, std::string> attributes_put = {{"RequestType", "PUT"}};
+
+ opentelemetry::sdk::metrics::SyncMetricStorage storage(
+ instr_desc, AggregationType::kSum, new DefaultAttributesProcessor(),
+ NoExemplarReservoir::GetNoExemplarReservoir());
+
+ storage.RecordLong(10l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{});
+ expected_total_get_requests += 10;
+
+ EXPECT_NO_THROW(storage.RecordLong(
+ 30l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 30;
+
+ storage.RecordLong(20l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{});
+ expected_total_get_requests += 20;
+
+ EXPECT_NO_THROW(storage.RecordLong(
+ 40l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 40;
+
+ std::shared_ptr<CollectorHandle> collector(new MockCollectorHandle(temporality));
+ std::vector<std::shared_ptr<CollectorHandle>> collectors;
+ collectors.push_back(collector);
+
+ // Some computation here
+ auto collection_ts = std::chrono::system_clock::now();
+ size_t count_attributes = 0;
+ storage.Collect(
+ collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) {
+ for (auto data_attr : data.point_data_attr_)
+ {
+ auto data = opentelemetry::nostd::get<SumPointData>(data_attr.point_data);
+ if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "GET")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_), expected_total_get_requests);
+ count_attributes++;
+ }
+ else if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "PUT")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_), expected_total_put_requests);
+ count_attributes++;
+ }
+ }
+ return true;
+ });
+
+ // In case of delta temporarily, subsequent collection would contain new data points, so resetting
+ // the counts
+ if (temporality == AggregationTemporality::kDelta)
+ {
+ expected_total_get_requests = 0;
+ expected_total_put_requests = 0;
+ }
+
+ EXPECT_NO_THROW(storage.RecordLong(
+ 50l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{}));
+ expected_total_get_requests += 50;
+ EXPECT_NO_THROW(storage.RecordLong(
+ 40l, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 40;
+
+ collection_ts = std::chrono::system_clock::now();
+ count_attributes = 0;
+ storage.Collect(
+ collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) {
+ for (auto data_attr : data.point_data_attr_)
+ {
+ auto data = opentelemetry::nostd::get<SumPointData>(data_attr.point_data);
+ if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "GET")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_), expected_total_get_requests);
+ count_attributes++;
+ }
+ else if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "PUT")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<long>(data.value_), expected_total_put_requests);
+ count_attributes++;
+ }
+ }
+ return true;
+ });
+}
+INSTANTIATE_TEST_SUITE_P(WritableMetricStorageTestLong,
+ WritableMetricStorageTestFixture,
+ ::testing::Values(AggregationTemporality::kCumulative,
+ AggregationTemporality::kDelta));
+
+TEST_P(WritableMetricStorageTestFixture, DoubleSumAggregation)
+{
+ AggregationTemporality temporality = GetParam();
+ auto sdk_start_ts = std::chrono::system_clock::now();
+ double expected_total_get_requests = 0;
+ double expected_total_put_requests = 0;
+ InstrumentDescriptor instr_desc = {"name", "desc", "1unit", InstrumentType::kCounter,
+ InstrumentValueType::kDouble};
+ std::map<std::string, std::string> attributes_get = {{"RequestType", "GET"}};
+ std::map<std::string, std::string> attributes_put = {{"RequestType", "PUT"}};
+
+ opentelemetry::sdk::metrics::SyncMetricStorage storage(
+ instr_desc, AggregationType::kSum, new DefaultAttributesProcessor(),
+ NoExemplarReservoir::GetNoExemplarReservoir());
+
+ storage.RecordDouble(10.0,
+ KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{});
+ expected_total_get_requests += 10;
+
+ EXPECT_NO_THROW(storage.RecordDouble(
+ 30.0, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 30;
+
+ storage.RecordDouble(20.0,
+ KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{});
+ expected_total_get_requests += 20;
+
+ EXPECT_NO_THROW(storage.RecordDouble(
+ 40.0, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 40;
+
+ std::shared_ptr<CollectorHandle> collector(new MockCollectorHandle(temporality));
+ std::vector<std::shared_ptr<CollectorHandle>> collectors;
+ collectors.push_back(collector);
+
+ // Some computation here
+ auto collection_ts = std::chrono::system_clock::now();
+ size_t count_attributes = 0;
+ storage.Collect(
+ collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) {
+ for (auto data_attr : data.point_data_attr_)
+ {
+ auto data = opentelemetry::nostd::get<SumPointData>(data_attr.point_data);
+ if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "GET")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<double>(data.value_), expected_total_get_requests);
+ count_attributes++;
+ }
+ else if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "PUT")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<double>(data.value_), expected_total_put_requests);
+ count_attributes++;
+ }
+ }
+ return true;
+ });
+
+ // In case of delta temporarily, subsequent collection would contain new data points, so resetting
+ // the counts
+ if (temporality == AggregationTemporality::kDelta)
+ {
+ expected_total_get_requests = 0;
+ expected_total_put_requests = 0;
+ }
+
+ EXPECT_NO_THROW(storage.RecordDouble(
+ 50.0, KeyValueIterableView<std::map<std::string, std::string>>(attributes_get),
+ opentelemetry::context::Context{}));
+ expected_total_get_requests += 50;
+ EXPECT_NO_THROW(storage.RecordDouble(
+ 40.0, KeyValueIterableView<std::map<std::string, std::string>>(attributes_put),
+ opentelemetry::context::Context{}));
+ expected_total_put_requests += 40;
+
+ collection_ts = std::chrono::system_clock::now();
+ count_attributes = 0;
+ storage.Collect(
+ collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) {
+ for (auto data_attr : data.point_data_attr_)
+ {
+ auto data = opentelemetry::nostd::get<SumPointData>(data_attr.point_data);
+ if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "GET")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<double>(data.value_), expected_total_get_requests);
+ count_attributes++;
+ }
+ else if (opentelemetry::nostd::get<std::string>(
+ data_attr.attributes.find("RequestType")->second) == "PUT")
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<double>(data.value_), expected_total_put_requests);
+ count_attributes++;
+ }
+ }
+ return true;
+ });
+}
+INSTANTIATE_TEST_SUITE_P(WritableMetricStorageTestDouble,
+ WritableMetricStorageTestFixture,
+ ::testing::Values(AggregationTemporality::kCumulative,
+ AggregationTemporality::kDelta));
+
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/view_registry_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/view_registry_test.cc
new file mode 100644
index 000000000..8151d3754
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/metrics/view_registry_test.cc
@@ -0,0 +1,82 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef ENABLE_METRICS_PREVIEW
+# include "opentelemetry/sdk/metrics/view/view_registry.h"
+# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h"
+# include "opentelemetry/sdk/metrics/instruments.h"
+# include "opentelemetry/sdk/metrics/view/predicate.h"
+
+# include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::metrics;
+using namespace opentelemetry::sdk::instrumentationlibrary;
+
+TEST(ViewRegistry, FindViewsEmptyRegistry)
+{
+ InstrumentDescriptor default_instrument_descriptor = {
+ "test_name", // name
+ "test_descr", // description
+ "1", // unit
+ InstrumentType::kCounter, // instrument type
+ InstrumentValueType::kLong};
+
+ auto default_instrumentation_lib =
+ InstrumentationLibrary::Create("default", "1.0.0", "https://opentelemetry.io/schemas/1.7.0");
+ int count = 0;
+ ViewRegistry registry;
+ auto status =
+ registry.FindViews(default_instrument_descriptor, *default_instrumentation_lib.get(),
+ [&count](const View &view) {
+ count++;
+ EXPECT_EQ(view.GetName(), "otel-default-view");
+ EXPECT_EQ(view.GetDescription(), "");
+ EXPECT_EQ(view.GetAggregationType(), AggregationType::kDefault);
+ return true;
+ });
+ EXPECT_EQ(count, 1);
+ EXPECT_EQ(status, true);
+}
+
+TEST(ViewRegistry, FindNonExistingView)
+{
+ // Add view
+ const std::string view_name = "test_view";
+ const std::string view_description = "test description";
+ const std::string instrumentation_name = "name1";
+ const std::string instrumentation_version = "version1";
+ const std::string instrumentation_schema = "schema1";
+ const std::string instrument_name = "testname";
+ const InstrumentType instrument_type = InstrumentType::kCounter;
+
+ std::unique_ptr<InstrumentSelector> instrument_selector{
+ new InstrumentSelector(instrument_type, instrument_name)};
+ std::unique_ptr<MeterSelector> meter_selector{
+ new MeterSelector(instrumentation_name, instrumentation_version, instrumentation_schema)};
+ std::unique_ptr<View> view = std::unique_ptr<View>(new View(view_name, view_description));
+
+ ViewRegistry registry;
+ registry.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view));
+ InstrumentDescriptor default_instrument_descriptor = {instrument_name, // name
+ "test_descr", // description
+ "1", // unit
+ instrument_type, // instrument type
+ InstrumentValueType::kLong};
+
+ auto default_instrumentation_lib = InstrumentationLibrary::Create(
+ instrumentation_name, instrumentation_version, instrumentation_schema);
+ int count = 0;
+ auto status =
+ registry.FindViews(default_instrument_descriptor, *default_instrumentation_lib.get(),
+ [&count, &view_name, &view_description](const View &view) {
+ count++;
+# if HAVE_WORKING_REGEX
+ EXPECT_EQ(view.GetName(), view_name);
+ EXPECT_EQ(view.GetDescription(), view_description);
+# endif
+ return true;
+ });
+ EXPECT_EQ(count, 1);
+ EXPECT_EQ(status, true);
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/BUILD
new file mode 100644
index 000000000..e70f16ee7
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/BUILD
@@ -0,0 +1,12 @@
+cc_test(
+ name = "resource_test",
+ srcs = [
+ "resource_test.cc",
+ ],
+ tags = ["test"],
+ deps = [
+ "//api",
+ "//sdk/src/resource",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/CMakeLists.txt
new file mode 100644
index 000000000..514b98680
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/CMakeLists.txt
@@ -0,0 +1,9 @@
+foreach(testname resource_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT} opentelemetry_resources)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX resources.
+ TEST_LIST ${testname})
+endforeach()
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/resource_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/resource_test.cc
new file mode 100644
index 000000000..5f058eafb
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/resource/resource_test.cc
@@ -0,0 +1,213 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/common/key_value_iterable_view.h"
+#include "opentelemetry/nostd/string_view.h"
+#include "opentelemetry/sdk/common/attribute_utils.h"
+#include "opentelemetry/sdk/resource/experimental_semantic_conventions.h"
+#include "opentelemetry/sdk/resource/resource_detector.h"
+
+#include <cstdlib>
+#include <string>
+#include <unordered_map>
+
+#include <gtest/gtest.h>
+
+#if defined(_MSC_VER)
+# include "opentelemetry/sdk/common/env_variables.h"
+using opentelemetry::sdk::common::setenv;
+using opentelemetry::sdk::common::unsetenv;
+#endif
+
+using namespace opentelemetry::sdk::resource;
+namespace nostd = opentelemetry::nostd;
+
+class TestResource : public Resource
+{
+public:
+ TestResource(ResourceAttributes attributes = ResourceAttributes()) : Resource(attributes) {}
+};
+
+TEST(ResourceTest, create_without_servicename)
+{
+ ResourceAttributes expected_attributes = {
+ {"service", "backend"},
+ {"version", (uint32_t)1},
+ {"cost", 234.23},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkLanguage), "cpp"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkName), "opentelemetry"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkVersion), OPENTELEMETRY_SDK_VERSION},
+ {OTEL_GET_RESOURCE_ATTR(AttrServiceName), "unknown_service"}};
+
+ ResourceAttributes attributes = {
+ {"service", "backend"}, {"version", (uint32_t)1}, {"cost", 234.23}};
+ auto resource = Resource::Create(attributes);
+ auto received_attributes = resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ if (e.first == "version")
+ EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),
+ nostd::get<uint32_t>(e.second));
+ else if (e.first == "cost")
+ EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),
+ nostd::get<double>(e.second));
+ else
+ EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),
+ opentelemetry::nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
+}
+
+TEST(ResourceTest, create_with_servicename)
+{
+ ResourceAttributes expected_attributes = {
+ {"version", (uint32_t)1},
+ {"cost", 234.23},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkLanguage), "cpp"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkName), "opentelemetry"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkVersion), OPENTELEMETRY_SDK_VERSION},
+ {OTEL_GET_RESOURCE_ATTR(AttrServiceName), "backend"},
+ };
+ ResourceAttributes attributes = {
+ {"service.name", "backend"}, {"version", (uint32_t)1}, {"cost", 234.23}};
+ auto resource = Resource::Create(attributes);
+ auto received_attributes = resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ if (e.first == "version")
+ EXPECT_EQ(nostd::get<uint32_t>(expected_attributes.find(e.first)->second),
+ nostd::get<uint32_t>(e.second));
+ else if (e.first == "cost")
+ EXPECT_EQ(nostd::get<double>(expected_attributes.find(e.first)->second),
+ nostd::get<double>(e.second));
+ else
+ EXPECT_EQ(nostd::get<std::string>(expected_attributes.find(e.first)->second),
+ nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
+}
+
+TEST(ResourceTest, create_with_emptyatrributes)
+{
+ ResourceAttributes expected_attributes = {
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkLanguage), "cpp"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkName), "opentelemetry"},
+ {OTEL_GET_RESOURCE_ATTR(AttrTelemetrySdkVersion), OPENTELEMETRY_SDK_VERSION},
+ {OTEL_GET_RESOURCE_ATTR(AttrServiceName), "unknown_service"},
+ };
+ ResourceAttributes attributes = {};
+ auto resource = Resource::Create(attributes);
+ auto received_attributes = resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ EXPECT_EQ(opentelemetry::nostd::get<std::string>(expected_attributes.find(e.first)->second),
+ opentelemetry::nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size()); // for missing service.name
+}
+
+TEST(ResourceTest, create_with_schemaurl)
+{
+ const std::string schema_url = "https://opentelemetry.io/schemas/1.2.0";
+ ResourceAttributes attributes = {};
+ auto resource = Resource::Create(attributes, schema_url);
+ auto received_schema_url = resource.GetSchemaURL();
+
+ EXPECT_EQ(received_schema_url, schema_url);
+}
+
+TEST(ResourceTest, Merge)
+{
+ TestResource resource1(ResourceAttributes({{"service", "backend"}}));
+ TestResource resource2(ResourceAttributes({{"host", "service-host"}}));
+ std::map<std::string, std::string> expected_attributes = {{"service", "backend"},
+ {"host", "service-host"}};
+
+ auto merged_resource = resource1.Merge(resource2);
+ auto received_attributes = merged_resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size());
+}
+
+TEST(ResourceTest, MergeEmptyString)
+{
+ TestResource resource1({{"service", "backend"}, {"host", "service-host"}});
+ TestResource resource2({{"service", ""}, {"host", "another-service-host"}});
+ std::map<std::string, std::string> expected_attributes = {{"service", ""},
+ {"host", "another-service-host"}};
+
+ auto merged_resource = resource1.Merge(resource2);
+ auto received_attributes = merged_resource.GetAttributes();
+
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size());
+}
+
+#ifndef NO_GETENV
+TEST(ResourceTest, OtelResourceDetector)
+{
+ std::map<std::string, std::string> expected_attributes = {{"k", "v"}};
+
+ setenv("OTEL_RESOURCE_ATTRIBUTES", "k=v", 1);
+
+ OTELResourceDetector detector;
+ auto resource = detector.Detect();
+ auto received_attributes = resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size());
+
+ unsetenv("OTEL_RESOURCE_ATTRIBUTES");
+}
+
+TEST(ResourceTest, OtelResourceDetectorEmptyEnv)
+{
+ std::map<std::string, std::string> expected_attributes = {};
+ unsetenv("OTEL_RESOURCE_ATTRIBUTES");
+ OTELResourceDetector detector;
+ auto resource = detector.Detect();
+ auto received_attributes = resource.GetAttributes();
+ for (auto &e : received_attributes)
+ {
+ EXPECT_TRUE(expected_attributes.find(e.first) != expected_attributes.end());
+ if (expected_attributes.find(e.first) != expected_attributes.end())
+ {
+ EXPECT_EQ(expected_attributes.find(e.first)->second, nostd::get<std::string>(e.second));
+ }
+ }
+ EXPECT_EQ(received_attributes.size(), expected_attributes.size());
+}
+#endif
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/BUILD b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/BUILD
new file mode 100644
index 000000000..70e517684
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/BUILD
@@ -0,0 +1,155 @@
+load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
+
+cc_test(
+ name = "tracer_provider_test",
+ srcs = [
+ "tracer_provider_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/resource",
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "span_data_test",
+ srcs = [
+ "span_data_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "simple_processor_test",
+ srcs = [
+ "simple_processor_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//exporters/memory:in_memory_span_exporter",
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "batch_span_processor_test",
+ srcs = [
+ "batch_span_processor_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "tracer_test",
+ srcs = [
+ "tracer_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//exporters/memory:in_memory_span_exporter",
+ "//sdk/src/resource",
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "always_on_sampler_test",
+ srcs = [
+ "always_on_sampler_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "always_off_sampler_test",
+ srcs = [
+ "always_off_sampler_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "parent_sampler_test",
+ srcs = [
+ "parent_sampler_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "trace_id_ratio_sampler_test",
+ srcs = [
+ "trace_id_ratio_sampler_test.cc",
+ ],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//sdk/src/common:random",
+ "//sdk/src/trace",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+otel_cc_benchmark(
+ name = "sampler_benchmark",
+ srcs = ["sampler_benchmark.cc"],
+ tags = [
+ "test",
+ "trace",
+ ],
+ deps = [
+ "//exporters/memory:in_memory_span_exporter",
+ "//sdk/src/resource",
+ "//sdk/src/trace",
+ ],
+)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/CMakeLists.txt b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/CMakeLists.txt
new file mode 100644
index 000000000..b02ff705f
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/CMakeLists.txt
@@ -0,0 +1,30 @@
+foreach(
+ testname
+ tracer_provider_test
+ span_data_test
+ simple_processor_test
+ tracer_test
+ always_off_sampler_test
+ always_on_sampler_test
+ parent_sampler_test
+ trace_id_ratio_sampler_test
+ batch_span_processor_test)
+ add_executable(${testname} "${testname}.cc")
+ target_link_libraries(
+ ${testname}
+ ${GTEST_BOTH_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ opentelemetry_common
+ opentelemetry_trace
+ opentelemetry_resources
+ opentelemetry_exporter_in_memory)
+ gtest_add_tests(
+ TARGET ${testname}
+ TEST_PREFIX trace.
+ TEST_LIST ${testname})
+endforeach()
+
+add_executable(sampler_benchmark sampler_benchmark.cc)
+target_link_libraries(
+ sampler_benchmark benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT}
+ opentelemetry_trace opentelemetry_resources opentelemetry_exporter_in_memory)
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_off_sampler_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_off_sampler_test.cc
new file mode 100644
index 000000000..1c32bd5a8
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_off_sampler_test.cc
@@ -0,0 +1,42 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <gtest/gtest.h>
+#include "opentelemetry/sdk/trace/samplers/always_off.h"
+#include "opentelemetry/trace/span_context_kv_iterable_view.h"
+
+using opentelemetry::sdk::trace::AlwaysOffSampler;
+using opentelemetry::sdk::trace::Decision;
+using opentelemetry::trace::SpanContext;
+namespace trace_api = opentelemetry::trace;
+
+TEST(AlwaysOffSampler, ShouldSample)
+{
+ AlwaysOffSampler sampler;
+
+ trace_api::TraceId trace_id;
+ trace_api::SpanKind span_kind = trace_api::SpanKind::kInternal;
+
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{SpanContext(false, false), {}}, {SpanContext(false, false), {}}};
+
+ opentelemetry::common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+
+ auto sampling_result =
+ sampler.ShouldSample(SpanContext::GetInvalid(), trace_id, "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::DROP, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+ ASSERT_EQ("", sampling_result.trace_state->ToHeader());
+}
+
+TEST(AlwaysOffSampler, GetDescription)
+{
+ AlwaysOffSampler sampler;
+
+ ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription());
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_on_sampler_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_on_sampler_test.cc
new file mode 100644
index 000000000..c483f9b8b
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/always_on_sampler_test.cc
@@ -0,0 +1,60 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/trace/span_context_kv_iterable_view.h"
+
+#include <gtest/gtest.h>
+#include <map>
+
+using namespace opentelemetry::sdk::trace;
+using namespace opentelemetry::nostd;
+using opentelemetry::trace::SpanContext;
+namespace trace_api = opentelemetry::trace;
+
+TEST(AlwaysOnSampler, ShouldSample)
+{
+ AlwaysOnSampler sampler;
+
+ // A buffer of trace_id with no specific meaning
+ constexpr uint8_t buf[] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
+
+ trace_api::TraceId trace_id_invalid;
+ trace_api::TraceId trace_id_valid(buf);
+ std::map<std::string, int> key_value_container = {{"key", 0}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ opentelemetry::trace::SpanContextKeyValueIterableView<L> links{l1};
+
+ // Test with invalid (empty) trace id and empty parent context
+ auto sampling_result = sampler.ShouldSample(
+ SpanContext::GetInvalid(), trace_id_invalid, "invalid trace id test",
+ trace_api::SpanKind::kServer,
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>>(key_value_container),
+ links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+ ASSERT_EQ("", sampling_result.trace_state->ToHeader());
+
+ // Test with a valid trace id and empty parent context
+ sampling_result = sampler.ShouldSample(
+ SpanContext::GetInvalid(), trace_id_valid, "valid trace id test",
+ trace_api::SpanKind::kServer,
+ opentelemetry::common::KeyValueIterableView<std::map<std::string, int>>(key_value_container),
+ links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+ ASSERT_EQ("", sampling_result.trace_state->ToHeader());
+}
+
+TEST(AlwaysOnSampler, GetDescription)
+{
+ AlwaysOnSampler sampler;
+
+ ASSERT_EQ("AlwaysOnSampler", sampler.GetDescription());
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/batch_span_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/batch_span_processor_test.cc
new file mode 100644
index 000000000..0e6f9c35a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/batch_span_processor_test.cc
@@ -0,0 +1,291 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/batch_span_processor.h"
+#include "opentelemetry/sdk/trace/span_data.h"
+#include "opentelemetry/sdk/trace/tracer.h"
+
+#include <gtest/gtest.h>
+#include <chrono>
+#include <thread>
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+
+/**
+ * Returns a mock span exporter meant exclusively for testing only
+ */
+class MockSpanExporter final : public sdk::trace::SpanExporter
+{
+public:
+ MockSpanExporter(
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received,
+ std::shared_ptr<std::atomic<bool>> is_shutdown,
+ std::shared_ptr<std::atomic<bool>> is_export_completed =
+ std::shared_ptr<std::atomic<bool>>(new std::atomic<bool>(false)),
+ const std::chrono::milliseconds export_delay = std::chrono::milliseconds(0)) noexcept
+ : spans_received_(spans_received),
+ is_shutdown_(is_shutdown),
+ is_export_completed_(is_export_completed),
+ export_delay_(export_delay)
+ {}
+
+ std::unique_ptr<sdk::trace::Recordable> MakeRecordable() noexcept override
+ {
+ return std::unique_ptr<sdk::trace::Recordable>(new sdk::trace::SpanData);
+ }
+
+ sdk::common::ExportResult Export(
+ const nostd::span<std::unique_ptr<sdk::trace::Recordable>> &recordables) noexcept override
+ {
+ *is_export_completed_ = false;
+
+ std::this_thread::sleep_for(export_delay_);
+
+ for (auto &recordable : recordables)
+ {
+ auto span = std::unique_ptr<sdk::trace::SpanData>(
+ static_cast<sdk::trace::SpanData *>(recordable.release()));
+
+ if (span != nullptr)
+ {
+ spans_received_->push_back(std::move(span));
+ }
+ }
+
+ *is_export_completed_ = true;
+ return sdk::common::ExportResult::kSuccess;
+ }
+
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override
+ {
+ *is_shutdown_ = true;
+ return true;
+ }
+
+ bool IsExportCompleted() { return is_export_completed_->load(); }
+
+private:
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received_;
+ std::shared_ptr<std::atomic<bool>> is_shutdown_;
+ std::shared_ptr<std::atomic<bool>> is_export_completed_;
+ // Meant exclusively to test force flush timeout
+ const std::chrono::milliseconds export_delay_;
+};
+
+/**
+ * Fixture Class
+ */
+class BatchSpanProcessorTestPeer : public testing::Test
+{
+public:
+ std::unique_ptr<std::vector<std::unique_ptr<sdk::trace::Recordable>>> GetTestSpans(
+ std::shared_ptr<sdk::trace::SpanProcessor> processor,
+ const int num_spans)
+ {
+ std::unique_ptr<std::vector<std::unique_ptr<sdk::trace::Recordable>>> test_spans(
+ new std::vector<std::unique_ptr<sdk::trace::Recordable>>);
+
+ for (int i = 0; i < num_spans; ++i)
+ {
+ test_spans->push_back(processor->MakeRecordable());
+ static_cast<sdk::trace::SpanData *>(test_spans->at(i).get())
+ ->SetName("Span " + std::to_string(i));
+ }
+
+ return test_spans;
+ }
+};
+
+/* ################################## TESTS ############################################ */
+
+TEST_F(BatchSpanProcessorTestPeer, TestShutdown)
+{
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received(
+ new std::vector<std::unique_ptr<sdk::trace::SpanData>>);
+
+ auto batch_processor =
+ std::shared_ptr<sdk::trace::BatchSpanProcessor>(new sdk::trace::BatchSpanProcessor(
+ std::unique_ptr<MockSpanExporter>(new MockSpanExporter(spans_received, is_shutdown)),
+ sdk::trace::BatchSpanProcessorOptions()));
+ const int num_spans = 3;
+
+ auto test_spans = GetTestSpans(batch_processor, num_spans);
+
+ for (int i = 0; i < num_spans; ++i)
+ {
+ batch_processor->OnEnd(std::move(test_spans->at(i)));
+ }
+
+ EXPECT_TRUE(batch_processor->Shutdown());
+ // It's safe to shutdown again
+ EXPECT_TRUE(batch_processor->Shutdown());
+
+ EXPECT_EQ(num_spans, spans_received->size());
+ for (int i = 0; i < num_spans; ++i)
+ {
+ EXPECT_EQ("Span " + std::to_string(i), spans_received->at(i)->GetName());
+ }
+
+ EXPECT_TRUE(is_shutdown->load());
+}
+
+TEST_F(BatchSpanProcessorTestPeer, TestForceFlush)
+{
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received(
+ new std::vector<std::unique_ptr<sdk::trace::SpanData>>);
+
+ auto batch_processor =
+ std::shared_ptr<sdk::trace::BatchSpanProcessor>(new sdk::trace::BatchSpanProcessor(
+ std::unique_ptr<MockSpanExporter>(new MockSpanExporter(spans_received, is_shutdown)),
+ sdk::trace::BatchSpanProcessorOptions()));
+ const int num_spans = 2048;
+
+ auto test_spans = GetTestSpans(batch_processor, num_spans);
+
+ for (int i = 0; i < num_spans; ++i)
+ {
+ batch_processor->OnEnd(std::move(test_spans->at(i)));
+ }
+
+ // Give some time to export
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_spans, spans_received->size());
+ for (int i = 0; i < num_spans; ++i)
+ {
+ EXPECT_EQ("Span " + std::to_string(i), spans_received->at(i)->GetName());
+ }
+
+ // Create some more spans to make sure that the processor still works
+ auto more_test_spans = GetTestSpans(batch_processor, num_spans);
+ for (int i = 0; i < num_spans; ++i)
+ {
+ batch_processor->OnEnd(std::move(more_test_spans->at(i)));
+ }
+
+ // Give some time to export the spans
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_spans * 2, spans_received->size());
+ for (int i = 0; i < num_spans; ++i)
+ {
+ EXPECT_EQ("Span " + std::to_string(i % num_spans),
+ spans_received->at(num_spans + i)->GetName());
+ }
+}
+
+TEST_F(BatchSpanProcessorTestPeer, TestManySpansLoss)
+{
+ /* Test that when exporting more than max_queue_size spans, some are most likely lost*/
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received(
+ new std::vector<std::unique_ptr<sdk::trace::SpanData>>);
+
+ const int max_queue_size = 4096;
+
+ auto batch_processor =
+ std::shared_ptr<sdk::trace::BatchSpanProcessor>(new sdk::trace::BatchSpanProcessor(
+ std::unique_ptr<MockSpanExporter>(new MockSpanExporter(spans_received, is_shutdown)),
+ sdk::trace::BatchSpanProcessorOptions()));
+
+ auto test_spans = GetTestSpans(batch_processor, max_queue_size);
+
+ for (int i = 0; i < max_queue_size; ++i)
+ {
+ batch_processor->OnEnd(std::move(test_spans->at(i)));
+ }
+
+ // Give some time to export the spans
+ std::this_thread::sleep_for(std::chrono::milliseconds(700));
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ // Span should be exported by now
+ EXPECT_GE(max_queue_size, spans_received->size());
+}
+
+TEST_F(BatchSpanProcessorTestPeer, TestManySpansLossLess)
+{
+ /* Test that no spans are lost when sending max_queue_size spans */
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received(
+ new std::vector<std::unique_ptr<sdk::trace::SpanData>>);
+
+ const int num_spans = 2048;
+
+ auto batch_processor =
+ std::shared_ptr<sdk::trace::BatchSpanProcessor>(new sdk::trace::BatchSpanProcessor(
+ std::unique_ptr<MockSpanExporter>(new MockSpanExporter(spans_received, is_shutdown)),
+ sdk::trace::BatchSpanProcessorOptions()));
+
+ auto test_spans = GetTestSpans(batch_processor, num_spans);
+
+ for (int i = 0; i < num_spans; ++i)
+ {
+ batch_processor->OnEnd(std::move(test_spans->at(i)));
+ }
+
+ // Give some time to export the spans
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ EXPECT_TRUE(batch_processor->ForceFlush());
+
+ EXPECT_EQ(num_spans, spans_received->size());
+ for (int i = 0; i < num_spans; ++i)
+ {
+ EXPECT_EQ("Span " + std::to_string(i), spans_received->at(i)->GetName());
+ }
+}
+
+TEST_F(BatchSpanProcessorTestPeer, TestScheduleDelayMillis)
+{
+ /* Test that max_export_batch_size spans are exported every schedule_delay_millis
+ seconds */
+
+ std::shared_ptr<std::atomic<bool>> is_shutdown(new std::atomic<bool>(false));
+ std::shared_ptr<std::atomic<bool>> is_export_completed(new std::atomic<bool>(false));
+ std::shared_ptr<std::vector<std::unique_ptr<sdk::trace::SpanData>>> spans_received(
+ new std::vector<std::unique_ptr<sdk::trace::SpanData>>);
+ const std::chrono::milliseconds export_delay(0);
+ const size_t max_export_batch_size = 512;
+ sdk::trace::BatchSpanProcessorOptions options{};
+ options.schedule_delay_millis = std::chrono::milliseconds(2000);
+
+ auto batch_processor =
+ std::shared_ptr<sdk::trace::BatchSpanProcessor>(new sdk::trace::BatchSpanProcessor(
+ std::unique_ptr<MockSpanExporter>(
+ new MockSpanExporter(spans_received, is_shutdown, is_export_completed, export_delay)),
+ options));
+
+ auto test_spans = GetTestSpans(batch_processor, max_export_batch_size);
+
+ for (size_t i = 0; i < max_export_batch_size; ++i)
+ {
+ batch_processor->OnEnd(std::move(test_spans->at(i)));
+ }
+
+ // Sleep for schedule_delay_millis milliseconds
+ std::this_thread::sleep_for(options.schedule_delay_millis);
+
+ // small delay to give time to export
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ // Spans should be exported by now
+ EXPECT_TRUE(is_export_completed->load());
+ EXPECT_EQ(max_export_batch_size, spans_received->size());
+ for (size_t i = 0; i < max_export_batch_size; ++i)
+ {
+ EXPECT_EQ("Span " + std::to_string(i), spans_received->at(i)->GetName());
+ }
+}
+
+OPENTELEMETRY_END_NAMESPACE
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/parent_sampler_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/parent_sampler_test.cc
new file mode 100644
index 000000000..124287598
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/parent_sampler_test.cc
@@ -0,0 +1,73 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include <gtest/gtest.h>
+#include <memory>
+#include "opentelemetry/sdk/trace/samplers/always_off.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/samplers/parent.h"
+#include "opentelemetry/trace/span_context_kv_iterable_view.h"
+
+using opentelemetry::sdk::trace::AlwaysOffSampler;
+using opentelemetry::sdk::trace::AlwaysOnSampler;
+using opentelemetry::sdk::trace::Decision;
+using opentelemetry::sdk::trace::ParentBasedSampler;
+namespace trace_api = opentelemetry::trace;
+
+TEST(ParentBasedSampler, ShouldSample)
+{
+ ParentBasedSampler sampler_off(std::make_shared<AlwaysOffSampler>());
+ ParentBasedSampler sampler_on(std::make_shared<AlwaysOnSampler>());
+
+ // Set up parameters
+ uint8_t trace_id_buffer[trace_api::TraceId::kSize] = {1};
+ trace_api::TraceId trace_id{trace_id_buffer};
+ uint8_t span_id_buffer[trace_api::SpanId::kSize] = {1};
+ trace_api::SpanId span_id{span_id_buffer};
+
+ trace_api::SpanKind span_kind = trace_api::SpanKind::kInternal;
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ opentelemetry::common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+ auto trace_state = trace_api::TraceState::FromHeader("congo=t61rcWkgMzE");
+ trace_api::SpanContext parent_context_sampled(trace_id, span_id, trace_api::TraceFlags{1}, false,
+ trace_state);
+ trace_api::SpanContext parent_context_nonsampled(trace_id, span_id, trace_api::TraceFlags{0},
+ false, trace_state);
+
+ // Case 1: Parent doesn't exist. Return result of delegateSampler()
+ auto sampling_result = sampler_off.ShouldSample(trace_api::SpanContext::GetInvalid(), trace_id,
+ "", span_kind, view, links);
+ auto sampling_result2 = sampler_on.ShouldSample(trace_api::SpanContext::GetInvalid(), trace_id,
+ "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::DROP, sampling_result.decision);
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result2.decision);
+ ASSERT_EQ("", sampling_result.trace_state->ToHeader());
+ ASSERT_EQ("", sampling_result2.trace_state->ToHeader());
+
+ // Case 2: Parent exists and SampledFlag is true
+ auto sampling_result3 =
+ sampler_off.ShouldSample(parent_context_sampled, trace_id, "", span_kind, view, links);
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result3.decision);
+ ASSERT_EQ("congo=t61rcWkgMzE", sampling_result3.trace_state->ToHeader());
+
+ // Case 3: Parent exists and SampledFlag is false
+ auto sampling_result4 =
+ sampler_on.ShouldSample(parent_context_nonsampled, trace_id, "", span_kind, view, links);
+ ASSERT_EQ(Decision::DROP, sampling_result4.decision);
+ ASSERT_EQ("congo=t61rcWkgMzE", sampling_result4.trace_state->ToHeader());
+}
+
+TEST(ParentBasedSampler, GetDescription)
+{
+ ParentBasedSampler sampler(std::make_shared<AlwaysOffSampler>());
+ ASSERT_EQ("ParentBased{AlwaysOffSampler}", sampler.GetDescription());
+ ParentBasedSampler sampler2(std::make_shared<AlwaysOnSampler>());
+ ASSERT_EQ("ParentBased{AlwaysOnSampler}", sampler2.GetDescription());
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc
new file mode 100644
index 000000000..b09cb5b0c
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc
@@ -0,0 +1,156 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/exporters/memory/in_memory_span_exporter.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/sampler.h"
+#include "opentelemetry/sdk/trace/samplers/always_off.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/samplers/parent.h"
+#include "opentelemetry/sdk/trace/samplers/trace_id_ratio.h"
+#include "opentelemetry/sdk/trace/simple_processor.h"
+#include "opentelemetry/sdk/trace/span_data.h"
+#include "opentelemetry/sdk/trace/tracer.h"
+
+#include <cstdint>
+
+#include <benchmark/benchmark.h>
+
+using namespace opentelemetry::sdk::trace;
+using opentelemetry::exporter::memory::InMemorySpanExporter;
+using opentelemetry::trace::SpanContext;
+
+namespace
+{
+// Sampler constructor used as a baseline to compare with other samplers
+void BM_AlwaysOffSamplerConstruction(benchmark::State &state)
+{
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(AlwaysOffSampler());
+ }
+}
+BENCHMARK(BM_AlwaysOffSamplerConstruction);
+
+// Sampler constructor used as a baseline to compare with other samplers
+void BM_AlwaysOnSamplerConstruction(benchmark::State &state)
+{
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(AlwaysOnSampler());
+ }
+}
+BENCHMARK(BM_AlwaysOnSamplerConstruction);
+
+void BM_ParentBasedSamplerConstruction(benchmark::State &state)
+{
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(ParentBasedSampler(std::make_shared<AlwaysOnSampler>()));
+ }
+}
+BENCHMARK(BM_ParentBasedSamplerConstruction);
+
+void BM_TraceIdRatioBasedSamplerConstruction(benchmark::State &state)
+{
+ while (state.KeepRunning())
+ {
+ benchmark::DoNotOptimize(TraceIdRatioBasedSampler(0.01));
+ }
+}
+BENCHMARK(BM_TraceIdRatioBasedSamplerConstruction);
+
+// Sampler Helper Function
+void BenchmarkShouldSampler(Sampler &sampler, benchmark::State &state)
+{
+ opentelemetry::trace::TraceId trace_id;
+ opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal;
+
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ opentelemetry::common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+
+ while (state.KeepRunning())
+ {
+ auto invalid_ctx = SpanContext::GetInvalid();
+ benchmark::DoNotOptimize(
+ sampler.ShouldSample(invalid_ctx, trace_id, "", span_kind, view, links));
+ }
+}
+
+// Sampler used as a baseline to compare with other samplers
+void BM_AlwaysOffSamplerShouldSample(benchmark::State &state)
+{
+ AlwaysOffSampler sampler;
+
+ BenchmarkShouldSampler(sampler, state);
+}
+BENCHMARK(BM_AlwaysOffSamplerShouldSample);
+
+// Sampler used as a baseline to compare with other samplers
+void BM_AlwaysOnSamplerShouldSample(benchmark::State &state)
+{
+ AlwaysOnSampler sampler;
+
+ BenchmarkShouldSampler(sampler, state);
+}
+BENCHMARK(BM_AlwaysOnSamplerShouldSample);
+
+void BM_ParentBasedSamplerShouldSample(benchmark::State &state)
+{
+ ParentBasedSampler sampler(std::make_shared<AlwaysOnSampler>());
+
+ BenchmarkShouldSampler(sampler, state);
+}
+BENCHMARK(BM_ParentBasedSamplerShouldSample);
+
+void BM_TraceIdRatioBasedSamplerShouldSample(benchmark::State &state)
+{
+ TraceIdRatioBasedSampler sampler(0.01);
+
+ BenchmarkShouldSampler(sampler, state);
+}
+BENCHMARK(BM_TraceIdRatioBasedSamplerShouldSample);
+
+// Sampler Helper Function
+void BenchmarkSpanCreation(std::shared_ptr<Sampler> sampler, benchmark::State &state)
+{
+ std::unique_ptr<SpanExporter> exporter(new InMemorySpanExporter());
+ std::unique_ptr<SpanProcessor> processor(new SimpleSpanProcessor(std::move(exporter)));
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+ auto context = std::make_shared<TracerContext>(std::move(processors));
+ auto resource = opentelemetry::sdk::resource::Resource::Create({});
+ auto tracer = std::shared_ptr<opentelemetry::trace::Tracer>(new Tracer(context));
+
+ while (state.KeepRunning())
+ {
+ auto span = tracer->StartSpan("span");
+
+ span->SetAttribute("attr1", 3.1);
+
+ span->End();
+ }
+}
+
+// Test to measure performance for span creation
+void BM_SpanCreation(benchmark::State &state)
+{
+ BenchmarkSpanCreation(std::move(std::make_shared<AlwaysOnSampler>()), state);
+}
+BENCHMARK(BM_SpanCreation);
+
+// Test to measure performance overhead for no-op span creation
+void BM_NoopSpanCreation(benchmark::State &state)
+{
+ BenchmarkSpanCreation(std::move(std::make_shared<AlwaysOffSampler>()), state);
+}
+BENCHMARK(BM_NoopSpanCreation);
+
+} // namespace
+BENCHMARK_MAIN();
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/simple_processor_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/simple_processor_test.cc
new file mode 100644
index 000000000..9398b922a
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/simple_processor_test.cc
@@ -0,0 +1,75 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/simple_processor.h"
+#include "opentelemetry/exporters/memory/in_memory_span_exporter.h"
+#include "opentelemetry/nostd/span.h"
+#include "opentelemetry/sdk/trace/exporter.h"
+#include "opentelemetry/sdk/trace/span_data.h"
+
+#include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::trace;
+using namespace opentelemetry::sdk::common;
+using opentelemetry::exporter::memory::InMemorySpanData;
+using opentelemetry::exporter::memory::InMemorySpanExporter;
+using opentelemetry::trace::SpanContext;
+
+TEST(SimpleProcessor, ToInMemorySpanExporter)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ SimpleSpanProcessor processor(std::move(exporter));
+
+ auto recordable = processor.MakeRecordable();
+
+ processor.OnStart(*recordable, SpanContext::GetInvalid());
+
+ ASSERT_EQ(0, span_data->GetSpans().size());
+
+ processor.OnEnd(std::move(recordable));
+
+ ASSERT_EQ(1, span_data->GetSpans().size());
+
+ EXPECT_TRUE(processor.Shutdown());
+}
+
+// An exporter that does nothing but record (and give back ) the # of times Shutdown was called.
+class RecordShutdownExporter final : public SpanExporter
+{
+public:
+ RecordShutdownExporter(int *shutdown_counter) : shutdown_counter_(shutdown_counter) {}
+
+ std::unique_ptr<Recordable> MakeRecordable() noexcept override
+ {
+ return std::unique_ptr<Recordable>(new SpanData());
+ }
+
+ ExportResult Export(
+ const opentelemetry::nostd::span<std::unique_ptr<Recordable>> &recordables) noexcept override
+ {
+ return ExportResult::kSuccess;
+ }
+
+ bool Shutdown(
+ std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override
+ {
+ *shutdown_counter_ += 1;
+ return true;
+ }
+
+private:
+ int *shutdown_counter_;
+};
+
+TEST(SimpleSpanProcessor, ShutdownCalledOnce)
+{
+ int shutdowns = 0;
+ std::unique_ptr<RecordShutdownExporter> exporter(new RecordShutdownExporter(&shutdowns));
+ SimpleSpanProcessor processor(std::move(exporter));
+ EXPECT_EQ(0, shutdowns);
+ processor.Shutdown();
+ EXPECT_EQ(1, shutdowns);
+ processor.Shutdown();
+ EXPECT_EQ(1, shutdowns);
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/span_data_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/span_data_test.cc
new file mode 100644
index 000000000..7a6c66c91
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/span_data_test.cc
@@ -0,0 +1,135 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/span_data.h"
+#include "opentelemetry/nostd/variant.h"
+#include "opentelemetry/trace/span.h"
+#include "opentelemetry/trace/span_id.h"
+#include "opentelemetry/trace/trace_id.h"
+
+#include <gtest/gtest.h>
+
+using opentelemetry::sdk::trace::SpanData;
+namespace trace_api = opentelemetry::trace;
+namespace common = opentelemetry::common;
+namespace nostd = opentelemetry::nostd;
+
+TEST(SpanData, DefaultValues)
+{
+ trace_api::SpanContext empty_span_context{false, false};
+ trace_api::SpanId zero_span_id;
+ SpanData data;
+
+ ASSERT_EQ(data.GetTraceId(), empty_span_context.trace_id());
+ ASSERT_EQ(data.GetSpanId(), empty_span_context.span_id());
+ ASSERT_EQ(data.GetSpanContext(), empty_span_context);
+ ASSERT_EQ(data.GetParentSpanId(), zero_span_id);
+ ASSERT_EQ(data.GetName(), "");
+ ASSERT_EQ(data.GetStatus(), trace_api::StatusCode::kUnset);
+ ASSERT_EQ(data.GetDescription(), "");
+ ASSERT_EQ(data.GetStartTime().time_since_epoch(), std::chrono::nanoseconds(0));
+ ASSERT_EQ(data.GetDuration(), std::chrono::nanoseconds(0));
+ ASSERT_EQ(data.GetAttributes().size(), 0);
+ ASSERT_EQ(data.GetEvents().size(), 0);
+}
+
+TEST(SpanData, Set)
+{
+ constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
+ constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ constexpr uint8_t parent_span_id_buf[] = {8, 7, 6, 5, 4, 3, 2, 1};
+ trace_api::TraceId trace_id{trace_id_buf};
+ trace_api::SpanId span_id{span_id_buf};
+ trace_api::SpanId parent_span_id{parent_span_id_buf};
+ const auto trace_state = trace_api::TraceState::GetDefault()->Set("key1", "value");
+ const trace_api::SpanContext span_context{
+ trace_id, span_id, trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled}, true,
+ trace_state};
+ common::SystemTimestamp now(std::chrono::system_clock::now());
+
+ SpanData data;
+ data.SetIdentity(span_context, parent_span_id);
+ data.SetName("span name");
+ data.SetSpanKind(trace_api::SpanKind::kServer);
+ data.SetStatus(trace_api::StatusCode::kOk, "description");
+ data.SetStartTime(now);
+ data.SetDuration(std::chrono::nanoseconds(1000000));
+ data.SetAttribute("attr1", (int64_t)314159);
+ data.AddEvent("event1", now);
+
+ ASSERT_EQ(data.GetTraceId(), trace_id);
+ ASSERT_EQ(data.GetSpanId(), span_id);
+ ASSERT_EQ(data.GetSpanContext(), span_context);
+ std::string trace_state_key1_value;
+ ASSERT_EQ(data.GetSpanContext().trace_state()->Get("key1", trace_state_key1_value), true);
+ ASSERT_EQ(trace_state_key1_value, "value");
+ ASSERT_EQ(data.GetParentSpanId(), parent_span_id);
+ ASSERT_EQ(data.GetName(), "span name");
+ ASSERT_EQ(data.GetSpanKind(), trace_api::SpanKind::kServer);
+ ASSERT_EQ(data.GetStatus(), trace_api::StatusCode::kOk);
+ ASSERT_EQ(data.GetDescription(), "description");
+ ASSERT_EQ(data.GetStartTime().time_since_epoch(), now.time_since_epoch());
+ ASSERT_EQ(data.GetDuration(), std::chrono::nanoseconds(1000000));
+ ASSERT_EQ(nostd::get<int64_t>(data.GetAttributes().at("attr1")), 314159);
+ ASSERT_EQ(data.GetEvents().at(0).GetName(), "event1");
+ ASSERT_EQ(data.GetEvents().at(0).GetTimestamp(), now);
+}
+
+TEST(SpanData, EventAttributes)
+{
+ SpanData data;
+ const int kNumAttributes = 3;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"};
+ int64_t values[kNumAttributes] = {3, 5, 20};
+ std::map<std::string, int64_t> attributes = {
+ {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}};
+
+ data.AddEvent("Test Event", std::chrono::system_clock::now(),
+ common::KeyValueIterableView<std::map<std::string, int64_t>>(attributes));
+
+ for (int i = 0; i < kNumAttributes; i++)
+ {
+ EXPECT_EQ(nostd::get<int64_t>(data.GetEvents().at(0).GetAttributes().at(keys[i])), values[i]);
+ }
+}
+
+TEST(SpanData, Resources)
+{
+ SpanData data;
+ auto resource = opentelemetry::sdk::resource::Resource::Create({});
+ auto input_attr = resource.GetAttributes();
+ data.SetResource(resource);
+ auto output_attr = data.GetResource().GetAttributes();
+ EXPECT_EQ(input_attr, output_attr);
+}
+
+TEST(SpanData, Links)
+{
+ SpanData data;
+ const int kNumAttributes = 3;
+ std::string keys[kNumAttributes] = {"attr1", "attr2", "attr3"};
+ int64_t values[kNumAttributes] = {4, 12, 33};
+ std::map<std::string, int64_t> attributes = {
+ {keys[0], values[0]}, {keys[1], values[1]}, {keys[2], values[2]}};
+
+ // produce valid SpanContext with pseudo span and trace Id.
+ uint8_t span_id_buf[trace_api::SpanId::kSize] = {
+ 1,
+ };
+ trace_api::SpanId span_id{span_id_buf};
+ uint8_t trace_id_buf[trace_api::TraceId::kSize] = {
+ 2,
+ };
+ trace_api::TraceId trace_id{trace_id_buf};
+ const auto span_context = trace_api::SpanContext(
+ trace_id, span_id, trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled}, true);
+
+ data.AddLink(span_context,
+ common::KeyValueIterableView<std::map<std::string, int64_t>>(attributes));
+
+ EXPECT_EQ(data.GetLinks().at(0).GetSpanContext(), span_context);
+ for (int i = 0; i < kNumAttributes; i++)
+ {
+ EXPECT_EQ(nostd::get<int64_t>(data.GetLinks().at(0).GetAttributes().at(keys[i])), values[i]);
+ }
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/trace_id_ratio_sampler_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/trace_id_ratio_sampler_test.cc
new file mode 100644
index 000000000..1b0088f13
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/trace_id_ratio_sampler_test.cc
@@ -0,0 +1,258 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/samplers/trace_id_ratio.h"
+#include "opentelemetry/trace/span_context_kv_iterable_view.h"
+#include "src/common/random.h"
+
+#include <gtest/gtest.h>
+#include <cstdlib>
+#include <ctime>
+
+using opentelemetry::sdk::common::Random;
+using opentelemetry::sdk::trace::Decision;
+using opentelemetry::sdk::trace::TraceIdRatioBasedSampler;
+namespace trace_api = opentelemetry::trace;
+namespace common = opentelemetry::common;
+
+namespace
+{
+/*
+ * Helper function for running TraceIdBased sampler tests.
+ * Given a span context, sampler, and number of iterations this function
+ * will return the number of RECORD_AND_SAMPLE decision based on randomly
+ * generated traces.
+ *
+ * @param context a required valid span context
+ * @param sampler a required valid sampler
+ * @param iterations a required number specifying the number of times to
+ * generate a random trace_id and check if it should sample using the provided
+ * provider and context
+ */
+int RunShouldSampleCountDecision(trace_api::SpanContext &context,
+ TraceIdRatioBasedSampler &sampler,
+ int iterations)
+{
+ int actual_count = 0;
+
+ trace_api::SpanKind span_kind = trace_api::SpanKind::kInternal;
+
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ uint8_t buf[16] = {0};
+ Random::GenerateRandomBuffer(buf);
+
+ trace_api::TraceId trace_id(buf);
+
+ auto result = sampler.ShouldSample(context, trace_id, "", span_kind, view, links);
+ if (result.decision == Decision::RECORD_AND_SAMPLE)
+ {
+ ++actual_count;
+ }
+ }
+
+ return actual_count;
+}
+} // namespace
+
+TEST(TraceIdRatioBasedSampler, ShouldSampleWithoutContext)
+{
+ trace_api::TraceId invalid_trace_id;
+
+ trace_api::SpanKind span_kind = trace_api::SpanKind::kInternal;
+
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+
+ TraceIdRatioBasedSampler s1(0.01);
+
+ auto sampling_result = s1.ShouldSample(trace_api::SpanContext::GetInvalid(), invalid_trace_id, "",
+ span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ constexpr uint8_t buf[] = {0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0};
+ trace_api::TraceId valid_trace_id(buf);
+
+ sampling_result = s1.ShouldSample(trace_api::SpanContext::GetInvalid(), valid_trace_id, "",
+ span_kind, view, links);
+
+ ASSERT_EQ(Decision::DROP, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ TraceIdRatioBasedSampler s2(0.50000001);
+
+ sampling_result = s2.ShouldSample(trace_api::SpanContext::GetInvalid(), valid_trace_id, "",
+ span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ TraceIdRatioBasedSampler s3(0.49999999);
+
+ sampling_result = s3.ShouldSample(trace_api::SpanContext::GetInvalid(), valid_trace_id, "",
+ span_kind, view, links);
+
+ ASSERT_EQ(Decision::DROP, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ TraceIdRatioBasedSampler s4(0.50000000);
+
+ sampling_result = s4.ShouldSample(trace_api::SpanContext::GetInvalid(), valid_trace_id, "",
+ span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+}
+
+TEST(TraceIdRatioBasedSampler, ShouldSampleWithContext)
+{
+
+ uint8_t trace_id_buffer[trace_api::TraceId::kSize] = {1};
+ trace_api::TraceId trace_id{trace_id_buffer};
+ uint8_t span_id_buffer[trace_api::SpanId::kSize] = {1};
+ trace_api::SpanId span_id{span_id_buffer};
+
+ trace_api::SpanKind span_kind = trace_api::SpanKind::kInternal;
+ trace_api::SpanContext c1(trace_id, span_id, trace_api::TraceFlags{0}, false);
+ trace_api::SpanContext c2(trace_id, span_id, trace_api::TraceFlags{1}, false);
+ trace_api::SpanContext c3(trace_id, span_id, trace_api::TraceFlags{0}, true);
+ trace_api::SpanContext c4(trace_id, span_id, trace_api::TraceFlags{1}, true);
+
+ using M = std::map<std::string, int>;
+ M m1 = {{}};
+
+ using L = std::vector<std::pair<trace_api::SpanContext, std::map<std::string, std::string>>>;
+ L l1 = {{trace_api::SpanContext(false, false), {}}, {trace_api::SpanContext(false, false), {}}};
+
+ common::KeyValueIterableView<M> view{m1};
+ trace_api::SpanContextKeyValueIterableView<L> links{l1};
+
+ TraceIdRatioBasedSampler s1(0.01);
+
+ auto sampling_result = s1.ShouldSample(c1, trace_id, "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ sampling_result = s1.ShouldSample(c2, trace_id, "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ sampling_result = s1.ShouldSample(c3, trace_id, "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+
+ sampling_result = s1.ShouldSample(c4, trace_id, "", span_kind, view, links);
+
+ ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision);
+ ASSERT_EQ(nullptr, sampling_result.attributes);
+}
+
+TEST(TraceIdRatioBasedSampler, TraceIdRatioBasedSamplerHalf)
+{
+ double ratio = 0.5;
+ int iterations = 100000;
+ int expected_count = static_cast<int>(iterations * ratio);
+ int variance = static_cast<int>(iterations * 0.01);
+
+ trace_api::SpanContext c(true, true);
+ TraceIdRatioBasedSampler s(ratio);
+
+ int actual_count = RunShouldSampleCountDecision(c, s, iterations);
+
+ ASSERT_TRUE(actual_count < (expected_count + variance));
+ ASSERT_TRUE(actual_count > (expected_count - variance));
+}
+
+TEST(TraceIdRatioBasedSampler, TraceIdRatioBasedSamplerOnePercent)
+{
+ double ratio = 0.01;
+ int iterations = 100000;
+ int expected_count = static_cast<int>(iterations * ratio);
+ int variance = static_cast<int>(iterations * 0.01);
+
+ trace_api::SpanContext c(true, true);
+ TraceIdRatioBasedSampler s(ratio);
+
+ int actual_count = RunShouldSampleCountDecision(c, s, iterations);
+
+ ASSERT_TRUE(actual_count < (expected_count + variance));
+ ASSERT_TRUE(actual_count > (expected_count - variance));
+}
+
+TEST(TraceIdRatioBasedSampler, TraceIdRatioBasedSamplerAll)
+{
+ double ratio = 1.0;
+ int iterations = 100000;
+ int expected_count = static_cast<int>(iterations * ratio);
+
+ trace_api::SpanContext c(true, true);
+ TraceIdRatioBasedSampler s(ratio);
+
+ int actual_count = RunShouldSampleCountDecision(c, s, iterations);
+
+ ASSERT_EQ(actual_count, expected_count);
+}
+
+TEST(TraceIdRatioBasedSampler, TraceIdRatioBasedSamplerNone)
+{
+ double ratio = 0.0;
+ int iterations = 100000;
+ int expected_count = static_cast<int>(iterations * ratio);
+
+ trace_api::SpanContext c(true, true);
+ TraceIdRatioBasedSampler s(ratio);
+
+ int actual_count = RunShouldSampleCountDecision(c, s, iterations);
+
+ ASSERT_EQ(actual_count, expected_count);
+}
+
+TEST(TraceIdRatioBasedSampler, GetDescription)
+{
+ TraceIdRatioBasedSampler s1(0.01);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.010000}", s1.GetDescription());
+
+ TraceIdRatioBasedSampler s2(0.00);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.000000}", s2.GetDescription());
+
+ TraceIdRatioBasedSampler s3(1.00);
+ ASSERT_EQ("TraceIdRatioBasedSampler{1.000000}", s3.GetDescription());
+
+ TraceIdRatioBasedSampler s4(0.102030405);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.102030}", s4.GetDescription());
+
+ TraceIdRatioBasedSampler s5(3.00);
+ ASSERT_EQ("TraceIdRatioBasedSampler{1.000000}", s5.GetDescription());
+
+ TraceIdRatioBasedSampler s6(-3.00);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.000000}", s6.GetDescription());
+
+ TraceIdRatioBasedSampler s7(1.00000000001);
+ ASSERT_EQ("TraceIdRatioBasedSampler{1.000000}", s7.GetDescription());
+
+ TraceIdRatioBasedSampler s8(-1.00000000001);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.000000}", s8.GetDescription());
+
+ TraceIdRatioBasedSampler s9(0.50);
+ ASSERT_EQ("TraceIdRatioBasedSampler{0.500000}", s9.GetDescription());
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_provider_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_provider_test.cc
new file mode 100644
index 000000000..498f66127
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_provider_test.cc
@@ -0,0 +1,99 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/tracer_provider.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/samplers/always_off.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/simple_processor.h"
+#include "opentelemetry/sdk/trace/tracer.h"
+
+#include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::trace;
+using namespace opentelemetry::sdk::resource;
+
+#include <iostream>
+
+TEST(TracerProvider, GetTracer)
+{
+ std::unique_ptr<SpanProcessor> processor(new SimpleSpanProcessor(nullptr));
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+ TracerProvider tp1(std::make_shared<TracerContext>(std::move(processors), Resource::Create({})));
+ auto t1 = tp1.GetTracer("test");
+ auto t2 = tp1.GetTracer("test");
+ auto t3 = tp1.GetTracer("different", "1.0.0");
+ auto t4 = tp1.GetTracer("");
+ auto t5 = tp1.GetTracer(opentelemetry::nostd::string_view{});
+ auto t6 = tp1.GetTracer("different", "1.0.0", "https://opentelemetry.io/schemas/1.2.0");
+ ASSERT_NE(nullptr, t1);
+ ASSERT_NE(nullptr, t2);
+ ASSERT_NE(nullptr, t3);
+ ASSERT_NE(nullptr, t6);
+
+ // Should return the same instance each time.
+ ASSERT_EQ(t1, t2);
+ ASSERT_NE(t1, t3);
+ ASSERT_EQ(t4, t5);
+ ASSERT_NE(t3, t6);
+
+ // Should be an sdk::trace::Tracer with the processor attached.
+#ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto sdkTracer1 = dynamic_cast<Tracer *>(t1.get());
+#else
+ auto sdkTracer1 = static_cast<Tracer *>(t1.get());
+#endif
+ ASSERT_NE(nullptr, sdkTracer1);
+ ASSERT_EQ("AlwaysOnSampler", sdkTracer1->GetSampler().GetDescription());
+ std::unique_ptr<SpanProcessor> processor2(new SimpleSpanProcessor(nullptr));
+ std::vector<std::unique_ptr<SpanProcessor>> processors2;
+ processors2.push_back(std::move(processor2));
+ TracerProvider tp2(
+ std::make_shared<TracerContext>(std::move(processors2), Resource::Create({}),
+ std::unique_ptr<Sampler>(new AlwaysOffSampler()),
+ std::unique_ptr<IdGenerator>(new RandomIdGenerator)));
+#ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto sdkTracer2 = dynamic_cast<Tracer *>(tp2.GetTracer("test").get());
+#else
+ auto sdkTracer2 = static_cast<Tracer *>(tp2.GetTracer("test").get());
+#endif
+ ASSERT_EQ("AlwaysOffSampler", sdkTracer2->GetSampler().GetDescription());
+
+ auto instrumentation_library1 = sdkTracer1->GetInstrumentationLibrary();
+ ASSERT_EQ(instrumentation_library1.GetName(), "test");
+ ASSERT_EQ(instrumentation_library1.GetVersion(), "");
+
+ // Should be an sdk::trace::Tracer with the processor attached.
+#ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto sdkTracer3 = dynamic_cast<Tracer *>(t3.get());
+#else
+ auto sdkTracer3 = static_cast<Tracer *>(t3.get());
+#endif
+ auto instrumentation_library3 = sdkTracer3->GetInstrumentationLibrary();
+ ASSERT_EQ(instrumentation_library3.GetName(), "different");
+ ASSERT_EQ(instrumentation_library3.GetVersion(), "1.0.0");
+}
+
+TEST(TracerProvider, Shutdown)
+{
+ std::unique_ptr<SpanProcessor> processor(new SimpleSpanProcessor(nullptr));
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+
+ TracerProvider tp1(std::make_shared<TracerContext>(std::move(processors)));
+
+ EXPECT_TRUE(tp1.Shutdown());
+
+ // It's safe to shutdown again
+ EXPECT_TRUE(tp1.Shutdown());
+}
+
+TEST(TracerProvider, ForceFlush)
+{
+ std::unique_ptr<SpanProcessor> processor1(new SimpleSpanProcessor(nullptr));
+
+ TracerProvider tp1(std::move(processor1));
+
+ EXPECT_TRUE(tp1.ForceFlush());
+}
diff --git a/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_test.cc b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_test.cc
new file mode 100644
index 000000000..15a7566b9
--- /dev/null
+++ b/src/jaegertracing/opentelemetry-cpp/sdk/test/trace/tracer_test.cc
@@ -0,0 +1,731 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#include "opentelemetry/sdk/trace/tracer.h"
+#include "opentelemetry/exporters/memory/in_memory_span_exporter.h"
+#include "opentelemetry/sdk/resource/resource.h"
+#include "opentelemetry/sdk/trace/samplers/always_off.h"
+#include "opentelemetry/sdk/trace/samplers/always_on.h"
+#include "opentelemetry/sdk/trace/samplers/parent.h"
+#include "opentelemetry/sdk/trace/simple_processor.h"
+#include "opentelemetry/sdk/trace/span_data.h"
+#include "opentelemetry/trace/context.h"
+
+#include <gtest/gtest.h>
+
+using namespace opentelemetry::sdk::trace;
+using namespace opentelemetry::sdk::resource;
+using opentelemetry::common::SteadyTimestamp;
+using opentelemetry::common::SystemTimestamp;
+namespace nostd = opentelemetry::nostd;
+namespace common = opentelemetry::common;
+using opentelemetry::common::KeyValueIterableView;
+using opentelemetry::exporter::memory::InMemorySpanData;
+using opentelemetry::exporter::memory::InMemorySpanExporter;
+using opentelemetry::trace::SpanContext;
+
+/**
+ * A mock sampler with ShouldSample returning:
+ * Decision::RECORD_AND_SAMPLE if trace_id is valid
+ * Decision::DROP otherwise.
+ */
+class MockSampler final : public Sampler
+{
+public:
+ SamplingResult ShouldSample(
+ const SpanContext & /*parent_context*/,
+ trace_api::TraceId trace_id,
+ nostd::string_view /*name*/,
+ trace_api::SpanKind /*span_kind*/,
+ const opentelemetry::common::KeyValueIterable & /*attributes*/,
+ const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override
+ {
+ // Sample only if valid trace_id ( This is to test Sampler get's valid trace id)
+ if (trace_id.IsValid())
+ {
+ // Return two pairs of attributes. These attributes should be added to the
+ // span attributes
+ return {Decision::RECORD_AND_SAMPLE,
+ nostd::unique_ptr<const std::map<std::string, opentelemetry::common::AttributeValue>>(
+ new const std::map<std::string, opentelemetry::common::AttributeValue>(
+ {{"sampling_attr1", 123}, {"sampling_attr2", "string"}}))};
+ }
+ else
+ {
+ // we should never reach here
+ assert(false);
+ return {Decision::DROP};
+ }
+ }
+
+ nostd::string_view GetDescription() const noexcept override { return "MockSampler"; }
+};
+
+/**
+ * A Mock Custom Id Generator
+ */
+class MockIdGenerator : public IdGenerator
+{
+ opentelemetry::trace::SpanId GenerateSpanId() noexcept override
+ {
+ return opentelemetry::trace::SpanId(buf_span);
+ }
+
+ opentelemetry::trace::TraceId GenerateTraceId() noexcept override
+ {
+ return opentelemetry::trace::TraceId(buf_trace);
+ }
+ uint8_t buf_span[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ uint8_t buf_trace[16] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1};
+};
+
+namespace
+{
+std::shared_ptr<opentelemetry::trace::Tracer> initTracer(std::unique_ptr<SpanExporter> &&exporter)
+{
+ auto processor = std::unique_ptr<SpanProcessor>(new SimpleSpanProcessor(std::move(exporter)));
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+ auto context = std::make_shared<TracerContext>(std::move(processors));
+ return std::shared_ptr<opentelemetry::trace::Tracer>(new Tracer(context));
+}
+
+std::shared_ptr<opentelemetry::trace::Tracer> initTracer(
+ std::unique_ptr<SpanExporter> &&exporter,
+ // For testing, just shove a pointer over, we'll take it over.
+ Sampler *sampler,
+ IdGenerator *id_generator = new RandomIdGenerator)
+{
+ auto processor = std::unique_ptr<SpanProcessor>(new SimpleSpanProcessor(std::move(exporter)));
+ std::vector<std::unique_ptr<SpanProcessor>> processors;
+ processors.push_back(std::move(processor));
+ auto resource = Resource::Create({});
+ auto context = std::make_shared<TracerContext>(std::move(processors), resource,
+ std::unique_ptr<Sampler>(sampler),
+ std::unique_ptr<IdGenerator>(id_generator));
+ return std::shared_ptr<opentelemetry::trace::Tracer>(new Tracer(context));
+}
+
+} // namespace
+
+TEST(Tracer, ToInMemorySpanExporter)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ auto span_first = tracer->StartSpan("span 1");
+ auto scope_first = tracer->WithActiveSpan(span_first);
+ auto span_second = tracer->StartSpan("span 2");
+
+ ASSERT_EQ(0, span_data->GetSpans().size());
+
+ span_second->End();
+
+ auto span2 = span_data->GetSpans();
+ ASSERT_EQ(1, span2.size());
+ ASSERT_EQ("span 2", span2.at(0)->GetName());
+ EXPECT_TRUE(span2.at(0)->GetTraceId().IsValid());
+ EXPECT_TRUE(span2.at(0)->GetSpanId().IsValid());
+ EXPECT_TRUE(span2.at(0)->GetParentSpanId().IsValid());
+
+ span_first->End();
+
+ auto span1 = span_data->GetSpans();
+ ASSERT_EQ(1, span1.size());
+ ASSERT_EQ("span 1", span1.at(0)->GetName());
+ EXPECT_TRUE(span1.at(0)->GetTraceId().IsValid());
+ EXPECT_TRUE(span1.at(0)->GetSpanId().IsValid());
+ EXPECT_FALSE(span1.at(0)->GetParentSpanId().IsValid());
+
+ // Verify trace and parent span id propagation
+ EXPECT_EQ(span1.at(0)->GetTraceId(), span2.at(0)->GetTraceId());
+ EXPECT_EQ(span2.at(0)->GetParentSpanId(), span1.at(0)->GetSpanId());
+}
+
+TEST(Tracer, StartSpanSampleOn)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer_on = initTracer(std::move(exporter));
+
+ tracer_on->StartSpan("span 1")->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &cur_span_data = spans.at(0);
+ ASSERT_LT(std::chrono::nanoseconds(0), cur_span_data->GetStartTime().time_since_epoch());
+ ASSERT_LT(std::chrono::nanoseconds(0), cur_span_data->GetDuration());
+}
+
+TEST(Tracer, StartSpanSampleOff)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer_off = initTracer(std::move(exporter), new AlwaysOffSampler());
+
+ // This span will not be recorded.
+ auto span = tracer_off->StartSpan("span 2");
+
+ // Always generate a valid span-context (span-id)
+ auto context = span->GetContext();
+ EXPECT_TRUE(context.IsValid());
+ EXPECT_FALSE(context.IsSampled());
+
+ span->End();
+ // The span doesn't write any span data because the sampling decision is alway
+ // DROP.
+ ASSERT_EQ(0, span_data->GetSpans().size());
+}
+
+TEST(Tracer, StartSpanCustomIdGenerator)
+{
+ IdGenerator *id_generator = new MockIdGenerator();
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter), new AlwaysOnSampler(), id_generator);
+
+ tracer->StartSpan("span 1")->End();
+ auto spans = span_data->GetSpans();
+ auto &cur_span_data = spans.at(0);
+
+ EXPECT_EQ(cur_span_data->GetTraceId(), id_generator->GenerateTraceId());
+ EXPECT_EQ(cur_span_data->GetSpanId(), id_generator->GenerateSpanId());
+}
+
+TEST(Tracer, StartSpanWithOptionsTime)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ opentelemetry::trace::StartSpanOptions start;
+ start.start_system_time = SystemTimestamp(std::chrono::nanoseconds(300));
+ start.start_steady_time = SteadyTimestamp(std::chrono::nanoseconds(10));
+
+ opentelemetry::trace::EndSpanOptions end;
+ end.end_steady_time = SteadyTimestamp(std::chrono::nanoseconds(40));
+
+ tracer->StartSpan("span 1", start)->End(end);
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &cur_span_data = spans.at(0);
+ ASSERT_EQ(std::chrono::nanoseconds(300), cur_span_data->GetStartTime().time_since_epoch());
+ ASSERT_EQ(std::chrono::nanoseconds(30), cur_span_data->GetDuration());
+}
+
+TEST(Tracer, StartSpanWithAttributes)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ // Start a span with all supported scalar attribute types.
+ tracer
+ ->StartSpan("span 1", {{"attr1", "string"},
+ {"attr2", false},
+ {"attr1", 314159},
+ {"attr3", (unsigned int)314159},
+ {"attr4", (int32_t)-20},
+ {"attr5", (uint32_t)20},
+ {"attr6", (int64_t)-20},
+ {"attr7", (uint64_t)20},
+ {"attr8", 3.1},
+ {"attr9", "string"}})
+ ->End();
+
+ // Start a span with all supported array attribute types.
+ int listInt[] = {1, 2, 3};
+ unsigned int listUInt[] = {1, 2, 3};
+ int32_t listInt32[] = {1, -2, 3};
+ uint32_t listUInt32[] = {1, 2, 3};
+ int64_t listInt64[] = {1, -2, 3};
+ uint64_t listUInt64[] = {1, 2, 3};
+ double listDouble[] = {1.1, 2.1, 3.1};
+ bool listBool[] = {true, false};
+ nostd::string_view listStringView[] = {"a", "b"};
+ std::map<std::string, common::AttributeValue> m;
+ m["attr1"] = nostd::span<int>(listInt);
+ m["attr2"] = nostd::span<unsigned int>(listUInt);
+ m["attr3"] = nostd::span<int32_t>(listInt32);
+ m["attr4"] = nostd::span<uint32_t>(listUInt32);
+ m["attr5"] = nostd::span<int64_t>(listInt64);
+ m["attr6"] = nostd::span<uint64_t>(listUInt64);
+ m["attr7"] = nostd::span<double>(listDouble);
+ m["attr8"] = nostd::span<bool>(listBool);
+ m["attr9"] = nostd::span<nostd::string_view>(listStringView);
+
+ tracer->StartSpan("span 2", m)->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(2, spans.size());
+
+ auto &cur_span_data = spans.at(0);
+ ASSERT_EQ(9, cur_span_data->GetAttributes().size());
+ ASSERT_EQ(314159, nostd::get<int32_t>(cur_span_data->GetAttributes().at("attr1")));
+ ASSERT_EQ(false, nostd::get<bool>(cur_span_data->GetAttributes().at("attr2")));
+ ASSERT_EQ(314159, nostd::get<uint32_t>(cur_span_data->GetAttributes().at("attr3")));
+ ASSERT_EQ(-20, nostd::get<int32_t>(cur_span_data->GetAttributes().at("attr4")));
+ ASSERT_EQ(20, nostd::get<uint32_t>(cur_span_data->GetAttributes().at("attr5")));
+ ASSERT_EQ(-20, nostd::get<int64_t>(cur_span_data->GetAttributes().at("attr6")));
+ ASSERT_EQ(20, nostd::get<uint64_t>(cur_span_data->GetAttributes().at("attr7")));
+ ASSERT_EQ(3.1, nostd::get<double>(cur_span_data->GetAttributes().at("attr8")));
+ ASSERT_EQ("string", nostd::get<std::string>(cur_span_data->GetAttributes().at("attr9")));
+
+ auto &cur_span_data2 = spans.at(1);
+ ASSERT_EQ(9, cur_span_data2->GetAttributes().size());
+ ASSERT_EQ(std::vector<int32_t>({1, 2, 3}),
+ nostd::get<std::vector<int32_t>>(cur_span_data2->GetAttributes().at("attr1")));
+ ASSERT_EQ(std::vector<uint32_t>({1, 2, 3}),
+ nostd::get<std::vector<uint32_t>>(cur_span_data2->GetAttributes().at("attr2")));
+ ASSERT_EQ(std::vector<int32_t>({1, -2, 3}),
+ nostd::get<std::vector<int32_t>>(cur_span_data2->GetAttributes().at("attr3")));
+ ASSERT_EQ(std::vector<uint32_t>({1, 2, 3}),
+ nostd::get<std::vector<uint32_t>>(cur_span_data2->GetAttributes().at("attr4")));
+ ASSERT_EQ(std::vector<int64_t>({1, -2, 3}),
+ nostd::get<std::vector<int64_t>>(cur_span_data2->GetAttributes().at("attr5")));
+ ASSERT_EQ(std::vector<uint64_t>({1, 2, 3}),
+ nostd::get<std::vector<uint64_t>>(cur_span_data2->GetAttributes().at("attr6")));
+ ASSERT_EQ(std::vector<double>({1.1, 2.1, 3.1}),
+ nostd::get<std::vector<double>>(cur_span_data2->GetAttributes().at("attr7")));
+ ASSERT_EQ(std::vector<bool>({true, false}),
+ nostd::get<std::vector<bool>>(cur_span_data2->GetAttributes().at("attr8")));
+ ASSERT_EQ(std::vector<std::string>({"a", "b"}),
+ nostd::get<std::vector<std::string>>(cur_span_data2->GetAttributes().at("attr9")));
+}
+
+TEST(Tracer, StartSpanWithAttributesCopy)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ {
+ std::unique_ptr<std::vector<int64_t>> numbers(new std::vector<int64_t>);
+ numbers->push_back(1);
+ numbers->push_back(2);
+ numbers->push_back(3);
+
+ std::unique_ptr<std::vector<nostd::string_view>> strings(new std::vector<nostd::string_view>);
+ std::string s1("a");
+ std::string s2("b");
+ std::string s3("c");
+ strings->push_back(s1);
+ strings->push_back(s2);
+ strings->push_back(s3);
+ tracer
+ ->StartSpan("span 1",
+ {{"attr1", *numbers}, {"attr2", nostd::span<nostd::string_view>(*strings)}})
+ ->End();
+ }
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &cur_span_data = spans.at(0);
+ ASSERT_EQ(2, cur_span_data->GetAttributes().size());
+
+ auto numbers = nostd::get<std::vector<int64_t>>(cur_span_data->GetAttributes().at("attr1"));
+ ASSERT_EQ(3, numbers.size());
+ ASSERT_EQ(1, numbers[0]);
+ ASSERT_EQ(2, numbers[1]);
+ ASSERT_EQ(3, numbers[2]);
+
+ auto strings = nostd::get<std::vector<std::string>>(cur_span_data->GetAttributes().at("attr2"));
+ ASSERT_EQ(3, strings.size());
+ ASSERT_EQ("a", strings[0]);
+ ASSERT_EQ("b", strings[1]);
+ ASSERT_EQ("c", strings[2]);
+}
+
+TEST(Tracer, GetSampler)
+{
+ auto resource = Resource::Create({});
+ // Create a Tracer with a default AlwaysOnSampler
+ auto tracer_on = initTracer(nullptr);
+
+#ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto &t1 = std::dynamic_pointer_cast<Tracer>(tracer_on)->GetSampler();
+#else
+ auto &t1 = std::static_pointer_cast<Tracer>(tracer_on)->GetSampler();
+#endif
+ ASSERT_EQ("AlwaysOnSampler", t1.GetDescription());
+
+ // Create a Tracer with a AlwaysOffSampler
+ auto tracer_off = initTracer(nullptr, new AlwaysOffSampler());
+
+#ifdef OPENTELEMETRY_RTTI_ENABLED
+ auto &t2 = std::dynamic_pointer_cast<Tracer>(tracer_off)->GetSampler();
+#else
+ auto &t2 = std::static_pointer_cast<Tracer>(tracer_off)->GetSampler();
+#endif
+ ASSERT_EQ("AlwaysOffSampler", t2.GetDescription());
+}
+
+TEST(Tracer, SpanSetAttribute)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ auto span = tracer->StartSpan("span 1");
+
+ span->SetAttribute("abc", 3.1);
+
+ span->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+ auto &cur_span_data = spans.at(0);
+ ASSERT_EQ(3.1, nostd::get<double>(cur_span_data->GetAttributes().at("abc")));
+}
+
+TEST(Tracer, TestAfterEnd)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+ auto span = tracer->StartSpan("span 1");
+ span->SetAttribute("abc", 3.1);
+
+ span->End();
+
+ // test after end
+ span->SetAttribute("testing null recordable", 3.1);
+ span->AddEvent("event 1");
+ span->AddEvent("event 2", std::chrono::system_clock::now());
+ span->AddEvent("event 3", std::chrono::system_clock::now(), {{"attr1", 1}});
+ std::string new_name{"new name"};
+ span->UpdateName(new_name);
+ span->SetAttribute("attr1", 3.1);
+ std::string description{"description"};
+ span->SetStatus(opentelemetry::trace::StatusCode::kError, description);
+ span->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+ auto &cur_span_data = spans.at(0);
+ ASSERT_EQ(3.1, nostd::get<double>(cur_span_data->GetAttributes().at("abc")));
+}
+
+TEST(Tracer, SpanSetEvents)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ auto span = tracer->StartSpan("span 1");
+ span->AddEvent("event 1");
+ span->AddEvent("event 2", std::chrono::system_clock::now());
+ span->AddEvent("event 3", std::chrono::system_clock::now(), {{"attr1", 1}});
+ span->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &span_data_events = spans.at(0)->GetEvents();
+ ASSERT_EQ(3, span_data_events.size());
+ ASSERT_EQ("event 1", span_data_events[0].GetName());
+ ASSERT_EQ("event 2", span_data_events[1].GetName());
+ ASSERT_EQ("event 3", span_data_events[2].GetName());
+ ASSERT_EQ(0, span_data_events[0].GetAttributes().size());
+ ASSERT_EQ(0, span_data_events[1].GetAttributes().size());
+ ASSERT_EQ(1, span_data_events[2].GetAttributes().size());
+}
+
+TEST(Tracer, SpanSetLinks)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+
+ {
+
+ // Single span link passed through Initialization list
+ tracer->StartSpan("efg", {{"attr1", 1}}, {{SpanContext(false, false), {{"attr2", 2}}}})->End();
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &span_data_links = spans.at(0)->GetLinks();
+ ASSERT_EQ(1, span_data_links.size());
+ auto link = span_data_links.at(0);
+ ASSERT_EQ(nostd::get<int>(link.GetAttributes().at("attr2")), 2);
+ }
+ {
+
+ // Multiple span links passed through Initialization list
+ tracer
+ ->StartSpan("efg", {{"attr1", 1}},
+ {{SpanContext(false, false), {{"attr2", 2}}},
+ {SpanContext(false, false), {{"attr3", 3}}}})
+ ->End();
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &span_data_links = spans.at(0)->GetLinks();
+ ASSERT_EQ(2, span_data_links.size());
+ auto link1 = span_data_links.at(0);
+ ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr2")), 2);
+ auto link2 = span_data_links.at(1);
+ ASSERT_EQ(nostd::get<int>(link2.GetAttributes().at("attr3")), 3);
+ }
+
+ {
+
+ // Multiple links, each with multiple attributes passed through Initialization list
+ tracer
+ ->StartSpan("efg", {{"attr1", 1}},
+ {{SpanContext(false, false), {{"attr2", 2}, {"attr3", 3}}},
+ {SpanContext(false, false), {{"attr4", 4}}}})
+ ->End();
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+
+ auto &span_data_links = spans.at(0)->GetLinks();
+ ASSERT_EQ(2, span_data_links.size());
+ auto link1 = span_data_links.at(0);
+ ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr2")), 2);
+ ASSERT_EQ(nostd::get<int>(link1.GetAttributes().at("attr3")), 3);
+ auto link2 = span_data_links.at(1);
+ ASSERT_EQ(nostd::get<int>(link2.GetAttributes().at("attr4")), 4);
+ }
+
+ {
+ std::map<std::string, std::string> attrs1 = {{"attr1", "1"}, {"attr2", "2"}};
+ std::map<std::string, std::string> attrs2 = {{"attr3", "3"}, {"attr4", "4"}};
+
+ std::vector<std::pair<SpanContext, std::map<std::string, std::string>>> links = {
+ {SpanContext(false, false), attrs1}, {SpanContext(false, false), attrs2}};
+ tracer->StartSpan("efg", attrs1, links)->End();
+ auto spans = span_data->GetSpans();
+
+ auto &span_data_links = spans.at(0)->GetLinks();
+ ASSERT_EQ(2, span_data_links.size());
+ auto link1 = span_data_links.at(0);
+ ASSERT_EQ(nostd::get<std::string>(link1.GetAttributes().at("attr1")), "1");
+ ASSERT_EQ(nostd::get<std::string>(link1.GetAttributes().at("attr2")), "2");
+ auto link2 = span_data_links.at(1);
+ ASSERT_EQ(nostd::get<std::string>(link2.GetAttributes().at("attr3")), "3");
+ ASSERT_EQ(nostd::get<std::string>(link2.GetAttributes().at("attr4")), "4");
+ }
+}
+
+TEST(Tracer, TestAlwaysOnSampler)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer_on = initTracer(std::move(exporter));
+
+ // Testing AlwaysOn sampler.
+ // Create two spans for each tracer. Check the exported result.
+ auto span_on_1 = tracer_on->StartSpan("span 1");
+ auto span_on_2 = tracer_on->StartSpan("span 2");
+ span_on_2->End();
+ span_on_1->End();
+
+ auto spans = span_data->GetSpans();
+ ASSERT_EQ(2, spans.size());
+ ASSERT_EQ("span 2", spans.at(0)->GetName()); // span 2 ends first.
+ ASSERT_EQ("span 1", spans.at(1)->GetName());
+}
+
+TEST(Tracer, TestAlwaysOffSampler)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer_off = initTracer(std::move(exporter), new AlwaysOffSampler());
+ auto span_off_1 = tracer_off->StartSpan("span 1");
+ auto span_off_2 = tracer_off->StartSpan("span 2");
+
+ span_off_1->SetAttribute("attr1", 3.1); // Not recorded.
+
+ span_off_2->End();
+ span_off_1->End();
+
+ // The tracer export nothing with an AlwaysOff sampler
+ ASSERT_EQ(0, span_data->GetSpans().size());
+}
+
+TEST(Tracer, TestParentBasedSampler)
+{
+ // Current ShouldSample always pass an empty ParentContext,
+ // so this sampler will work as an AlwaysOnSampler.
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data_parent_on = exporter->GetData();
+ auto tracer_parent_on =
+ initTracer(std::move(exporter), new ParentBasedSampler(std::make_shared<AlwaysOnSampler>()));
+
+ auto span_parent_on_1 = tracer_parent_on->StartSpan("span 1");
+ auto span_parent_on_2 = tracer_parent_on->StartSpan("span 2");
+
+ span_parent_on_1->SetAttribute("attr1", 3.1);
+
+ span_parent_on_2->End();
+ span_parent_on_1->End();
+
+ auto spans = span_data_parent_on->GetSpans();
+ ASSERT_EQ(2, spans.size());
+ ASSERT_EQ("span 2", spans.at(0)->GetName());
+ ASSERT_EQ("span 1", spans.at(1)->GetName());
+
+ // Current ShouldSample always pass an empty ParentContext,
+ // so this sampler will work as an AlwaysOnSampler.
+ std::unique_ptr<InMemorySpanExporter> exporter2(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data_parent_off = exporter2->GetData();
+ auto tracer_parent_off =
+ initTracer(std::move(exporter2),
+ // Add this to avoid different results for old and new version of clang-format
+ new ParentBasedSampler(std::make_shared<AlwaysOffSampler>()));
+
+ auto span_parent_off_1 = tracer_parent_off->StartSpan("span 1");
+ auto span_parent_off_2 = tracer_parent_off->StartSpan("span 2");
+
+ span_parent_off_1->SetAttribute("attr1", 3.1);
+
+ span_parent_off_1->End();
+ span_parent_off_2->End();
+ ASSERT_EQ(0, span_data_parent_off->GetSpans().size());
+}
+
+TEST(Tracer, WithActiveSpan)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+ auto spans = span_data.get()->GetSpans();
+
+ ASSERT_EQ(0, spans.size());
+
+ {
+ auto span_first = tracer->StartSpan("span 1");
+ auto scope_first = tracer->WithActiveSpan(span_first);
+
+ {
+ auto span_second = tracer->StartSpan("span 2");
+ auto scope_second = tracer->WithActiveSpan(span_second);
+
+ spans = span_data->GetSpans();
+ ASSERT_EQ(0, spans.size());
+
+ span_second->End();
+ }
+
+ spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+ EXPECT_EQ("span 2", spans.at(0)->GetName());
+
+ span_first->End();
+ }
+
+ spans = span_data->GetSpans();
+ ASSERT_EQ(1, spans.size());
+ EXPECT_EQ("span 1", spans.at(0)->GetName());
+}
+
+TEST(Tracer, ExpectParent)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+ auto spans = span_data.get()->GetSpans();
+
+ ASSERT_EQ(0, spans.size());
+
+ auto span_first = tracer->StartSpan("span 1");
+
+ trace_api::StartSpanOptions options;
+ options.parent = span_first->GetContext();
+ auto span_second = tracer->StartSpan("span 2", options);
+
+ options.parent = span_second->GetContext();
+ auto span_third = tracer->StartSpan("span 3", options);
+
+ span_third->End();
+ span_second->End();
+ span_first->End();
+
+ spans = span_data->GetSpans();
+ ASSERT_EQ(3, spans.size());
+ auto spandata_first = std::move(spans.at(2));
+ auto spandata_second = std::move(spans.at(1));
+ auto spandata_third = std::move(spans.at(0));
+ EXPECT_EQ("span 1", spandata_first->GetName());
+ EXPECT_EQ("span 2", spandata_second->GetName());
+ EXPECT_EQ("span 3", spandata_third->GetName());
+
+ EXPECT_EQ(spandata_first->GetSpanId(), spandata_second->GetParentSpanId());
+ EXPECT_EQ(spandata_second->GetSpanId(), spandata_third->GetParentSpanId());
+}
+
+TEST(Tracer, ExpectParentAsContext)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+ auto spans = span_data.get()->GetSpans();
+
+ ASSERT_EQ(0, spans.size());
+
+ auto span_first = tracer->StartSpan("span 1");
+
+ opentelemetry::context::Context c1;
+ auto c2 = trace_api::SetSpan(c1, span_first);
+ trace_api::StartSpanOptions options;
+ options.parent = c2;
+ auto span_second = tracer->StartSpan("span 2", options);
+
+ auto c3 = trace_api::SetSpan(c2, span_second);
+ options.parent = c3;
+ auto span_third = tracer->StartSpan("span 3", options);
+
+ span_third->End();
+ span_second->End();
+ span_first->End();
+
+ spans = span_data->GetSpans();
+ ASSERT_EQ(3, spans.size());
+ auto spandata_first = std::move(spans.at(2));
+ auto spandata_second = std::move(spans.at(1));
+ auto spandata_third = std::move(spans.at(0));
+ EXPECT_EQ("span 1", spandata_first->GetName());
+ EXPECT_EQ("span 2", spandata_second->GetName());
+ EXPECT_EQ("span 3", spandata_third->GetName());
+
+ EXPECT_EQ(spandata_first->GetSpanId(), spandata_second->GetParentSpanId());
+ EXPECT_EQ(spandata_second->GetSpanId(), spandata_third->GetParentSpanId());
+}
+
+TEST(Tracer, ValidTraceIdToSampler)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter), new MockSampler());
+
+ auto span = tracer->StartSpan("span 1");
+ // sampler was fed with valid trace_id, so span shouldn't be NoOp Span.
+ EXPECT_TRUE(span->IsRecording());
+ EXPECT_TRUE(span->GetContext().IsValid());
+}
+
+TEST(Tracer, SpanCleanupWithScope)
+{
+ std::unique_ptr<InMemorySpanExporter> exporter(new InMemorySpanExporter());
+ std::shared_ptr<InMemorySpanData> span_data = exporter->GetData();
+ auto tracer = initTracer(std::move(exporter));
+ {
+ auto span0 = tracer->StartSpan("Span0");
+ auto span1 = tracer->StartSpan("span1");
+ {
+ trace_api::Scope scope(span1);
+ auto span2 = tracer->StartSpan("span2");
+ {
+ trace_api::Scope scope(span2);
+ auto span3 = tracer->StartSpan("span3");
+ }
+ }
+ }
+ EXPECT_EQ(4, span_data->GetSpans().size());
+}